summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Baumann <abaumann@yahoo.com>2009-03-27 18:31:27 +0100
committerAndreas Baumann <abaumann@yahoo.com>2009-03-27 18:31:27 +0100
commitbaa035aa68b7b72fe301c933227aa2530bbec66d (patch)
treed42e0636d34289a4c00645f5cc115e26e0bb91e0 /src
parentf83210c88e7376e12b5cf0e86a073c59e4185efb (diff)
downloadwolfbones-baa035aa68b7b72fe301c933227aa2530bbec66d.tar.gz
wolfbones-baa035aa68b7b72fe301c933227aa2530bbec66d.tar.bz2
added service termination on console control events
Diffstat (limited to 'src')
-rw-r--r--src/service/service.c104
1 files changed, 95 insertions, 9 deletions
diff --git a/src/service/service.c b/src/service/service.c
index bae331a..48a32e4 100644
--- a/src/service/service.c
+++ b/src/service/service.c
@@ -12,6 +12,8 @@ static SERVICE_STATUS service_status;
static HANDLE service_stop_event = NULL;
static LPSERVICE_MAIN_FUNCTION service_service_main = NULL;
+LPWOLF_SERVICE_SUSPEND_FUNCTION wolf_service_events_suspend = NULL;
+
#define SERVICE_NAME "testservice"
wolf_error_t wolf_service_install( wolf_service_params_t params ) {
@@ -317,18 +319,34 @@ void WINAPI wolf_service_main( DWORD argc, LPTSTR *argv ) {
return;
}
-wolf_service_event_t wolf_service_events_suspend( int timeout, wolf_error_t *error ) {
+wolf_service_event_t wolf_service_events_suspend_console( int timeout, wolf_error_t *error ) {
DWORD res;
char errbuf[512];
- /* non-service mode, return after timeout */
- /* TODO: how to catch stopping of console application and to send a terminate
- * event? */
- if( service_stop_event == NULL ) {
- Sleep( timeout );
- *error = WOLF_ERR_TIMEOUT;
- return WOLF_SERVICE_NO_EVENT;
+ res = WaitForSingleObject( service_stop_event, timeout * 1000 );
+ switch( res ) {
+ case WAIT_OBJECT_0:
+ /* stop signal received */
+ *error = WOLF_OK;
+ return WOLF_SERVICE_EVENT_TERMINATE;
+
+ case WAIT_TIMEOUT:
+ *error = WOLF_ERR_TIMEOUT;
+ return WOLF_SERVICE_NO_EVENT;
+
+ 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 events in the service '%s' failed: %s (%d)" ),
+ SERVICE_NAME, errbuf, GetLastError( ) );
+ *error = WOLF_ERR_INTERNAL;
+ return WOLF_SERVICE_NO_EVENT;
}
+}
+
+wolf_service_event_t wolf_service_events_suspend_service( int timeout, wolf_error_t *error ) {
+ DWORD res;
+ char errbuf[512];
res = WaitForSingleObject( service_stop_event, timeout * 1000 );
switch( res ) {
@@ -353,12 +371,77 @@ wolf_service_event_t wolf_service_events_suspend( int timeout, wolf_error_t *err
}
}
+/* constants and values from WinCon.h: */
+static const char *wolf_service_console_ctrl_to_str( DWORD ctrl ) {
+ switch( ctrl ) {
+ case CTRL_C_EVENT: return "CTRL_C_EVENT";
+ case CTRL_BREAK_EVENT: return "CTRL_BREAK_EVENT";
+ case CTRL_CLOSE_EVENT: return "CTRL_CLOSE_EVENT";
+ case CTRL_LOGOFF_EVENT: return "CTRL_LOGOFF_EVENT";
+ case CTRL_SHUTDOWN_EVENT: return "CTRL_SHUTDOWN_EVENT";
+ default: return "<unknown control>";
+ }
+}
+
+static BOOL WINAPI wolf_service_console_ctrl_handler( DWORD ctrl ) {
+ wolf_log( WOLF_LOG_DEBUG, WOLF_CATEGORY_SERVICE, WOLF_MSG_SERVICE_CONSOLE_CTRL_RECEIVED,
+ _( "Got a console control event '%s' (%d)" ),
+ wolf_service_console_ctrl_to_str( ctrl ), ctrl );
+
+ switch( ctrl ) {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ case CTRL_CLOSE_EVENT:
+ case CTRL_LOGOFF_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ SetEvent( service_stop_event );
+ return TRUE;
+ }
+
+ return FALSE;
+}
wolf_error_t wolf_service_start_console( LPTSTR service_name,
LPSERVICE_MAIN_FUNCTION service_main,
DWORD argc,
LPTSTR *argv ) {
- service_main( argc, argv );
+ BOOL res;
+ char errbuf[512];
+
+ /* register the user-defined service main (what he should actually program */
+ service_service_main = service_main;
+
+ /* register the right suspend function */
+ wolf_service_events_suspend = wolf_service_events_suspend_console;
+
+ /* register a stop event, the console control handler will send
+ * the event.
+ */
+ 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( ) );
+ return WOLF_ERR_INTERNAL;
+ }
+
+ /* catch console events for proper termination of the service in console mode */
+ res = SetConsoleCtrlHandler( wolf_service_console_ctrl_handler, TRUE );
+ if( !res ) {
+ WOLF_LOG_GET_LAST_ERROR( GetLastError( ), errbuf, 512 );
+ wolf_log( WOLF_LOG_ERR, WOLF_CATEGORY_SERVICE, WOLF_MSG_SERVICE_CANT_REGISTER_CONSOLE_CTRL_HANDLER,
+ _( "Unable to register the console control handler for foreground service '%s': %s (%d)" ),
+ service_name, errbuf, GetLastError( ) );
+ return WOLF_ERR_INTERNAL;
+ }
+
+ /* now call the user-defined service main function */
+ service_service_main( argc, argv );
return WOLF_OK;
}
@@ -374,6 +457,9 @@ wolf_error_t wolf_service_start( LPTSTR service_name,
/* register the user-defined service main (what he should actually program */
service_service_main = service_main;
+ /* register the right suspend function */
+ wolf_service_events_suspend = wolf_service_events_suspend_service;
+
/* register the wolf_service_main to the SCM, which is the entry point for
* the service (doing some things we want to hide from the service developer),
* and which in the end calls 'service_service_main' (the user-defined main