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)
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 ***********************************************************************/
15 #include <fc_config.h>
18 #include "fc_prehdrs.h"
23 #ifdef FREECIV_HAVE_SYS_TYPES_H
24 #include <sys/types.h>
26 #ifdef HAVE_SYS_SOCKET_H
27 #include <sys/socket.h>
29 #ifdef HAVE_NETINET_IN_H
30 #include <netinet/in.h>
32 #ifdef HAVE_ARPA_INET_H
33 #include <arpa/inet.h>
41 #ifdef HAVE_SYS_SELECT_H
42 #include <sys/select.h>
44 #ifdef HAVE_SYS_TIME_H
64 #include "rand.h" /* fc_rand() */
76 #include "chatline_common.h"
77 #include "chatline_g.h"
78 #include "client_main.h"
81 #include "gui_main_g.h"
84 enum server_scan_type type
;
85 ServerScanErrorFunc error_func
;
87 struct srv_list srvrs
;
90 /* Only used for metaserver */
92 enum server_scan_status status
;
98 struct netfile_write_cb_data mem
;
102 extern enum announce_type announce
;
104 static bool begin_metaserver_scan(struct server_scan
*scan
);
105 static void delete_server_list(struct server_list
*server_list
);
107 /**************************************************************************
108 The server sends a stream in a registry 'ini' type format.
109 Read it using secfile functions and fill the server_list structs.
110 **************************************************************************/
111 static struct server_list
*parse_metaserver_data(fz_FILE
*f
)
113 struct server_list
*server_list
;
114 struct section_file
*file
;
116 const char *latest_ver
;
119 /* This call closes f. */
120 if (!(file
= secfile_from_stream(f
, TRUE
))) {
124 latest_ver
= secfile_lookup_str_default(file
, NULL
, "versions." FOLLOWTAG
);
125 comment
= secfile_lookup_str_default(file
, NULL
, "version_comments." FOLLOWTAG
);
127 if (latest_ver
!= NULL
) {
128 const char *my_comparable
= fc_comparable_version();
131 log_verbose("Metaserver says latest '" FOLLOWTAG
"' version is '%s'; we have '%s'",
132 latest_ver
, my_comparable
);
133 if (cvercmp_greater(latest_ver
, my_comparable
)) {
134 const char *const followtag
= "?vertag:" FOLLOWTAG
;
135 fc_snprintf(vertext
, sizeof(vertext
),
136 /* TRANS: Type is version tag name like "stable", "S2_4",
137 * "win32" (which can also be localised -- msgids start
139 _("Latest %s release of Freeciv is %s, this is %s."),
140 Q_(followtag
), latest_ver
, my_comparable
);
142 version_message(vertext
);
143 } else if (comment
== NULL
) {
144 fc_snprintf(vertext
, sizeof(vertext
),
145 _("There is no newer %s release of Freeciv available."),
148 version_message(vertext
);
152 if (comment
!= NULL
) {
153 log_verbose("Mesaserver comment about '" FOLLOWTAG
"': %s", comment
);
154 version_message(comment
);
157 server_list
= server_list_new();
158 nservers
= secfile_lookup_int_default(file
, 0, "main.nservers");
160 for (i
= 0; i
< nservers
; i
++) {
161 const char *host
, *port
, *version
, *state
, *message
, *nplayers
, *nhumans
;
163 struct server
*pserver
= (struct server
*)fc_malloc(sizeof(struct server
));
165 host
= secfile_lookup_str_default(file
, "", "server%d.host", i
);
166 pserver
->host
= fc_strdup(host
);
168 port
= secfile_lookup_str_default(file
, "", "server%d.port", i
);
169 pserver
->port
= atoi(port
);
171 version
= secfile_lookup_str_default(file
, "", "server%d.version", i
);
172 pserver
->version
= fc_strdup(version
);
174 state
= secfile_lookup_str_default(file
, "", "server%d.state", i
);
175 pserver
->state
= fc_strdup(state
);
177 message
= secfile_lookup_str_default(file
, "", "server%d.message", i
);
178 pserver
->message
= fc_strdup(message
);
180 nplayers
= secfile_lookup_str_default(file
, "0", "server%d.nplayers", i
);
182 pserver
->nplayers
= n
;
184 nhumans
= secfile_lookup_str_default(file
, "-1", "server%d.humans", i
);
188 if (pserver
->nplayers
> 0) {
189 pserver
->players
= fc_malloc(pserver
->nplayers
* sizeof(*pserver
->players
));
191 pserver
->players
= NULL
;
194 for (j
= 0; j
< pserver
->nplayers
; j
++) {
195 const char *name
, *nation
, *type
, *plrhost
;
197 name
= secfile_lookup_str_default(file
, "",
198 "server%d.player%d.name", i
, j
);
199 pserver
->players
[j
].name
= fc_strdup(name
);
201 type
= secfile_lookup_str_default(file
, "",
202 "server%d.player%d.type", i
, j
);
203 pserver
->players
[j
].type
= fc_strdup(type
);
205 plrhost
= secfile_lookup_str_default(file
, "",
206 "server%d.player%d.host", i
, j
);
207 pserver
->players
[j
].host
= fc_strdup(plrhost
);
209 nation
= secfile_lookup_str_default(file
, "",
210 "server%d.player%d.nation", i
, j
);
211 pserver
->players
[j
].nation
= fc_strdup(nation
);
214 server_list_append(server_list
, pserver
);
217 secfile_destroy(file
);
222 /****************************************************************************
223 Read the reply string from the metaserver.
224 ****************************************************************************/
225 static bool meta_read_response(struct server_scan
*scan
)
229 struct server_list
*srvrs
;
231 f
= fz_from_memory(scan
->meta
.mem
.mem
, scan
->meta
.mem
.size
, TRUE
);
233 fc_snprintf(str
, sizeof(str
),
234 _("Failed to read the metaserver data from %s."),
236 scan
->error_func(scan
, str
);
241 /* parse message body */
242 fc_allocate_mutex(&scan
->srvrs
.mutex
);
243 srvrs
= parse_metaserver_data(f
);
244 scan
->srvrs
.servers
= srvrs
;
245 fc_release_mutex(&scan
->srvrs
.mutex
);
247 /* 'f' (hence 'meta.mem.mem') was closed in parse_metaserver_data(). */
248 scan
->meta
.mem
.mem
= NULL
;
251 fc_snprintf(str
, sizeof(str
),
252 _("Failed to parse the metaserver data from %s:\n"
254 metaserver
, secfile_error());
255 scan
->error_func(scan
, str
);
263 /****************************************************************************
264 Metaserver scan thread entry point
265 ****************************************************************************/
266 static void metaserver_scan(void *arg
)
268 struct server_scan
*scan
= arg
;
270 if (!begin_metaserver_scan(scan
)) {
271 fc_allocate_mutex(&scan
->meta
.mutex
);
272 scan
->meta
.status
= SCAN_STATUS_ERROR
;
274 if (!meta_read_response(scan
)) {
275 fc_allocate_mutex(&scan
->meta
.mutex
);
276 scan
->meta
.status
= SCAN_STATUS_ERROR
;
278 fc_allocate_mutex(&scan
->meta
.mutex
);
279 if (scan
->meta
.status
== SCAN_STATUS_WAITING
) {
280 scan
->meta
.status
= SCAN_STATUS_DONE
;
285 fc_release_mutex(&scan
->meta
.mutex
);
288 /****************************************************************************
289 Begin a metaserver scan for servers.
291 Returns FALSE on error (in which case errbuf will contain an error
293 ****************************************************************************/
294 static bool begin_metaserver_scan(struct server_scan
*scan
)
296 struct netfile_post
*post
;
299 post
= netfile_start_post();
300 netfile_add_form_str(post
, "client_cap", our_capability
);
302 if (!netfile_send_post(metaserver
, post
, NULL
, &scan
->meta
.mem
, NULL
)) {
303 scan
->error_func(scan
, _("Error connecting to metaserver"));
307 netfile_close_post(post
);
312 /**************************************************************************
313 Frees everything associated with a server list including
314 the server list itself (so the server_list is no longer
315 valid after calling this function)
316 **************************************************************************/
317 static void delete_server_list(struct server_list
*server_list
)
323 server_list_iterate(server_list
, ptmp
) {
325 int n
= ptmp
->nplayers
;
333 for (i
= 0; i
< n
; i
++) {
334 free(ptmp
->players
[i
].name
);
335 free(ptmp
->players
[i
].type
);
336 free(ptmp
->players
[i
].host
);
337 free(ptmp
->players
[i
].nation
);
343 } server_list_iterate_end
;
345 server_list_destroy(server_list
);
348 /**************************************************************************
349 Broadcast an UDP package to all servers on LAN, requesting information
350 about the server. The packet is send to all Freeciv servers in the same
351 multicast group as the client.
352 **************************************************************************/
353 static bool begin_lanserver_scan(struct server_scan
*scan
)
355 union fc_sockaddr addr
;
356 struct data_out dout
;
357 int send_sock
, opt
= 1;
358 #ifndef FREECIV_HAVE_WINSOCK
359 unsigned char buffer
[MAX_LEN_PACKET
];
360 #else /* FREECIV_HAVE_WINSOCK */
361 char buffer
[MAX_LEN_PACKET
];
362 #endif /* FREECIV_HAVE_WINSOCK */
364 struct ip_mreqn mreq4
;
366 struct ip_mreq mreq4
;
372 #ifdef FREECIV_IPV6_SUPPORT
373 struct ipv6_mreq mreq6
;
376 #ifndef FREECIV_HAVE_WINSOCK
380 if (announce
== ANNOUNCE_NONE
) {
381 /* Succeeded in doing nothing */
385 #ifdef FREECIV_IPV6_SUPPORT
386 if (announce
== ANNOUNCE_IPV6
) {
389 #endif /* IPv6 support */
394 /* Set the UDP Multicast group IP address. */
395 group
= get_multicast_group(announce
== ANNOUNCE_IPV6
);
397 /* Create a socket for listening for server packets. */
398 if ((scan
->sock
= socket(family
, SOCK_DGRAM
, 0)) < 0) {
401 fc_snprintf(errstr
, sizeof(errstr
),
402 _("Opening socket to listen LAN announcements failed:\n%s"),
403 fc_strerror(fc_get_errno()));
404 scan
->error_func(scan
, errstr
);
409 fc_nonblock(scan
->sock
);
411 if (setsockopt(scan
->sock
, SOL_SOCKET
, SO_REUSEADDR
,
412 (char *)&opt
, sizeof(opt
)) == -1) {
413 log_error("SO_REUSEADDR failed: %s", fc_strerror(fc_get_errno()));
416 memset(&addr
, 0, sizeof(addr
));
418 #ifdef FREECIV_IPV6_SUPPORT
419 if (family
== AF_INET6
) {
420 addr
.saddr
.sa_family
= AF_INET6
;
421 addr
.saddr_in6
.sin6_port
= htons(SERVER_LAN_PORT
+ 1);
422 addr
.saddr_in6
.sin6_addr
= in6addr_any
;
424 #endif /* IPv6 support */
425 if (family
== AF_INET
) {
426 addr
.saddr
.sa_family
= AF_INET
;
427 addr
.saddr_in4
.sin_port
= htons(SERVER_LAN_PORT
+ 1);
428 addr
.saddr_in4
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
430 /* This is not only error situation worth assert() This
431 * is error situation that has check (with assert) against
432 * earlier already. */
438 if (bind(scan
->sock
, &addr
.saddr
, sockaddr_size(&addr
)) < 0) {
441 fc_snprintf(errstr
, sizeof(errstr
),
442 _("Binding socket to listen LAN announcements failed:\n%s"),
443 fc_strerror(fc_get_errno()));
444 scan
->error_func(scan
, errstr
);
449 #ifndef FREECIV_IPV6_SUPPORT
451 #ifdef HAVE_INET_ATON
452 inet_aton(group
, &mreq4
.imr_multiaddr
);
453 #else /* HAVE_INET_ATON */
454 mreq4
.imr_multiaddr
.s_addr
= inet_addr(group
);
455 #endif /* HAVE_INET_ATON */
456 #else /* IPv6 support */
457 if (family
== AF_INET6
) {
458 inet_pton(AF_INET6
, group
, &mreq6
.ipv6mr_multiaddr
.s6_addr
);
459 mreq6
.ipv6mr_interface
= 0; /* TODO: Interface selection */
461 if (setsockopt(scan
->sock
, IPPROTO_IPV6
, FC_IPV6_ADD_MEMBERSHIP
,
462 (const char*)&mreq6
, sizeof(mreq6
)) < 0) {
465 fc_snprintf(errstr
, sizeof(errstr
),
466 _("Adding membership for IPv6 LAN announcement group failed:\n%s"),
467 fc_strerror(fc_get_errno()));
468 scan
->error_func(scan
, errstr
);
471 inet_pton(AF_INET
, group
, &mreq4
.imr_multiaddr
.s_addr
);
472 #endif /* IPv6 support */
474 mreq4
.imr_address
.s_addr
= htonl(INADDR_ANY
);
475 mreq4
.imr_ifindex
= 0;
477 mreq4
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
480 if (setsockopt(scan
->sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
481 (const char*)&mreq4
, sizeof(mreq4
)) < 0) {
484 fc_snprintf(errstr
, sizeof(errstr
),
485 _("Adding membership for IPv4 LAN announcement group failed:\n%s"),
486 fc_strerror(fc_get_errno()));
487 scan
->error_func(scan
, errstr
);
493 /* Create a socket for broadcasting to servers. */
494 if ((send_sock
= socket(family
, SOCK_DGRAM
, 0)) < 0) {
495 log_error("socket failed: %s", fc_strerror(fc_get_errno()));
499 memset(&addr
, 0, sizeof(addr
));
501 #ifndef FREECIV_IPV6_SUPPORT
502 if (family
== AF_INET
) {
503 #ifdef HAVE_INET_ATON
504 inet_aton(group
, &addr
.saddr_in4
.sin_addr
);
505 #else /* HAVE_INET_ATON */
506 addr
.saddr_in4
.sin_addr
.s_addr
= inet_addr(group
);
507 #endif /* HAVE_INET_ATON */
508 #else /* IPv6 support */
509 if (family
== AF_INET6
) {
510 addr
.saddr
.sa_family
= AF_INET6
;
511 inet_pton(AF_INET6
, group
, &addr
.saddr_in6
.sin6_addr
);
512 addr
.saddr_in6
.sin6_port
= htons(SERVER_LAN_PORT
);
513 } else if (family
== AF_INET
) {
514 inet_pton(AF_INET
, group
, &addr
.saddr_in4
.sin_addr
);
515 #endif /* IPv6 support */
516 addr
.saddr
.sa_family
= AF_INET
;
517 addr
.saddr_in4
.sin_port
= htons(SERVER_LAN_PORT
);
521 log_error("Unsupported address family in begin_lanserver_scan()");
526 /* this setsockopt call fails on Windows 98, so we stick with the default
527 * value of 1 on Windows, which should be fine in most cases */
528 #ifndef FREECIV_HAVE_WINSOCK
529 /* Set the Time-to-Live field for the packet */
530 ttl
= SERVER_LAN_TTL
;
531 if (setsockopt(send_sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (const char*)&ttl
,
533 log_error("setsockopt failed: %s", fc_strerror(fc_get_errno()));
536 #endif /* FREECIV_HAVE_WINSOCK */
538 if (setsockopt(send_sock
, SOL_SOCKET
, SO_BROADCAST
, (const char*)&opt
,
540 log_error("setsockopt failed: %s", fc_strerror(fc_get_errno()));
544 dio_output_init(&dout
, buffer
, sizeof(buffer
));
545 dio_put_uint8(&dout
, SERVER_LAN_VERSION
);
546 size
= dio_output_used(&dout
);
549 if (sendto(send_sock
, buffer
, size
, 0, &addr
.saddr
,
550 sockaddr_size(&addr
)) < 0) {
551 /* This can happen when there's no network connection - it should
552 * give an in-game message. */
553 log_error("lanserver scan sendto failed: %s",
554 fc_strerror(fc_get_errno()));
557 log_debug("Sending request for server announcement on LAN.");
560 fc_closesocket(send_sock
);
562 fc_allocate_mutex(&scan
->srvrs
.mutex
);
563 scan
->srvrs
.servers
= server_list_new();
564 fc_release_mutex(&scan
->srvrs
.mutex
);
569 /**************************************************************************
570 Listens for UDP packets broadcasted from a server that responded
571 to the request-packet sent from the client.
572 **************************************************************************/
573 static enum server_scan_status
574 get_lan_server_list(struct server_scan
*scan
)
577 union fc_sockaddr fromend
;
581 char servername
[512];
589 bool found_new
= FALSE
;
592 struct server
*pserver
;
593 bool duplicate
= FALSE
;
595 dio_input_init(&din
, msgbuf
, sizeof(msgbuf
));
596 fromlen
= sizeof(fromend
);
598 /* Try to receive a packet from a server. No select loop is needed;
599 * we just keep on reading until recvfrom returns -1. */
600 if (recvfrom(scan
->sock
, msgbuf
, sizeof(msgbuf
), 0,
601 &fromend
.saddr
, &fromlen
) < 0) {
605 dio_get_uint8(&din
, &type
);
606 if (type
!= SERVER_LAN_VERSION
) {
609 dio_get_string(&din
, servername
, sizeof(servername
));
610 dio_get_string(&din
, portstr
, sizeof(portstr
));
611 port
= atoi(portstr
);
612 dio_get_string(&din
, version
, sizeof(version
));
613 dio_get_string(&din
, status
, sizeof(status
));
614 dio_get_string(&din
, players
, sizeof(players
));
615 dio_get_string(&din
, humans
, sizeof(humans
));
616 dio_get_string(&din
, message
, sizeof(message
));
618 if (!fc_strcasecmp("none", servername
)) {
619 bool nameinfo
= FALSE
;
620 #ifdef FREECIV_IPV6_SUPPORT
621 char dst
[INET6_ADDRSTRLEN
];
622 char host
[NI_MAXHOST
], service
[NI_MAXSERV
];
624 if (!getnameinfo(&fromend
.saddr
, fromlen
, host
, NI_MAXHOST
,
625 service
, NI_MAXSERV
, NI_NUMERICSERV
)) {
629 if (fromend
.saddr
.sa_family
== AF_INET6
) {
630 inet_ntop(AF_INET6
, &fromend
.saddr_in6
.sin6_addr
,
632 } else if (fromend
.saddr
.sa_family
== AF_INET
) {
633 inet_ntop(AF_INET
, &fromend
.saddr_in4
.sin_addr
, dst
, sizeof(dst
));;
637 log_error("Unsupported address family in get_lan_server_list()");
639 fc_snprintf(dst
, sizeof(dst
), "Unknown");
642 #else /* IPv6 support */
643 const char *dst
= NULL
;
644 struct hostent
*from
;
645 const char *host
= NULL
;
647 from
= gethostbyaddr((char *) &fromend
.saddr_in4
.sin_addr
,
648 sizeof(fromend
.saddr_in4
.sin_addr
), AF_INET
);
654 dst
= inet_ntoa(fromend
.saddr_in4
.sin_addr
);
656 #endif /* IPv6 support */
658 sz_strlcpy(servername
, nameinfo
? host
: dst
);
661 /* UDP can send duplicate or delayed packets. */
662 fc_allocate_mutex(&scan
->srvrs
.mutex
);
663 server_list_iterate(scan
->srvrs
.servers
, aserver
) {
664 if (0 == fc_strcasecmp(aserver
->host
, servername
)
665 && aserver
->port
== port
) {
669 } server_list_iterate_end
;
672 fc_release_mutex(&scan
->srvrs
.mutex
);
676 log_debug("Received a valid announcement from a server on the LAN.");
678 pserver
= fc_malloc(sizeof(*pserver
));
679 pserver
->host
= fc_strdup(servername
);
680 pserver
->port
= port
;
681 pserver
->version
= fc_strdup(version
);
682 pserver
->state
= fc_strdup(status
);
683 pserver
->nplayers
= atoi(players
);
684 pserver
->humans
= atoi(humans
);
685 pserver
->message
= fc_strdup(message
);
686 pserver
->players
= NULL
;
689 server_list_prepend(scan
->srvrs
.servers
, pserver
);
690 fc_release_mutex(&scan
->srvrs
.mutex
);
694 return SCAN_STATUS_PARTIAL
;
696 return SCAN_STATUS_WAITING
;
699 /****************************************************************************
700 Creates a new server scan and returns it, or NULL if impossible.
702 Depending on 'type' the scan will look for either local or internet
705 error_func provides a callback to be used in case of error; this
706 callback probably should call server_scan_finish.
708 NB: You must call server_scan_finish() when you are done with the
709 scan to free the memory and resources allocated by it.
710 ****************************************************************************/
711 struct server_scan
*server_scan_begin(enum server_scan_type type
,
712 ServerScanErrorFunc error_func
)
714 struct server_scan
*scan
;
717 scan
= fc_calloc(1, sizeof(*scan
));
719 scan
->error_func
= error_func
;
721 fc_init_mutex(&scan
->srvrs
.mutex
);
724 case SERVER_SCAN_GLOBAL
:
728 fc_init_mutex(&scan
->meta
.mutex
);
729 scan
->meta
.status
= SCAN_STATUS_WAITING
;
730 thr_ret
= fc_thread_start(&scan
->meta
.thr
, metaserver_scan
, scan
);
738 case SERVER_SCAN_LOCAL
:
739 ok
= begin_lanserver_scan(scan
);
746 server_scan_finish(scan
);
753 /****************************************************************************
754 A simple query function to determine the type of a server scan (previously
755 allocated in server_scan_begin).
756 ****************************************************************************/
757 enum server_scan_type
server_scan_get_type(const struct server_scan
*scan
)
760 return SERVER_SCAN_LAST
;
765 /****************************************************************************
766 A function to query servers of the server scan. This will check any
767 pending network data and update the server list.
769 The return value indicates the status of the server scan:
770 SCAN_STATUS_ERROR - The scan failed and should be aborted.
771 SCAN_STATUS_WAITING - The scan is in progress (continue polling).
772 SCAN_STATUS_PARTIAL - The scan received some data, with more expected.
773 Get the servers with server_scan_get_list(), and
775 SCAN_STATUS_DONE - The scan received all data it expected to receive.
776 Get the servers with server_scan_get_list(), and
777 stop calling this function.
778 SCAN_STATUS_ABORT - The scan has been aborted
779 ****************************************************************************/
780 enum server_scan_status
server_scan_poll(struct server_scan
*scan
)
783 return SCAN_STATUS_ERROR
;
786 switch (scan
->type
) {
787 case SERVER_SCAN_GLOBAL
:
789 enum server_scan_status status
;
791 fc_allocate_mutex(&scan
->meta
.mutex
);
792 status
= scan
->meta
.status
;
793 fc_release_mutex(&scan
->meta
.mutex
);
798 case SERVER_SCAN_LOCAL
:
799 return get_lan_server_list(scan
);
805 return SCAN_STATUS_ERROR
;
808 /**************************************************************************
809 Returns the srv_list currently held by the scan (may be NULL).
810 **************************************************************************/
812 server_scan_get_list(struct server_scan
*scan
)
821 /**************************************************************************
822 Closes the socket listening on the scan, frees the list of servers, and
823 frees the memory allocated for 'scan' by server_scan_begin().
824 **************************************************************************/
825 void server_scan_finish(struct server_scan
*scan
)
831 if (scan
->type
== SERVER_SCAN_GLOBAL
) {
832 /* Signal metaserver scan thread to stop */
833 fc_allocate_mutex(&scan
->meta
.mutex
);
834 scan
->meta
.status
= SCAN_STATUS_ABORT
;
835 fc_release_mutex(&scan
->meta
.mutex
);
837 /* Wait thread to stop */
838 fc_thread_wait(&scan
->meta
.thr
);
839 fc_destroy_mutex(&scan
->meta
.mutex
);
841 /* This mainly duplicates code from below "else" block.
842 * That's intentional, since they will be completely different in future versions.
843 * We are better prepared for that by having them separately already. */
844 if (scan
->sock
>= 0) {
845 fc_closesocket(scan
->sock
);
849 if (scan
->srvrs
.servers
) {
850 fc_allocate_mutex(&scan
->srvrs
.mutex
);
851 delete_server_list(scan
->srvrs
.servers
);
852 scan
->srvrs
.servers
= NULL
;
853 fc_release_mutex(&scan
->srvrs
.mutex
);
856 if (scan
->meta
.mem
.mem
) {
857 FC_FREE(scan
->meta
.mem
.mem
);
858 scan
->meta
.mem
.mem
= NULL
;
861 if (scan
->sock
>= 0) {
862 fc_closesocket(scan
->sock
);
866 if (scan
->srvrs
.servers
) {
867 delete_server_list(scan
->srvrs
.servers
);
868 scan
->srvrs
.servers
= NULL
;
872 fc_destroy_mutex(&scan
->srvrs
.mutex
);