2 * Copyright (c) 2014 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "poll-loop.h"
24 VLOG_DEFINE_THIS_MODULE(daemon);
26 static bool detach; /* Was --service specified? */
27 static bool detached; /* Have we already detached? */
29 /* --service-monitor: Should the service be restarted if it dies
33 /* Handle to the Services Manager and the created service. */
34 static SC_HANDLE manager, service;
36 /* Handle to the status information structure for the current service. */
37 static SERVICE_STATUS_HANDLE hstatus;
39 /* Hold the service's current status. */
40 static SERVICE_STATUS service_status;
42 /* Handle to an event object used to wakeup from poll_block(). */
45 /* Hold the arguments sent to the main function. */
47 static char ***sargvp;
49 static void check_service(void);
50 static void handle_scm_callback(void);
51 static void init_service_status(void);
52 static void set_config_failure_actions(void);
54 extern int main(int argc, char *argv[]);
60 "\nService options:\n"
61 " --service run in background as a service.\n"
62 " --service-monitor restart the service in case of an "
63 "unexpected failure. \n",
64 ovs_rundir(), program_name);
67 /* Registers the call-back and configures the actions in case of a failure
68 * with the Windows services manager. */
70 service_start(int *argcp, char **argvp[])
75 SERVICE_TABLE_ENTRY service_table[] = {
76 {(LPTSTR)program_name, (LPSERVICE_MAIN_FUNCTION)main},
80 /* 'detached' is 'false' when service_start() is called the first time.
81 * It is 'true', when it is called the second time by the Windows services
84 init_service_status();
86 wevent = CreateEvent(NULL, TRUE, FALSE, NULL);
88 char *msg_buf = ovs_lasterror_to_string();
89 VLOG_FATAL("Failed to create a event (%s).", msg_buf);
92 poll_fd_wait_event(0, wevent, POLLIN);
94 /* Register the control handler. This function is called by the service
95 * manager to stop the service. */
96 hstatus = RegisterServiceCtrlHandler(program_name,
97 (LPHANDLER_FUNCTION)control_handler);
99 char *msg_buf = ovs_lasterror_to_string();
100 VLOG_FATAL("Failed to register the service control handler (%s).",
105 set_config_failure_actions();
108 /* When the service control manager does the call back, it does not
109 * send the same arguments as sent to the main function during the
110 * service start. So, use the arguments passed over during the first
115 /* XXX: Windows implementation cannot have a unixctl commands in the
116 * traditional sense of unix domain sockets. If an implementation is
117 * done that involves 'unixctl' vlog commands the following call is
118 * needed to make sure that the unixctl commands for vlog get
119 * registered in a daemon, even before the first log message. */
125 assert_single_threaded();
127 /* A reference to arguments passed to the main function the first time.
128 * We need it after the call-back from service control manager. */
132 /* We are only interested in the '--service' and '--service-monitor'
133 * options before the call-back from the service control manager. */
134 for (i = 0; i < argc; i ++) {
135 if (!strcmp(argv[i], "--service")) {
137 } else if (!strcmp(argv[i], "--service-monitor")) {
142 /* If '--service' is not a command line option, run in foreground. */
147 /* If we have been configured to run as a service, then that service
148 * should already have been created either manually or through a start up
154 /* StartServiceCtrlDispatcher blocks and returns after the service is
156 if (!StartServiceCtrlDispatcher(service_table)) {
157 char *msg_buf = ovs_lasterror_to_string();
158 VLOG_FATAL("Failed at StartServiceCtrlDispatcher (%s)", msg_buf);
163 /* This function is registered with the Windows services manager through
164 * a call to RegisterServiceCtrlHandler() and will be called by the Windows
165 * services manager asynchronously to stop the service. */
167 control_handler(DWORD request)
170 case SERVICE_CONTROL_STOP:
171 case SERVICE_CONTROL_SHUTDOWN:
172 service_status.dwCurrentState = SERVICE_STOPPED;
173 service_status.dwWin32ExitCode = NO_ERROR;
182 /* Return 'true' if the Windows services manager has called the
183 * control_handler() and asked the program to terminate. */
185 should_service_stop(void)
188 if (service_status.dwCurrentState != SERVICE_RUNNING) {
191 poll_fd_wait_event(0, wevent, POLLIN);
197 /* Set the service as stopped. The control manager will terminate the
198 * service soon after this call. Hence, this should ideally be the last
199 * call before termination. */
206 service_status.dwCurrentState = SERVICE_STOPPED;
207 service_status.dwWin32ExitCode = NO_ERROR;
208 SetServiceStatus(hstatus, &service_status);
211 /* Call this function to signal that the daemon is ready. init_service()
212 * or control_handler() has already initalized/set the
213 * service_status.dwCurrentState .*/
215 service_complete(void)
218 SetServiceStatus(hstatus, &service_status);
222 /* Check whether 'program_name' has been created as a service. */
226 /* Establish a connection to the local service control manager. */
227 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
229 char *msg_buf = ovs_lasterror_to_string();
230 VLOG_FATAL("Failed to open the service control manager (%s).",
234 service = OpenService(manager, program_name, SERVICE_ALL_ACCESS);
236 char *msg_buf = ovs_lasterror_to_string();
237 VLOG_FATAL("Failed to open service (%s).", msg_buf);
241 /* Service status of a service can be checked asynchronously through
242 * tools like 'sc' or through Windows services manager and is set
243 * through a call to SetServiceStatus(). */
245 init_service_status()
247 /* The service runs in its own process. */
248 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
250 /* The control codes the service accepts. */
251 service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
252 SERVICE_ACCEPT_SHUTDOWN;
254 /* Initialize the current state as SERVICE_RUNNING. */
255 service_status.dwCurrentState = SERVICE_RUNNING;
257 /* The exit code to indicate if there was an error. */
258 service_status.dwWin32ExitCode = NO_ERROR;
260 /* The checkpoint value the service increments periodically. Set as 0
261 * as we do not plan to periodically increment the value. */
262 service_status.dwCheckPoint = 0;
264 /* The estimated time required for the stop operation in ms. */
265 service_status.dwWaitHint = 1000;
268 /* In case of an unexpected termination, configure the action to be
271 set_config_failure_actions()
273 /* In case of a failure, restart the process the first two times
274 * After 'dwResetPeriod', the failure count is reset. */
275 SC_ACTION fail_action[3] = {
276 {SC_ACTION_RESTART, 0},
277 {SC_ACTION_RESTART, 0},
280 SERVICE_FAILURE_ACTIONS service_fail_action;
282 /* Reset failure count after (in seconds). */
283 service_fail_action.dwResetPeriod = 10;
285 /* Reboot message. */
286 service_fail_action.lpRebootMsg = NULL;
288 /* The command line of the process. */
289 service_fail_action.lpCommand = NULL;
291 /* Number of elements in 'fail_actions'. */
292 service_fail_action.cActions = sizeof(fail_action)/sizeof(fail_action[0]);
294 /* A pointer to an array of SC_ACTION structures. */
295 service_fail_action.lpsaActions = fail_action;
297 if (!ChangeServiceConfig2(service, SERVICE_CONFIG_FAILURE_ACTIONS,
298 &service_fail_action)) {
299 char *msg_buf = ovs_lasterror_to_string();
300 VLOG_FATAL("Failed to configure service fail actions (%s).", msg_buf);
305 /* Stub functions to handle daemonize related calls in non-windows platform. */
313 daemon_save_fd(int fd OVS_UNUSED)
322 void daemonize_start(void)
327 daemonize_complete(void)