From: Guy Harris Date: Sun, 1 Apr 2018 09:59:00 +0000 (-0700) Subject: Terminate rpcapd-as-a-service the same way it's done with ^C. X-Git-Tag: libpcap-1.9-bp~136 X-Git-Url: https://git.tcpdump.org/libpcap/commitdiff_plain/dedd8a3cd21861a8b19743ec2d0e5e1c5ea875d1?hp=-c Terminate rpcapd-as-a-service the same way it's done with ^C. Call send_shutdown_event() on a SERVICE_CONTROL_STOP opcode. Handle the SERVICE_CONTROL_PARAMCHANGE opcode as well. Also, close all the listen sockets and clean up the socket mechanism before accept_connections() returns. --- dedd8a3cd21861a8b19743ec2d0e5e1c5ea875d1 diff --git a/rpcapd/rpcapd.c b/rpcapd/rpcapd.c index 1e93f142..69cc5aca 100755 --- a/rpcapd/rpcapd.c +++ b/rpcapd/rpcapd.c @@ -98,9 +98,7 @@ static void main_reread_config(int sign); #endif static void accept_connections(void); static void accept_connection(SOCKET listen_sock); -#ifdef _WIN32 -static void main_abort(int sign); -#else +#ifndef _WIN32 static void main_reap_children(int sign); #endif @@ -346,9 +344,6 @@ int main(int argc, char *argv[]) // umask(0); // chdir("/"); #else - // We use the SIGABRT signal to kill the Win32 service - signal(SIGABRT, main_abort); - // If this call succeeds, it is blocking on Win32 if (svc_start() != 1) SOCK_ASSERT("Unable to start the service", 1); @@ -522,10 +517,20 @@ void main_startup(void) } #ifdef _WIN32 -static BOOL WINAPI main_ctrl_event(DWORD ctrltype) +void +send_shutdown_event(void) { char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + if (!SetEvent(shutdown_event)) + { + sock_geterror(NULL, errbuf, PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "SetEvent on shutdown event failed: %s", errbuf); + } +} + +static BOOL WINAPI main_ctrl_event(DWORD ctrltype) +{ // // ctrltype is one of: // @@ -550,11 +555,7 @@ static BOOL WINAPI main_ctrl_event(DWORD ctrltype) // Set the shutdown event. // That will wake up WSAWaitForMultipleEvents(). // - if (!SetEvent(shutdown_event)) - { - sock_geterror(NULL, errbuf, PCAP_ERRBUF_SIZE); - rpcapd_log(LOGPRIO_ERROR, "SetEvent on shutdown event failed: %s", errbuf); - } + send_shutdown_event(); break; default: @@ -588,38 +589,6 @@ static void main_reread_config(int sign) } #endif -#ifdef _WIN32 -static void main_abort(int sign) -{ - struct listen_sock *sock_info; - - SOCK_ASSERT(PROGRAM_NAME " is closing due to a SIGABRT.\n", 1); - - // - // XXX - there should be a way to poke the main thread to get - // it to shut down the service. - // - - // - // Close all the listen sockets. - // - for (sock_info = listen_socks; sock_info; sock_info = sock_info->next) - { - closesocket(sock_info->sock); - } - sock_cleanup(); - - /* - * This is a Win32 service, so we're a child thread, and we want - * just to terminate ourself. This is because the exit(0) will - * be invoked by the main thread, which is blocked waiting that - * all childs terminates. We are forced to call exit from the - * main thread, otherwise the Win32 service control manager - * (SCM) does not work well. - */ -} -#endif - #ifndef _WIN32 static void main_reap_children(int sign) { @@ -883,6 +852,15 @@ accept_connections(void) } } #endif + + // + // Close all the listen sockets. + // + for (sock_info = listen_socks; sock_info; sock_info = sock_info->next) + { + closesocket(sock_info->sock); + } + sock_cleanup(); } // diff --git a/rpcapd/rpcapd.h b/rpcapd/rpcapd.h index b819d8c1..6c840ba1 100755 --- a/rpcapd/rpcapd.h +++ b/rpcapd/rpcapd.h @@ -51,6 +51,9 @@ extern struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of t extern int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise extern char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration +#ifdef _WIN32 +void send_shutdown_event(void); // Send event to shut down the daemon +#endif void main_startup(void); #endif diff --git a/rpcapd/win32-svc.c b/rpcapd/win32-svc.c index 00f0ed9f..782849ba 100755 --- a/rpcapd/win32-svc.c +++ b/rpcapd/win32-svc.c @@ -32,17 +32,17 @@ #include "rpcapd.h" -#include #include // for PCAP_ERRBUF_SIZE #include "sockutils.h" // for SOCK_ASSERT #include "portability.h" #include "fileconf.h" -SERVICE_STATUS_HANDLE service_status_handle; -SERVICE_STATUS service_status; +static SERVICE_STATUS_HANDLE service_status_handle; +static SERVICE_STATUS service_status; void svc_geterr(char *str); -void WINAPI svc_main(DWORD argc, char **argv); +static void WINAPI svc_main(DWORD argc, char **argv); +static void update_svc_status(DWORD state, DWORD progress_indicator); int svc_start(void) { @@ -80,27 +80,26 @@ void svc_geterr(char *str) void WINAPI svc_control_handler(DWORD Opcode) { - service_status.dwWin32ExitCode = 0; - service_status.dwCheckPoint = 0; - service_status.dwWaitHint = 0; - switch(Opcode) { case SERVICE_CONTROL_STOP: - service_status.dwCurrentState = SERVICE_STOPPED; - - /* - Uses ABORT to clean up the service. To be really honest, only the main socket and - such these stuffs are cleared; however the thread which are running are not stopped. - This can be seen by placing a breakpoint at the end of svc_main(), in which you will - see that is never reached. However, as soon as you set the service status to "stopped", - the StartServiceCtrlDispatcher() returns and the main thread ends. Then, Win32 has a good - automatic cleanup, so that all the threads which are still running are stopped - when the main thread ends. - */ - raise(SIGABRT); - - SetServiceStatus(service_status_handle, &service_status); + // + // XXX - is this sufficient to clean up the service? + // To be really honest, only the main socket and + // such these stuffs are cleared; however the threads + // that are running are not stopped. + // This can be seen by placing a breakpoint at the + // end of svc_main(), in which you will see that is + // never reached. However, as soon as you set the + // service status to "stopped", the + // StartServiceCtrlDispatcher() returns and the main + // thread ends. Then, Win32 has a good automatic + // cleanup, so that all the threads which are still + // running are stopped when the main thread ends. + // + send_shutdown_event(); + + update_svc_status(SERVICE_STOP_PENDING, 0); break; /* @@ -114,22 +113,24 @@ void WINAPI svc_control_handler(DWORD Opcode) can be needed according to the new configuration. */ case SERVICE_CONTROL_PAUSE: - service_status.dwCurrentState = SERVICE_PAUSED; - SetServiceStatus(service_status_handle, &service_status); + update_svc_status(SERVICE_PAUSED, 0); break; case SERVICE_CONTROL_CONTINUE: - service_status.dwCurrentState = SERVICE_RUNNING; - SetServiceStatus(service_status_handle, &service_status); + update_svc_status(SERVICE_RUNNING, 0); fileconf_read(); break; case SERVICE_CONTROL_INTERROGATE: // Fall through to send current status. // WARNING: not implemented - SetServiceStatus(service_status_handle, &service_status); + update_svc_status(SERVICE_RUNNING, 0); MessageBox(NULL, "Not implemented", "warning", MB_OK); break; + + case SERVICE_CONTROL_PARAMCHANGE: + fileconf_read(); + break; } // Send current status. @@ -144,17 +145,29 @@ void WINAPI svc_main(DWORD argc, char **argv) return; service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS; - service_status.dwCurrentState = SERVICE_RUNNING; service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; // | SERVICE_ACCEPT_SHUTDOWN ; - service_status.dwWin32ExitCode = 0; - service_status.dwServiceSpecificExitCode = 0; - service_status.dwCheckPoint = 0; - service_status.dwWaitHint = 0; - - SetServiceStatus(service_status_handle, &service_status); + update_svc_status(SERVICE_RUNNING, 0); + // + // Service requests until we're told to stop. + // main_startup(); + + // + // It returned, so we were told to stop. + // + update_svc_status(SERVICE_STOPPED, 0); +} + +static void +update_svc_status(DWORD state, DWORD progress_indicator) +{ + service_status.dwWin32ExitCode = NO_ERROR; + service_status.dwCurrentState = state; + service_status.dwCheckPoint = progress_indicator; + service_status.dwWaitHint = 0; + SetServiceStatus(service_status_handle, &service_status); } /*