From: Guy Harris Date: Mon, 2 Apr 2018 07:44:47 +0000 (-0700) Subject: Merge pull request #685 from jmayer/add-static X-Git-Tag: libpcap-1.9-bp~128 X-Git-Url: https://git.tcpdump.org/libpcap/commitdiff_plain/d7d31639251c64e32aad97e85ec0b66280ab3c77?hp=-c Merge pull request #685 from jmayer/add-static Declare some variables static (found via -Wmissing-variable-declarations) --- d7d31639251c64e32aad97e85ec0b66280ab3c77 diff --combined rpcapd/rpcapd.c index 8c1ca3ee,c46e3106..21217c8b --- a/rpcapd/rpcapd.c +++ b/rpcapd/rpcapd.c @@@ -46,7 -46,6 +46,7 @@@ #include "sockutils.h" // for socket calls #include "portability.h" #include "rpcapd.h" +#include "config_params.h" // configuration file parameters #include "fileconf.h" // for the configuration file management #include "rpcap-protocol.h" #include "daemon.h" // the true main() method of this daemon @@@ -57,7 -56,6 +57,7 @@@ #include "win32-svc.h" // for Win32 service stuff #include "getopt.h" // for getopt()-for-Windows #else + #include // for open() #include // for exit() #include // waitpid() #endif @@@ -72,19 -70,20 +72,19 @@@ struct listen_sock // Global variables char hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server - struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode) + struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode) int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise static struct listen_sock *listen_socks; //!< sockets on which we listen char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration - int passivemode = 1; //!< '1' if we want to run in passive mode as well - struct addrinfo mainhints; //!< temporary struct to keep settings needed to open the new socket - char address[MAX_LINE + 1]; //!< keeps the network address (either numeric or literal) to bind to - char port[MAX_LINE + 1]; //!< keeps the network port to bind to + static int passivemode = 1; //!< '1' if we want to run in passive mode as well + static struct addrinfo mainhints; //!< temporary struct to keep settings needed to open the new socket + static char address[MAX_LINE + 1]; //!< keeps the network address (either numeric or literal) to bind to + static char port[MAX_LINE + 1]; //!< keeps the network port to bind to #ifdef _WIN32 -static HANDLE shutdown_event; //!< event to signal to shut down the main loop -#else +static HANDLE state_change_event; //!< event to signal that a state change should take place +#endif static volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down static volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration -#endif extern char *optarg; // for getopt() @@@ -102,9 -101,6 +102,9 @@@ static void accept_connection(SOCKET li #ifndef _WIN32 static void main_reap_children(int sign); #endif +#ifdef _WIN32 +static unsigned __stdcall main_passive_serviceloop_thread(void *ptr); +#endif #define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */ @@@ -116,11 -112,7 +116,11 @@@ static void printusage(void char *usagetext = "USAGE:" " " PROGRAM_NAME " [-b
] [-p ] [-4] [-l ] [-a ]\n" - " [-n] [-v] [-d] [-s ] [-f ]\n\n" + " [-n] [-v] [-d] " +#ifndef _WIN32 + "[-i] " +#endif + "[-s ] [-f ]\n\n" " -b
the address to bind to (either numeric or literal).\n" " Default: binds to all local IPv4 and IPv6 addresses\n\n" " -p the port to bind to.\n" @@@ -128,21 -120,17 +128,21 @@@ " -4 use only IPv4.\n" " Default: use both IPv4 and IPv6 waiting sockets\n\n" " -l a file that contains a list of hosts that are allowed\n" - " to connect to this server (if more than one, list them one per line).\n" - " We suggest to use literal names (instead of numeric ones) in\n" - " order to avoid problems with different address families.\n\n" + " to connect to this server (if more than one, list them one\n" + " per line).\n" + " We suggest to use literal names (instead of numeric ones)\n" + " in order to avoid problems with different address families.\n\n" " -n permit NULL authentication (usually used with '-l')\n\n" " -a run in active mode when connecting to 'host' on port 'port'\n" " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n" - " -v run in active mode only (default: if '-a' is specified, it accepts\n" - " passive connections as well\n\n" + " -v run in active mode only (default: if '-a' is specified, it\n" + " accepts passive connections as well)\n\n" " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n" - " Warning (Win32): this switch is provided automatically when the service\n" - " is started from the control panel\n\n" + " Warning (Win32): this switch is provided automatically when\n" + " the service is started from the control panel\n\n" +#ifndef _WIN32 + " -i run in inetd mode (UNIX only)\n\n" +#endif " -s save the current configuration to file\n\n" " -f load the current configuration from file; all switches\n" " specified from the command line are ignored\n\n" @@@ -159,10 -147,7 +159,10 @@@ int main(int argc, char *argv[]) { char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration - int isdaemon = 0; // Not null if the user wants to run this program as a daemon + int isdaemon = 0; // Non-zero if the user wants to run this program as a daemon +#ifndef _WIN32 + int isrunbyinetd = 0; // Non-zero if this is being run by inetd or something inetd-like +#endif int retval; // keeps the returning value from several functions char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed #ifndef _WIN32 @@@ -178,7 -163,7 +178,7 @@@ if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) { - SOCK_ASSERT(errbuf, 1); + SOCK_DEBUG_MESSAGE(errbuf); exit(-1); } @@@ -193,7 -178,7 +193,7 @@@ mainhints.ai_socktype = SOCK_STREAM; // Getting the proper command line options - while ((retval = getopt(argc, argv, "b:dhp:4l:na:s:f:v")) != -1) + while ((retval = getopt(argc, argv, "b:dhip:4l:na:s:f:v")) != -1) { switch (retval) { @@@ -209,14 -194,6 +209,14 @@@ case 'd': isdaemon = 1; break; + case 'i': +#ifdef _WIN32 + printusage(); + exit(1); +#else + isrunbyinetd = 1; +#endif + break; case 'n': nullAuthAllowed = 1; break; @@@ -253,7 -230,7 +253,7 @@@ } if (i > MAX_ACTIVE_LIST) - SOCK_ASSERT("Only MAX_ACTIVE_LIST active connections are currently supported.", 1); + SOCK_DEBUG_MESSAGE("Only MAX_ACTIVE_LIST active connections are currently supported."); // I don't initialize the remaining part of the structure, since // it is already zeroed (it is a global var) @@@ -268,23 -245,16 +268,23 @@@ case 'h': printusage(); exit(0); + break; default: + exit(1); break; } } - if (savefile[0]) +#ifndef _WIN32 + if (isdaemon && isrunbyinetd) { - if (fileconf_save(savefile)) - SOCK_ASSERT("Error when saving the configuration to file", 1); + fprintf(stderr, "rpcapd: -d and -i can't be used together\n"); + exit(1); } +#endif + + if (savefile[0] && fileconf_save(savefile)) + SOCK_DEBUG_MESSAGE("Error when saving the configuration to file"); // If the file does not exist, it keeps the settings provided by the command line if (loadfile[0]) @@@ -292,14 -262,25 +292,14 @@@ #ifdef WIN32 // - // Create a handle to signal when the main loop is to shut down. - // - // Events are a bit annoying if you're waiting for multiple - // events; unlike UN*X select() and poll(), which indicate - // which FDs are available, WaitForMultipleObjects() and - // WSAWaitForMultipleEvents() don't give you an indication - // of *all* of the events that are signaled, they just tell - // you the first one that's signaled. - // - // Therefore, we must use WaitForSingleObject() to test - // this event; that means it must not be auto-reset, - // as that means that once WSAWaitForMultipleEvents() is - // woken up, it's no longer signaled. + // Create a handle to signal the main loop to tell it to do + // something. // - shutdown_event = CreateEvent(NULL, TRUE, FALSE, NULL); - if (shutdown_event == NULL) + state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (state_change_event == NULL) { sock_geterror(NULL, errbuf, PCAP_ERRBUF_SIZE); - rpcapd_log(LOGPRIO_ERROR, "Can't create shutdown event: %s", + rpcapd_log(LOGPRIO_ERROR, "Can't create state change event: %s", errbuf); exit(2); } @@@ -330,86 -311,13 +330,86 @@@ signal(SIGPIPE, SIG_IGN); #endif - // forking a daemon, if it is needed +#ifndef _WIN32 + if (isrunbyinetd) + { + // + // -i was specified, indicating that this is being run + // by inetd or something that can run network daemons + // as if it were inetd (xinetd, launchd, systemd, etc.). + // + // Our standard input is the input side of a connection, + // and our standard output is the output side of a + // connection. + // + int sockctrl_in, sockctrl_out; + int devnull_fd; + + // + // Duplicate the standard input and output, making them + // the input and output side of the control connection. + // + sockctrl_in = dup(0); + if (sockctrl_in == -1) + { + sock_geterror(NULL, errbuf, PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "Can't dup standard input: %s", + errbuf); + exit(2); + } + sockctrl_out = dup(1); + if (sockctrl_out == -1) + { + sock_geterror(NULL, errbuf, PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "Can't dup standard output: %s", + errbuf); + exit(2); + } + + // + // Try to set the standard input and output to /dev/null. + // + devnull_fd = open("/dev/null", O_RDWR); + if (devnull_fd != -1) + { + // + // If this fails, just drive on. + // + (void)dup2(devnull_fd, 0); + (void)dup2(devnull_fd, 1); + close(devnull_fd); + } + + // + // Handle this client. + // This is passive mode, so we don't care whether we were + // told by the client to close. + // + (void)daemon_serviceloop(sockctrl_in, sockctrl_out, 0, + nullAuthAllowed); + + // + // Nothing more to do. + // + exit(0); + } +#endif + if (isdaemon) { + // + // This is being run as a daemon. + // On UN*X, it might be manually run, or run from an + // rc file. + // #ifndef _WIN32 int pid; + // + // Daemonize ourselves. + // // Unix Network Programming, pg 336 + // if ((pid = fork()) != 0) exit(0); // Parent terminates @@@ -436,13 -344,9 +436,13 @@@ // umask(0); // chdir("/"); #else + // + // This is being run as a service on Windows. + // // If this call succeeds, it is blocking on Win32 + // if (svc_start() != 1) - SOCK_ASSERT("Unable to start the service", 1); + SOCK_DEBUG_MESSAGE("Unable to start the service"); // When the previous call returns, the entire application has to be stopped. exit(0); @@@ -503,7 -407,7 +503,7 @@@ void main_startup(void (void *)&activelist[i], 0, NULL); if (threadId == 0) { - SOCK_ASSERT("Error creating the active child threads", 1); + SOCK_DEBUG_MESSAGE("Error creating the active child threads"); continue; } CloseHandle(threadId); @@@ -538,7 -442,7 +538,7 @@@ // if (sock_initaddress((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) { - SOCK_ASSERT(errbuf, 1); + SOCK_DEBUG_MESSAGE(errbuf); return; } @@@ -550,7 -454,7 +550,7 @@@ if ((sock = sock_open(tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) { - SOCK_ASSERT(errbuf, 1); + SOCK_DEBUG_MESSAGE(errbuf); continue; } @@@ -576,7 -480,7 +576,7 @@@ // // We're done; exit. // - SOCK_ASSERT(PROGRAM_NAME " is closing.\n", 1); + SOCK_DEBUG_MESSAGE(PROGRAM_NAME " is closing.\n"); #ifndef _WIN32 // @@@ -613,46 -517,18 +613,46 @@@ } #ifdef _WIN32 -void -send_shutdown_event(void) +static void +send_state_change_event(void) { char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed - if (!SetEvent(shutdown_event)) + if (!SetEvent(state_change_event)) { sock_geterror(NULL, errbuf, PCAP_ERRBUF_SIZE); rpcapd_log(LOGPRIO_ERROR, "SetEvent on shutdown event failed: %s", errbuf); } } +void +send_shutdown_notification(void) +{ + // + // Indicate that the server should shut down. + // + shutdown_server = 1; + + // + // Send a state change event, to wake up WSAWaitForMultipleEvents(). + // + send_state_change_event(); +} + +void +send_reread_configuration_notification(void) +{ + // + // Indicate that the server should re-read its configuration file. + // + reread_config = 1; + + // + // Send a state change event, to wake up WSAWaitForMultipleEvents(). + // + send_state_change_event(); +} + static BOOL WINAPI main_ctrl_event(DWORD ctrltype) { // @@@ -676,9 -552,10 +676,9 @@@ case CTRL_CLOSE_EVENT: case CTRL_SHUTDOWN_EVENT: // - // Set the shutdown event. - // That will wake up WSAWaitForMultipleEvents(). + // Set a shutdown notification. // - send_shutdown_event(); + send_shutdown_notification(); break; default: @@@ -710,7 -587,9 +710,7 @@@ static void main_reread_config(int sign // reread_config = 1; } -#endif -#ifndef _WIN32 static void main_reap_children(int sign) { pid_t pid; @@@ -720,7 -599,7 +720,7 @@@ // For reference, Stevens, pg 128 while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0) - SOCK_ASSERT("Child terminated", 1); + SOCK_DEBUG_MESSAGE("Child terminated"); return; } @@@ -774,7 -653,7 +774,7 @@@ accept_connections(void // // Fill it in. // - events[0] = shutdown_event; // shutdown event first + events[0] = state_change_event; // state change event first for (sock_info = listen_socks, i = 1; sock_info; sock_info = sock_info->next, i++) { @@@ -816,27 -695,25 +816,27 @@@ exit(2); } - // - // Check the shutdown event. - // - if (WaitForSingleObject(shutdown_event, 0) == WAIT_OBJECT_0) + if (ret == WSA_WAIT_EVENT_0) { // - // Time to quit. - // Clear the event, for cleanliness. + // The state change event was set. // - if (!ResetEvent(shutdown_event)) + if (shutdown_server) { - sock_geterror(NULL, errbuf, PCAP_ERRBUF_SIZE); - rpcapd_log(LOGPRIO_ERROR, "ResetEvent on shutdown event failed: %s", errbuf); + // + // Time to quit. Exit the loop. + // + break; + } + if (reread_config) + { + // + // We should re-read the configuration + // file. + // + reread_config = 0; // clear the indicator + fileconf_read(); } - - // - // Exit the loop, so we quit. - // - break; } // @@@ -934,26 -811,22 +934,26 @@@ // otherwise just keep trying. // if (shutdown_server) + { + // + // Time to quit. Exit the loop. + // break; - else { - if (reread_config) - { - // - // This is a "re-read the - // configuration file" - // signal. Clear the - // flag and re-read - // the file. - // - reread_config = 0; - fileconf_read(); - } - continue; } + if (reread_config) + { + // + // We should re-read the configuration + // file. + // + reread_config = 0; // clear the indicator + fileconf_read(); + } + + // + // Go back and wait again. + // + continue; } else { @@@ -1005,10 -878,10 +1005,10 @@@ accept_connection(SOCKET listen_sock #ifdef _WIN32 HANDLE threadId; // handle for the subthread u_long off = 0; + SOCKET *sockctrl_temp; #else pid_t pid; #endif - struct daemon_slpars *pars; // parameters needed by the daemon_serviceloop() // Initialize errbuf memset(errbuf, 0, sizeof(errbuf)); @@@ -1080,15 -953,9 +1080,15 @@@ return; } - // in case of passive mode, this variable is deallocated by the daemon_serviceloop() - pars = (struct daemon_slpars *) malloc (sizeof(struct daemon_slpars)); - if (pars == NULL) + // + // Allocate a location to hold the value of sockctrl. + // It will be freed in the newly-created thread once it's + // finished with it. + // I guess we *could* just cast sockctrl to a void *, but that's + // a bit ugly. + // + sockctrl_temp = (SOCKET *)malloc(sizeof (SOCKET)); + if (sockctrl_temp == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc() failed"); @@@ -1096,16 -963,19 +1096,16 @@@ sock_close(sockctrl, NULL, 0); return; } + *sockctrl_temp = sockctrl; - pars->sockctrl = sockctrl; - pars->activeclose = 0; // useless in passive mode - pars->isactive = 0; - pars->nullAuthAllowed = nullAuthAllowed; - - threadId = (HANDLE)_beginthreadex(NULL, 0, daemon_serviceloop, - (void *) pars, 0, NULL); + threadId = (HANDLE)_beginthreadex(NULL, 0, + main_passive_serviceloop_thread, (void *) sockctrl_temp, 0, NULL); if (threadId == 0) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the child thread"); rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL); sock_close(sockctrl, NULL, 0); + free(sockctrl_temp); return; } CloseHandle(threadId); @@@ -1122,36 -992,33 +1122,36 @@@ { // // Child process. - // This is passive mode, so this variable is deallocated - // by the daemon_serviceloop(). - // - pars = (struct daemon_slpars *) malloc (sizeof(struct daemon_slpars)); - if (pars == NULL) - { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Can't allocate memory for the child process"); - rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL); - sock_close(sockctrl, NULL, 0); - return; - } - - pars->sockctrl = sockctrl; - pars->activeclose = 0; // useless in passive mode - pars->isactive = 0; - pars->nullAuthAllowed = nullAuthAllowed; - // // Close the socket on which we're listening (must // be open only in the parent). // closesocket(listen_sock); +#if 0 + // + // Modify thread params so that it can be killed at any time + // XXX - is this necessary? This is the main and, currently, + // only thread in the child process, and nobody tries to + // cancel us, although *we* may cancel the thread that's + // handling the capture loop. + // + if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) + goto end; + if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) + goto end; +#endif + // // Run the service loop. + // This is passive mode, so we don't care whether we were + // told by the client to close. // - daemon_serviceloop((void *) pars); + (void)daemon_serviceloop(sockctrl, sockctrl, 0, + nullAuthAllowed); + + close(sockctrl); + exit(0); } @@@ -1182,6 -1049,7 +1182,6 @@@ main_active(void *ptr struct addrinfo hints; // temporary struct to keep settings needed to open the new socket struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket struct active_pars *activepars; - struct daemon_slpars *pars; // parameters needed by the daemon_serviceloop() activepars = (struct active_pars *) ptr; @@@ -1195,7 -1063,7 +1195,7 @@@ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Connecting to host %s, port %s, using protocol %s", activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified"); - SOCK_ASSERT(errbuf, 1); + SOCK_DEBUG_MESSAGE(errbuf); // Initialize errbuf memset(errbuf, 0, sizeof(errbuf)); @@@ -1203,7 -1071,7 +1203,7 @@@ // Do the work if (sock_initaddress(activepars->address, activepars->port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) { - SOCK_ASSERT(errbuf, 1); + SOCK_DEBUG_MESSAGE(errbuf); return 0; } @@@ -1213,23 -1081,37 +1213,23 @@@ if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) { - SOCK_ASSERT(errbuf, 1); + SOCK_DEBUG_MESSAGE(errbuf); pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s", activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified"); - SOCK_ASSERT(errbuf, 1); + SOCK_DEBUG_MESSAGE(errbuf); sleep_secs(RPCAP_ACTIVE_WAIT); continue; } - pars = (struct daemon_slpars *) malloc (sizeof(struct daemon_slpars)); - if (pars == NULL) - { - pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, - errno, "malloc() failed"); - continue; - } + activeclose = daemon_serviceloop(sockctrl, sockctrl, 1, + nullAuthAllowed); - pars->sockctrl = sockctrl; - pars->activeclose = 0; - pars->isactive = 1; - pars->nullAuthAllowed = nullAuthAllowed; - - daemon_serviceloop((void *) pars); - - activeclose = pars->activeclose; - - free(pars); + sock_close(sockctrl, NULL, 0); // If the connection is closed by the user explicitely, don't try to connect to it again // just exit the program @@@ -1240,27 -1122,3 +1240,27 @@@ freeaddrinfo(addrinfo); return 0; } + +#ifdef _WIN32 +// +// Main routine of a passive-mode service thread. +// +unsigned __stdcall main_passive_serviceloop_thread(void *ptr) +{ + SOCKET sockctrl; + + sockctrl = *((SOCKET *)ptr); + free(ptr); + + // + // Handle this client. + // This is passive mode, so we don't care whether we were + // told by the client to close. + // + (void)daemon_serviceloop(sockctrl, sockctrl, 0, nullAuthAllowed); + + sock_close(sockctrl, NULL, 0); + + return 0; +} +#endif