]> The Tcpdump Group git mirrors - libpcap/commitdiff
Terminate rpcapd-as-a-service the same way it's done with ^C.
authorGuy Harris <[email protected]>
Sun, 1 Apr 2018 09:59:00 +0000 (02:59 -0700)
committerGuy Harris <[email protected]>
Sun, 1 Apr 2018 09:59:00 +0000 (02:59 -0700)
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.

rpcapd/rpcapd.c
rpcapd/rpcapd.h
rpcapd/win32-svc.c

index 1e93f142299f6961f72189060c8aa8fd1d8b1cad..69cc5aca941f7db5aa43cd6fe1f32054931ba37c 100755 (executable)
@@ -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();
 }
 
 //
index b819d8c104d2d057681ec641969d584111769006..6c840ba185a9a227b4eb97d1a86a048b60c3ca51 100755 (executable)
@@ -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
index 00f0ed9fe4ad2b8c9a24bfa877eaf4e48d727c3a..782849baa1f5487d39301266972aabf5873bd399 100755 (executable)
 
 
 #include "rpcapd.h"
-#include <signal.h>
 #include <pcap.h>              // 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);
 }
 
 /*