Freeciv-3.1: /fast/freeciv/nightly/S3_1/client/servers.c Source File

Freeciv-3.1

Loading...
Searching...
No Matches
servers.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996-2005 - Freeciv Development Team
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include "fc_prehdrs.h"
19
20#include <errno.h>
21#include <stdlib.h>
22
23#ifdef FREECIV_HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26#ifdef HAVE_SYS_SOCKET_H
27#include <sys/socket.h>
28#endif
29#ifdef HAVE_NETINET_IN_H
30#include <netinet/in.h>
31#endif
32#ifdef HAVE_ARPA_INET_H
33#include <arpa/inet.h>
34#endif
35#ifdef HAVE_NETDB_H
36#include <netdb.h>
37#endif
38#ifdef HAVE_PWD_H
39#include <pwd.h>
40#endif
41#ifdef HAVE_SYS_SELECT_H
42#include <sys/select.h>
43#endif
44#ifdef HAVE_SYS_TIME_H
45#include <sys/time.h>
46#endif
47#ifdef HAVE_SYS_UIO_H
48#include <sys/uio.h>
49#endif
50#ifdef HAVE_UNISTD_H
51#include <unistd.h>
52#endif
53
54/* dependencies */
55#include "cvercmp.h"
56
57/* utility */
58#include "fcintl.h"
59#include "fcthread.h"
60#include "log.h"
61#include "mem.h"
62#include "netfile.h"
63#include "netintf.h"
64#include "rand.h" /* fc_rand() */
65#include "registry.h"
66#include "support.h"
67
68/* common */
69#include "capstr.h"
70#include "dataio.h"
71#include "game.h"
72#include "packets.h"
73#include "version.h"
74
75/* client */
76#include "chatline_common.h"
77#include "chatline_g.h"
78#include "client_main.h"
79#include "servers.h"
80
81#include "gui_main_g.h"
82
83 struct server_scan {
84 enum server_scan_type type;
85 ServerScanErrorFunc error_func;
86
87 struct srv_list srvrs;
88 int sock;
89
90#ifdef FREECIV_META_ENABLED
91 /* Only used for metaserver */
92 struct {
93 enum server_scan_status status;
94
95 fc_thread thr;
96 fc_mutex mutex;
97
98 const char *urlpath;
99 struct netfile_write_cb_data mem;
100 } meta;
101#endif /* FREECIV_META_ENABLED */
102};
103
104extern enum announce_type announce;
105
106static void delete_server_list(struct server_list *server_list);
107
108#ifdef FREECIV_META_ENABLED
109static bool begin_metaserver_scan(struct server_scan *scan);
110
111/**********************************************************************/
115static struct server_list *parse_metaserver_data(fz_FILE *f)
116{
117 struct server_list *server_list;
118 struct section_file *file;
119 int nservers, i, j;
120 const char *latest_ver;
121 const char *comment;
122
123 /* Have the string outside Q_() so it won't get collected for translation here.
124 * Actual collected string lives in translations/Strings.txt */
125#define QUALIFIED_FOLLOWTAG "?vertag:" FOLLOWTAG
126
127 /* This call closes f. */
128 if (!(file = secfile_from_stream(f, TRUE))) {
129 return NULL;
130 }
131
132 latest_ver = secfile_lookup_str_default(file, NULL, "versions." FOLLOWTAG);
133 comment = secfile_lookup_str_default(file, NULL, "version_comments." FOLLOWTAG);
134
135 if (latest_ver == NULL && comment == NULL) {
136 char vertext[2048];
137
138 fc_snprintf(vertext, sizeof(vertext),
139 /* TRANS: Type is version tag name like "stable", "S3_2",
140 * "windows" (which can also be localised -- msgids start
141 * '?vertag:') */
142 _("There's no %s release yet."), Q_(QUALIFIED_FOLLOWTAG));
143 log_verbose("%s", vertext);
144 version_message(vertext);
145 } else {
146 if (latest_ver != NULL) {
147 const char *my_comparable = fc_comparable_version();
148 char vertext[2048];
149
150 log_verbose("Metaserver says latest '" FOLLOWTAG "' version is '%s'; we have '%s'",
151 latest_ver, my_comparable);
152 if (cvercmp_greater(latest_ver, my_comparable)) {
153
154 fc_snprintf(vertext, sizeof(vertext),
155 /* TRANS: Type is version tag name like "stable", "S3_2",
156 * "windows" (which can also be localised -- msgids start
157 * '?vertag:') */
158 _("Latest %s release of Freeciv is %s, this is %s."),
159 Q_(QUALIFIED_FOLLOWTAG), latest_ver, my_comparable);
160
161 version_message(vertext);
162 } else if (comment == NULL) {
163 fc_snprintf(vertext, sizeof(vertext),
164 _("There is no newer %s release of Freeciv available."),
165 FOLLOWTAG);
166
167 version_message(vertext);
168 }
169 }
170
171 if (comment != NULL) {
172 log_verbose("Mesaserver comment about '" FOLLOWTAG "': %s", comment);
173 version_message(comment);
174 }
175 }
176
177 server_list = server_list_new();
178 nservers = secfile_lookup_int_default(file, 0, "main.nservers");
179
180 for (i = 0; i < nservers; i++) {
181 const char *host, *port, *version, *state, *message, *nplayers, *nhumans;
182 int n;
183 struct server *pserver = (struct server*)fc_malloc(sizeof(struct server));
184
185 host = secfile_lookup_str_default(file, "", "server%d.host", i);
186 pserver->host = fc_strdup(host);
187
188 port = secfile_lookup_str_default(file, "", "server%d.port", i);
189 pserver->port = atoi(port);
190
191 version = secfile_lookup_str_default(file, "", "server%d.version", i);
192 pserver->version = fc_strdup(version);
193
194 state = secfile_lookup_str_default(file, "", "server%d.state", i);
195 pserver->state = fc_strdup(state);
196
197 message = secfile_lookup_str_default(file, "", "server%d.message", i);
198 pserver->message = fc_strdup(message);
199
200 nplayers = secfile_lookup_str_default(file, "0", "server%d.nplayers", i);
201 n = atoi(nplayers);
202 pserver->nplayers = n;
203
204 nhumans = secfile_lookup_str_default(file, "-1", "server%d.humans", i);
205 n = atoi(nhumans);
206 pserver->humans = n;
207
208 if (pserver->nplayers > 0) {
209 pserver->players = fc_malloc(pserver->nplayers * sizeof(*pserver->players));
210 } else {
211 pserver->players = NULL;
212 }
213
214 for (j = 0; j < pserver->nplayers ; j++) {
215 const char *name, *nation, *type, *plrhost;
216
217 name = secfile_lookup_str_default(file, "",
218 "server%d.player%d.name", i, j);
219 pserver->players[j].name = fc_strdup(name);
220
221 type = secfile_lookup_str_default(file, "",
222 "server%d.player%d.type", i, j);
223 pserver->players[j].type = fc_strdup(type);
224
225 plrhost = secfile_lookup_str_default(file, "",
226 "server%d.player%d.host", i, j);
227 pserver->players[j].host = fc_strdup(plrhost);
228
229 nation = secfile_lookup_str_default(file, "",
230 "server%d.player%d.nation", i, j);
231 pserver->players[j].nation = fc_strdup(nation);
232 }
233
234 server_list_append(server_list, pserver);
235 }
236
237 secfile_destroy(file);
238
239 return server_list;
240}
241
242/**********************************************************************/
245static bool meta_read_response(struct server_scan *scan)
246{
247 fz_FILE *f;
248 char str[4096];
249 struct server_list *srvrs;
250
251 f = fz_from_memory(scan->meta.mem.mem, scan->meta.mem.size, TRUE);
252 if (NULL == f) {
253 fc_snprintf(str, sizeof(str),
254 _("Failed to read the metaserver data from %s."),
255 metaserver);
256 scan->error_func(scan, str);
257
258 return FALSE;
259 }
260
261 /* parse message body */
262 fc_allocate_mutex(&scan->srvrs.mutex);
263 srvrs = parse_metaserver_data(f);
264 scan->srvrs.servers = srvrs;
265 fc_release_mutex(&scan->srvrs.mutex);
266
267 /* 'f' (hence 'meta.mem.mem') was closed in parse_metaserver_data(). */
268 scan->meta.mem.mem = NULL;
269
270 if (NULL == srvrs) {
271 fc_snprintf(str, sizeof(str),
272 _("Failed to parse the metaserver data from %s:\n"
273 "%s."),
274 metaserver, secfile_error());
275 scan->error_func(scan, str);
276
277 return FALSE;
278 }
279
280 return TRUE;
281}
282
283/**********************************************************************/
286static void metaserver_scan(void *arg)
287{
288 struct server_scan *scan = arg;
289
290 if (!begin_metaserver_scan(scan)) {
291 fc_allocate_mutex(&scan->meta.mutex);
292 scan->meta.status = SCAN_STATUS_ERROR;
293 } else {
294 if (!meta_read_response(scan)) {
295 fc_allocate_mutex(&scan->meta.mutex);
296 scan->meta.status = SCAN_STATUS_ERROR;
297 } else {
298 fc_allocate_mutex(&scan->meta.mutex);
299 if (scan->meta.status == SCAN_STATUS_WAITING) {
300 scan->meta.status = SCAN_STATUS_DONE;
301 }
302 }
303 }
304
305 fc_release_mutex(&scan->meta.mutex);
306}
307
308/**********************************************************************/
314static bool begin_metaserver_scan(struct server_scan *scan)
315{
316 struct netfile_post *post;
317 bool retval = TRUE;
318
319 post = netfile_start_post();
320 netfile_add_form_str(post, "client_cap", our_capability);
321
322 if (!netfile_send_post(metaserver, post, NULL, &scan->meta.mem, NULL)) {
323 scan->error_func(scan, _("Error connecting to metaserver"));
324 retval = FALSE;
325 }
326
327 netfile_close_post(post);
328
329 return retval;
330}
331#endif /* FREECIV_META_ENABLED */
332
333/**********************************************************************/
338 static void delete_server_list(struct server_list *server_list)
339{
340 if (!server_list) {
341 return;
342 }
343
344 server_list_iterate(server_list, ptmp) {
345 int i;
346 int n = ptmp->nplayers;
347
348 free(ptmp->host);
349 free(ptmp->version);
350 free(ptmp->state);
351 free(ptmp->message);
352
353 if (ptmp->players) {
354 for (i = 0; i < n; i++) {
355 free(ptmp->players[i].name);
356 free(ptmp->players[i].type);
357 free(ptmp->players[i].host);
358 free(ptmp->players[i].nation);
359 }
360 free(ptmp->players);
361 }
362
363 free(ptmp);
364 } server_list_iterate_end;
365
366 server_list_destroy(server_list);
367}
368
369/**********************************************************************/
374 static bool begin_lanserver_scan(struct server_scan *scan)
375{
376 union fc_sockaddr addr;
377 struct raw_data_out dout;
378 int send_sock, opt = 1;
379#ifndef FREECIV_HAVE_WINSOCK
380 unsigned char buffer[MAX_LEN_PACKET];
381#else /* FREECIV_HAVE_WINSOCK */
382 char buffer[MAX_LEN_PACKET];
383#endif /* FREECIV_HAVE_WINSOCK */
384#ifdef HAVE_IP_MREQN
385 struct ip_mreqn mreq4;
386#else
387 struct ip_mreq mreq4;
388#endif
389 const char *group;
390 size_t size;
391 int family;
392
393#ifdef FREECIV_IPV6_SUPPORT
394 struct ipv6_mreq mreq6;
395#endif
396
397#ifndef FREECIV_HAVE_WINSOCK
398 unsigned char ttl;
399#endif
400
401 if (announce == ANNOUNCE_NONE) {
402 /* Succeeded in doing nothing */
403 return TRUE;
404 }
405
406#ifdef FREECIV_IPV6_SUPPORT
407 if (announce == ANNOUNCE_IPV6) {
408 family = AF_INET6;
409 } else
410#endif /* IPv6 support */
411 {
412 family = AF_INET;
413 }
414
415 /* Set the UDP Multicast group IP address. */
416 group = get_multicast_group(announce == ANNOUNCE_IPV6);
417
418 /* Create a socket for listening for server packets. */
419 if ((scan->sock = socket(family, SOCK_DGRAM, 0)) < 0) {
420 char errstr[2048];
421
422 fc_snprintf(errstr, sizeof(errstr),
423 _("Opening socket to listen LAN announcements failed:\n%s"),
424 fc_strerror(fc_get_errno()));
425 scan->error_func(scan, errstr);
426
427 return FALSE;
428 }
429
430 fc_nonblock(scan->sock);
431
432 if (setsockopt(scan->sock, SOL_SOCKET, SO_REUSEADDR,
433 (char *)&opt, sizeof(opt)) == -1) {
434 log_error("SO_REUSEADDR failed: %s", fc_strerror(fc_get_errno()));
435 }
436
437 memset(&addr, 0, sizeof(addr));
438
439#ifdef FREECIV_IPV6_SUPPORT
440 if (family == AF_INET6) {
441 addr.saddr.sa_family = AF_INET6;
442 addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT + 1);
443 addr.saddr_in6.sin6_addr = in6addr_any;
444 } else
445#endif /* IPv6 support */
446 if (family == AF_INET) {
447 addr.saddr.sa_family = AF_INET;
448 addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT + 1);
449 addr.saddr_in4.sin_addr.s_addr = htonl(INADDR_ANY);
450 } else {
451 /* This is not only error situation worth assert() This
452 * is error situation that has check (with assert) against
453 * earlier already. */
454 fc_assert(FALSE);
455
456 return FALSE;
457 }
458
459 if (bind(scan->sock, &addr.saddr, sockaddr_size(&addr)) < 0) {
460 char errstr[2048];
461
462 fc_snprintf(errstr, sizeof(errstr),
463 _("Binding socket to listen LAN announcements failed:\n%s"),
464 fc_strerror(fc_get_errno()));
465 scan->error_func(scan, errstr);
466
467 return FALSE;
468 }
469
470#ifdef FREECIV_IPV6_SUPPORT
471 if (family == AF_INET6) {
472 inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr.s6_addr);
473 mreq6.ipv6mr_interface = 0; /* TODO: Interface selection */
474
475 if (setsockopt(scan->sock, IPPROTO_IPV6, FC_IPV6_ADD_MEMBERSHIP,
476 (const char*)&mreq6, sizeof(mreq6)) < 0) {
477 char errstr[2048];
478
479 fc_snprintf(errstr, sizeof(errstr),
480 _("Adding membership for IPv6 LAN announcement group failed:\n%s"),
481 fc_strerror(fc_get_errno()));
482 scan->error_func(scan, errstr);
483 }
484 } else
485#endif /* IPv6 support */
486 {
487 fc_inet_aton(group, &mreq4.imr_multiaddr, FALSE);
488#ifdef HAVE_IP_MREQN
489 mreq4.imr_address.s_addr = htonl(INADDR_ANY);
490 mreq4.imr_ifindex = 0;
491#else
492 mreq4.imr_interface.s_addr = htonl(INADDR_ANY);
493#endif
494
495 if (setsockopt(scan->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
496 (const char*)&mreq4, sizeof(mreq4)) < 0) {
497 char errstr[2048];
498
499 fc_snprintf(errstr, sizeof(errstr),
500 _("Adding membership for IPv4 LAN announcement group failed:\n%s"),
501 fc_strerror(fc_get_errno()));
502 scan->error_func(scan, errstr);
503
504 return FALSE;
505 }
506 }
507
508 /* Create a socket for broadcasting to servers. */
509 if ((send_sock = socket(family, SOCK_DGRAM, 0)) < 0) {
510 char errstr[2048];
511
512 fc_snprintf(errstr, sizeof(errstr),
513 _("Opening socket for sending LAN announcement request failed:\n%s"),
514 fc_strerror(fc_get_errno()));
515 scan->error_func(scan, errstr);
516
517 return FALSE;
518 }
519
520 memset(&addr, 0, sizeof(addr));
521
522#ifdef FREECIV_IPV6_SUPPORT
523 if (family == AF_INET6) {
524 addr.saddr.sa_family = AF_INET6;
525 inet_pton(AF_INET6, group, &addr.saddr_in6.sin6_addr);
526 addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT);
527 } else
528#endif /* IPv6 Support */
529 if (family == AF_INET) {
530 fc_inet_aton(group, &addr.saddr_in4.sin_addr, FALSE);
531 addr.saddr.sa_family = AF_INET;
532 addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT);
533 } else {
534 fc_assert(FALSE);
535
536 log_error("Unsupported address family in begin_lanserver_scan()");
537
538 return FALSE;
539 }
540
541/* this setsockopt call fails on Windows 98, so we stick with the default
542 * value of 1 on Windows, which should be fine in most cases */
543#ifndef FREECIV_HAVE_WINSOCK
544 /* Set the Time-to-Live field for the packet */
545 ttl = SERVER_LAN_TTL;
546 if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl,
547 sizeof(ttl))) {
548 char errstr[2048];
549
550 fc_snprintf(errstr, sizeof(errstr),
551 _("Setting Time-to-Live failed:\n%s"),
552 fc_strerror(fc_get_errno()));
553 scan->error_func(scan, errstr);
554
555 /* FIXME: Is this really supposed to be an hard error, or should we
556 * just continue? After all, Windows builds do not even attempt this. */
557 return FALSE;
558 }
559#endif /* FREECIV_HAVE_WINSOCK */
560
561 if (setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (const char*)&opt,
562 sizeof(opt))) {
563 char errstr[2048];
564
565 fc_snprintf(errstr, sizeof(errstr),
566 _("Setting Broadcast option failed:\n%s"),
567 fc_strerror(fc_get_errno()));
568 scan->error_func(scan, errstr);
569
570 return FALSE;
571 }
572
573 dio_output_init(&dout, buffer, sizeof(buffer));
574 dio_put_uint8_raw(&dout, SERVER_LAN_VERSION);
575 size = dio_output_used(&dout);
576
577
578 if (sendto(send_sock, buffer, size, 0, &addr.saddr,
579 sockaddr_size(&addr)) < 0) {
580 /* This can happen when there's no network connection */
581 char errstr[2048];
582
583 fc_snprintf(errstr, sizeof(errstr),
584 _("Sending LAN announcement request failed:\n%s"),
585 fc_strerror(fc_get_errno()));
586 scan->error_func(scan, errstr);
587
588 return FALSE;
589 } else {
590 log_debug("Sending request for server announcement on LAN.");
591 }
592
593 fc_closesocket(send_sock);
594
595 fc_allocate_mutex(&scan->srvrs.mutex);
596 scan->srvrs.servers = server_list_new();
597 fc_release_mutex(&scan->srvrs.mutex);
598
599 return TRUE;
600}
601
602/**********************************************************************/
606static enum server_scan_status
607get_lan_server_list(struct server_scan *scan)
608{
609 socklen_t fromlen;
610 union fc_sockaddr fromend;
611 char msgbuf[128];
612 int type;
613 struct data_in din;
614 char servername[512];
615 char portstr[256];
616 int port;
617 char version[256];
618 char status[256];
619 char players[256];
620 char humans[256];
621 char message[1024];
622 bool found_new = FALSE;
623
624 while (TRUE) {
625 struct server *pserver;
626 bool duplicate = FALSE;
627
628 dio_input_init(&din, msgbuf, sizeof(msgbuf));
629 fromlen = sizeof(fromend);
630
631 /* Try to receive a packet from a server. No select loop is needed;
632 * we just keep on reading until recvfrom returns -1. */
633 if (recvfrom(scan->sock, msgbuf, sizeof(msgbuf), 0,
634 &fromend.saddr, &fromlen) < 0) {
635 break;
636 }
637
638 dio_get_uint8_raw(&din, &type);
639 if (type != SERVER_LAN_VERSION) {
640 continue;
641 }
642 dio_get_string_raw(&din, servername, sizeof(servername));
643 dio_get_string_raw(&din, portstr, sizeof(portstr));
644 port = atoi(portstr);
645 dio_get_string_raw(&din, version, sizeof(version));
646 dio_get_string_raw(&din, status, sizeof(status));
647 dio_get_string_raw(&din, players, sizeof(players));
648 dio_get_string_raw(&din, humans, sizeof(humans));
649 dio_get_string_raw(&din, message, sizeof(message));
650
651 if (!fc_strcasecmp("none", servername)) {
652 bool nameinfo = FALSE;
653#ifdef FREECIV_IPV6_SUPPORT
654 char dst[INET6_ADDRSTRLEN];
655 char host[NI_MAXHOST], service[NI_MAXSERV];
656
657 if (!getnameinfo(&fromend.saddr, fromlen, host, NI_MAXHOST,
658 service, NI_MAXSERV, NI_NUMERICSERV)) {
659 nameinfo = TRUE;
660 }
661 if (!nameinfo) {
662 if (fromend.saddr.sa_family == AF_INET6) {
663 inet_ntop(AF_INET6, &fromend.saddr_in6.sin6_addr,
664 dst, sizeof(dst));
665 } else if (fromend.saddr.sa_family == AF_INET) {
666 inet_ntop(AF_INET, &fromend.saddr_in4.sin_addr, dst, sizeof(dst));;
667 } else {
668 fc_assert(FALSE);
669
670 log_error("Unsupported address family in get_lan_server_list()");
671
672 fc_snprintf(dst, sizeof(dst), "Unknown");
673 }
674 }
675#else /* IPv6 support */
676 const char *dst = NULL;
677 struct hostent *from;
678 const char *host = NULL;
679
680 from = gethostbyaddr((char *) &fromend.saddr_in4.sin_addr,
681 sizeof(fromend.saddr_in4.sin_addr), AF_INET);
682 if (from) {
683 host = from->h_name;
684 nameinfo = TRUE;
685 }
686 if (!nameinfo) {
687 dst = inet_ntoa(fromend.saddr_in4.sin_addr);
688 }
689#endif /* IPv6 support */
690
691 sz_strlcpy(servername, nameinfo ? host : dst);
692 }
693
694 /* UDP can send duplicate or delayed packets. */
695 fc_allocate_mutex(&scan->srvrs.mutex);
696 server_list_iterate(scan->srvrs.servers, aserver) {
697 if (0 == fc_strcasecmp(aserver->host, servername)
698 && aserver->port == port) {
699 duplicate = TRUE;
700 break;
701 }
702 } server_list_iterate_end;
703
704 if (duplicate) {
705 fc_release_mutex(&scan->srvrs.mutex);
706 continue;
707 }
708
709 log_debug("Received a valid announcement from a server on the LAN.");
710
711 pserver = fc_malloc(sizeof(*pserver));
712 pserver->host = fc_strdup(servername);
713 pserver->port = port;
714 pserver->version = fc_strdup(version);
715 pserver->state = fc_strdup(status);
716 pserver->nplayers = atoi(players);
717 pserver->humans = atoi(humans);
718 pserver->message = fc_strdup(message);
719 pserver->players = NULL;
720 found_new = TRUE;
721
722 server_list_prepend(scan->srvrs.servers, pserver);
723 fc_release_mutex(&scan->srvrs.mutex);
724 }
725
726 if (found_new) {
727 return SCAN_STATUS_PARTIAL;
728 }
729 return SCAN_STATUS_WAITING;
730}
731
732/**********************************************************************/
744 struct server_scan *server_scan_begin(enum server_scan_type type,
745 ServerScanErrorFunc error_func)
746{
747 struct server_scan *scan;
748 bool ok = FALSE;
749
750#ifndef FREECIV_META_ENABLED
751 if (type == SERVER_SCAN_GLOBAL) {
752 return NULL;
753 }
754#endif /* FREECIV_META_ENABLED */
755
756 scan = fc_calloc(1, sizeof(*scan));
757 scan->type = type;
758 scan->error_func = error_func;
759 scan->sock = -1;
760 fc_init_mutex(&scan->srvrs.mutex);
761
762 switch (type) {
763 case SERVER_SCAN_GLOBAL:
764 {
765#ifdef FREECIV_META_ENABLED
766 int thr_ret;
767
768 fc_init_mutex(&scan->meta.mutex);
769 scan->meta.status = SCAN_STATUS_WAITING;
770 thr_ret = fc_thread_start(&scan->meta.thr, metaserver_scan, scan);
771 if (thr_ret) {
772 ok = FALSE;
773 } else {
774 ok = TRUE;
775 }
776#endif /* FREECIV_META_ENABLED */
777 }
778 break;
779 case SERVER_SCAN_LOCAL:
780 ok = begin_lanserver_scan(scan);
781 break;
782 case SERVER_SCAN_LAST:
783 break;
784 }
785
786 if (!ok) {
787 server_scan_finish(scan);
788 scan = NULL;
789 }
790
791 return scan;
792}
793
794/**********************************************************************/
798 enum server_scan_type server_scan_get_type(const struct server_scan *scan)
799{
800 if (!scan) {
801 return SERVER_SCAN_LAST;
802 }
803 return scan->type;
804}
805
806/**********************************************************************/
821 enum server_scan_status server_scan_poll(struct server_scan *scan)
822{
823 if (!scan) {
824 return SCAN_STATUS_ERROR;
825 }
826
827 switch (scan->type) {
828 case SERVER_SCAN_GLOBAL:
829#ifdef FREECIV_META_ENABLED
830 {
831 enum server_scan_status status;
832
833 fc_allocate_mutex(&scan->meta.mutex);
834 status = scan->meta.status;
835 fc_release_mutex(&scan->meta.mutex);
836
837 return status;
838 }
839#endif /* FREECIV_META_ENABLED */
840 break;
841 case SERVER_SCAN_LOCAL:
842 return get_lan_server_list(scan);
843 break;
844 case SERVER_SCAN_LAST:
845 break;
846 }
847
848 return SCAN_STATUS_ERROR;
849}
850
851/**********************************************************************/
854struct srv_list *
855server_scan_get_list(struct server_scan *scan)
856{
857 if (!scan) {
858 return NULL;
859 }
860
861 return &scan->srvrs;
862}
863
864/**********************************************************************/
868 void server_scan_finish(struct server_scan *scan)
869{
870 if (!scan) {
871 return;
872 }
873
874 if (scan->type == SERVER_SCAN_GLOBAL) {
875#ifdef FREECIV_META_ENABLED
876 /* Signal metaserver scan thread to stop */
877 fc_allocate_mutex(&scan->meta.mutex);
878 scan->meta.status = SCAN_STATUS_ABORT;
879 fc_release_mutex(&scan->meta.mutex);
880
881 /* Wait thread to stop */
882 fc_thread_wait(&scan->meta.thr);
883 fc_destroy_mutex(&scan->meta.mutex);
884
885 /* This mainly duplicates code from below "else" block.
886 * That's intentional, since they will be completely different in future versions.
887 * We are better prepared for that by having them separately already. */
888 if (scan->sock >= 0) {
889 fc_closesocket(scan->sock);
890 scan->sock = -1;
891 }
892
893 if (scan->srvrs.servers) {
894 fc_allocate_mutex(&scan->srvrs.mutex);
895 delete_server_list(scan->srvrs.servers);
896 scan->srvrs.servers = NULL;
897 fc_release_mutex(&scan->srvrs.mutex);
898 }
899
900 if (scan->meta.mem.mem) {
901 FC_FREE(scan->meta.mem.mem);
902 scan->meta.mem.mem = NULL;
903 }
904#endif /* FREECIV_META_ENABLED */
905 } else {
906 if (scan->sock >= 0) {
907 fc_closesocket(scan->sock);
908 scan->sock = -1;
909 }
910
911 if (scan->srvrs.servers) {
912 delete_server_list(scan->srvrs.servers);
913 scan->srvrs.servers = NULL;
914 }
915 }
916
917 fc_destroy_mutex(&scan->srvrs.mutex);
918
919 free(scan);
920}
str
#define str
Definition astring.c:76
n
#define n
Definition astring.c:77
our_capability
const char *const our_capability
Definition capstr.c:32
capstr.h
chatline_common.h
chatline_g.h
metaserver
char metaserver[512]
Definition client_main.c:143
client_main.h
MAX_LEN_PACKET
#define MAX_LEN_PACKET
Definition connection.h:56
dataio.h
dio_output_init
void dio_output_init(struct raw_data_out *dout, void *destination, size_t dest_size)
Definition dataio_raw.c:171
dio_put_uint8_raw
void dio_put_uint8_raw(struct raw_data_out *dout, int value)
Definition dataio_raw.c:265
dio_get_uint8_raw
bool dio_get_uint8_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:572
dio_output_used
size_t dio_output_used(struct raw_data_out *dout)
Definition dataio_raw.c:184
dio_input_init
void dio_input_init(struct data_in *din, const void *src, size_t src_size)
Definition dataio_raw.c:202
dio_get_string_raw
bool dio_get_string_raw(struct data_in *din, char *dest, size_t max_dest_size)
Definition dataio_raw.c:805
fc_prehdrs.h
fcintl.h
Q_
#define Q_(String)
Definition fcintl.h:70
_
#define _(String)
Definition fcintl.h:67
fcthread.h
fc_thread_start
int fc_thread_start(fc_thread *thread, void(*function)(void *arg), void *arg)
fc_allocate_mutex
void fc_allocate_mutex(fc_mutex *mutex)
fc_release_mutex
void fc_release_mutex(fc_mutex *mutex)
fc_thread_wait
void fc_thread_wait(fc_thread *thread)
fc_destroy_mutex
void fc_destroy_mutex(fc_mutex *mutex)
fc_init_mutex
void fc_init_mutex(fc_mutex *mutex)
game.h
version_message
void version_message(const char *vertext)
Definition chatline.c:1469
type
GType type
Definition repodlgs.c:1312
server_list
static struct server_list * server_list
Definition connectdlg.c:61
gui_main_g.h
name
const char * name
Definition inputfile.c:127
fz_from_memory
fz_FILE * fz_from_memory(char *buffer, int size, bool control)
Definition ioz.c:207
log.h
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
log_debug
#define log_debug(message,...)
Definition log.h:115
log_error
#define log_error(message,...)
Definition log.h:103
mem.h
fc_calloc
#define fc_calloc(n, esz)
Definition mem.h:38
FC_FREE
#define FC_FREE(ptr)
Definition mem.h:41
fc_strdup
#define fc_strdup(str)
Definition mem.h:43
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
announce_type
announce_type
Definition net_types.h:53
ANNOUNCE_IPV6
@ ANNOUNCE_IPV6
Definition net_types.h:56
ANNOUNCE_NONE
@ ANNOUNCE_NONE
Definition net_types.h:54
netfile_close_post
void netfile_close_post(struct netfile_post *post)
Definition netfile.c:244
netfile_start_post
struct netfile_post * netfile_start_post(void)
Definition netfile.c:197
netfile_send_post
bool netfile_send_post(const char *URL, struct netfile_post *post, FILE *reply_fp, struct netfile_write_cb_data *mem_data, const char *addr)
Definition netfile.c:268
netfile_add_form_str
void netfile_add_form_str(struct netfile_post *post, const char *name, const char *val)
Definition netfile.c:211
netfile.h
fc_inet_aton
bool fc_inet_aton(const char *cp, struct in_addr *inp, bool addr_none_ok)
Definition netintf.c:466
fc_closesocket
void fc_closesocket(int sock)
Definition netintf.c:186
sockaddr_size
int sockaddr_size(union fc_sockaddr *addr)
Definition netintf.c:305
fc_nonblock
void fc_nonblock(int sockfd)
Definition netintf.c:227
netintf.h
socklen_t
int socklen_t
Definition netintf.h:67
FC_IPV6_ADD_MEMBERSHIP
#define FC_IPV6_ADD_MEMBERSHIP
Definition netintf.h:63
packets.h
rand.h
registry.h
secfile_error
const char * secfile_error(void)
Definition section_file.c:36
secfile_destroy
void secfile_destroy(struct section_file *secfile)
Definition section_file.c:95
secfile_from_stream
struct section_file * secfile_from_stream(fz_FILE *stream, bool allow_duplicates)
Definition registry_ini.c:607
secfile_lookup_int_default
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
Definition registry_ini.c:1937
secfile_lookup_str_default
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Definition registry_ini.c:2142
SERVER_LAN_TTL
#define SERVER_LAN_TTL
Definition sernet.h:25
SERVER_LAN_VERSION
#define SERVER_LAN_VERSION
Definition sernet.h:26
SERVER_LAN_PORT
#define SERVER_LAN_PORT
Definition sernet.h:24
delete_server_list
static void delete_server_list(struct server_list *server_list)
Definition servers.c:338
server_scan_get_list
struct srv_list * server_scan_get_list(struct server_scan *scan)
Definition servers.c:855
announce
enum announce_type announce
Definition client_main.c:147
get_lan_server_list
static enum server_scan_status get_lan_server_list(struct server_scan *scan)
Definition servers.c:607
server_scan_finish
void server_scan_finish(struct server_scan *scan)
Definition servers.c:868
server_scan_begin
struct server_scan * server_scan_begin(enum server_scan_type type, ServerScanErrorFunc error_func)
Definition servers.c:744
begin_lanserver_scan
static bool begin_lanserver_scan(struct server_scan *scan)
Definition servers.c:374
server_scan_get_type
enum server_scan_type server_scan_get_type(const struct server_scan *scan)
Definition servers.c:798
server_scan_poll
enum server_scan_status server_scan_poll(struct server_scan *scan)
Definition servers.c:821
servers.h
server_list_iterate_end
#define server_list_iterate_end
Definition servers.h:57
server_scan_status
server_scan_status
Definition servers.h:79
SCAN_STATUS_WAITING
@ SCAN_STATUS_WAITING
Definition servers.h:81
SCAN_STATUS_ABORT
@ SCAN_STATUS_ABORT
Definition servers.h:84
SCAN_STATUS_PARTIAL
@ SCAN_STATUS_PARTIAL
Definition servers.h:82
SCAN_STATUS_ERROR
@ SCAN_STATUS_ERROR
Definition servers.h:80
SCAN_STATUS_DONE
@ SCAN_STATUS_DONE
Definition servers.h:83
server_list_iterate
#define server_list_iterate(serverlist, pserver)
Definition servers.h:55
server_scan_type
server_scan_type
Definition servers.h:67
SERVER_SCAN_LOCAL
@ SERVER_SCAN_LOCAL
Definition servers.h:68
SERVER_SCAN_LAST
@ SERVER_SCAN_LAST
Definition servers.h:70
SERVER_SCAN_GLOBAL
@ SERVER_SCAN_GLOBAL
Definition servers.h:69
ServerScanErrorFunc
void(* ServerScanErrorFunc)(struct server_scan *scan, const char *message)
Definition servers.h:73
get_multicast_group
char * get_multicast_group(bool ipv6_preferred)
Definition shared.c:1662
size
size_t size
Definition specvec.h:72
data_in
Definition dataio_raw.h:30
fz_FILE_s
Definition ioz.c:149
message
Definition messagewin_common.h:29
netfile_post
Definition netfile.c:39
netfile_write_cb_data
Definition netfile.h:27
raw_data_out
Definition dataio_raw.h:35
section_file
Definition section_file.h:36
server::players::host
char * host
Definition servers.h:43
server::players::name
char * name
Definition servers.h:41
server::players::nation
char * nation
Definition servers.h:44
server::players::type
char * type
Definition servers.h:42
server_scan
Definition servers.c:83
server_scan::sock
int sock
Definition servers.c:88
server_scan::error_func
ServerScanErrorFunc error_func
Definition servers.c:85
server_scan::srvrs
struct srv_list srvrs
Definition servers.c:87
server_scan::type
enum server_scan_type type
Definition servers.c:84
server
Definition servers.h:29
server::humans
int humans
Definition servers.h:48
server::host
char * host
Definition servers.h:30
server::version
char * version
Definition servers.h:34
server::message
char * message
Definition servers.h:37
server::state
char * state
Definition servers.h:35
server::players
struct server::players * players
server::port
int port
Definition servers.h:31
server::nplayers
int nplayers
Definition servers.h:47
srv_list
Definition servers.h:62
srv_list::mutex
fc_mutex mutex
Definition servers.h:64
srv_list::servers
struct server_list * servers
Definition servers.h:63
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
fc_strerror
const char * fc_strerror(fc_errno err)
Definition support.c:610
fc_get_errno
fc_errno fc_get_errno(void)
Definition support.c:593
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:161
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
fc_sockaddr
Definition netintf.h:70
fc_sockaddr::saddr
struct sockaddr saddr
Definition netintf.h:71
fc_sockaddr::saddr_in4
struct sockaddr_in saddr_in4
Definition netintf.h:72
fc_comparable_version
const char * fc_comparable_version(void)
Definition version.c:95
version.h