static void WINAPI service_control(DWORD ctrlcode) { switch (ctrlcode) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: service_report_status(SERVICE_STOP_PENDING, 30); svc_paused = 0; SetEvent(sigterm_handle); break; case SERVICE_CONTROL_PARAMCHANGE: // Win2000/XP service_report_status(svc_status.dwCurrentState, 0); svc_paused = 0; SetEvent(sighup_handle); // reload break; case SERVICE_CONTROL_PAUSE: service_report_status(SERVICE_PAUSED, 0); svc_paused = 1; break; case SERVICE_CONTROL_CONTINUE: service_report_status(SERVICE_RUNNING, 0); { int was_paused = svc_paused; svc_paused = 0; SetEvent(was_paused ? sighup_handle : sigusr1_handle); // reload:recheck } break; case SERVICE_CONTROL_INTERROGATE: default: // unknown service_report_status(svc_status.dwCurrentState, 0); break; } }
static void WINAPI service_main(DWORD /*argc*/, LPSTR * argv) { char path[MAX_PATH], *p; // Register control handler svc_handle = RegisterServiceCtrlHandler(argv[0], service_control); // Init service status svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_report_status(SERVICE_START_PENDING, 10); // Service started in \windows\system32, change to .exe directory if (GetModuleFileNameA(NULL, path, sizeof(path)) && (p = strrchr(path, '\\'))) { *p = 0; SetCurrentDirectoryA(path); } // Install exit handler atexit(service_exit); // Do the real work, service status later updated by daemon_detach() daemon_winsvc_exitcode = svc_main_func(svc_main_argc, svc_main_argv); exit(daemon_winsvc_exitcode); // ... continued in service_exit() }
int daemon_detach(const char * ident) { if (!svc_mode) { if (ident) { // Print help FILE * f = ( isatty(fileno(stdout)) ? stdout : isatty(fileno(stderr)) ? stderr : NULL); if (f) daemon_help(f, ident, "now detaches from console into background mode"); } // Signal detach to parent if (sig_event(EVT_DETACHED) != 1) { if (!debugging()) return -1; } daemon_disable_console(); } else { // Signal end of initialization to service control manager service_report_status(SERVICE_RUNNING, 0); reopen_stdin = reopen_stdout = reopen_stderr = 1; } return 0; }
// events from SCM and Windows comes here. Be responsive!! void WINAPI serviceCtrlFunction( DWORD control ) { switch( control ) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: service_report_status( SERVICE_STOP_PENDING, NO_ERROR, DEFAULT_SERVICE_TIMEOUT ); LOG_INFO << "Stopping service"; // signal stopping now SetEvent( serviceStopEvent ); break; case SERVICE_CONTROL_INTERROGATE: // see below break; } // report current status of service to SCM service_report_status( serviceStatus.dwCurrentState, NO_ERROR, DEFAULT_SERVICE_TIMEOUT ); }
static void service_exit(void) { // Close signal events int i; for (i = 0; i < num_sig_handlers; i++) CloseHandle(sig_events[i]); num_sig_handlers = 0; // Set exitcode if (daemon_winsvc_exitcode) { svc_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; svc_status.dwServiceSpecificExitCode = daemon_winsvc_exitcode; } // Report stopped service_report_status(SERVICE_STOPPED, 0); }
static void WINAPI service_main( DWORD argc, LPTSTR *argv ) { try { // set an emergency logger (debug view), is set in 'ImagePath' in the registry of the service description _Wolframe::log::LogBackend::instance().setWinDebugLevel( winDbgLevel ); // read configuration (from the location passed in the command line arguments of the main, not the service_main) _Wolframe::config::CmdLineConfig cmdLineCfg; // empty for a service with --service cmdLineCfg.command = _Wolframe::config::CmdLineConfig::RUN_SERVICE; const char *configFile = serviceConfig.c_str( ); // configuration comes from main thread std::string configurationPath = boost::filesystem::path( configFile).branch_path().string(); _Wolframe::module::ModulesDirectory modDir( configurationPath); _Wolframe::config::ApplicationConfiguration conf; conf.addModules( &modDir ); _Wolframe::config::ApplicationConfiguration::ConfigFileType cfgType = _Wolframe::config::ApplicationConfiguration::fileType( configFile, cmdLineCfg.cfgType ); if ( cfgType == _Wolframe::config::ApplicationConfiguration::CONFIG_UNDEFINED ) return; if ( !conf.parseModules( configFile, cfgType )) return; if ( ! modDir.loadModules( conf.moduleList() )) return; if ( !conf.parse( configFile, cfgType )) return; // configuration file has been parsed successfully // build the final configuration conf.finalize( cmdLineCfg ); // create the final logger based on the configuration _Wolframe::log::LogBackend::instance().setConsoleLevel( conf.loggerCfg->stderrLogLevel ); _Wolframe::log::LogBackend::instance().setLogfileLevel( conf.loggerCfg->logFileLogLevel ); _Wolframe::log::LogBackend::instance().setLogfileName( conf.loggerCfg->logFile ); _Wolframe::log::LogBackend::instance().setSyslogLevel( conf.loggerCfg->syslogLogLevel ); _Wolframe::log::LogBackend::instance().setSyslogFacility( conf.loggerCfg->syslogFacility ); _Wolframe::log::LogBackend::instance().setSyslogIdent( conf.loggerCfg->syslogIdent ); _Wolframe::log::LogBackend::instance().setEventlogLevel( conf.loggerCfg->eventlogLogLevel ); _Wolframe::log::LogBackend::instance().setEventlogLog( conf.loggerCfg->eventlogLogName ); _Wolframe::log::LogBackend::instance().setEventlogSource( conf.loggerCfg->eventlogSource ); // register the event callback where we get called by Windows and the SCM serviceStatusHandle = RegisterServiceCtrlHandler( conf.serviceCfg->serviceName.c_str( ), serviceCtrlFunction ); if( serviceStatusHandle == 0 ) { LOG_FATAL << "Unable to register service control handler function: " << _Wolframe::log::LogError::LogWinerror; return; } // send "we are starting up now" to the SCM service_report_status( SERVICE_START_PENDING, NO_ERROR, DEFAULT_SERVICE_TIMEOUT ); // register a stop event serviceStopEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); if( serviceStopEvent == NULL ) { LOG_FATAL << "Unable to create the stop event for the termination of the service: " << _Wolframe::log::LogError::LogWinerror; service_report_status( SERVICE_STOPPED, NO_ERROR, DEFAULT_SERVICE_TIMEOUT ); return; } LOG_NOTICE << "Starting service"; // run server in background thread(s). _Wolframe::ServerHandler handler( conf.handlerCfg, &modDir ); _Wolframe::net::server s( conf.serverCfg, handler ); boost::thread t( boost::bind( &_Wolframe::net::server::run, &s )); // we are up and running now (hopefully), signal this to the SCM service_report_status( SERVICE_RUNNING, NO_ERROR, DEFAULT_SERVICE_TIMEOUT ); // Sit and wait here for the stop event to happen, terminate then WAIT_FOR_STOP_EVENT: DWORD res = WaitForSingleObject( serviceStopEvent, DEFAULT_SERVICE_TIMEOUT ); switch( res ) { case WAIT_OBJECT_0: s.stop( ); // stop signal received, signal "going to stop" to SCM service_report_status( SERVICE_STOP_PENDING, NO_ERROR, DEFAULT_SERVICE_TIMEOUT ); break; case WAIT_TIMEOUT: // we could do something periodic here goto WAIT_FOR_STOP_EVENT; case WAIT_ABANDONED: // this is bad, not really sure how we could recover from this one. For // now let's assume that stopping here is safer, so treat it like a successful // event, but log the fact we run into that state LOG_CRITICAL << "Waiting for stop event in service main resulted in WAIT_ABANDONED!"; break; case WAIT_FAILED: // error, stop now immediatelly LOG_FATAL << "Waiting for stop event in service main failed, stopping now" << _Wolframe::log::LogError::LogWinerror; s.stop( ); service_report_status( SERVICE_STOPPED, NO_ERROR, DEFAULT_SERVICE_TIMEOUT ); return; } // signal the SCM that we are done LOG_NOTICE << "Stopped service"; service_report_status( SERVICE_STOPPED, NO_ERROR, DEFAULT_SERVICE_TIMEOUT ); } catch (std::exception& e) { LOG_FATAL << e.what( ); // any exception should signal the SCM that the service is down now service_report_status( SERVICE_STOPPED, NO_ERROR, DEFAULT_SERVICE_TIMEOUT ); } }