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 raw_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 #ifdef FREECIV_IPV6_SUPPORT
450 if (family
== AF_INET6
) {
451 inet_pton(AF_INET6
, group
, &mreq6
.ipv6mr_multiaddr
.s6_addr
);
452 mreq6
.ipv6mr_interface
= 0; /* TODO: Interface selection */
454 if (setsockopt(scan
->sock
, IPPROTO_IPV6
, FC_IPV6_ADD_MEMBERSHIP
,
455 (const char*)&mreq6
, sizeof(mreq6
)) < 0) {
458 fc_snprintf(errstr
, sizeof(errstr
),
459 _("Adding membership for IPv6 LAN announcement group failed:\n%s"),
460 fc_strerror(fc_get_errno()));
461 scan
->error_func(scan
, errstr
);
464 #endif /* IPv6 support */
466 fc_inet_aton(group
, &mreq4
.imr_multiaddr
, FALSE
);
468 mreq4
.imr_address
.s_addr
= htonl(INADDR_ANY
);
469 mreq4
.imr_ifindex
= 0;
471 mreq4
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
474 if (setsockopt(scan
->sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
475 (const char*)&mreq4
, sizeof(mreq4
)) < 0) {
478 fc_snprintf(errstr
, sizeof(errstr
),
479 _("Adding membership for IPv4 LAN announcement group failed:\n%s"),
480 fc_strerror(fc_get_errno()));
481 scan
->error_func(scan
, errstr
);
487 /* Create a socket for broadcasting to servers. */
488 if ((send_sock
= socket(family
, SOCK_DGRAM
, 0)) < 0) {
489 log_error("socket failed: %s", fc_strerror(fc_get_errno()));
493 memset(&addr
, 0, sizeof(addr
));
495 #ifdef FREECIV_IPV6_SUPPORT
496 if (family
== AF_INET6
) {
497 addr
.saddr
.sa_family
= AF_INET6
;
498 inet_pton(AF_INET6
, group
, &addr
.saddr_in6
.sin6_addr
);
499 addr
.saddr_in6
.sin6_port
= htons(SERVER_LAN_PORT
);
501 #endif /* IPv6 Support */
502 if (family
== AF_INET
) {
503 fc_inet_aton(group
, &addr
.saddr_in4
.sin_addr
, FALSE
);
504 addr
.saddr
.sa_family
= AF_INET
;
505 addr
.saddr_in4
.sin_port
= htons(SERVER_LAN_PORT
);
509 log_error("Unsupported address family in begin_lanserver_scan()");
514 /* this setsockopt call fails on Windows 98, so we stick with the default
515 * value of 1 on Windows, which should be fine in most cases */
516 #ifndef FREECIV_HAVE_WINSOCK
517 /* Set the Time-to-Live field for the packet */
518 ttl
= SERVER_LAN_TTL
;
519 if (setsockopt(send_sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (const char*)&ttl
,
521 log_error("setsockopt failed: %s", fc_strerror(fc_get_errno()));
524 #endif /* FREECIV_HAVE_WINSOCK */
526 if (setsockopt(send_sock
, SOL_SOCKET
, SO_BROADCAST
, (const char*)&opt
,
528 log_error("setsockopt failed: %s", fc_strerror(fc_get_errno()));
532 dio_output_init(&dout
, buffer
, sizeof(buffer
));
533 dio_put_uint8_raw(&dout
, SERVER_LAN_VERSION
);
534 size
= dio_output_used(&dout
);
537 if (sendto(send_sock
, buffer
, size
, 0, &addr
.saddr
,
538 sockaddr_size(&addr
)) < 0) {
539 /* This can happen when there's no network connection - it should
540 * give an in-game message. */
541 log_error("lanserver scan sendto failed: %s",
542 fc_strerror(fc_get_errno()));
545 log_debug("Sending request for server announcement on LAN.");
548 fc_closesocket(send_sock
);
550 fc_allocate_mutex(&scan
->srvrs
.mutex
);
551 scan
->srvrs
.servers
= server_list_new();
552 fc_release_mutex(&scan
->srvrs
.mutex
);
557 /**************************************************************************
558 Listens for UDP packets broadcasted from a server that responded
559 to the request-packet sent from the client.
560 **************************************************************************/
561 static enum server_scan_status
562 get_lan_server_list(struct server_scan
*scan
)
565 union fc_sockaddr fromend
;
569 char servername
[512];
577 bool found_new
= FALSE
;
580 struct server
*pserver
;
581 bool duplicate
= FALSE
;
583 dio_input_init(&din
, msgbuf
, sizeof(msgbuf
));
584 fromlen
= sizeof(fromend
);
586 /* Try to receive a packet from a server. No select loop is needed;
587 * we just keep on reading until recvfrom returns -1. */
588 if (recvfrom(scan
->sock
, msgbuf
, sizeof(msgbuf
), 0,
589 &fromend
.saddr
, &fromlen
) < 0) {
593 dio_get_uint8_raw(&din
, &type
);
594 if (type
!= SERVER_LAN_VERSION
) {
597 dio_get_string_raw(&din
, servername
, sizeof(servername
));
598 dio_get_string_raw(&din
, portstr
, sizeof(portstr
));
599 port
= atoi(portstr
);
600 dio_get_string_raw(&din
, version
, sizeof(version
));
601 dio_get_string_raw(&din
, status
, sizeof(status
));
602 dio_get_string_raw(&din
, players
, sizeof(players
));
603 dio_get_string_raw(&din
, humans
, sizeof(humans
));
604 dio_get_string_raw(&din
, message
, sizeof(message
));
606 if (!fc_strcasecmp("none", servername
)) {
607 bool nameinfo
= FALSE
;
608 #ifdef FREECIV_IPV6_SUPPORT
609 char dst
[INET6_ADDRSTRLEN
];
610 char host
[NI_MAXHOST
], service
[NI_MAXSERV
];
612 if (!getnameinfo(&fromend
.saddr
, fromlen
, host
, NI_MAXHOST
,
613 service
, NI_MAXSERV
, NI_NUMERICSERV
)) {
617 if (fromend
.saddr
.sa_family
== AF_INET6
) {
618 inet_ntop(AF_INET6
, &fromend
.saddr_in6
.sin6_addr
,
620 } else if (fromend
.saddr
.sa_family
== AF_INET
) {
621 inet_ntop(AF_INET
, &fromend
.saddr_in4
.sin_addr
, dst
, sizeof(dst
));;
625 log_error("Unsupported address family in get_lan_server_list()");
627 fc_snprintf(dst
, sizeof(dst
), "Unknown");
630 #else /* IPv6 support */
631 const char *dst
= NULL
;
632 struct hostent
*from
;
633 const char *host
= NULL
;
635 from
= gethostbyaddr((char *) &fromend
.saddr_in4
.sin_addr
,
636 sizeof(fromend
.saddr_in4
.sin_addr
), AF_INET
);
642 dst
= inet_ntoa(fromend
.saddr_in4
.sin_addr
);
644 #endif /* IPv6 support */
646 sz_strlcpy(servername
, nameinfo
? host
: dst
);
649 /* UDP can send duplicate or delayed packets. */
650 fc_allocate_mutex(&scan
->srvrs
.mutex
);
651 server_list_iterate(scan
->srvrs
.servers
, aserver
) {
652 if (0 == fc_strcasecmp(aserver
->host
, servername
)
653 && aserver
->port
== port
) {
657 } server_list_iterate_end
;
660 fc_release_mutex(&scan
->srvrs
.mutex
);
664 log_debug("Received a valid announcement from a server on the LAN.");
666 pserver
= fc_malloc(sizeof(*pserver
));
667 pserver
->host
= fc_strdup(servername
);
668 pserver
->port
= port
;
669 pserver
->version
= fc_strdup(version
);
670 pserver
->state
= fc_strdup(status
);
671 pserver
->nplayers
= atoi(players
);
672 pserver
->humans
= atoi(humans
);
673 pserver
->message
= fc_strdup(message
);
674 pserver
->players
= NULL
;
677 server_list_prepend(scan
->srvrs
.servers
, pserver
);
678 fc_release_mutex(&scan
->srvrs
.mutex
);
682 return SCAN_STATUS_PARTIAL
;
684 return SCAN_STATUS_WAITING
;
687 /****************************************************************************
688 Creates a new server scan and returns it, or NULL if impossible.
690 Depending on 'type' the scan will look for either local or internet
693 error_func provides a callback to be used in case of error; this
694 callback probably should call server_scan_finish.
696 NB: You must call server_scan_finish() when you are done with the
697 scan to free the memory and resources allocated by it.
698 ****************************************************************************/
699 struct server_scan
*server_scan_begin(enum server_scan_type type
,
700 ServerScanErrorFunc error_func
)
702 struct server_scan
*scan
;
705 scan
= fc_calloc(1, sizeof(*scan
));
707 scan
->error_func
= error_func
;
709 fc_init_mutex(&scan
->srvrs
.mutex
);
712 case SERVER_SCAN_GLOBAL
:
716 fc_init_mutex(&scan
->meta
.mutex
);
717 scan
->meta
.status
= SCAN_STATUS_WAITING
;
718 thr_ret
= fc_thread_start(&scan
->meta
.thr
, metaserver_scan
, scan
);
726 case SERVER_SCAN_LOCAL
:
727 ok
= begin_lanserver_scan(scan
);
734 server_scan_finish(scan
);
741 /****************************************************************************
742 A simple query function to determine the type of a server scan (previously
743 allocated in server_scan_begin).
744 ****************************************************************************/
745 enum server_scan_type
server_scan_get_type(const struct server_scan
*scan
)
748 return SERVER_SCAN_LAST
;
753 /****************************************************************************
754 A function to query servers of the server scan. This will check any
755 pending network data and update the server list.
757 The return value indicates the status of the server scan:
758 SCAN_STATUS_ERROR - The scan failed and should be aborted.
759 SCAN_STATUS_WAITING - The scan is in progress (continue polling).
760 SCAN_STATUS_PARTIAL - The scan received some data, with more expected.
761 Get the servers with server_scan_get_list(), and
763 SCAN_STATUS_DONE - The scan received all data it expected to receive.
764 Get the servers with server_scan_get_list(), and
765 stop calling this function.
766 SCAN_STATUS_ABORT - The scan has been aborted
767 ****************************************************************************/
768 enum server_scan_status
server_scan_poll(struct server_scan
*scan
)
771 return SCAN_STATUS_ERROR
;
774 switch (scan
->type
) {
775 case SERVER_SCAN_GLOBAL
:
777 enum server_scan_status status
;
779 fc_allocate_mutex(&scan
->meta
.mutex
);
780 status
= scan
->meta
.status
;
781 fc_release_mutex(&scan
->meta
.mutex
);
786 case SERVER_SCAN_LOCAL
:
787 return get_lan_server_list(scan
);
793 return SCAN_STATUS_ERROR
;
796 /**************************************************************************
797 Returns the srv_list currently held by the scan (may be NULL).
798 **************************************************************************/
800 server_scan_get_list(struct server_scan
*scan
)
809 /**************************************************************************
810 Closes the socket listening on the scan, frees the list of servers, and
811 frees the memory allocated for 'scan' by server_scan_begin().
812 **************************************************************************/
813 void server_scan_finish(struct server_scan
*scan
)
819 if (scan
->type
== SERVER_SCAN_GLOBAL
) {
820 /* Signal metaserver scan thread to stop */
821 fc_allocate_mutex(&scan
->meta
.mutex
);
822 scan
->meta
.status
= SCAN_STATUS_ABORT
;
823 fc_release_mutex(&scan
->meta
.mutex
);
825 /* Wait thread to stop */
826 fc_thread_wait(&scan
->meta
.thr
);
827 fc_destroy_mutex(&scan
->meta
.mutex
);
829 /* This mainly duplicates code from below "else" block.
830 * That's intentional, since they will be completely different in future versions.
831 * We are better prepared for that by having them separately already. */
832 if (scan
->sock
>= 0) {
833 fc_closesocket(scan
->sock
);
837 if (scan
->srvrs
.servers
) {
838 fc_allocate_mutex(&scan
->srvrs
.mutex
);
839 delete_server_list(scan
->srvrs
.servers
);
840 scan
->srvrs
.servers
= NULL
;
841 fc_release_mutex(&scan
->srvrs
.mutex
);
844 if (scan
->meta
.mem
.mem
) {
845 FC_FREE(scan
->meta
.mem
.mem
);
846 scan
->meta
.mem
.mem
= NULL
;
849 if (scan
->sock
>= 0) {
850 fc_closesocket(scan
->sock
);
854 if (scan
->srvrs
.servers
) {
855 delete_server_list(scan
->srvrs
.servers
);
856 scan
->srvrs
.servers
= NULL
;
860 fc_destroy_mutex(&scan
->srvrs
.mutex
);