netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / lib / daemon-windows.c
1 /*
2  * Copyright (c) 2014 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #include "daemon.h"
19 #include "daemon-private.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include "dirs.h"
23 #include "ovs-thread.h"
24 #include "poll-loop.h"
25 #include "openvswitch/vlog.h"
26
27 VLOG_DEFINE_THIS_MODULE(daemon_windows);
28
29 static bool service_create;          /* Was --service specified? */
30 static bool service_started;         /* Have we dispatched service to start? */
31
32 /* --service-monitor: Should the service be restarted if it dies
33  * unexpectedly? */
34 static bool monitor;
35
36 bool detach;                 /* Was --detach specified? */
37 static bool detached;        /* Running as the child process. */
38 static HANDLE write_handle;  /* End of pipe to write to parent. */
39
40 char *pidfile;                 /* --pidfile: Name of pidfile (null if none). */
41 static FILE *filep_pidfile;    /* File pointer to access the pidfile. */
42
43 /* Handle to the Services Manager and the created service. */
44 static SC_HANDLE manager, service;
45
46 /* Handle to the status information structure for the current service. */
47 static SERVICE_STATUS_HANDLE hstatus;
48
49 /* Hold the service's current status. */
50 static SERVICE_STATUS service_status;
51
52 /* Handle to an event object used to wakeup from poll_block(). */
53 static HANDLE wevent;
54
55 /* Hold the arguments sent to the main function. */
56 static int sargc;
57 static char ***sargvp;
58
59 static void check_service(void);
60 static void handle_scm_callback(void);
61 static void init_service_status(void);
62 static void set_config_failure_actions(void);
63
64 static bool detach_process(int argc, char *argv[]);
65
66 extern int main(int argc, char *argv[]);
67
68 void
69 daemon_usage(void)
70 {
71     printf(
72         "\nService options:\n"
73         "  --service               run in background as a service.\n"
74         "  --service-monitor       restart the service in case of an "
75                                    "unexpected failure. \n",
76         ovs_rundir(), program_name);
77 }
78
79 /* Registers the call-back and configures the actions in case of a failure
80  * with the Windows services manager. */
81 void
82 service_start(int *argcp, char **argvp[])
83 {
84     int argc = *argcp;
85     char **argv = *argvp;
86     int i;
87     SERVICE_TABLE_ENTRY service_table[] = {
88         {(LPTSTR)program_name, (LPSERVICE_MAIN_FUNCTION)main},
89         {NULL, NULL}
90     };
91
92     /* If one of the command line option is "--detach", we create
93      * a new process in case of parent, wait for child to start and exit.
94      * In case of the child, we just return. We should not be creating a
95      * service in either case. */
96     if (detach_process(argc, argv)) {
97         return;
98     }
99
100     /* 'service_started' is 'false' when service_start() is called the first
101      * time.  It is 'true', when it is called the second time by the Windows
102      * services manager. */
103     if (service_started) {
104         init_service_status();
105
106         wevent = CreateEvent(NULL, TRUE, FALSE, NULL);
107         if (!wevent) {
108             char *msg_buf = ovs_lasterror_to_string();
109             VLOG_FATAL("Failed to create a event (%s).", msg_buf);
110         }
111
112         poll_wevent_wait(wevent);
113
114         /* Register the control handler. This function is called by the service
115          * manager to stop the service. */
116         hstatus = RegisterServiceCtrlHandler(program_name,
117                                          (LPHANDLER_FUNCTION)control_handler);
118         if (!hstatus) {
119             char *msg_buf = ovs_lasterror_to_string();
120             VLOG_FATAL("Failed to register the service control handler (%s).",
121                         msg_buf);
122         }
123
124         if (monitor) {
125             set_config_failure_actions();
126         }
127
128         /* When the service control manager does the call back, it does not
129          * send the same arguments as sent to the main function during the
130          * service start. So, use the arguments passed over during the first
131          * time. */
132         *argcp = sargc;
133         *argvp = *sargvp;
134
135         /* XXX: Windows implementation cannot have a unixctl commands in the
136         * traditional sense of unix domain sockets. If an implementation is
137         * done that involves 'unixctl' vlog commands the following call is
138         * needed to make sure that the unixctl commands for vlog get
139         * registered in a daemon, even before the first log message. */
140         vlog_init();
141
142         return;
143     }
144
145     assert_single_threaded();
146
147     /* A reference to arguments passed to the main function the first time.
148      * We need it after the call-back from service control manager. */
149     sargc = argc;
150     sargvp = argvp;
151
152     /* We are only interested in the '--service' and '--service-monitor'
153      * options before the call-back from the service control manager. */
154     for (i = 0; i < argc; i ++) {
155         if (!strcmp(argv[i], "--service")) {
156             service_create = true;
157         } else if (!strcmp(argv[i], "--service-monitor")) {
158             monitor = true;
159         }
160     }
161
162     /* If '--service' is not a command line option, run in foreground. */
163     if (!service_create) {
164         return;
165     }
166
167     /* If we have been configured to run as a service, then that service
168      * should already have been created either manually or through a start up
169      * script. */
170     check_service();
171
172     service_started = true;
173
174     /* StartServiceCtrlDispatcher blocks and returns after the service is
175      * stopped. */
176     if (!StartServiceCtrlDispatcher(service_table)) {
177         char *msg_buf = ovs_lasterror_to_string();
178         VLOG_FATAL("Failed at StartServiceCtrlDispatcher (%s)", msg_buf);
179     }
180     exit(0);
181 }
182
183 /* This function is registered with the Windows services manager through
184  * a call to RegisterServiceCtrlHandler() and will be called by the Windows
185  * services manager asynchronously to stop the service. */
186 void
187 control_handler(DWORD request)
188 {
189     switch (request) {
190     case SERVICE_CONTROL_STOP:
191     case SERVICE_CONTROL_SHUTDOWN:
192         service_status.dwCurrentState = SERVICE_STOPPED;
193         service_status.dwWin32ExitCode = NO_ERROR;
194         SetEvent(wevent);
195         break;
196
197     default:
198         break;
199     }
200 }
201
202 /* Return 'true' if the Windows services manager has called the
203  * control_handler() and asked the program to terminate. */
204 bool
205 should_service_stop(void)
206 {
207     if (service_started) {
208         if (service_status.dwCurrentState != SERVICE_RUNNING) {
209             return true;
210         } else {
211             poll_wevent_wait(wevent);
212         }
213     }
214     return false;
215 }
216
217 /* Set the service as stopped. The control manager will terminate the
218  * service soon after this call. Hence, this should ideally be the last
219  * call before termination. */
220 void
221 service_stop()
222 {
223     if (!service_started) {
224         return;
225     }
226     fatal_signal_atexit_handler();
227
228     ResetEvent(wevent);
229     CloseHandle(wevent);
230
231     service_status.dwCurrentState = SERVICE_STOPPED;
232     service_status.dwWin32ExitCode = NO_ERROR;
233     SetServiceStatus(hstatus, &service_status);
234 }
235
236 /* Call this function to signal that the daemon is ready. init_service()
237  * or control_handler() has already initalized/set the
238  * service_status.dwCurrentState .*/
239 static void
240 service_complete(void)
241 {
242     if (hstatus) {
243         SetServiceStatus(hstatus, &service_status);
244     }
245 }
246
247 /* Check whether 'program_name' has been created as a service. */
248 static void
249 check_service()
250 {
251     /* Establish a connection to the local service control manager. */
252     manager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
253     if (!manager) {
254         char *msg_buf = ovs_lasterror_to_string();
255         VLOG_FATAL("Failed to open the service control manager (%s).",
256                    msg_buf);
257     }
258
259     service = OpenService(manager, program_name, SERVICE_ALL_ACCESS);
260     if (!service) {
261         char *msg_buf = ovs_lasterror_to_string();
262         VLOG_FATAL("Failed to open service (%s).", msg_buf);
263     }
264 }
265
266 /* Service status of a service can be checked asynchronously through
267  * tools like 'sc' or through Windows services manager and is set
268  * through a call to SetServiceStatus(). */
269 static void
270 init_service_status()
271 {
272     /* The service runs in its own process. */
273     service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
274
275     /* The control codes the service accepts. */
276     service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
277                                             SERVICE_ACCEPT_SHUTDOWN;
278
279     /* Initialize the current state as SERVICE_RUNNING. */
280     service_status.dwCurrentState = SERVICE_RUNNING;
281
282     /* The exit code to indicate if there was an error. */
283     service_status.dwWin32ExitCode = NO_ERROR;
284
285     /* The checkpoint value the service increments periodically. Set as 0
286      * as we do not plan to periodically increment the value. */
287     service_status.dwCheckPoint = 0;
288
289     /* The estimated time required for the stop operation in ms. */
290     service_status.dwWaitHint = 1000;
291 }
292
293 /* In case of an unexpected termination, configure the action to be
294  * taken. */
295 static void
296 set_config_failure_actions()
297 {
298     /* In case of a failure, restart the process the first two times
299      * After 'dwResetPeriod', the failure count is reset. */
300     SC_ACTION fail_action[3] = {
301         {SC_ACTION_RESTART, 0},
302         {SC_ACTION_RESTART, 0},
303         {SC_ACTION_NONE, 0}
304     };
305     SERVICE_FAILURE_ACTIONS service_fail_action;
306
307     /* Reset failure count after (in seconds). */
308     service_fail_action.dwResetPeriod = 10;
309
310     /* Reboot message. */
311     service_fail_action.lpRebootMsg = NULL;
312
313     /* The command line of the process. */
314     service_fail_action.lpCommand = NULL;
315
316     /* Number of elements in 'fail_actions'. */
317     service_fail_action.cActions = sizeof(fail_action)/sizeof(fail_action[0]);
318
319     /* A pointer to an array of SC_ACTION structures. */
320     service_fail_action.lpsaActions = fail_action;
321
322     if (!ChangeServiceConfig2(service, SERVICE_CONFIG_FAILURE_ACTIONS,
323                               &service_fail_action)) {
324         char *msg_buf = ovs_lasterror_to_string();
325         VLOG_FATAL("Failed to configure service fail actions (%s).", msg_buf);
326     }
327 }
328
329 /* When a daemon is passed the --detach option, we create a new
330  * process and pass an additional non-documented option called --pipe-handle.
331  * Through this option, the parent passes one end of a pipe handle. */
332 void
333 set_pipe_handle(const char *pipe_handle)
334 {
335     write_handle = (HANDLE) atoi(pipe_handle);
336 }
337
338 /* If one of the command line option is "--detach", creates
339  * a new process in case of parent, waits for child to start and exits.
340  * In case of the child, returns. */
341 static bool
342 detach_process(int argc, char *argv[])
343 {
344     SECURITY_ATTRIBUTES sa;
345     STARTUPINFO si;
346     PROCESS_INFORMATION pi;
347     HANDLE read_pipe, write_pipe;
348     char *buffer;
349     int error, i;
350     char ch;
351
352     /* We are only interested in the '--detach' and '--pipe-handle'. */
353     for (i = 0; i < argc; i ++) {
354         if (!strcmp(argv[i], "--detach")) {
355             detach = true;
356         } else if (!strncmp(argv[i], "--pipe-handle", 13)) {
357             /* If running as a child, return. */
358             detached = true;
359             return true;
360         }
361     }
362
363     /* Nothing to do if the option --detach is not set. */
364     if (!detach) {
365         return false;
366     }
367
368     /* Set the security attribute such that a process created will
369      * inherit the pipe handles. */
370     sa.nLength = sizeof(sa);
371     sa.lpSecurityDescriptor = NULL;
372     sa.bInheritHandle = TRUE;
373
374     /* Create an anonymous pipe to communicate with the child. */
375     error = CreatePipe(&read_pipe, &write_pipe, &sa, 0);
376     if (!error) {
377         VLOG_FATAL("CreatePipe failed (%s)", ovs_lasterror_to_string());
378     }
379
380     GetStartupInfo(&si);
381
382     /* To the child, we pass an extra argument '--pipe-handle=write_pipe' */
383     buffer = xasprintf("%s %s=%ld", GetCommandLine(), "--pipe-handle",
384                        write_pipe);
385
386     /* Create a detached child */
387     error = CreateProcess(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS,
388                           NULL, NULL, &si, &pi);
389     if (!error) {
390         VLOG_FATAL("CreateProcess failed (%s)", ovs_lasterror_to_string());
391     }
392
393     /* Close one end of the pipe in the parent. */
394     CloseHandle(write_pipe);
395
396     /* Block and wait for child to say it is ready. */
397     error = ReadFile(read_pipe, &ch, 1, NULL, NULL);
398     if (!error) {
399         VLOG_FATAL("Failed to read from child (%s)",
400                    ovs_lasterror_to_string());
401     }
402     /* The child has successfully started and is ready. */
403     exit(0);
404 }
405
406 static void
407 unlink_pidfile(void)
408 {
409     if (filep_pidfile) {
410         fclose(filep_pidfile);
411     }
412     if (pidfile) {
413         unlink(pidfile);
414     }
415 }
416
417 /* If a pidfile has been configured, creates it and stores the running
418  * process's pid in it.  Ensures that the pidfile will be deleted when the
419  * process exits. */
420 static void
421 make_pidfile(void)
422 {
423     int error;
424
425     error = GetFileAttributes(pidfile);
426     if (error != INVALID_FILE_ATTRIBUTES) {
427         /* pidfile exists. Try to unlink() it. */
428         error = unlink(pidfile);
429         if (error) {
430             VLOG_FATAL("Failed to delete existing pidfile %s (%s)", pidfile,
431                        ovs_strerror(errno));
432         }
433     }
434
435     filep_pidfile = fopen(pidfile, "w");
436     if (filep_pidfile == NULL) {
437         VLOG_FATAL("failed to open %s (%s)", pidfile, ovs_strerror(errno));
438     }
439
440     fatal_signal_add_hook(unlink_pidfile, NULL, NULL, true);
441
442     fprintf(filep_pidfile, "%d\n", _getpid());
443     if (fflush(filep_pidfile) == EOF) {
444         VLOG_FATAL("Failed to write into the pidfile %s", pidfile);
445     }
446
447     /* Don't close the pidfile till the process exits. */
448 }
449
450 void
451 daemonize_start(bool access_datapath OVS_UNUSED)
452 {
453     if (pidfile) {
454         make_pidfile();
455     }
456 }
457
458 void
459 daemonize_complete(void)
460 {
461     /* If running as a child because '--detach' option was specified,
462      * communicate with the parent to inform that the child is ready. */
463     if (detached) {
464         int error;
465
466         close_standard_fds();
467
468         error = WriteFile(write_handle, "a", 1, NULL, NULL);
469         if (!error) {
470             VLOG_FATAL("Failed to communicate with the parent (%s)",
471                        ovs_lasterror_to_string());
472         }
473     }
474
475     service_complete();
476 }
477
478 void
479 daemon_become_new_user(bool access_datapath OVS_UNUSED)
480 {
481 }
482
483 /* Returns the file name that would be used for a pidfile if 'name' were
484  * provided to set_pidfile().  The caller must free the returned string. */
485 char *
486 make_pidfile_name(const char *name)
487 {
488     if (name && strchr(name, ':')) {
489         return xstrdup(name);
490     } else {
491         return xasprintf("%s/%s.pid", ovs_rundir(), program_name);
492     }
493 }
494
495 void
496 daemon_set_new_user(const char *user_spec OVS_UNUSED)
497 {
498     VLOG_FATAL("--user options is not currently supported.");
499 }