xref: /netbsd/external/bsd/libpcap/dist/rpcapd/rpcapd.c (revision 9a3414cb)
10036d835Schristos /*
20036d835Schristos  * Copyright (c) 2002 - 2003
30036d835Schristos  * NetGroup, Politecnico di Torino (Italy)
40036d835Schristos  * All rights reserved.
50036d835Schristos  *
60036d835Schristos  * Redistribution and use in source and binary forms, with or without
70036d835Schristos  * modification, are permitted provided that the following conditions
80036d835Schristos  * are met:
90036d835Schristos  *
100036d835Schristos  * 1. Redistributions of source code must retain the above copyright
110036d835Schristos  * notice, this list of conditions and the following disclaimer.
120036d835Schristos  * 2. Redistributions in binary form must reproduce the above copyright
130036d835Schristos  * notice, this list of conditions and the following disclaimer in the
140036d835Schristos  * documentation and/or other materials provided with the distribution.
150036d835Schristos  * 3. Neither the name of the Politecnico di Torino nor the names of its
160036d835Schristos  * contributors may be used to endorse or promote products derived from
170036d835Schristos  * this software without specific prior written permission.
180036d835Schristos  *
190036d835Schristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
200036d835Schristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
210036d835Schristos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
220036d835Schristos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
230036d835Schristos  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
240036d835Schristos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
250036d835Schristos  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
260036d835Schristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
270036d835Schristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
280036d835Schristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
290036d835Schristos  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
300036d835Schristos  *
310036d835Schristos  */
320036d835Schristos 
330036d835Schristos #ifdef HAVE_CONFIG_H
340036d835Schristos #include <config.h>
350036d835Schristos #endif
360036d835Schristos 
370036d835Schristos #include "ftmacros.h"
380036d835Schristos 
390036d835Schristos #include <errno.h>		// for the errno variable
400036d835Schristos #include <string.h>		// for strtok, etc
410036d835Schristos #include <stdlib.h>		// for malloc(), free(), ...
420036d835Schristos #include <pcap.h>		// for PCAP_ERRBUF_SIZE
430036d835Schristos #include <signal.h>		// for signal()
440036d835Schristos 
450036d835Schristos #include "fmtutils.h"
460036d835Schristos #include "sockutils.h"		// for socket calls
470036d835Schristos #include "varattrs.h"		// for _U_
480036d835Schristos #include "portability.h"
490036d835Schristos #include "rpcapd.h"
500036d835Schristos #include "config_params.h"	// configuration file parameters
510036d835Schristos #include "fileconf.h"		// for the configuration file management
520036d835Schristos #include "rpcap-protocol.h"
530036d835Schristos #include "daemon.h"		// the true main() method of this daemon
540036d835Schristos #include "log.h"
550036d835Schristos 
560036d835Schristos #ifdef _WIN32
570036d835Schristos   #include <process.h>		// for thread stuff
580036d835Schristos   #include "win32-svc.h"	// for Win32 service stuff
590036d835Schristos   #include "getopt.h"		// for getopt()-for-Windows
600036d835Schristos #else
610036d835Schristos   #include <fcntl.h>		// for open()
620036d835Schristos   #include <unistd.h>		// for exit()
630036d835Schristos   #include <sys/wait.h>		// waitpid()
640036d835Schristos #endif
650036d835Schristos 
660036d835Schristos //
670036d835Schristos // Element in list of sockets on which we're listening for connections.
680036d835Schristos //
690036d835Schristos struct listen_sock {
700036d835Schristos 	struct listen_sock *next;
710036d835Schristos 	SOCKET sock;
720036d835Schristos };
730036d835Schristos 
740036d835Schristos // Global variables
750036d835Schristos char hostlist[MAX_HOST_LIST + 1];		//!< Keeps the list of the hosts that are allowed to connect to this server
760036d835Schristos struct active_pars activelist[MAX_ACTIVE_LIST];	//!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
770036d835Schristos int nullAuthAllowed;				//!< '1' if we permit NULL authentication, '0' otherwise
780036d835Schristos static struct listen_sock *listen_socks;	//!< sockets on which we listen
790036d835Schristos char loadfile[MAX_LINE + 1];			//!< Name of the file from which we have to load the configuration
800036d835Schristos static int passivemode = 1;			//!< '1' if we want to run in passive mode as well
810036d835Schristos static struct addrinfo mainhints;		//!< temporary struct to keep settings needed to open the new socket
820036d835Schristos static char address[MAX_LINE + 1];		//!< keeps the network address (either numeric or literal) to bind to
830036d835Schristos static char port[MAX_LINE + 1];			//!< keeps the network port to bind to
840036d835Schristos #ifdef _WIN32
850036d835Schristos static HANDLE state_change_event;		//!< event to signal that a state change should take place
860036d835Schristos #endif
870036d835Schristos static volatile sig_atomic_t shutdown_server;	//!< '1' if the server is to shut down
880036d835Schristos static volatile sig_atomic_t reread_config;	//!< '1' if the server is to re-read its configuration
890036d835Schristos 
900036d835Schristos extern char *optarg;	// for getopt()
910036d835Schristos 
920036d835Schristos // Function definition
930036d835Schristos #ifdef _WIN32
940036d835Schristos static unsigned __stdcall main_active(void *ptr);
950036d835Schristos static BOOL WINAPI main_ctrl_event(DWORD);
960036d835Schristos #else
970036d835Schristos static void *main_active(void *ptr);
980036d835Schristos static void main_terminate(int sign);
990036d835Schristos static void main_reread_config(int sign);
1000036d835Schristos #endif
1010036d835Schristos static void accept_connections(void);
1020036d835Schristos static void accept_connection(SOCKET listen_sock);
1030036d835Schristos #ifndef _WIN32
1040036d835Schristos static void main_reap_children(int sign);
1050036d835Schristos #endif
1060036d835Schristos #ifdef _WIN32
1070036d835Schristos static unsigned __stdcall main_passive_serviceloop_thread(void *ptr);
1080036d835Schristos #endif
1090036d835Schristos 
1100036d835Schristos #define RPCAP_ACTIVE_WAIT 30		/* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
1110036d835Schristos 
1120036d835Schristos /*!
1130036d835Schristos 	\brief Prints the usage screen if it is launched in console mode.
1140036d835Schristos */
printusage(void)1150036d835Schristos static void printusage(void)
1160036d835Schristos {
1170036d835Schristos 	const char *usagetext =
1180036d835Schristos 	"USAGE:"
1190036d835Schristos 	" "  PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
1200036d835Schristos 	"              [-n] [-v] [-d] "
1210036d835Schristos #ifndef _WIN32
1220036d835Schristos 	"[-i] "
1230036d835Schristos #endif
124*9a3414cbSchristos         "[-D] [-s <config_file>] [-f <config_file>]\n\n"
1250036d835Schristos 	"  -b <address>    the address to bind to (either numeric or literal).\n"
1260036d835Schristos 	"                  Default: binds to all local IPv4 and IPv6 addresses\n\n"
1270036d835Schristos 	"  -p <port>       the port to bind to.\n"
1280036d835Schristos 	"                  Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n"
1290036d835Schristos 	"  -4              use only IPv4.\n"
1300036d835Schristos 	"                  Default: use both IPv4 and IPv6 waiting sockets\n\n"
1310036d835Schristos 	"  -l <host_list>  a file that contains a list of hosts that are allowed\n"
1320036d835Schristos 	"                  to connect to this server (if more than one, list them one\n"
1330036d835Schristos 	"                  per line).\n"
1340036d835Schristos 	"                  We suggest to use literal names (instead of numeric ones)\n"
1350036d835Schristos 	"                  in order to avoid problems with different address families.\n\n"
1360036d835Schristos 	"  -n              permit NULL authentication (usually used with '-l')\n\n"
1370036d835Schristos 	"  -a <host,port>  run in active mode when connecting to 'host' on port 'port'\n"
1380036d835Schristos 	"                  In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n"
1390036d835Schristos 	"  -v              run in active mode only (default: if '-a' is specified, it\n"
1400036d835Schristos 	"                  accepts passive connections as well)\n\n"
1410036d835Schristos 	"  -d              run in daemon mode (UNIX only) or as a service (Win32 only)\n"
1420036d835Schristos 	"                  Warning (Win32): this switch is provided automatically when\n"
1430036d835Schristos 	"                  the service is started from the control panel\n\n"
1440036d835Schristos #ifndef _WIN32
1450036d835Schristos 	"  -i              run in inetd mode (UNIX only)\n\n"
1460036d835Schristos #endif
147*9a3414cbSchristos 	"  -D              log debugging messages\n\n"
1480036d835Schristos 	"  -s <config_file> save the current configuration to file\n\n"
1490036d835Schristos 	"  -f <config_file> load the current configuration from file; all switches\n"
1500036d835Schristos 	"                  specified from the command line are ignored\n\n"
1510036d835Schristos 	"  -h              print this help screen\n\n";
1520036d835Schristos 
1530036d835Schristos 	(void)fprintf(stderr, "RPCAPD, a remote packet capture daemon.\n"
1540036d835Schristos 	"Compiled with %s\n\n", pcap_lib_version());
1550036d835Schristos 	printf("%s", usagetext);
1560036d835Schristos }
1570036d835Schristos 
1580036d835Schristos 
1590036d835Schristos 
1600036d835Schristos //! Program main
main(int argc,char * argv[])1610036d835Schristos int main(int argc, char *argv[])
1620036d835Schristos {
1630036d835Schristos 	char savefile[MAX_LINE + 1];		// name of the file on which we have to save the configuration
164*9a3414cbSchristos 	int log_to_systemlog = 0;		// Non-zero if we should log to the "system log" rather than the standard error
1650036d835Schristos 	int isdaemon = 0;			// Non-zero if the user wants to run this program as a daemon
1660036d835Schristos #ifndef _WIN32
1670036d835Schristos 	int isrunbyinetd = 0;			// Non-zero if this is being run by inetd or something inetd-like
1680036d835Schristos #endif
169*9a3414cbSchristos 	int log_debug_messages = 0;		// Non-zero if the user wants debug messages logged
1700036d835Schristos 	int retval;				// keeps the returning value from several functions
1710036d835Schristos 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
1720036d835Schristos #ifndef _WIN32
1730036d835Schristos 	struct sigaction action;
1740036d835Schristos #endif
1750036d835Schristos 
1760036d835Schristos 	savefile[0] = 0;
1770036d835Schristos 	loadfile[0] = 0;
1780036d835Schristos 	hostlist[0] = 0;
1790036d835Schristos 
1800036d835Schristos 	// Initialize errbuf
1810036d835Schristos 	memset(errbuf, 0, sizeof(errbuf));
1820036d835Schristos 
1830036d835Schristos 	strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE);
1840036d835Schristos 	strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE);
1850036d835Schristos 
1860036d835Schristos 	// Prepare to open a new server socket
1870036d835Schristos 	memset(&mainhints, 0, sizeof(struct addrinfo));
1880036d835Schristos 
1890036d835Schristos 	mainhints.ai_family = PF_UNSPEC;
1900036d835Schristos 	mainhints.ai_flags = AI_PASSIVE;	// Ready to a bind() socket
1910036d835Schristos 	mainhints.ai_socktype = SOCK_STREAM;
1920036d835Schristos 
1930036d835Schristos 	// Getting the proper command line options
194*9a3414cbSchristos 	while ((retval = getopt(argc, argv, "b:dDhip:4l:na:s:f:v")) != -1)
1950036d835Schristos 	{
1960036d835Schristos 		switch (retval)
1970036d835Schristos 		{
198*9a3414cbSchristos 			case 'D':
199*9a3414cbSchristos 				log_debug_messages = 1;
200*9a3414cbSchristos 				rpcapd_log_set(log_to_systemlog, log_debug_messages);
201*9a3414cbSchristos 				break;
2020036d835Schristos 			case 'b':
2030036d835Schristos 				strncpy(address, optarg, MAX_LINE);
2040036d835Schristos 				break;
2050036d835Schristos 			case 'p':
2060036d835Schristos 				strncpy(port, optarg, MAX_LINE);
2070036d835Schristos 				break;
2080036d835Schristos 			case '4':
2090036d835Schristos 				mainhints.ai_family = PF_INET;		// IPv4 server only
2100036d835Schristos 				break;
2110036d835Schristos 			case 'd':
2120036d835Schristos 				isdaemon = 1;
213*9a3414cbSchristos 				log_to_systemlog = 1;
214*9a3414cbSchristos 				rpcapd_log_set(log_to_systemlog, log_debug_messages);
2150036d835Schristos 				break;
2160036d835Schristos 			case 'i':
2170036d835Schristos #ifdef _WIN32
2180036d835Schristos 				printusage();
2190036d835Schristos 				exit(1);
2200036d835Schristos #else
2210036d835Schristos 				isrunbyinetd = 1;
222*9a3414cbSchristos 				log_to_systemlog = 1;
223*9a3414cbSchristos 				rpcapd_log_set(log_to_systemlog, log_debug_messages);
2240036d835Schristos #endif
2250036d835Schristos 				break;
2260036d835Schristos 			case 'n':
2270036d835Schristos 				nullAuthAllowed = 1;
2280036d835Schristos 				break;
2290036d835Schristos 			case 'v':
2300036d835Schristos 				passivemode = 0;
2310036d835Schristos 				break;
2320036d835Schristos 			case 'l':
2330036d835Schristos 			{
2340036d835Schristos 				strncpy(hostlist, optarg, sizeof(hostlist));
2350036d835Schristos 				break;
2360036d835Schristos 			}
2370036d835Schristos 			case 'a':
2380036d835Schristos 			{
2390036d835Schristos 				char *tmpaddress, *tmpport;
2400036d835Schristos 				char *lasts;
2410036d835Schristos 				int i = 0;
2420036d835Schristos 
2430036d835Schristos 				tmpaddress = pcap_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts);
2440036d835Schristos 
2450036d835Schristos 				while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST))
2460036d835Schristos 				{
2470036d835Schristos 					tmpport = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
2480036d835Schristos 
249*9a3414cbSchristos 					pcap_strlcpy(activelist[i].address, tmpaddress, MAX_LINE);
2500036d835Schristos 
2510036d835Schristos 					if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port
252*9a3414cbSchristos 						pcap_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE);
2530036d835Schristos 					else
254*9a3414cbSchristos 						pcap_strlcpy(activelist[i].port, tmpport, MAX_LINE);
2550036d835Schristos 
2560036d835Schristos 					tmpaddress = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
2570036d835Schristos 
2580036d835Schristos 					i++;
2590036d835Schristos 				}
2600036d835Schristos 
2610036d835Schristos 				if (i > MAX_ACTIVE_LIST)
262*9a3414cbSchristos 					rpcapd_log(LOGPRIO_ERROR, "Only MAX_ACTIVE_LIST active connections are currently supported.");
2630036d835Schristos 
2640036d835Schristos 				// I don't initialize the remaining part of the structure, since
2650036d835Schristos 				// it is already zeroed (it is a global var)
2660036d835Schristos 				break;
2670036d835Schristos 			}
2680036d835Schristos 			case 'f':
269*9a3414cbSchristos 				pcap_strlcpy(loadfile, optarg, MAX_LINE);
2700036d835Schristos 				break;
2710036d835Schristos 			case 's':
272*9a3414cbSchristos 				pcap_strlcpy(savefile, optarg, MAX_LINE);
2730036d835Schristos 				break;
2740036d835Schristos 			case 'h':
2750036d835Schristos 				printusage();
2760036d835Schristos 				exit(0);
277*9a3414cbSchristos 				/*NOTREACHED*/
2780036d835Schristos 			default:
2790036d835Schristos 				exit(1);
280*9a3414cbSchristos 				/*NOTREACHED*/
2810036d835Schristos 		}
2820036d835Schristos 	}
2830036d835Schristos 
2840036d835Schristos #ifndef _WIN32
2850036d835Schristos 	if (isdaemon && isrunbyinetd)
2860036d835Schristos 	{
287*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "rpcapd: -d and -i can't be used together");
2880036d835Schristos 		exit(1);
2890036d835Schristos 	}
2900036d835Schristos #endif
2910036d835Schristos 
292*9a3414cbSchristos 	if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
293*9a3414cbSchristos 	{
294*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
295*9a3414cbSchristos 		exit(-1);
296*9a3414cbSchristos 	}
297*9a3414cbSchristos 
2980036d835Schristos 	if (savefile[0] && fileconf_save(savefile))
299*9a3414cbSchristos 		rpcapd_log(LOGPRIO_DEBUG, "Error when saving the configuration to file");
3000036d835Schristos 
3010036d835Schristos 	// If the file does not exist, it keeps the settings provided by the command line
3020036d835Schristos 	if (loadfile[0])
3030036d835Schristos 		fileconf_read();
3040036d835Schristos 
3050036d835Schristos #ifdef WIN32
3060036d835Schristos 	//
3070036d835Schristos 	// Create a handle to signal the main loop to tell it to do
3080036d835Schristos 	// something.
3090036d835Schristos 	//
3100036d835Schristos 	state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL);
3110036d835Schristos 	if (state_change_event == NULL)
3120036d835Schristos 	{
313*9a3414cbSchristos 		sock_geterror("Can't create state change event", errbuf,
314*9a3414cbSchristos 		    PCAP_ERRBUF_SIZE);
315*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
3160036d835Schristos 		exit(2);
3170036d835Schristos 	}
3180036d835Schristos 
3190036d835Schristos 	//
3200036d835Schristos 	// Catch control signals.
3210036d835Schristos 	//
3220036d835Schristos 	if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE))
3230036d835Schristos 	{
324*9a3414cbSchristos 		sock_geterror("Can't set control handler", errbuf,
325*9a3414cbSchristos 		    PCAP_ERRBUF_SIZE);
326*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
3270036d835Schristos 		exit(2);
3280036d835Schristos 	}
3290036d835Schristos #else
3300036d835Schristos 	memset(&action, 0, sizeof (action));
3310036d835Schristos 	action.sa_handler = main_terminate;
3320036d835Schristos 	action.sa_flags = 0;
3330036d835Schristos 	sigemptyset(&action.sa_mask);
3340036d835Schristos 	sigaction(SIGTERM, &action, NULL);
3350036d835Schristos 	memset(&action, 0, sizeof (action));
3360036d835Schristos 	action.sa_handler = main_reap_children;
3370036d835Schristos 	action.sa_flags = 0;
3380036d835Schristos 	sigemptyset(&action.sa_mask);
3390036d835Schristos 	sigaction(SIGCHLD, &action, NULL);
3400036d835Schristos 	// Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed
3410036d835Schristos 	// connection, we don't want to get killed by a signal in that case
3420036d835Schristos 	signal(SIGPIPE, SIG_IGN);
3430036d835Schristos #endif
3440036d835Schristos 
3450036d835Schristos #ifndef _WIN32
3460036d835Schristos 	if (isrunbyinetd)
3470036d835Schristos 	{
3480036d835Schristos 		//
3490036d835Schristos 		// -i was specified, indicating that this is being run
3500036d835Schristos 		// by inetd or something that can run network daemons
3510036d835Schristos 		// as if it were inetd (xinetd, launchd, systemd, etc.).
3520036d835Schristos 		//
353*9a3414cbSchristos 		// We assume that the program that launched us just
354*9a3414cbSchristos 		// duplicated a single socket for the connection
355*9a3414cbSchristos 		// to our standard input, output, and error, so we
356*9a3414cbSchristos 		// can just use the standard input as our control
357*9a3414cbSchristos 		// socket.
3580036d835Schristos 		//
359*9a3414cbSchristos 		int sockctrl;
3600036d835Schristos 		int devnull_fd;
3610036d835Schristos 
3620036d835Schristos 		//
363*9a3414cbSchristos 		// Duplicate the standard input as the control socket.
3640036d835Schristos 		//
365*9a3414cbSchristos 		sockctrl = dup(0);
366*9a3414cbSchristos 		if (sockctrl == -1)
3670036d835Schristos 		{
368*9a3414cbSchristos 			sock_geterror("Can't dup standard input", errbuf,
369*9a3414cbSchristos 			    PCAP_ERRBUF_SIZE);
370*9a3414cbSchristos 			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
3710036d835Schristos 			exit(2);
3720036d835Schristos 		}
3730036d835Schristos 
3740036d835Schristos 		//
375*9a3414cbSchristos 		// Try to set the standard input, output, and error
376*9a3414cbSchristos 		// to /dev/null.
3770036d835Schristos 		//
3780036d835Schristos 		devnull_fd = open("/dev/null", O_RDWR);
3790036d835Schristos 		if (devnull_fd != -1)
3800036d835Schristos 		{
3810036d835Schristos 			//
3820036d835Schristos 			// If this fails, just drive on.
3830036d835Schristos 			//
3840036d835Schristos 			(void)dup2(devnull_fd, 0);
3850036d835Schristos 			(void)dup2(devnull_fd, 1);
386*9a3414cbSchristos 			(void)dup2(devnull_fd, 2);
3870036d835Schristos 			close(devnull_fd);
3880036d835Schristos 		}
3890036d835Schristos 
3900036d835Schristos 		//
3910036d835Schristos 		// Handle this client.
3920036d835Schristos 		// This is passive mode, so we don't care whether we were
3930036d835Schristos 		// told by the client to close.
3940036d835Schristos 		//
395*9a3414cbSchristos 		char *hostlist_copy = strdup(hostlist);
396*9a3414cbSchristos 		if (hostlist_copy == NULL)
397*9a3414cbSchristos 		{
398*9a3414cbSchristos 			rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
399*9a3414cbSchristos 			exit(0);
400*9a3414cbSchristos 		}
401*9a3414cbSchristos 		(void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
4020036d835Schristos 		    nullAuthAllowed);
4030036d835Schristos 
4040036d835Schristos 		//
4050036d835Schristos 		// Nothing more to do.
4060036d835Schristos 		//
4070036d835Schristos 		exit(0);
4080036d835Schristos 	}
4090036d835Schristos #endif
4100036d835Schristos 
4110036d835Schristos 	if (isdaemon)
4120036d835Schristos 	{
4130036d835Schristos 		//
4140036d835Schristos 		// This is being run as a daemon.
4150036d835Schristos 		// On UN*X, it might be manually run, or run from an
4160036d835Schristos 		// rc file.
4170036d835Schristos 		//
4180036d835Schristos #ifndef _WIN32
4190036d835Schristos 		int pid;
4200036d835Schristos 
4210036d835Schristos 		//
4220036d835Schristos 		// Daemonize ourselves.
4230036d835Schristos 		//
4240036d835Schristos 		// Unix Network Programming, pg 336
4250036d835Schristos 		//
4260036d835Schristos 		if ((pid = fork()) != 0)
4270036d835Schristos 			exit(0);		// Parent terminates
4280036d835Schristos 
4290036d835Schristos 		// First child continues
4300036d835Schristos 		// Set daemon mode
4310036d835Schristos 		setsid();
4320036d835Schristos 
4330036d835Schristos 		// generated under unix with 'kill -HUP', needed to reload the configuration
4340036d835Schristos 		memset(&action, 0, sizeof (action));
4350036d835Schristos 		action.sa_handler = main_reread_config;
4360036d835Schristos 		action.sa_flags = 0;
4370036d835Schristos 		sigemptyset(&action.sa_mask);
4380036d835Schristos 		sigaction(SIGHUP, &action, NULL);
4390036d835Schristos 
4400036d835Schristos 		if ((pid = fork()) != 0)
4410036d835Schristos 			exit(0);		// First child terminates
4420036d835Schristos 
4430036d835Schristos 		// LINUX WARNING: the current linux implementation of pthreads requires a management thread
4440036d835Schristos 		// to handle some hidden stuff. So, as soon as you create the first thread, two threads are
4450036d835Schristos 		// created. Fom this point on, the number of threads active are always one more compared
4460036d835Schristos 		// to the number you're expecting
4470036d835Schristos 
4480036d835Schristos 		// Second child continues
4490036d835Schristos //		umask(0);
4500036d835Schristos //		chdir("/");
4510036d835Schristos #else
4520036d835Schristos 		//
4530036d835Schristos 		// This is being run as a service on Windows.
4540036d835Schristos 		//
4550036d835Schristos 		// If this call succeeds, it is blocking on Win32
4560036d835Schristos 		//
4570036d835Schristos 		if (svc_start() != 1)
458*9a3414cbSchristos 			rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service");
4590036d835Schristos 
4600036d835Schristos 		// When the previous call returns, the entire application has to be stopped.
4610036d835Schristos 		exit(0);
4620036d835Schristos #endif
4630036d835Schristos 	}
4640036d835Schristos 	else	// Console mode
4650036d835Schristos 	{
4660036d835Schristos #ifndef _WIN32
4670036d835Schristos 		// Enable the catching of Ctrl+C
4680036d835Schristos 		memset(&action, 0, sizeof (action));
4690036d835Schristos 		action.sa_handler = main_terminate;
4700036d835Schristos 		action.sa_flags = 0;
4710036d835Schristos 		sigemptyset(&action.sa_mask);
4720036d835Schristos 		sigaction(SIGINT, &action, NULL);
4730036d835Schristos 
4740036d835Schristos 		// generated under unix with 'kill -HUP', needed to reload the configuration
4750036d835Schristos 		// We do not have this kind of signal in Win32
4760036d835Schristos 		memset(&action, 0, sizeof (action));
4770036d835Schristos 		action.sa_handler = main_reread_config;
4780036d835Schristos 		action.sa_flags = 0;
4790036d835Schristos 		sigemptyset(&action.sa_mask);
4800036d835Schristos 		sigaction(SIGHUP, &action, NULL);
4810036d835Schristos #endif
4820036d835Schristos 
4830036d835Schristos 		printf("Press CTRL + C to stop the server...\n");
4840036d835Schristos 	}
4850036d835Schristos 
4860036d835Schristos 	// If we're a Win32 service, we have already called this function in the service_main
4870036d835Schristos 	main_startup();
4880036d835Schristos 
4890036d835Schristos 	// The code should never arrive here (since the main_startup is blocking)
4900036d835Schristos 	//  however this avoids a compiler warning
4910036d835Schristos 	exit(0);
4920036d835Schristos }
4930036d835Schristos 
main_startup(void)4940036d835Schristos void main_startup(void)
4950036d835Schristos {
4960036d835Schristos 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
4970036d835Schristos 	struct addrinfo *addrinfo;		// keeps the addrinfo chain; required to open a new socket
4980036d835Schristos 	int i;
4990036d835Schristos #ifdef _WIN32
5000036d835Schristos 	HANDLE threadId;			// handle for the subthread
5010036d835Schristos #else
5020036d835Schristos 	pid_t pid;
5030036d835Schristos #endif
5040036d835Schristos 
5050036d835Schristos 	i = 0;
5060036d835Schristos 	addrinfo = NULL;
5070036d835Schristos 	memset(errbuf, 0, sizeof(errbuf));
5080036d835Schristos 
5090036d835Schristos 	// Starts all the active threads
5100036d835Schristos 	while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
5110036d835Schristos 	{
5120036d835Schristos 		activelist[i].ai_family = mainhints.ai_family;
5130036d835Schristos 
5140036d835Schristos #ifdef _WIN32
5150036d835Schristos 		threadId = (HANDLE)_beginthreadex(NULL, 0, main_active,
5160036d835Schristos 		    (void *)&activelist[i], 0, NULL);
5170036d835Schristos 		if (threadId == 0)
5180036d835Schristos 		{
519*9a3414cbSchristos 			rpcapd_log(LOGPRIO_DEBUG, "Error creating the active child threads");
5200036d835Schristos 			continue;
5210036d835Schristos 		}
5220036d835Schristos 		CloseHandle(threadId);
5230036d835Schristos #else
5240036d835Schristos 		if ((pid = fork()) == 0)	// I am the child
5250036d835Schristos 		{
5260036d835Schristos 			main_active((void *) &activelist[i]);
5270036d835Schristos 			exit(0);
5280036d835Schristos 		}
5290036d835Schristos #endif
5300036d835Schristos 		i++;
5310036d835Schristos 	}
5320036d835Schristos 
5330036d835Schristos 	/*
5340036d835Schristos 	 * The code that manages the active connections is not blocking;
5350036d835Schristos 	 * the code that manages the passive connection is blocking.
5360036d835Schristos 	 * So, if the user does not want to run in passive mode, we have
5370036d835Schristos 	 * to block the main thread here, otherwise the program ends and
5380036d835Schristos 	 * all threads are stopped.
5390036d835Schristos 	 *
5400036d835Schristos 	 * WARNING: this means that in case we have only active mode,
5410036d835Schristos 	 * the program does not terminate even if all the child thread
5420036d835Schristos 	 * terminates. The user has always to press Ctrl+C (or send a
5430036d835Schristos 	 * SIGTERM) to terminate the program.
5440036d835Schristos 	 */
5450036d835Schristos 	if (passivemode)
5460036d835Schristos 	{
5470036d835Schristos 		struct addrinfo *tempaddrinfo;
5480036d835Schristos 
5490036d835Schristos 		//
5500036d835Schristos 		// Get a list of sockets on which to listen.
5510036d835Schristos 		//
5520036d835Schristos 		if (sock_initaddress((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
5530036d835Schristos 		{
554*9a3414cbSchristos 			rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
5550036d835Schristos 			return;
5560036d835Schristos 		}
5570036d835Schristos 
5580036d835Schristos 		for (tempaddrinfo = addrinfo; tempaddrinfo;
5590036d835Schristos 		     tempaddrinfo = tempaddrinfo->ai_next)
5600036d835Schristos 		{
5610036d835Schristos 			SOCKET sock;
5620036d835Schristos 			struct listen_sock *sock_info;
5630036d835Schristos 
5640036d835Schristos 			if ((sock = sock_open(tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
5650036d835Schristos 			{
5660036d835Schristos 				switch (tempaddrinfo->ai_family)
5670036d835Schristos 				{
5680036d835Schristos 				case AF_INET:
5690036d835Schristos 				{
5700036d835Schristos 					struct sockaddr_in *in;
5710036d835Schristos 					char addrbuf[INET_ADDRSTRLEN];
5720036d835Schristos 
5730036d835Schristos 					in = (struct sockaddr_in *)tempaddrinfo->ai_addr;
5740036d835Schristos 					rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
5750036d835Schristos 					    inet_ntop(AF_INET, &in->sin_addr,
5760036d835Schristos 						addrbuf, sizeof (addrbuf)),
5770036d835Schristos 					    ntohs(in->sin_port),
5780036d835Schristos 					    errbuf);
5790036d835Schristos 					break;
5800036d835Schristos 				}
5810036d835Schristos 
5820036d835Schristos 				case AF_INET6:
5830036d835Schristos 				{
5840036d835Schristos 					struct sockaddr_in6 *in6;
5850036d835Schristos 					char addrbuf[INET6_ADDRSTRLEN];
5860036d835Schristos 
5870036d835Schristos 					in6 = (struct sockaddr_in6 *)tempaddrinfo->ai_addr;
5880036d835Schristos 					rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
5890036d835Schristos 					    inet_ntop(AF_INET6, &in6->sin6_addr,
5900036d835Schristos 						addrbuf, sizeof (addrbuf)),
5910036d835Schristos 					    ntohs(in6->sin6_port),
5920036d835Schristos 					    errbuf);
5930036d835Schristos 					break;
5940036d835Schristos 				}
5950036d835Schristos 
5960036d835Schristos 				default:
5970036d835Schristos 					rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for address family %u: %s",
5980036d835Schristos 					    tempaddrinfo->ai_family,
5990036d835Schristos 					    errbuf);
6000036d835Schristos 					break;
6010036d835Schristos 				}
6020036d835Schristos 				continue;
6030036d835Schristos 			}
6040036d835Schristos 
6050036d835Schristos 			sock_info = (struct listen_sock *) malloc(sizeof (struct listen_sock));
6060036d835Schristos 			if (sock_info == NULL)
6070036d835Schristos 			{
6080036d835Schristos 				rpcapd_log(LOGPRIO_ERROR, "Can't allocate structure for listen socket");
6090036d835Schristos 				exit(2);
6100036d835Schristos 			}
6110036d835Schristos 			sock_info->sock = sock;
6120036d835Schristos 			sock_info->next = listen_socks;
6130036d835Schristos 			listen_socks = sock_info;
6140036d835Schristos 		}
6150036d835Schristos 
6160036d835Schristos 		freeaddrinfo(addrinfo);
6170036d835Schristos 
6180036d835Schristos 		if (listen_socks == NULL)
6190036d835Schristos 		{
6200036d835Schristos 			rpcapd_log(LOGPRIO_ERROR, "Can't listen on any address");
6210036d835Schristos 			exit(2);
6220036d835Schristos 		}
6230036d835Schristos 
6240036d835Schristos 		//
6250036d835Schristos 		// Now listen on all of them, waiting for connections.
6260036d835Schristos 		//
6270036d835Schristos 		accept_connections();
6280036d835Schristos 	}
6290036d835Schristos 
6300036d835Schristos 	//
6310036d835Schristos 	// We're done; exit.
6320036d835Schristos 	//
633*9a3414cbSchristos 	rpcapd_log(LOGPRIO_DEBUG, PROGRAM_NAME " is closing.\n");
6340036d835Schristos 
6350036d835Schristos #ifndef _WIN32
6360036d835Schristos 	//
6370036d835Schristos 	// Sends a KILL signal to all the processes in this process's
6380036d835Schristos 	// process group; i.e., it kills all the child processes
6390036d835Schristos 	// we've created.
6400036d835Schristos 	//
6410036d835Schristos 	// XXX - that also includes us, so we will be killed as well;
6420036d835Schristos 	// that may cause a message to be printed or logged.
6430036d835Schristos 	//
6440036d835Schristos 	kill(0, SIGKILL);
6450036d835Schristos #endif
6460036d835Schristos 
6470036d835Schristos 	//
6480036d835Schristos 	// Just leave.  We shouldn't need to clean up sockets or
6490036d835Schristos 	// anything else, and if we try to do so, we'll could end
6500036d835Schristos 	// up closing sockets, or shutting Winsock down, out from
6510036d835Schristos 	// under service loops, causing all sorts of noisy error
6520036d835Schristos 	// messages.
6530036d835Schristos 	//
6540036d835Schristos 	// We shouldn't need to worry about cleaning up any resources
6550036d835Schristos 	// such as handles, sockets, threads, etc. - exit() should
6560036d835Schristos 	// terminate the process, causing all those resources to be
6570036d835Schristos 	// cleaned up (including the threads; Microsoft claims in the
6580036d835Schristos 	// ExitProcess() documentation that, if ExitProcess() is called,
6590036d835Schristos 	// "If a thread is waiting on a kernel object, it will not be
6600036d835Schristos 	// terminated until the wait has completed.", but claims in the
6610036d835Schristos 	// _beginthread()/_beginthreadex() documentation that "All threads
6620036d835Schristos 	// are terminated if any thread calls abort, exit, _exit, or
6630036d835Schristos 	// ExitProcess." - the latter appears to be the case, even for
6640036d835Schristos 	// threads waiting on the event for a pcap_t).
6650036d835Schristos 	//
6660036d835Schristos 	exit(0);
6670036d835Schristos }
6680036d835Schristos 
6690036d835Schristos #ifdef _WIN32
6700036d835Schristos static void
send_state_change_event(void)6710036d835Schristos send_state_change_event(void)
6720036d835Schristos {
6730036d835Schristos 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
6740036d835Schristos 
6750036d835Schristos 	if (!SetEvent(state_change_event))
6760036d835Schristos 	{
677*9a3414cbSchristos 		sock_geterror("SetEvent on shutdown event failed", errbuf,
678*9a3414cbSchristos 		    PCAP_ERRBUF_SIZE);
679*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
6800036d835Schristos 	}
6810036d835Schristos }
6820036d835Schristos 
6830036d835Schristos void
send_shutdown_notification(void)6840036d835Schristos send_shutdown_notification(void)
6850036d835Schristos {
6860036d835Schristos 	//
6870036d835Schristos 	// Indicate that the server should shut down.
6880036d835Schristos 	//
6890036d835Schristos 	shutdown_server = 1;
6900036d835Schristos 
6910036d835Schristos 	//
6920036d835Schristos 	// Send a state change event, to wake up WSAWaitForMultipleEvents().
6930036d835Schristos 	//
6940036d835Schristos 	send_state_change_event();
6950036d835Schristos }
6960036d835Schristos 
6970036d835Schristos void
send_reread_configuration_notification(void)6980036d835Schristos send_reread_configuration_notification(void)
6990036d835Schristos {
7000036d835Schristos 	//
7010036d835Schristos 	// Indicate that the server should re-read its configuration file.
7020036d835Schristos 	//
7030036d835Schristos 	reread_config = 1;
7040036d835Schristos 
7050036d835Schristos 	//
7060036d835Schristos 	// Send a state change event, to wake up WSAWaitForMultipleEvents().
7070036d835Schristos 	//
7080036d835Schristos 	send_state_change_event();
7090036d835Schristos }
7100036d835Schristos 
main_ctrl_event(DWORD ctrltype)7110036d835Schristos static BOOL WINAPI main_ctrl_event(DWORD ctrltype)
7120036d835Schristos {
7130036d835Schristos 	//
7140036d835Schristos 	// ctrltype is one of:
7150036d835Schristos 	//
7160036d835Schristos 	// CTRL_C_EVENT - we got a ^C; this is like SIGINT
7170036d835Schristos 	// CTRL_BREAK_EVENT - we got Ctrl+Break
7180036d835Schristos 	// CTRL_CLOSE_EVENT - the console was closed; this is like SIGHUP
7190036d835Schristos 	// CTRL_LOGOFF_EVENT - a user is logging off; this is received
7200036d835Schristos 	//   only by services
7210036d835Schristos 	// CTRL_SHUTDOWN_EVENT - the systemis shutting down; this is
7220036d835Schristos 	//   received only by services
7230036d835Schristos 	//
7240036d835Schristos 	// For now, we treat all but CTRL_LOGOFF_EVENT as indications
7250036d835Schristos 	// that we should shut down.
7260036d835Schristos 	//
7270036d835Schristos 	switch (ctrltype)
7280036d835Schristos 	{
7290036d835Schristos 		case CTRL_C_EVENT:
7300036d835Schristos 		case CTRL_BREAK_EVENT:
7310036d835Schristos 		case CTRL_CLOSE_EVENT:
7320036d835Schristos 		case CTRL_SHUTDOWN_EVENT:
7330036d835Schristos 			//
7340036d835Schristos 			// Set a shutdown notification.
7350036d835Schristos 			//
7360036d835Schristos 			send_shutdown_notification();
7370036d835Schristos 			break;
7380036d835Schristos 
7390036d835Schristos 		default:
7400036d835Schristos 			break;
7410036d835Schristos 	}
7420036d835Schristos 
7430036d835Schristos 	//
7440036d835Schristos 	// We handled this.
7450036d835Schristos 	//
7460036d835Schristos 	return TRUE;
7470036d835Schristos }
7480036d835Schristos #else
main_terminate(int sign _U_)7490036d835Schristos static void main_terminate(int sign _U_)
7500036d835Schristos {
7510036d835Schristos 	//
7520036d835Schristos 	// Note that the server should shut down.
7530036d835Schristos 	// select() should get an EINTR error when we return,
7540036d835Schristos 	// so it will wake up and know it needs to check the flag.
7550036d835Schristos 	//
7560036d835Schristos 	shutdown_server = 1;
7570036d835Schristos }
7580036d835Schristos 
main_reread_config(int sign _U_)7590036d835Schristos static void main_reread_config(int sign _U_)
7600036d835Schristos {
7610036d835Schristos 	//
7620036d835Schristos 	// Note that the server should re-read its configuration file.
7630036d835Schristos 	// select() should get an EINTR error when we return,
7640036d835Schristos 	// so it will wake up and know it needs to check the flag.
7650036d835Schristos 	//
7660036d835Schristos 	reread_config = 1;
7670036d835Schristos }
7680036d835Schristos 
main_reap_children(int sign _U_)7690036d835Schristos static void main_reap_children(int sign _U_)
7700036d835Schristos {
7710036d835Schristos 	pid_t pid;
7720036d835Schristos 	int exitstat;
7730036d835Schristos 
7740036d835Schristos 	// Reap all child processes that have exited.
7750036d835Schristos 	// For reference, Stevens, pg 128
7760036d835Schristos 
7770036d835Schristos 	while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0)
778*9a3414cbSchristos 		rpcapd_log(LOGPRIO_DEBUG, "Child terminated");
7790036d835Schristos 
7800036d835Schristos 	return;
7810036d835Schristos }
7820036d835Schristos #endif
7830036d835Schristos 
7840036d835Schristos //
7850036d835Schristos // Loop waiting for incoming connections and accepting them.
7860036d835Schristos //
7870036d835Schristos static void
accept_connections(void)7880036d835Schristos accept_connections(void)
7890036d835Schristos {
7900036d835Schristos #ifdef _WIN32
7910036d835Schristos 	struct listen_sock *sock_info;
7920036d835Schristos 	DWORD num_events;
7930036d835Schristos 	WSAEVENT *events;
7940036d835Schristos 	int i;
7950036d835Schristos 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
7960036d835Schristos 
7970036d835Schristos 	//
7980036d835Schristos 	// How big does the set of events need to be?
7990036d835Schristos 	// One for the shutdown event, plus one for every socket on which
8000036d835Schristos 	// we'll be listening.
8010036d835Schristos 	//
8020036d835Schristos 	num_events = 1;		// shutdown event
8030036d835Schristos 	for (sock_info = listen_socks; sock_info;
8040036d835Schristos 	    sock_info = sock_info->next)
8050036d835Schristos 	{
8060036d835Schristos 		if (num_events == WSA_MAXIMUM_WAIT_EVENTS)
8070036d835Schristos 		{
8080036d835Schristos 			//
8090036d835Schristos 			// WSAWaitForMultipleEvents() doesn't support
8100036d835Schristos 			// more than WSA_MAXIMUM_WAIT_EVENTS events
8110036d835Schristos 			// on which to wait.
8120036d835Schristos 			//
8130036d835Schristos 			rpcapd_log(LOGPRIO_ERROR, "Too many sockets on which to listen");
8140036d835Schristos 			exit(2);
8150036d835Schristos 		}
8160036d835Schristos 		num_events++;
8170036d835Schristos 	}
8180036d835Schristos 
8190036d835Schristos 	//
8200036d835Schristos 	// Allocate the array of events.
8210036d835Schristos 	//
8220036d835Schristos 	events = (WSAEVENT *) malloc(num_events * sizeof (WSAEVENT));
8230036d835Schristos 	if (events == NULL)
8240036d835Schristos 	{
8250036d835Schristos 		rpcapd_log(LOGPRIO_ERROR, "Can't allocate array of events which to listen");
8260036d835Schristos 		exit(2);
8270036d835Schristos 	}
8280036d835Schristos 
8290036d835Schristos 	//
8300036d835Schristos 	// Fill it in.
8310036d835Schristos 	//
8320036d835Schristos 	events[0] = state_change_event;	// state change event first
8330036d835Schristos 	for (sock_info = listen_socks, i = 1; sock_info;
8340036d835Schristos 	    sock_info = sock_info->next, i++)
8350036d835Schristos 	{
8360036d835Schristos 		WSAEVENT event;
8370036d835Schristos 
8380036d835Schristos 		//
8390036d835Schristos 		// Create an event that is signaled if there's a connection
8400036d835Schristos 		// to accept on the socket in question.
8410036d835Schristos 		//
8420036d835Schristos 		event = WSACreateEvent();
8430036d835Schristos 		if (event == WSA_INVALID_EVENT)
8440036d835Schristos 		{
845*9a3414cbSchristos 			sock_geterror("Can't create socket event", errbuf,
846*9a3414cbSchristos 			    PCAP_ERRBUF_SIZE);
847*9a3414cbSchristos 			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
8480036d835Schristos 			exit(2);
8490036d835Schristos 		}
8500036d835Schristos 		if (WSAEventSelect(sock_info->sock, event, FD_ACCEPT) == SOCKET_ERROR)
8510036d835Schristos 		{
852*9a3414cbSchristos 			sock_geterror("Can't setup socket event", errbuf,
853*9a3414cbSchristos 			    PCAP_ERRBUF_SIZE);
854*9a3414cbSchristos 			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
8550036d835Schristos 			exit(2);
8560036d835Schristos 		}
8570036d835Schristos 		events[i] = event;
8580036d835Schristos 	}
8590036d835Schristos 
8600036d835Schristos 	for (;;)
8610036d835Schristos 	{
8620036d835Schristos 		//
8630036d835Schristos 		// Wait for incoming connections.
8640036d835Schristos 		//
8650036d835Schristos 		DWORD ret;
8660036d835Schristos 
8670036d835Schristos 		ret = WSAWaitForMultipleEvents(num_events, events, FALSE,
8680036d835Schristos 		    WSA_INFINITE, FALSE);
8690036d835Schristos 		if (ret == WSA_WAIT_FAILED)
8700036d835Schristos 		{
871*9a3414cbSchristos 			sock_geterror("WSAWaitForMultipleEvents failed", errbuf,
872*9a3414cbSchristos 			    PCAP_ERRBUF_SIZE);
873*9a3414cbSchristos 			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
8740036d835Schristos 			exit(2);
8750036d835Schristos 		}
8760036d835Schristos 
8770036d835Schristos 		if (ret == WSA_WAIT_EVENT_0)
8780036d835Schristos 		{
8790036d835Schristos 			//
8800036d835Schristos 			// The state change event was set.
8810036d835Schristos 			//
8820036d835Schristos 			if (shutdown_server)
8830036d835Schristos 			{
8840036d835Schristos 				//
8850036d835Schristos 				// Time to quit. Exit the loop.
8860036d835Schristos 				//
8870036d835Schristos 				break;
8880036d835Schristos 			}
8890036d835Schristos 			if (reread_config)
8900036d835Schristos 			{
8910036d835Schristos 				//
8920036d835Schristos 				// We should re-read the configuration
8930036d835Schristos 				// file.
8940036d835Schristos 				//
8950036d835Schristos 				reread_config = 0;	// clear the indicator
8960036d835Schristos 				fileconf_read();
8970036d835Schristos 			}
8980036d835Schristos 		}
8990036d835Schristos 
9000036d835Schristos 		//
9010036d835Schristos 		// Check each socket.
9020036d835Schristos 		//
9030036d835Schristos 		for (sock_info = listen_socks, i = 1; sock_info;
9040036d835Schristos 		    sock_info = sock_info->next, i++)
9050036d835Schristos 		{
9060036d835Schristos 			WSANETWORKEVENTS network_events;
9070036d835Schristos 
9080036d835Schristos 			if (WSAEnumNetworkEvents(sock_info->sock,
9090036d835Schristos 			    events[i], &network_events) == SOCKET_ERROR)
9100036d835Schristos 			{
911*9a3414cbSchristos 				sock_geterror("WSAEnumNetworkEvents failed",
912*9a3414cbSchristos 				    errbuf, PCAP_ERRBUF_SIZE);
913*9a3414cbSchristos 				rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
9140036d835Schristos 				exit(2);
9150036d835Schristos 			}
9160036d835Schristos 			if (network_events.lNetworkEvents & FD_ACCEPT)
9170036d835Schristos 			{
9180036d835Schristos 				//
9190036d835Schristos 				// Did an error occur?
9200036d835Schristos 				//
9210036d835Schristos 			 	if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
9220036d835Schristos 			 	{
9230036d835Schristos 					//
9240036d835Schristos 					// Yes - report it and keep going.
9250036d835Schristos 					//
926*9a3414cbSchristos 					sock_fmterror("Socket error",
9270036d835Schristos 					    network_events.iErrorCode[FD_ACCEPT_BIT],
9280036d835Schristos 					    errbuf,
9290036d835Schristos 					    PCAP_ERRBUF_SIZE);
930*9a3414cbSchristos 					rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
9310036d835Schristos 					continue;
9320036d835Schristos 				}
9330036d835Schristos 
9340036d835Schristos 				//
9350036d835Schristos 				// Accept the connection.
9360036d835Schristos 				//
9370036d835Schristos 				accept_connection(sock_info->sock);
9380036d835Schristos 			}
9390036d835Schristos 		}
9400036d835Schristos 	}
9410036d835Schristos #else
9420036d835Schristos 	struct listen_sock *sock_info;
9430036d835Schristos 	int num_sock_fds;
9440036d835Schristos 
9450036d835Schristos 	//
9460036d835Schristos 	// How big does the bitset of sockets on which to select() have
9470036d835Schristos 	// to be?
9480036d835Schristos 	//
9490036d835Schristos 	num_sock_fds = 0;
9500036d835Schristos 	for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
9510036d835Schristos 	{
9520036d835Schristos 		if (sock_info->sock + 1 > num_sock_fds)
9530036d835Schristos 		{
9540036d835Schristos 			if ((unsigned int)(sock_info->sock + 1) >
9550036d835Schristos 			    (unsigned int)FD_SETSIZE)
9560036d835Schristos 			{
9570036d835Schristos 				rpcapd_log(LOGPRIO_ERROR, "Socket FD is too bit for an fd_set");
9580036d835Schristos 				exit(2);
9590036d835Schristos 			}
9600036d835Schristos 			num_sock_fds = sock_info->sock + 1;
9610036d835Schristos 		}
9620036d835Schristos 	}
9630036d835Schristos 
9640036d835Schristos 	for (;;)
9650036d835Schristos 	{
9660036d835Schristos 		fd_set sock_fds;
9670036d835Schristos 		int ret;
9680036d835Schristos 
9690036d835Schristos 		//
9700036d835Schristos 		// Set up an fd_set for all the sockets on which we're
9710036d835Schristos 		// listening.
9720036d835Schristos 		//
9730036d835Schristos 		// This set is modified by select(), so we have to
9740036d835Schristos 		// construct it anew each time.
9750036d835Schristos 		//
9760036d835Schristos 		FD_ZERO(&sock_fds);
9770036d835Schristos 		for (sock_info = listen_socks; sock_info;
9780036d835Schristos 		    sock_info = sock_info->next)
9790036d835Schristos 		{
9800036d835Schristos 			FD_SET(sock_info->sock, &sock_fds);
9810036d835Schristos 		}
9820036d835Schristos 
9830036d835Schristos 		//
9840036d835Schristos 		// Wait for incoming connections.
9850036d835Schristos 		//
9860036d835Schristos 		ret = select(num_sock_fds, &sock_fds, NULL, NULL, NULL);
9870036d835Schristos 		if (ret == -1)
9880036d835Schristos 		{
9890036d835Schristos 			if (errno == EINTR)
9900036d835Schristos 			{
9910036d835Schristos 				//
9920036d835Schristos 				// If this is a "terminate the
9930036d835Schristos 				// server" signal, exit the loop,
9940036d835Schristos 				// otherwise just keep trying.
9950036d835Schristos 				//
9960036d835Schristos 				if (shutdown_server)
9970036d835Schristos 				{
9980036d835Schristos 					//
9990036d835Schristos 					// Time to quit.  Exit the loop.
10000036d835Schristos 					//
10010036d835Schristos 					break;
10020036d835Schristos 				}
10030036d835Schristos 				if (reread_config)
10040036d835Schristos 				{
10050036d835Schristos 					//
10060036d835Schristos 					// We should re-read the configuration
10070036d835Schristos 					// file.
10080036d835Schristos 					//
10090036d835Schristos 					reread_config = 0;	// clear the indicator
10100036d835Schristos 					fileconf_read();
10110036d835Schristos 				}
10120036d835Schristos 
10130036d835Schristos 				//
10140036d835Schristos 				// Go back and wait again.
10150036d835Schristos 				//
10160036d835Schristos 				continue;
10170036d835Schristos 			}
10180036d835Schristos 			else
10190036d835Schristos 			{
10200036d835Schristos 				rpcapd_log(LOGPRIO_ERROR, "select failed: %s",
10210036d835Schristos 				    strerror(errno));
10220036d835Schristos 				exit(2);
10230036d835Schristos 			}
10240036d835Schristos 		}
10250036d835Schristos 
10260036d835Schristos 		//
10270036d835Schristos 		// Check each socket.
10280036d835Schristos 		//
10290036d835Schristos 		for (sock_info = listen_socks; sock_info;
10300036d835Schristos 		    sock_info = sock_info->next)
10310036d835Schristos 		{
10320036d835Schristos 			if (FD_ISSET(sock_info->sock, &sock_fds))
10330036d835Schristos 			{
10340036d835Schristos 				//
10350036d835Schristos 				// Accept the connection.
10360036d835Schristos 				//
10370036d835Schristos 				accept_connection(sock_info->sock);
10380036d835Schristos 			}
10390036d835Schristos 		}
10400036d835Schristos 	}
10410036d835Schristos #endif
10420036d835Schristos 
10430036d835Schristos 	//
10440036d835Schristos 	// Close all the listen sockets.
10450036d835Schristos 	//
10460036d835Schristos 	for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
10470036d835Schristos 	{
10480036d835Schristos 		closesocket(sock_info->sock);
10490036d835Schristos 	}
10500036d835Schristos 	sock_cleanup();
10510036d835Schristos }
10520036d835Schristos 
1053*9a3414cbSchristos #ifdef _WIN32
1054*9a3414cbSchristos //
1055*9a3414cbSchristos // A structure to hold the parameters to the daemon service loop
1056*9a3414cbSchristos // thread on Windows.
1057*9a3414cbSchristos //
1058*9a3414cbSchristos // (On UN*X, there is no need for this explicit copy since the
1059*9a3414cbSchristos // fork "inherits" the parent stack.)
1060*9a3414cbSchristos //
1061*9a3414cbSchristos struct params_copy {
1062*9a3414cbSchristos 	SOCKET sockctrl;
1063*9a3414cbSchristos 	char *hostlist;
1064*9a3414cbSchristos };
1065*9a3414cbSchristos #endif
1066*9a3414cbSchristos 
10670036d835Schristos //
10680036d835Schristos // Accept a connection and start a worker thread, on Windows, or a
10690036d835Schristos // worker process, on UN*X, to handle the connection.
10700036d835Schristos //
10710036d835Schristos static void
accept_connection(SOCKET listen_sock)10720036d835Schristos accept_connection(SOCKET listen_sock)
10730036d835Schristos {
10740036d835Schristos 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
10750036d835Schristos 	SOCKET sockctrl;			// keeps the socket ID for this control connection
10760036d835Schristos 	struct sockaddr_storage from;		// generic sockaddr_storage variable
10770036d835Schristos 	socklen_t fromlen;			// keeps the length of the sockaddr_storage variable
10780036d835Schristos 
10790036d835Schristos #ifdef _WIN32
10800036d835Schristos 	HANDLE threadId;			// handle for the subthread
10810036d835Schristos 	u_long off = 0;
1082*9a3414cbSchristos 	struct params_copy *params_copy = NULL;
10830036d835Schristos #else
10840036d835Schristos 	pid_t pid;
10850036d835Schristos #endif
10860036d835Schristos 
10870036d835Schristos 	// Initialize errbuf
10880036d835Schristos 	memset(errbuf, 0, sizeof(errbuf));
10890036d835Schristos 
10900036d835Schristos 	for (;;)
10910036d835Schristos 	{
10920036d835Schristos 		// Accept the connection
10930036d835Schristos 		fromlen = sizeof(struct sockaddr_storage);
10940036d835Schristos 
10950036d835Schristos 		sockctrl = accept(listen_sock, (struct sockaddr *) &from, &fromlen);
10960036d835Schristos 
10970036d835Schristos 		if (sockctrl != INVALID_SOCKET)
10980036d835Schristos 		{
10990036d835Schristos 			// Success.
11000036d835Schristos 			break;
11010036d835Schristos 		}
11020036d835Schristos 
11030036d835Schristos 		// The accept() call can return this error when a signal is catched
11040036d835Schristos 		// In this case, we have simply to ignore this error code
11050036d835Schristos 		// Stevens, pg 124
11060036d835Schristos #ifdef _WIN32
11070036d835Schristos 		if (WSAGetLastError() == WSAEINTR)
11080036d835Schristos #else
11090036d835Schristos 		if (errno == EINTR)
11100036d835Schristos #endif
11110036d835Schristos 			continue;
11120036d835Schristos 
11130036d835Schristos 		// Don't check for errors here, since the error can be due to the fact that the thread
11140036d835Schristos 		// has been killed
1115*9a3414cbSchristos 		sock_geterror("accept()", errbuf, PCAP_ERRBUF_SIZE);
11160036d835Schristos 		rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s",
11170036d835Schristos 		    errbuf);
11180036d835Schristos 		return;
11190036d835Schristos 	}
11200036d835Schristos 
11210036d835Schristos #ifdef _WIN32
11220036d835Schristos 	//
11230036d835Schristos 	// Put the socket back into blocking mode; doing WSAEventSelect()
11240036d835Schristos 	// on the listen socket makes that socket non-blocking, and it
11250036d835Schristos 	// appears that sockets returned from an accept() on that socket
11260036d835Schristos 	// are also non-blocking.
11270036d835Schristos 	//
11280036d835Schristos 	// First, we have to un-WSAEventSelect() this socket, and then
11290036d835Schristos 	// we can turn non-blocking mode off.
11300036d835Schristos 	//
1131*9a3414cbSchristos 	// If this fails, we aren't guaranteed that, for example, any
1132*9a3414cbSchristos 	// of the error message will be sent - if it can't be put in
1133*9a3414cbSchristos 	// the socket queue, the send will just fail.
1134*9a3414cbSchristos 	//
1135*9a3414cbSchristos 	// So we just log the message and close the connection.
1136*9a3414cbSchristos 	//
11370036d835Schristos 	if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR)
11380036d835Schristos 	{
1139*9a3414cbSchristos 		sock_geterror("WSAEventSelect()", errbuf, PCAP_ERRBUF_SIZE);
1140*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
11410036d835Schristos 		sock_close(sockctrl, NULL, 0);
11420036d835Schristos 		return;
11430036d835Schristos 	}
11440036d835Schristos 	if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR)
11450036d835Schristos 	{
1146*9a3414cbSchristos 		sock_geterror("ioctlsocket(FIONBIO)", errbuf, PCAP_ERRBUF_SIZE);
1147*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
11480036d835Schristos 		sock_close(sockctrl, NULL, 0);
11490036d835Schristos 		return;
11500036d835Schristos 	}
11510036d835Schristos 
11520036d835Schristos 	//
1153*9a3414cbSchristos 	// Make a copy of the host list to pass to the new thread, so that
1154*9a3414cbSchristos 	// if we update it in the main thread, it won't catch us in the
1155*9a3414cbSchristos 	// middle of updating it.
1156*9a3414cbSchristos 	//
1157*9a3414cbSchristos 	// daemon_serviceloop() will free it once it's done with it.
1158*9a3414cbSchristos 	//
1159*9a3414cbSchristos 	char *hostlist_copy = strdup(hostlist);
1160*9a3414cbSchristos 	if (hostlist_copy == NULL)
1161*9a3414cbSchristos 	{
1162*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1163*9a3414cbSchristos 		sock_close(sockctrl, NULL, 0);
1164*9a3414cbSchristos 		return;
1165*9a3414cbSchristos 	}
1166*9a3414cbSchristos 
1167*9a3414cbSchristos 	//
1168*9a3414cbSchristos 	// Allocate a location to hold the values of sockctrl.
11690036d835Schristos 	// It will be freed in the newly-created thread once it's
11700036d835Schristos 	// finished with it.
11710036d835Schristos 	//
1172*9a3414cbSchristos 	params_copy = malloc(sizeof(*params_copy));
1173*9a3414cbSchristos 	if (params_copy == NULL)
11740036d835Schristos 	{
1175*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "Out of memory allocating the parameter copy structure");
1176*9a3414cbSchristos 		free(hostlist_copy);
11770036d835Schristos 		sock_close(sockctrl, NULL, 0);
11780036d835Schristos 		return;
11790036d835Schristos 	}
1180*9a3414cbSchristos 	params_copy->sockctrl = sockctrl;
1181*9a3414cbSchristos 	params_copy->hostlist = hostlist_copy;
11820036d835Schristos 
11830036d835Schristos 	threadId = (HANDLE)_beginthreadex(NULL, 0,
1184*9a3414cbSchristos 	    main_passive_serviceloop_thread, (void *) params_copy, 0, NULL);
11850036d835Schristos 	if (threadId == 0)
11860036d835Schristos 	{
1187*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "Error creating the child thread");
1188*9a3414cbSchristos 		free(params_copy);
1189*9a3414cbSchristos 		free(hostlist_copy);
11900036d835Schristos 		sock_close(sockctrl, NULL, 0);
11910036d835Schristos 		return;
11920036d835Schristos 	}
11930036d835Schristos 	CloseHandle(threadId);
1194*9a3414cbSchristos #else /* _WIN32 */
11950036d835Schristos 	pid = fork();
11960036d835Schristos 	if (pid == -1)
11970036d835Schristos 	{
1198*9a3414cbSchristos 		rpcapd_log(LOGPRIO_ERROR, "Error creating the child process: %s",
1199*9a3414cbSchristos 		    strerror(errno));
12000036d835Schristos 		sock_close(sockctrl, NULL, 0);
12010036d835Schristos 		return;
12020036d835Schristos 	}
12030036d835Schristos 	if (pid == 0)
12040036d835Schristos 	{
12050036d835Schristos 		//
12060036d835Schristos 		// Child process.
12070036d835Schristos 		//
12080036d835Schristos 		// Close the socket on which we're listening (must
12090036d835Schristos 		// be open only in the parent).
12100036d835Schristos 		//
12110036d835Schristos 		closesocket(listen_sock);
12120036d835Schristos 
12130036d835Schristos #if 0
12140036d835Schristos 		//
12150036d835Schristos 		// Modify thread params so that it can be killed at any time
12160036d835Schristos 		// XXX - is this necessary?  This is the main and, currently,
12170036d835Schristos 		// only thread in the child process, and nobody tries to
12180036d835Schristos 		// cancel us, although *we* may cancel the thread that's
12190036d835Schristos 		// handling the capture loop.
12200036d835Schristos 		//
12210036d835Schristos 		if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
12220036d835Schristos 			goto end;
12230036d835Schristos 		if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
12240036d835Schristos 			goto end;
12250036d835Schristos #endif
12260036d835Schristos 
12270036d835Schristos 		//
12280036d835Schristos 		// Run the service loop.
12290036d835Schristos 		// This is passive mode, so we don't care whether we were
12300036d835Schristos 		// told by the client to close.
12310036d835Schristos 		//
1232*9a3414cbSchristos 		char *hostlist_copy = strdup(hostlist);
1233*9a3414cbSchristos 		if (hostlist_copy == NULL)
1234*9a3414cbSchristos 		{
1235*9a3414cbSchristos 			rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1236*9a3414cbSchristos 			exit(0);
1237*9a3414cbSchristos 		}
1238*9a3414cbSchristos 		(void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
12390036d835Schristos 		    nullAuthAllowed);
12400036d835Schristos 
12410036d835Schristos 		exit(0);
12420036d835Schristos 	}
12430036d835Schristos 
12440036d835Schristos 	// I am the parent
12450036d835Schristos 	// Close the socket for this session (must be open only in the child)
12460036d835Schristos 	closesocket(sockctrl);
1247*9a3414cbSchristos #endif /* _WIN32 */
12480036d835Schristos }
12490036d835Schristos 
12500036d835Schristos /*!
12510036d835Schristos 	\brief 'true' main of the program in case the active mode is turned on.
12520036d835Schristos 
12530036d835Schristos 	This function loops forever trying to connect to the remote host, until the
12540036d835Schristos 	daemon is turned down.
12550036d835Schristos 
12560036d835Schristos 	\param ptr: it keeps the 'activepars' parameters.  It is a 'void *'
12570036d835Schristos 	just because the thread APIs want this format.
12580036d835Schristos */
12590036d835Schristos #ifdef _WIN32
12600036d835Schristos static unsigned __stdcall
12610036d835Schristos #else
12620036d835Schristos static void *
12630036d835Schristos #endif
main_active(void * ptr)12640036d835Schristos main_active(void *ptr)
12650036d835Schristos {
12660036d835Schristos 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
12670036d835Schristos 	SOCKET sockctrl;			// keeps the socket ID for this control connection
12680036d835Schristos 	struct addrinfo hints;			// temporary struct to keep settings needed to open the new socket
12690036d835Schristos 	struct addrinfo *addrinfo;		// keeps the addrinfo chain; required to open a new socket
12700036d835Schristos 	struct active_pars *activepars;
12710036d835Schristos 
12720036d835Schristos 	activepars = (struct active_pars *) ptr;
12730036d835Schristos 
12740036d835Schristos 	// Prepare to open a new server socket
12750036d835Schristos 	memset(&hints, 0, sizeof(struct addrinfo));
12760036d835Schristos 						// WARNING Currently it supports only ONE socket family among IPv4 and IPv6
12770036d835Schristos 	hints.ai_family = AF_INET;		// PF_UNSPEC to have both IPv4 and IPv6 server
12780036d835Schristos 	hints.ai_socktype = SOCK_STREAM;
12790036d835Schristos 	hints.ai_family = activepars->ai_family;
12800036d835Schristos 
1281*9a3414cbSchristos 	rpcapd_log(LOGPRIO_DEBUG, "Connecting to host %s, port %s, using protocol %s",
12820036d835Schristos 	    activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
12830036d835Schristos 	    (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
12840036d835Schristos 
12850036d835Schristos 	// Initialize errbuf
12860036d835Schristos 	memset(errbuf, 0, sizeof(errbuf));
12870036d835Schristos 
12880036d835Schristos 	// Do the work
12890036d835Schristos 	if (sock_initaddress(activepars->address, activepars->port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
12900036d835Schristos 	{
1291*9a3414cbSchristos 		rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
12920036d835Schristos 		return 0;
12930036d835Schristos 	}
12940036d835Schristos 
12950036d835Schristos 	for (;;)
12960036d835Schristos 	{
12970036d835Schristos 		int activeclose;
12980036d835Schristos 
12990036d835Schristos 		if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
13000036d835Schristos 		{
1301*9a3414cbSchristos 			rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
13020036d835Schristos 
13030036d835Schristos 			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
13040036d835Schristos 					activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
13050036d835Schristos 					(hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
13060036d835Schristos 
1307*9a3414cbSchristos 			rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
13080036d835Schristos 
13090036d835Schristos 			sleep_secs(RPCAP_ACTIVE_WAIT);
13100036d835Schristos 
13110036d835Schristos 			continue;
13120036d835Schristos 		}
13130036d835Schristos 
1314*9a3414cbSchristos 		char *hostlist_copy = strdup(hostlist);
1315*9a3414cbSchristos 		if (hostlist_copy == NULL)
1316*9a3414cbSchristos 		{
1317*9a3414cbSchristos 			rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1318*9a3414cbSchristos 			activeclose = 0;
13190036d835Schristos 			sock_close(sockctrl, NULL, 0);
1320*9a3414cbSchristos 		}
1321*9a3414cbSchristos 		else
1322*9a3414cbSchristos 		{
1323*9a3414cbSchristos 			//
1324*9a3414cbSchristos 			// daemon_serviceloop() will free the copy.
1325*9a3414cbSchristos 			//
1326*9a3414cbSchristos 			activeclose = daemon_serviceloop(sockctrl, 1,
1327*9a3414cbSchristos 			    hostlist_copy, nullAuthAllowed);
1328*9a3414cbSchristos 		}
13290036d835Schristos 
13300036d835Schristos 		// If the connection is closed by the user explicitely, don't try to connect to it again
13310036d835Schristos 		// just exit the program
13320036d835Schristos 		if (activeclose == 1)
13330036d835Schristos 			break;
13340036d835Schristos 	}
13350036d835Schristos 
13360036d835Schristos 	freeaddrinfo(addrinfo);
13370036d835Schristos 	return 0;
13380036d835Schristos }
13390036d835Schristos 
13400036d835Schristos #ifdef _WIN32
13410036d835Schristos //
13420036d835Schristos // Main routine of a passive-mode service thread.
13430036d835Schristos //
main_passive_serviceloop_thread(void * ptr)13440036d835Schristos unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
13450036d835Schristos {
1346*9a3414cbSchristos 	struct params_copy params = *(struct params_copy *)ptr;
13470036d835Schristos 	free(ptr);
13480036d835Schristos 
13490036d835Schristos 	//
13500036d835Schristos 	// Handle this client.
13510036d835Schristos 	// This is passive mode, so we don't care whether we were
13520036d835Schristos 	// told by the client to close.
13530036d835Schristos 	//
1354*9a3414cbSchristos 	(void)daemon_serviceloop(params.sockctrl, 0, params.hostlist,
1355*9a3414cbSchristos 	    nullAuthAllowed);
13560036d835Schristos 
13570036d835Schristos 	return 0;
13580036d835Schristos }
13590036d835Schristos #endif
1360