xref: /freebsd/contrib/libpcap/rpcapd/win32-svc.c (revision 57e22627f9459b9dfd6043b32e02ecfcf205e176)
1*57e22627SCy Schubert /*
2*57e22627SCy Schubert  * Copyright (c) 2002 - 2003
3*57e22627SCy Schubert  * NetGroup, Politecnico di Torino (Italy)
4*57e22627SCy Schubert  * All rights reserved.
5*57e22627SCy Schubert  *
6*57e22627SCy Schubert  * Redistribution and use in source and binary forms, with or without
7*57e22627SCy Schubert  * modification, are permitted provided that the following conditions
8*57e22627SCy Schubert  * are met:
9*57e22627SCy Schubert  *
10*57e22627SCy Schubert  * 1. Redistributions of source code must retain the above copyright
11*57e22627SCy Schubert  * notice, this list of conditions and the following disclaimer.
12*57e22627SCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
13*57e22627SCy Schubert  * notice, this list of conditions and the following disclaimer in the
14*57e22627SCy Schubert  * documentation and/or other materials provided with the distribution.
15*57e22627SCy Schubert  * 3. Neither the name of the Politecnico di Torino nor the names of its
16*57e22627SCy Schubert  * contributors may be used to endorse or promote products derived from
17*57e22627SCy Schubert  * this software without specific prior written permission.
18*57e22627SCy Schubert  *
19*57e22627SCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*57e22627SCy Schubert  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*57e22627SCy Schubert  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*57e22627SCy Schubert  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23*57e22627SCy Schubert  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24*57e22627SCy Schubert  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25*57e22627SCy Schubert  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*57e22627SCy Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*57e22627SCy Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*57e22627SCy Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29*57e22627SCy Schubert  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*57e22627SCy Schubert  *
31*57e22627SCy Schubert  */
32*57e22627SCy Schubert 
33*57e22627SCy Schubert 
34*57e22627SCy Schubert #include "rpcapd.h"
35*57e22627SCy Schubert #include <pcap.h>		// for PCAP_ERRBUF_SIZE
36*57e22627SCy Schubert #include "fmtutils.h"
37*57e22627SCy Schubert #include "portability.h"
38*57e22627SCy Schubert #include "fileconf.h"
39*57e22627SCy Schubert #include "log.h"
40*57e22627SCy Schubert 
41*57e22627SCy Schubert static SERVICE_STATUS_HANDLE service_status_handle;
42*57e22627SCy Schubert static SERVICE_STATUS service_status;
43*57e22627SCy Schubert 
44*57e22627SCy Schubert static void WINAPI svc_main(DWORD argc, char **argv);
45*57e22627SCy Schubert static void update_svc_status(DWORD state, DWORD progress_indicator);
46*57e22627SCy Schubert 
47*57e22627SCy Schubert int svc_start(void)
48*57e22627SCy Schubert {
49*57e22627SCy Schubert 	int rc;
50*57e22627SCy Schubert 	SERVICE_TABLE_ENTRY ste[] =
51*57e22627SCy Schubert 	{
52*57e22627SCy Schubert 		{ PROGRAM_NAME, svc_main },
53*57e22627SCy Schubert 		{ NULL, NULL }
54*57e22627SCy Schubert 	};
55*57e22627SCy Schubert 	char string[PCAP_ERRBUF_SIZE];
56*57e22627SCy Schubert 
57*57e22627SCy Schubert 	// This call is blocking. A new thread is created which will launch
58*57e22627SCy Schubert 	// the svc_main() function
59*57e22627SCy Schubert 	if ((rc = StartServiceCtrlDispatcher(ste)) == 0) {
60*57e22627SCy Schubert 		pcap_fmt_errmsg_for_win32_err(string, sizeof (string),
61*57e22627SCy Schubert 		    GetLastError(), "StartServiceCtrlDispatcher() failed");
62*57e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "%s", string);
63*57e22627SCy Schubert 	}
64*57e22627SCy Schubert 
65*57e22627SCy Schubert 	return rc; // FALSE if this is not started as a service
66*57e22627SCy Schubert }
67*57e22627SCy Schubert 
68*57e22627SCy Schubert void WINAPI svc_control_handler(DWORD Opcode)
69*57e22627SCy Schubert {
70*57e22627SCy Schubert 	switch(Opcode)
71*57e22627SCy Schubert 	{
72*57e22627SCy Schubert 		case SERVICE_CONTROL_STOP:
73*57e22627SCy Schubert 			//
74*57e22627SCy Schubert 			// XXX - is this sufficient to clean up the service?
75*57e22627SCy Schubert 			// To be really honest, only the main socket and
76*57e22627SCy Schubert 			// such these stuffs are cleared; however the threads
77*57e22627SCy Schubert 			// that are running are not stopped.
78*57e22627SCy Schubert 			// This can be seen by placing a breakpoint at the
79*57e22627SCy Schubert 			// end of svc_main(), in which you will see that is
80*57e22627SCy Schubert 			// never reached. However, as soon as you set the
81*57e22627SCy Schubert 			// service status to "stopped",	the
82*57e22627SCy Schubert 			// StartServiceCtrlDispatcher() returns and the main
83*57e22627SCy Schubert 			// thread ends. Then, Win32 has a good automatic
84*57e22627SCy Schubert 			// cleanup, so that all the threads which are still
85*57e22627SCy Schubert 			// running are stopped when the main thread ends.
86*57e22627SCy Schubert 			//
87*57e22627SCy Schubert 			send_shutdown_notification();
88*57e22627SCy Schubert 
89*57e22627SCy Schubert 			update_svc_status(SERVICE_STOP_PENDING, 0);
90*57e22627SCy Schubert 			break;
91*57e22627SCy Schubert 
92*57e22627SCy Schubert 		/*
93*57e22627SCy Schubert 			Pause and Continue have an usual meaning and they are used just to be able
94*57e22627SCy Schubert 			to change the running parameters at run-time. In other words, they act
95*57e22627SCy Schubert 			like the SIGHUP signal on UNIX. All the running threads continue to run and
96*57e22627SCy Schubert 			they are not paused at all.
97*57e22627SCy Schubert 			Particularly,
98*57e22627SCy Schubert 			- PAUSE does nothing
99*57e22627SCy Schubert 			- CONTINUE re-reads the configuration file and creates the new threads that
100*57e22627SCy Schubert 			can be needed according to the new configuration.
101*57e22627SCy Schubert 		*/
102*57e22627SCy Schubert 		case SERVICE_CONTROL_PAUSE:
103*57e22627SCy Schubert 			update_svc_status(SERVICE_PAUSED, 0);
104*57e22627SCy Schubert 			break;
105*57e22627SCy Schubert 
106*57e22627SCy Schubert 		case SERVICE_CONTROL_CONTINUE:
107*57e22627SCy Schubert 			update_svc_status(SERVICE_RUNNING, 0);
108*57e22627SCy Schubert 			//
109*57e22627SCy Schubert 			// Tell the main loop to re-read the configuration.
110*57e22627SCy Schubert 			//
111*57e22627SCy Schubert 			send_reread_configuration_notification();
112*57e22627SCy Schubert 			break;
113*57e22627SCy Schubert 
114*57e22627SCy Schubert 		case SERVICE_CONTROL_INTERROGATE:
115*57e22627SCy Schubert 			// Fall through to send current status.
116*57e22627SCy Schubert 			//	WARNING: not implemented
117*57e22627SCy Schubert 			update_svc_status(SERVICE_RUNNING, 0);
118*57e22627SCy Schubert 			MessageBox(NULL, "Not implemented", "warning", MB_OK);
119*57e22627SCy Schubert 			break;
120*57e22627SCy Schubert 
121*57e22627SCy Schubert 		case SERVICE_CONTROL_PARAMCHANGE:
122*57e22627SCy Schubert 			//
123*57e22627SCy Schubert 			// Tell the main loop to re-read the configuration.
124*57e22627SCy Schubert 			//
125*57e22627SCy Schubert 			send_reread_configuration_notification();
126*57e22627SCy Schubert 			break;
127*57e22627SCy Schubert 	}
128*57e22627SCy Schubert 
129*57e22627SCy Schubert 	// Send current status.
130*57e22627SCy Schubert 	return;
131*57e22627SCy Schubert }
132*57e22627SCy Schubert 
133*57e22627SCy Schubert void WINAPI svc_main(DWORD argc, char **argv)
134*57e22627SCy Schubert {
135*57e22627SCy Schubert 	service_status_handle = RegisterServiceCtrlHandler(PROGRAM_NAME, svc_control_handler);
136*57e22627SCy Schubert 
137*57e22627SCy Schubert 	if (!service_status_handle)
138*57e22627SCy Schubert 		return;
139*57e22627SCy Schubert 
140*57e22627SCy Schubert 	service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
141*57e22627SCy Schubert 	service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_PARAMCHANGE;
142*57e22627SCy Schubert 	// | SERVICE_ACCEPT_SHUTDOWN ;
143*57e22627SCy Schubert 	update_svc_status(SERVICE_RUNNING, 0);
144*57e22627SCy Schubert 
145*57e22627SCy Schubert 	//
146*57e22627SCy Schubert 	// Service requests until we're told to stop.
147*57e22627SCy Schubert 	//
148*57e22627SCy Schubert 	main_startup();
149*57e22627SCy Schubert 
150*57e22627SCy Schubert 	//
151*57e22627SCy Schubert 	// It returned, so we were told to stop.
152*57e22627SCy Schubert 	//
153*57e22627SCy Schubert 	update_svc_status(SERVICE_STOPPED, 0);
154*57e22627SCy Schubert }
155*57e22627SCy Schubert 
156*57e22627SCy Schubert static void
157*57e22627SCy Schubert update_svc_status(DWORD state, DWORD progress_indicator)
158*57e22627SCy Schubert {
159*57e22627SCy Schubert 	service_status.dwWin32ExitCode = NO_ERROR;
160*57e22627SCy Schubert 	service_status.dwCurrentState = state;
161*57e22627SCy Schubert 	service_status.dwCheckPoint = progress_indicator;
162*57e22627SCy Schubert 	service_status.dwWaitHint = 0;
163*57e22627SCy Schubert 	SetServiceStatus(service_status_handle, &service_status);
164*57e22627SCy Schubert }
165*57e22627SCy Schubert 
166*57e22627SCy Schubert /*
167*57e22627SCy Schubert sc create rpcapd DisplayName= "Remote Packet Capture Protocol v.0 (experimental)" binpath= "C:\cvsroot\winpcap\wpcap\PRJ\Debug\rpcapd -d -f rpcapd.ini"
168*57e22627SCy Schubert sc description rpcapd "Allows to capture traffic on this host from a remote machine."
169*57e22627SCy Schubert */
170