Freeciv-3.3: /fast/freeciv/nightly/main/client/servers.c Source File

Freeciv-3.3

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 "options.h"
80#include "servers.h"
81
82#include "gui_main_g.h"
83
84 struct server_scan {
85 enum server_scan_type type;
86 ServerScanErrorFunc error_func;
87
88 struct srv_list srvrs;
89 int sock;
90
91#ifdef FREECIV_META_ENABLED
92 /* Only used for metaserver */
93 struct {
94 enum server_scan_status status;
95
96 fc_thread thr;
97 fc_mutex mutex;
98
99 const char *urlpath;
100 struct netfile_write_cb_data mem;
101 } meta;
102#endif /* FREECIV_META_ENABLED */
103};
104
105extern enum announce_type announce;
106
107static void delete_server_list(struct server_list *server_list);
108
109#ifdef FREECIV_META_ENABLED
110static bool begin_metaserver_scan(struct server_scan *scan);
111
112/**********************************************************************/
116static struct server_list *parse_metaserver_data(fz_FILE *f)
117{
118 struct server_list *server_list;
119 struct section_file *file;
120 int nservers, i, j;
121 const char *latest_ver;
122 const char *comment;
123 char *followtag;
124 char *q_followtag;
125
126 /* Have the string outside Q_() so it won't get collected for translation here.
127 * Actual collected string lives in translations/Strings.txt */
128#define QUALIFIED_FOLLOWTAG "?vertag:" FOLLOWTAG
129
130 /* This call closes f. */
131 if (!(file = secfile_from_stream(f, TRUE))) {
132 return NULL;
133 }
134
135 if (fc_strcasecmp(DEFAULT_FOLLOWTAG_OPTION, gui_options.followtag_override)) {
136 followtag = gui_options.followtag_override;
137 q_followtag = gui_options.followtag_override;
138 } else {
139 followtag = FOLLOWTAG;
140 q_followtag = QUALIFIED_FOLLOWTAG;
141 }
142
143 latest_ver = secfile_lookup_str_default(file, NULL, "versions.%s", followtag);
144 comment = secfile_lookup_str_default(file, NULL, "version_comments.%s", followtag);
145
146 if (latest_ver == NULL && comment == NULL) {
147 char vertext[2048];
148
149 fc_snprintf(vertext, sizeof(vertext),
150 /* TRANS: Type is version tag name like "stable", "S3_2",
151 * "windows" (which can also be localised -- msgids start
152 * '?vertag:') */
153 _("There's no %s release yet."), Q_(q_followtag));
154 log_verbose("%s", vertext);
155 version_message(vertext);
156 } else {
157 if (latest_ver != NULL) {
158 const char *my_comparable = fc_comparable_version();
159 char vertext[2048];
160
161 log_verbose("Metaserver says latest '%s' version is '%s'; we have '%s'",
162 followtag, latest_ver, my_comparable);
163 if (cvercmp_greater(latest_ver, my_comparable)) {
164
165 fc_snprintf(vertext, sizeof(vertext),
166 /* TRANS: Type is version tag name like "stable", "S3_2",
167 * "windows" (which can also be localised -- msgids start
168 * '?vertag:') */
169 _("Latest %s release of Freeciv is %s, this is %s."),
170 Q_(q_followtag), latest_ver, my_comparable);
171
172 version_message(vertext);
173 } else if (comment == NULL) {
174 fc_snprintf(vertext, sizeof(vertext),
175 _("There is no newer %s release of Freeciv available."),
176 followtag);
177
178 version_message(vertext);
179 }
180 }
181
182 if (comment != NULL) {
183 log_verbose("Mesaserver comment about '%s': %s", followtag, comment);
184 version_message(comment);
185 }
186 }
187
188 server_list = server_list_new();
189 nservers = secfile_lookup_int_default(file, 0, "main.nservers");
190
191 for (i = 0; i < nservers; i++) {
192 const char *host, *port, *version, *state, *message, *nplayers, *nhumans;
193 int n;
194 struct server *pserver = (struct server*)fc_malloc(sizeof(struct server));
195
196 host = secfile_lookup_str_default(file, "", "server%d.host", i);
197 pserver->host = fc_strdup(host);
198
199 port = secfile_lookup_str_default(file, "", "server%d.port", i);
200 pserver->port = atoi(port);
201
202 version = secfile_lookup_str_default(file, "", "server%d.version", i);
203 pserver->version = fc_strdup(version);
204
205 state = secfile_lookup_str_default(file, "", "server%d.state", i);
206 pserver->state = fc_strdup(state);
207
208 message = secfile_lookup_str_default(file, "", "server%d.message", i);
209 pserver->message = fc_strdup(message);
210
211 nplayers = secfile_lookup_str_default(file, "0", "server%d.nplayers", i);
212 n = atoi(nplayers);
213 pserver->nplayers = n;
214
215 nhumans = secfile_lookup_str_default(file, "-1", "server%d.humans", i);
216 n = atoi(nhumans);
217 pserver->humans = n;
218
219 if (pserver->nplayers > 0) {
220 pserver->players = fc_malloc(pserver->nplayers * sizeof(*pserver->players));
221 } else {
222 pserver->players = NULL;
223 }
224
225 for (j = 0; j < pserver->nplayers ; j++) {
226 const char *name, *nation, *type, *plrhost;
227
228 name = secfile_lookup_str_default(file, "",
229 "server%d.player%d.name", i, j);
230 pserver->players[j].name = fc_strdup(name);
231
232 type = secfile_lookup_str_default(file, "",
233 "server%d.player%d.type", i, j);
234 pserver->players[j].type = fc_strdup(type);
235
236 plrhost = secfile_lookup_str_default(file, "",
237 "server%d.player%d.host", i, j);
238 pserver->players[j].host = fc_strdup(plrhost);
239
240 nation = secfile_lookup_str_default(file, "",
241 "server%d.player%d.nation", i, j);
242 pserver->players[j].nation = fc_strdup(nation);
243 }
244
245 server_list_append(server_list, pserver);
246 }
247
248 secfile_destroy(file);
249
250 return server_list;
251}
252
253/**********************************************************************/
256static bool meta_read_response(struct server_scan *scan)
257{
258 fz_FILE *f;
259 char str[4096];
260 struct server_list *srvrs;
261
262 f = fz_from_memory(scan->meta.mem.mem, scan->meta.mem.size, TRUE);
263 if (NULL == f) {
264 fc_snprintf(str, sizeof(str),
265 _("Failed to read the metaserver data from %s."),
266 metaserver);
267 scan->error_func(scan, str);
268
269 return FALSE;
270 }
271
272 /* Parse message body */
273 fc_mutex_allocate(&scan->srvrs.mutex);
274 srvrs = parse_metaserver_data(f);
275 scan->srvrs.servers = srvrs;
276 fc_mutex_release(&scan->srvrs.mutex);
277
278 /* 'f' (hence 'meta.mem.mem') was closed in parse_metaserver_data(). */
279 scan->meta.mem.mem = NULL;
280
281 if (NULL == srvrs) {
282 fc_snprintf(str, sizeof(str),
283 _("Failed to parse the metaserver data from %s:\n"
284 "%s."),
285 metaserver, secfile_error());
286 scan->error_func(scan, str);
287
288 return FALSE;
289 }
290
291 return TRUE;
292}
293
294/**********************************************************************/
297static void metaserver_scan(void *arg)
298{
299 struct server_scan *scan = arg;
300
301 if (!begin_metaserver_scan(scan)) {
302 fc_mutex_allocate(&scan->meta.mutex);
303 scan->meta.status = SCAN_STATUS_ERROR;
304 } else {
305 if (!meta_read_response(scan)) {
306 fc_mutex_allocate(&scan->meta.mutex);
307 scan->meta.status = SCAN_STATUS_ERROR;
308 } else {
309 fc_mutex_allocate(&scan->meta.mutex);
310 if (scan->meta.status == SCAN_STATUS_WAITING) {
311 scan->meta.status = SCAN_STATUS_DONE;
312 }
313 }
314 }
315
316 fc_mutex_release(&scan->meta.mutex);
317}
318
319/**********************************************************************/
325static bool begin_metaserver_scan(struct server_scan *scan)
326{
327 struct netfile_post *post;
328 bool retval = TRUE;
329
330 post = netfile_start_post();
331 netfile_add_form_str(post, "client_cap", our_capability);
332
333 if (!netfile_send_post(metaserver, post, NULL, &scan->meta.mem, NULL)) {
334 scan->error_func(scan, _("Error connecting to metaserver"));
335 retval = FALSE;
336 }
337
338 netfile_close_post(post);
339
340 return retval;
341}
342#endif /* FREECIV_META_ENABLED */
343
344/**********************************************************************/
349 static void delete_server_list(struct server_list *server_list)
350{
351 if (!server_list) {
352 return;
353 }
354
355 server_list_iterate(server_list, ptmp) {
356 int i;
357 int n = ptmp->nplayers;
358
359 free(ptmp->host);
360 free(ptmp->version);
361 free(ptmp->state);
362 free(ptmp->message);
363
364 if (ptmp->players) {
365 for (i = 0; i < n; i++) {
366 free(ptmp->players[i].name);
367 free(ptmp->players[i].type);
368 free(ptmp->players[i].host);
369 free(ptmp->players[i].nation);
370 }
371 free(ptmp->players);
372 }
373
374 free(ptmp);
375 } server_list_iterate_end;
376
377 server_list_destroy(server_list);
378}
379
380/**********************************************************************/
385 static bool begin_lanserver_scan(struct server_scan *scan)
386{
387 union fc_sockaddr addr;
388 struct raw_data_out dout;
389 int send_sock, opt = 1;
390#ifndef FREECIV_HAVE_WINSOCK
391 unsigned char buffer[MAX_LEN_PACKET];
392#else /* FREECIV_HAVE_WINSOCK */
393 char buffer[MAX_LEN_PACKET];
394#endif /* FREECIV_HAVE_WINSOCK */
395#ifdef HAVE_IP_MREQN
396 struct ip_mreqn mreq4;
397#else
398 struct ip_mreq mreq4;
399#endif
400 const char *group;
401 size_t size;
402 int family;
403
404#ifdef FREECIV_IPV6_SUPPORT
405 struct ipv6_mreq mreq6;
406#endif
407
408#ifndef FREECIV_HAVE_WINSOCK
409 unsigned char ttl;
410#endif
411
412 if (announce == ANNOUNCE_NONE) {
413 /* Succeeded in doing nothing */
414 return TRUE;
415 }
416
417#ifdef FREECIV_IPV6_SUPPORT
418 if (announce == ANNOUNCE_IPV6) {
419 family = AF_INET6;
420 } else
421#endif /* IPv6 support */
422 {
423 family = AF_INET;
424 }
425
426 /* Set the UDP Multicast group IP address. */
427 group = get_multicast_group(announce == ANNOUNCE_IPV6);
428
429 /* Create a socket for listening for server packets. */
430 if ((scan->sock = socket(family, SOCK_DGRAM, 0)) < 0) {
431 char errstr[2048];
432
433 fc_snprintf(errstr, sizeof(errstr),
434 _("Opening socket to listen LAN announcements failed:\n%s"),
435 fc_strerror(fc_get_errno()));
436 scan->error_func(scan, errstr);
437
438 return FALSE;
439 }
440
441 fc_nonblock(scan->sock);
442
443 if (setsockopt(scan->sock, SOL_SOCKET, SO_REUSEADDR,
444 (char *)&opt, sizeof(opt)) == -1) {
445 log_error("SO_REUSEADDR failed: %s", fc_strerror(fc_get_errno()));
446 }
447
448 memset(&addr, 0, sizeof(addr));
449
450#ifdef FREECIV_IPV6_SUPPORT
451 if (family == AF_INET6) {
452 addr.saddr.sa_family = AF_INET6;
453 addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT + 1);
454 addr.saddr_in6.sin6_addr = in6addr_any;
455 } else
456#endif /* IPv6 support */
457 if (family == AF_INET) {
458 addr.saddr.sa_family = AF_INET;
459 addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT + 1);
460 addr.saddr_in4.sin_addr.s_addr = htonl(INADDR_ANY);
461 } else {
462 /* This is not only error situation worth assert() This
463 * is error situation that has check (with assert) against
464 * earlier already. */
465 fc_assert(FALSE);
466
467 return FALSE;
468 }
469
470 if (bind(scan->sock, &addr.saddr, sockaddr_size(&addr)) < 0) {
471 char errstr[2048];
472
473 fc_snprintf(errstr, sizeof(errstr),
474 _("Binding socket to listen LAN announcements failed:\n%s"),
475 fc_strerror(fc_get_errno()));
476 scan->error_func(scan, errstr);
477
478 return FALSE;
479 }
480
481#ifdef FREECIV_IPV6_SUPPORT
482 if (family == AF_INET6) {
483 inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr.s6_addr);
484 mreq6.ipv6mr_interface = 0; /* TODO: Interface selection */
485
486 if (setsockopt(scan->sock, IPPROTO_IPV6, FC_IPV6_ADD_MEMBERSHIP,
487 (const char*)&mreq6, sizeof(mreq6)) < 0) {
488 char errstr[2048];
489
490 fc_snprintf(errstr, sizeof(errstr),
491 _("Adding membership for IPv6 LAN announcement group failed:\n%s"),
492 fc_strerror(fc_get_errno()));
493 scan->error_func(scan, errstr);
494 }
495 } else
496#endif /* IPv6 support */
497 {
498 fc_inet_aton(group, &mreq4.imr_multiaddr, FALSE);
499#ifdef HAVE_IP_MREQN
500 mreq4.imr_address.s_addr = htonl(INADDR_ANY);
501 mreq4.imr_ifindex = 0;
502#else
503 mreq4.imr_interface.s_addr = htonl(INADDR_ANY);
504#endif
505
506 if (setsockopt(scan->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
507 (const char*)&mreq4, sizeof(mreq4)) < 0) {
508 char errstr[2048];
509
510 fc_snprintf(errstr, sizeof(errstr),
511 _("Adding membership for IPv4 LAN announcement group failed:\n%s"),
512 fc_strerror(fc_get_errno()));
513 scan->error_func(scan, errstr);
514
515 return FALSE;
516 }
517 }
518
519 /* Create a socket for broadcasting to servers. */
520 if ((send_sock = socket(family, SOCK_DGRAM, 0)) < 0) {
521 char errstr[2048];
522
523 fc_snprintf(errstr, sizeof(errstr),
524 _("Opening socket for sending LAN announcement request failed:\n%s"),
525 fc_strerror(fc_get_errno()));
526 scan->error_func(scan, errstr);
527
528 return FALSE;
529 }
530
531 memset(&addr, 0, sizeof(addr));
532
533#ifdef FREECIV_IPV6_SUPPORT
534 if (family == AF_INET6) {
535 addr.saddr.sa_family = AF_INET6;
536 inet_pton(AF_INET6, group, &addr.saddr_in6.sin6_addr);
537 addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT);
538 } else
539#endif /* IPv6 Support */
540 if (family == AF_INET) {
541 fc_inet_aton(group, &addr.saddr_in4.sin_addr, FALSE);
542 addr.saddr.sa_family = AF_INET;
543 addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT);
544 } else {
545 fc_assert(FALSE);
546
547 log_error("Unsupported address family in begin_lanserver_scan()");
548
549 return FALSE;
550 }
551
552/* this setsockopt call fails on Windows 98, so we stick with the default
553 * value of 1 on Windows, which should be fine in most cases */
554#ifndef FREECIV_HAVE_WINSOCK
555 /* Set the Time-to-Live field for the packet */
556 ttl = SERVER_LAN_TTL;
557 if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl,
558 sizeof(ttl))) {
559 char errstr[2048];
560
561 fc_snprintf(errstr, sizeof(errstr),
562 _("Setting Time-to-Live failed:\n%s"),
563 fc_strerror(fc_get_errno()));
564 scan->error_func(scan, errstr);
565
566 /* FIXME: Is this really supposed to be an hard error, or should we
567 * just continue? After all, Windows builds do not even attempt this. */
568 return FALSE;
569 }
570#endif /* FREECIV_HAVE_WINSOCK */
571
572 if (setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (const char*)&opt,
573 sizeof(opt))) {
574 char errstr[2048];
575
576 fc_snprintf(errstr, sizeof(errstr),
577 _("Setting Broadcast option failed:\n%s"),
578 fc_strerror(fc_get_errno()));
579 scan->error_func(scan, errstr);
580
581 return FALSE;
582 }
583
584 dio_output_init(&dout, buffer, sizeof(buffer));
585 dio_put_uint8_raw(&dout, SERVER_LAN_VERSION);
586 size = dio_output_used(&dout);
587
588
589 if (sendto(send_sock, buffer, size, 0, &addr.saddr,
590 sockaddr_size(&addr)) < 0) {
591 /* This can happen when there's no network connection */
592 char errstr[2048];
593
594 fc_snprintf(errstr, sizeof(errstr),
595 _("Sending LAN announcement request failed:\n%s"),
596 fc_strerror(fc_get_errno()));
597 scan->error_func(scan, errstr);
598
599 return FALSE;
600 } else {
601 log_debug("Sending request for server announcement on LAN.");
602 }
603
604 fc_closesocket(send_sock);
605
606 fc_mutex_allocate(&scan->srvrs.mutex);
607 scan->srvrs.servers = server_list_new();
608 fc_mutex_release(&scan->srvrs.mutex);
609
610 return TRUE;
611}
612
613/**********************************************************************/
617static enum server_scan_status
618get_lan_server_list(struct server_scan *scan)
619{
620 socklen_t fromlen;
621 union fc_sockaddr fromend;
622 char msgbuf[128];
623 int type;
624 struct data_in din;
625 char servername[512];
626 char portstr[256];
627 int port;
628 char version[256];
629 char status[256];
630 char players[256];
631 char humans[256];
632 char message[1024];
633 bool found_new = FALSE;
634
635 while (TRUE) {
636 struct server *pserver;
637 bool duplicate = FALSE;
638
639 dio_input_init(&din, msgbuf, sizeof(msgbuf));
640 fromlen = sizeof(fromend);
641
642 /* Try to receive a packet from a server. No select loop is needed;
643 * we just keep on reading until recvfrom returns -1. */
644 if (recvfrom(scan->sock, msgbuf, sizeof(msgbuf), 0,
645 &fromend.saddr, &fromlen) < 0) {
646 break;
647 }
648
649 dio_get_uint8_raw(&din, &type);
650 if (type != SERVER_LAN_VERSION) {
651 continue;
652 }
653 dio_get_string_raw(&din, servername, sizeof(servername));
654 dio_get_string_raw(&din, portstr, sizeof(portstr));
655 port = atoi(portstr);
656 dio_get_string_raw(&din, version, sizeof(version));
657 dio_get_string_raw(&din, status, sizeof(status));
658 dio_get_string_raw(&din, players, sizeof(players));
659 dio_get_string_raw(&din, humans, sizeof(humans));
660 dio_get_string_raw(&din, message, sizeof(message));
661
662 if (!fc_strcasecmp("none", servername)) {
663 bool nameinfo = FALSE;
664#ifdef FREECIV_IPV6_SUPPORT
665 char dst[INET6_ADDRSTRLEN];
666 char host[NI_MAXHOST], service[NI_MAXSERV];
667
668 if (!getnameinfo(&fromend.saddr, fromlen, host, NI_MAXHOST,
669 service, NI_MAXSERV, NI_NUMERICSERV)) {
670 nameinfo = TRUE;
671 }
672 if (!nameinfo) {
673 if (fromend.saddr.sa_family == AF_INET6) {
674 inet_ntop(AF_INET6, &fromend.saddr_in6.sin6_addr,
675 dst, sizeof(dst));
676 } else if (fromend.saddr.sa_family == AF_INET) {
677 inet_ntop(AF_INET, &fromend.saddr_in4.sin_addr, dst, sizeof(dst));
678 } else {
679 fc_assert(FALSE);
680
681 log_error("Unsupported address family in get_lan_server_list()");
682
683 fc_snprintf(dst, sizeof(dst), "Unknown");
684 }
685 }
686#else /* IPv6 support */
687 const char *dst = NULL;
688 struct hostent *from;
689 const char *host = NULL;
690
691 from = gethostbyaddr((char *) &fromend.saddr_in4.sin_addr,
692 sizeof(fromend.saddr_in4.sin_addr), AF_INET);
693 if (from) {
694 host = from->h_name;
695 nameinfo = TRUE;
696 }
697 if (!nameinfo) {
698 dst = inet_ntoa(fromend.saddr_in4.sin_addr);
699 }
700#endif /* IPv6 support */
701
702 sz_strlcpy(servername, nameinfo ? host : dst);
703 }
704
705 /* UDP can send duplicate or delayed packets. */
706 fc_mutex_allocate(&scan->srvrs.mutex);
707 server_list_iterate(scan->srvrs.servers, aserver) {
708 if (0 == fc_strcasecmp(aserver->host, servername)
709 && aserver->port == port) {
710 duplicate = TRUE;
711 break;
712 }
713 } server_list_iterate_end;
714
715 if (duplicate) {
716 fc_mutex_release(&scan->srvrs.mutex);
717 continue;
718 }
719
720 log_debug("Received a valid announcement from a server on the LAN.");
721
722 pserver = fc_malloc(sizeof(*pserver));
723 pserver->host = fc_strdup(servername);
724 pserver->port = port;
725 pserver->version = fc_strdup(version);
726 pserver->state = fc_strdup(status);
727 pserver->nplayers = atoi(players);
728 pserver->humans = atoi(humans);
729 pserver->message = fc_strdup(message);
730 pserver->players = NULL;
731 found_new = TRUE;
732
733 server_list_prepend(scan->srvrs.servers, pserver);
734 fc_mutex_release(&scan->srvrs.mutex);
735 }
736
737 if (found_new) {
738 return SCAN_STATUS_PARTIAL;
739 }
740 return SCAN_STATUS_WAITING;
741}
742
743/**********************************************************************/
755 struct server_scan *server_scan_begin(enum server_scan_type type,
756 ServerScanErrorFunc error_func)
757{
758 struct server_scan *scan;
759 bool ok = FALSE;
760
761#ifndef FREECIV_META_ENABLED
762 if (type == SERVER_SCAN_GLOBAL) {
763 return NULL;
764 }
765#endif /* FREECIV_META_ENABLED */
766
767 scan = fc_calloc(1, sizeof(*scan));
768 scan->type = type;
769 scan->error_func = error_func;
770 scan->sock = -1;
771 fc_mutex_init(&scan->srvrs.mutex);
772
773 switch (type) {
774 case SERVER_SCAN_GLOBAL:
775 {
776#ifdef FREECIV_META_ENABLED
777 int thr_ret;
778
779 fc_mutex_init(&scan->meta.mutex);
780 scan->meta.status = SCAN_STATUS_WAITING;
781 thr_ret = fc_thread_start(&scan->meta.thr, metaserver_scan, scan);
782 if (thr_ret) {
783 ok = FALSE;
784 } else {
785 ok = TRUE;
786 }
787#endif /* FREECIV_META_ENABLED */
788 }
789 break;
790 case SERVER_SCAN_LOCAL:
791 ok = begin_lanserver_scan(scan);
792 break;
793 case SERVER_SCAN_LAST:
794 break;
795 }
796
797 if (!ok) {
798 server_scan_finish(scan);
799 scan = NULL;
800 }
801
802 return scan;
803}
804
805/**********************************************************************/
809 enum server_scan_type server_scan_get_type(const struct server_scan *scan)
810{
811 if (!scan) {
812 return SERVER_SCAN_LAST;
813 }
814 return scan->type;
815}
816
817/**********************************************************************/
832 enum server_scan_status server_scan_poll(struct server_scan *scan)
833{
834 if (!scan) {
835 return SCAN_STATUS_ERROR;
836 }
837
838 switch (scan->type) {
839 case SERVER_SCAN_GLOBAL:
840#ifdef FREECIV_META_ENABLED
841 {
842 enum server_scan_status status;
843
844 fc_mutex_allocate(&scan->meta.mutex);
845 status = scan->meta.status;
846 fc_mutex_release(&scan->meta.mutex);
847
848 return status;
849 }
850#endif /* FREECIV_META_ENABLED */
851 break;
852 case SERVER_SCAN_LOCAL:
853 return get_lan_server_list(scan);
854 break;
855 case SERVER_SCAN_LAST:
856 break;
857 }
858
859 return SCAN_STATUS_ERROR;
860}
861
862/**********************************************************************/
865struct srv_list *
866server_scan_get_list(struct server_scan *scan)
867{
868 if (!scan) {
869 return NULL;
870 }
871
872 return &scan->srvrs;
873}
874
875/**********************************************************************/
879 void server_scan_finish(struct server_scan *scan)
880{
881 if (!scan) {
882 return;
883 }
884
885 if (scan->type == SERVER_SCAN_GLOBAL) {
886#ifdef FREECIV_META_ENABLED
887 /* Signal metaserver scan thread to stop */
888 fc_mutex_allocate(&scan->meta.mutex);
889 scan->meta.status = SCAN_STATUS_ABORT;
890 fc_mutex_release(&scan->meta.mutex);
891
892 /* Wait thread to stop */
893 fc_thread_wait(&scan->meta.thr);
894 fc_mutex_destroy(&scan->meta.mutex);
895
896 /* This mainly duplicates code from below "else" block.
897 * That's intentional, since they will be completely different in future versions.
898 * We are better prepared for that by having them separately already. */
899 if (scan->sock >= 0) {
900 fc_closesocket(scan->sock);
901 scan->sock = -1;
902 }
903
904 if (scan->srvrs.servers) {
905 fc_mutex_allocate(&scan->srvrs.mutex);
906 delete_server_list(scan->srvrs.servers);
907 scan->srvrs.servers = NULL;
908 fc_mutex_release(&scan->srvrs.mutex);
909 }
910
911 if (scan->meta.mem.mem) {
912 FC_FREE(scan->meta.mem.mem);
913 scan->meta.mem.mem = NULL;
914 }
915#endif /* FREECIV_META_ENABLED */
916 } else {
917 if (scan->sock >= 0) {
918 fc_closesocket(scan->sock);
919 scan->sock = -1;
920 }
921
922 if (scan->srvrs.servers) {
923 delete_server_list(scan->srvrs.servers);
924 scan->srvrs.servers = NULL;
925 }
926 }
927
928 fc_mutex_destroy(&scan->srvrs.mutex);
929
930 free(scan);
931}
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:147
client_main.h
incite_cost
char * incite_cost
Definition comments.c:74
MAX_LEN_PACKET
#define MAX_LEN_PACKET
Definition conn_types.h:29
dataio.h
dio_put_uint8_raw
int dio_put_uint8_raw(struct raw_data_out *dout, int value)
Definition dataio_raw.c:265
dio_output_init
void dio_output_init(struct raw_data_out *dout, void *destination, size_t dest_size)
Definition dataio_raw.c:171
dio_get_uint8_raw
bool dio_get_uint8_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:598
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:831
fc_prehdrs.h
fcintl.h
Q_
#define Q_(String)
Definition fcintl.h:70
_
#define _(String)
Definition fcintl.h:67
fcthread.h
fc_mutex_allocate
void fc_mutex_allocate(fc_mutex *mutex)
fc_thread_start
int fc_thread_start(fc_thread *thread, void(*function)(void *arg), void *arg)
fc_mutex_init
void fc_mutex_init(fc_mutex *mutex)
fc_mutex_release
void fc_mutex_release(fc_mutex *mutex)
fc_thread_wait
void fc_thread_wait(fc_thread *thread)
fc_mutex_destroy
void fc_mutex_destroy(fc_mutex *mutex)
game.h
version_message
void version_message(const char *vertext)
Definition chatline.c:1478
type
GType type
Definition repodlgs.c:1313
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
gui_options
struct client_options gui_options
Definition options.c:71
options.h
DEFAULT_FOLLOWTAG_OPTION
#define DEFAULT_FOLLOWTAG_OPTION
Definition options.h:30
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:610
secfile_lookup_int_default
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
Definition registry_ini.c:2004
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:2210
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:349
server_scan_get_list
struct srv_list * server_scan_get_list(struct server_scan *scan)
Definition servers.c:866
announce
enum announce_type announce
Definition client_main.c:151
get_lan_server_list
static enum server_scan_status get_lan_server_list(struct server_scan *scan)
Definition servers.c:618
server_scan_finish
void server_scan_finish(struct server_scan *scan)
Definition servers.c:879
server_scan_begin
struct server_scan * server_scan_begin(enum server_scan_type type, ServerScanErrorFunc error_func)
Definition servers.c:755
begin_lanserver_scan
static bool begin_lanserver_scan(struct server_scan *scan)
Definition servers.c:385
server_scan_get_type
enum server_scan_type server_scan_get_type(const struct server_scan *scan)
Definition servers.c:809
server_scan_poll
enum server_scan_status server_scan_poll(struct server_scan *scan)
Definition servers.c:832
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:1664
size
size_t size
Definition specvec.h:72
client_options::followtag_override
char followtag_override[5112]
Definition options.h:115
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_scan
Definition servers.c:84
server_scan::sock
int sock
Definition servers.c:89
server_scan::error_func
ServerScanErrorFunc error_func
Definition servers.c:86
server_scan::srvrs
struct srv_list srvrs
Definition servers.c:88
server_scan::type
enum server_scan_type type
Definition servers.c:85
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::state
char * state
Definition servers.h:35
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:960
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
fc_strerror
const char * fc_strerror(fc_errno err)
Definition support.c:609
fc_get_errno
fc_errno fc_get_errno(void)
Definition support.c:592
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
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