diff options
author | Andreas Baumann <abaumann@yahoo.com> | 2009-03-25 21:09:25 +0100 |
---|---|---|
committer | Andreas Baumann <abaumann@yahoo.com> | 2009-03-25 21:09:25 +0100 |
commit | 065315f7fd84f1707626113a1f29de9bc46d4bcd (patch) | |
tree | 3195e77e7a437972ba7e34d74c93ae81b04af24a /tests/service | |
parent | ba20ff72bf3c6a90cb44ada1a16f9e121f2d6ca5 (diff) | |
download | wolfbones-065315f7fd84f1707626113a1f29de9bc46d4bcd.tar.gz wolfbones-065315f7fd84f1707626113a1f29de9bc46d4bcd.tar.bz2 |
completly overhauled the testservice, the former sample code was completly wrong! take MS knoledge base!
Diffstat (limited to 'tests/service')
-rw-r--r-- | tests/service/Makefile.W32 | 2 | ||||
-rw-r--r-- | tests/service/testservice.c | 167 |
2 files changed, 166 insertions, 3 deletions
diff --git a/tests/service/Makefile.W32 b/tests/service/Makefile.W32 index 21bf4be..29a0c94 100644 --- a/tests/service/Makefile.W32 +++ b/tests/service/Makefile.W32 @@ -33,6 +33,8 @@ local_test: $(LIBRARIES) @echo Testing service.. @copy testservice.dll C:\TEMP >NUL @testservice /install 2>NUL + @net start testservice >NUL + @net stop testservice >NUL @testservice /remove 2>NUL local_all: diff --git a/tests/service/testservice.c b/tests/service/testservice.c index 7ccbac2..3370644 100644 --- a/tests/service/testservice.c +++ b/tests/service/testservice.c @@ -23,11 +23,18 @@ #define WOLF_MSG_TESTSERVICE_CANT_OPEN_SERVICE WOLF_MSG_TESTSERVICE_BASE+9 #define WOLF_MSG_TESTSERVICE_CANT_DELETE_SERVICE WOLF_MSG_TESTSERVICE_BASE+10 #define WOLF_MSG_TESTSERVICE_CANT_DISPATCH_SERVICE WOLF_MSG_TESTSERVICE_BASE+11 +#define WOLF_MSG_TESTSERVICE_CANT_REGISTER_SERVICE_CTRL_HANDLER WOLF_MSG_TESTSERVICE_BASE+12 +#define WOLF_MSG_TESTSERVICE_HANDLING_EVENT WOLF_MSG_TESTSERVICE_BASE+13 +#define WOLF_MSG_TESTSERVICE_STARTED_SERVICE WOLF_MSG_TESTSERVICE_BASE+14 +#define WOLF_MSG_TESTSERVICE_STOPPED_SERVICE WOLF_MSG_TESTSERVICE_BASE+15 +#define WOLF_MSG_TESTSERVICE_CANT_CREATE_STOP_EVENT WOLF_MSG_TESTSERVICE_BASE+16 +#define WOLF_MSG_TESTSERVICE_CANT_REPORT_STATUS WOLF_MSG_TESTSERVICE_BASE+17 +#define WOLF_MSG_TESTSERVICE_WAIT_FOR_OBJECT_FAILED WOLF_MSG_TESTSERVICE_BASE+18 +#define WOLF_MSG_TESTSERVICE_REPORT_STATUS WOLF_MSG_TESTSERVICE_BASE+19 #define SERVICE_NAME "testservice" #define SERVICE_NAME_DESCR "Wolf Test Service" - static wolf_error_t wolf_service_install( LPCTSTR service_name, LPCTSTR service_name_descr ) { SC_HANDLE scm; @@ -161,7 +168,157 @@ static wolf_error_t wolf_service_remove( LPCTSTR service_name ) { return WOLF_OK; } +/* FIXME: should be passed in the event contect as struct */ +static SERVICE_STATUS_HANDLE service_status_handle; +static SERVICE_STATUS service_status; +static HANDLE service_stop_event = NULL; + +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_TESTSERVICE, WOLF_MSG_TESTSERVICE_REPORT_STATUS, + _( "reporting status with new state %d (currently in state %d)" ), + service_status.dwCurrentState, current_state ); + + 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; + break; + + case SERVICE_RUNNING: + case SERVICE_STOPPED: + /* reset checkpoint for status bar in final states */ + service_status.dwCheckPoint = 0; + break; + + defaut: + /* 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_TESTSERVICE, WOLF_MSG_TESTSERVICE_CANT_REPORT_STATUS, + _( "Unable to report state %d of service '%s' to SCM '%s (%d)" ), + 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_TESTSERVICE, WOLF_MSG_TESTSERVICE_HANDLING_EVENT, + _( "service handler received event %d" ), + control ); + + switch( control ) { + case SERVICE_CONTROL_STOP: + wolf_service_report_status( SERVICE_STOP_PENDING, NO_ERROR, 0 ); + 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, 0 ); +} + + void WINAPI wolf_service_main( DWORD argc, LPTSTR *argv ) { + char errbuf[512]; + BOOL res; + + /* 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_TESTSERVICE, WOLF_MSG_TESTSERVICE_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_TESTSERVICE, WOLF_MSG_TESTSERVICE_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, 0 ); + } + + wolf_service_report_status( SERVICE_RUNNING, NO_ERROR, 0 ); + wolf_log( WOLF_LOG_NOTICE, WOLF_CATEGORY_DAEMON, WOLF_MSG_TESTSERVICE_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 */ + wolf_service_report_status( SERVICE_STOPPED, NO_ERROR, 0 ); + 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_TESTSERVICE, WOLF_MSG_TESTSERVICE_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, 0 ); + return; + } + } + +SERVICE_END: + wolf_log( WOLF_LOG_NOTICE, WOLF_CATEGORY_DAEMON, WOLF_MSG_TESTSERVICE_STOPPED_SERVICE, + _( "Stopped %s service" ), SERVICE_NAME ); + return; } @@ -169,9 +326,9 @@ void __cdecl _tmain( int argc, TCHAR *argv[] ) { char errbuf[512]; wolf_log_openlogtostderr( WOLF_LOG_DEBUG ); - wolf_log_openlogtofile( "testservice.log", WOLF_LOG_NOTICE ); + wolf_log_openlogtofile( "testservice.log", WOLF_LOG_DEBUG ); wolf_log_openlogtoeventlog( NULL, "Application", "testservice", - "C:\\Temp\\testsrevice.dll", 3, WOLF_LOG_NOTICE ); + "C:\\Temp\\testsrevice.dll", 3, WOLF_LOG_DEBUG ); /* called as service, dispatch the main service thread */ if( argc < 2 ) { @@ -191,6 +348,10 @@ void __cdecl _tmain( int argc, TCHAR *argv[] ) { return; } + /* not as service: provide functions like installation and + * deinstallation of the service. Also starting or stopping + * is an option here for easy handling from the shell. + */ if( strcasecmp( argv[1], "/help" ) == 0 ) { printf( "testsrevice [options]\r\n" ); printf( " /help show this help page\r\n" ); |