summaryrefslogtreecommitdiff
path: root/tests/service
diff options
context:
space:
mode:
authorAndreas Baumann <abaumann@yahoo.com>2009-03-25 21:09:25 +0100
committerAndreas Baumann <abaumann@yahoo.com>2009-03-25 21:09:25 +0100
commit065315f7fd84f1707626113a1f29de9bc46d4bcd (patch)
tree3195e77e7a437972ba7e34d74c93ae81b04af24a /tests/service
parentba20ff72bf3c6a90cb44ada1a16f9e121f2d6ca5 (diff)
downloadwolfbones-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.W322
-rw-r--r--tests/service/testservice.c167
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" );