diff options
author | Andreas Baumann <abaumann@yahoo.com> | 2009-03-26 17:26:00 +0100 |
---|---|---|
committer | Andreas Baumann <abaumann@yahoo.com> | 2009-03-26 17:26:00 +0100 |
commit | a92ee231c47556681311ae27fdfdb5e36d3e2582 (patch) | |
tree | 31c067d164b43d5c641aeaffd731473cf34777df /src | |
parent | cbc6aaca6dd7ac57a6115b3512a85045e51303dd (diff) | |
download | wolfbones-a92ee231c47556681311ae27fdfdb5e36d3e2582.tar.gz wolfbones-a92ee231c47556681311ae27fdfdb5e36d3e2582.tar.bz2 |
code moved, works again somehow, now cleanup in the service
Diffstat (limited to 'src')
-rw-r--r-- | src/service/service.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/service/service.c b/src/service/service.c index 0b7bbfa..1252c52 100644 --- a/src/service/service.c +++ b/src/service/service.c @@ -7,6 +7,12 @@ #include <WinSvc.h> /* for service functions */ +SERVICE_STATUS_HANDLE service_status_handle; +SERVICE_STATUS service_status; +HANDLE service_stop_event = NULL; + +#define SERVICE_NAME "testservice" + wolf_error_t wolf_service_install( wolf_service_params_t params ) { SC_HANDLE scm; SC_HANDLE service; @@ -138,3 +144,199 @@ wolf_error_t wolf_service_remove( LPCTSTR service_name ) { return WOLF_OK; } + +/* constants and values from WinSvc.h: */ +static const char *wolf_service_state_to_str( DWORD current_state ) { + switch( current_state ) { + case SERVICE_STOPPED: return "SERVICE_STOPPED"; + case SERVICE_START_PENDING: return "SERVICE_START_PENDING"; + case SERVICE_STOP_PENDING: return "SERVICE_STOP_PENDING"; + case SERVICE_RUNNING: return "SERVICE_RUNNING"; + case SERVICE_CONTINUE_PENDING: return "SERVICE_CONTINUE_PENDING"; + case SERVICE_PAUSE_PENDING: return "SERVICE_PAUSE_PENDING"; + case SERVICE_PAUSED: return "SERVICE_PAUSED"; + default: return "<unknown service state>"; + } +} + +/* constants and values from WinSvc.h: */ +static const char *wolf_service_control_to_str( DWORD control ) { + switch( control ) { + case SERVICE_CONTROL_STOP: return "SERVICE_CONTROL_STOP"; + case SERVICE_CONTROL_PAUSE: return "SERVICE_CONTROL_PAUSE"; + case SERVICE_CONTROL_CONTINUE: return "SERVICE_CONTROL_CONTINUE"; + case SERVICE_CONTROL_INTERROGATE: return "SERVICE_CONTROL_INTERROGATE"; + case SERVICE_CONTROL_SHUTDOWN: return "SERVICE_CONTROL_SHUTDOWN"; + case SERVICE_CONTROL_PARAMCHANGE: return "SERVICE_CONTROL_PARAMCHANGE"; + case SERVICE_CONTROL_NETBINDADD: return "SERVICE_CONTROL_NETBINDADD"; + case SERVICE_CONTROL_NETBINDREMOVE: return "SERVICE_CONTROL_NETBINDREMOVE"; + case SERVICE_CONTROL_NETBINDENABLE: return "SERVICE_CONTROL_NETBINDENABLE"; + case SERVICE_CONTROL_NETBINDDISABLE: return "SERVICE_CONTROL_NETBINDDISABLE"; + case SERVICE_CONTROL_DEVICEEVENT: return "SERVICE_CONTROL_DEVICEEVENT"; + case SERVICE_CONTROL_HARDWAREPROFILECHANGE: return "SERVICE_CONTROL_HARDWAREPROFILECHANGE"; + case SERVICE_CONTROL_POWEREVENT: return "SERVICE_CONTROL_POWEREVENT"; + case SERVICE_CONTROL_SESSIONCHANGE: return "SERVICE_CONTROL_SESSIONCHANGE"; + default: return "<unknown service control>"; + } +} + +static void wolf_service_report_status( DWORD current_state, + DWORD exit_code, + DWORD wait_hint ) { + BOOL res; + char errbuf[512]; + + wolf_log( WOLF_LOG_DEBUG, WOLF_CATEGORY_SERVICE, WOLF_MSG_SERVICE_REPORT_STATUS, + _( "reporting status with new state '%s' (%d) (currently in state '%s' (%d))" ), + wolf_service_state_to_str( current_state ), current_state, + wolf_service_state_to_str( service_status.dwCurrentState ), service_status.dwCurrentState ); + + service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + service_status.dwCurrentState = current_state; + service_status.dwWin32ExitCode = exit_code; + service_status.dwServiceSpecificExitCode = 0; + service_status.dwWaitHint = wait_hint; + service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + switch( current_state ) { + case SERVICE_START_PENDING: + /* during startup we should not accept events, otherwise our + * state machine could get troubled! + */ + service_status.dwControlsAccepted = 0; + service_status.dwCheckPoint++; + break; + + case SERVICE_RUNNING: + case SERVICE_STOPPED: + /* reset checkpoint for status bar in final states */ + service_status.dwCheckPoint = 0; + break; + + default: + /* increate the tick for transient states */ + service_status.dwCheckPoint++; + break; + } + + res = SetServiceStatus( service_status_handle, &service_status ); + if( !res ) { + WOLF_LOG_GET_LAST_ERROR( GetLastError( ), errbuf, 512 ); + wolf_log( WOLF_LOG_ERR, WOLF_CATEGORY_SERVICE, WOLF_MSG_SERVICE_CANT_REPORT_STATUS, + _( "Unable to report state '%s' (%d) of service '%s' to SCM '%s (%d)" ), + wolf_service_state_to_str( current_state ), current_state, + SERVICE_NAME, errbuf, GetLastError( ) ); + return; + } +} + +/* we get called here by the system and the service control manager, + * be as short as possible, report states and trigger new events at + * most! + */ +void WINAPI wolf_service_ctrl_handler( DWORD control ) { + char errbuf[512]; + BOOL res; + + wolf_log( WOLF_LOG_DEBUG, WOLF_CATEGORY_SERVICE, WOLF_MSG_SERVICE_HANDLING_EVENT, + _( "service handler received status change '%s' (%d)" ), + wolf_service_control_to_str( control ), + control ); + + switch( control ) { + case SERVICE_CONTROL_STOP: + wolf_service_report_status( SERVICE_STOP_PENDING, NO_ERROR, 1000 ); + SetEvent( service_stop_event ); + break; + + case SERVICE_CONTROL_INTERROGATE: + /* fall through to send current status */ + break; + } + + /* report current state */ + wolf_service_report_status( service_status.dwCurrentState, NO_ERROR, 1000 ); +} + +void WINAPI wolf_service_main( DWORD argc, LPTSTR *argv ) { + char errbuf[512]; + BOOL res; + + /* all other loggers make no sense: a service is not supposed + * to have a logfile or interaction with the user in any way! + */ + wolf_log_openlogtoeventlog( NULL, "Application", "testservice", + "C:\\Temp\\testservicemsg.dll", WOLF_LAST_INTERNAL_CATEGORY+1, WOLF_LOG_DEBUG ); + + /* register the event callback where we get called by the service + * manager and the system + */ + service_status_handle = RegisterServiceCtrlHandler( + SERVICE_NAME, wolf_service_ctrl_handler ); + + if( service_status_handle == 0 ) { + WOLF_LOG_GET_LAST_ERROR( GetLastError( ), errbuf, 512 ); + wolf_log( WOLF_LOG_ERR, WOLF_CATEGORY_SERVICE, WOLF_MSG_SERVICE_CANT_REGISTER_SERVICE_CTRL_HANDLER, + _( "Unable to register service control handler function for service '%s': %s (%d)" ), + SERVICE_NAME, errbuf, GetLastError( ) ); + return; + } + + /* signal that we are now up and running */ + wolf_service_report_status( SERVICE_START_PENDING, NO_ERROR, 3000 ); + + /* register a stop event, the service control handler will send + * the event. From now on we have a service event handler installed, + * so if something goes wrong we can set the service state to + * SERVICE_STOPPED and terminate gracefully. + */ + service_stop_event = CreateEvent( + NULL, /* default security attributes */ + TRUE, /* manual reset event */ + FALSE, /* not signalled */ + NULL ); /* no name */ + if( service_stop_event == NULL ) { + WOLF_LOG_GET_LAST_ERROR( GetLastError( ), errbuf, 512 ); + wolf_log( WOLF_LOG_ERR, WOLF_CATEGORY_SERVICE, WOLF_MSG_SERVICE_CANT_CREATE_STOP_EVENT, + _( "Unable to create the stop event for service '%s': %s (%d)" ), + SERVICE_NAME, errbuf, GetLastError( ) ); + wolf_service_report_status( SERVICE_STOPPED, NO_ERROR, 1000 ); + } + + wolf_service_report_status( SERVICE_RUNNING, NO_ERROR, 1000 ); + wolf_log( WOLF_LOG_NOTICE, WOLF_CATEGORY_SERVICE, WOLF_MSG_SERVICE_STARTED_SERVICE, + _( "Started %s service" ), SERVICE_NAME ); + + /* main loop */ + while( 1 ) { + DWORD r; + r = WaitForSingleObject( service_stop_event, 1000 ); + switch( r ) { + case WAIT_OBJECT_0: + /* stop signal received */ + goto SERVICE_END; + + case WAIT_TIMEOUT: + /* we can do periodic things here */ + break; + + default: + WOLF_LOG_GET_LAST_ERROR( GetLastError( ), errbuf, 512 ); + wolf_log( WOLF_LOG_ERR, WOLF_CATEGORY_SERVICE, WOLF_MSG_SERVICE_WAIT_FOR_OBJECT_FAILED, + _( "Waiting for the stop event for service '%s' failed: %s (%d)" ), + SERVICE_NAME, errbuf, GetLastError( ) ); + wolf_service_report_status( SERVICE_STOPPED, NO_ERROR, 1000 ); + return; + } + } + +SERVICE_END: + wolf_log( WOLF_LOG_NOTICE, WOLF_CATEGORY_SERVICE, WOLF_MSG_SERVICE_STOPPED_SERVICE, + _( "Stopped %s service" ), SERVICE_NAME ); + + wolf_service_report_status( SERVICE_STOPPED, NO_ERROR, 1000 ); + + wolf_log_closelogtoeventlog( ); + + return; +} |