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;
}
Example #4
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);
}
Example #6
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 );
	}
}