charon-svc: Register for stop events not before reaching STATUS_RUNNING
MSDN SetServiceStatus(): "Do not register to accept controls while the status is SERVICE_START_PENDING or the service can crash."
This commit is contained in:
parent
ef7bfadabb
commit
4ce8b0cae6
|
@ -45,6 +45,12 @@ static HANDLE event;
|
||||||
*/
|
*/
|
||||||
extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
|
extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward declaration
|
||||||
|
*/
|
||||||
|
static DWORD service_handler(DWORD dwControl, DWORD dwEventType,
|
||||||
|
LPVOID lpEventData, LPVOID lpContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logging hook for library logs, using stderr output
|
* Logging hook for library logs, using stderr output
|
||||||
*/
|
*/
|
||||||
|
@ -103,9 +109,90 @@ static void update_status(DWORD state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize and run charon
|
* Control handler for console
|
||||||
*/
|
*/
|
||||||
static void init_and_run(DWORD dwArgc, LPTSTR *lpszArgv)
|
static BOOL console_handler(DWORD dwCtrlType)
|
||||||
|
{
|
||||||
|
switch (dwCtrlType)
|
||||||
|
{
|
||||||
|
case CTRL_C_EVENT:
|
||||||
|
case CTRL_BREAK_EVENT:
|
||||||
|
case CTRL_CLOSE_EVENT:
|
||||||
|
DBG1(DBG_DMN, "application is stopping, cleaning up");
|
||||||
|
if (status.dwCurrentState == SERVICE_RUNNING)
|
||||||
|
{
|
||||||
|
charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL,
|
||||||
|
dwCtrlType);
|
||||||
|
}
|
||||||
|
/* signal main thread to clean up */
|
||||||
|
SetEvent(event);
|
||||||
|
return TRUE;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service handler function
|
||||||
|
*/
|
||||||
|
static DWORD service_handler(DWORD dwControl, DWORD dwEventType,
|
||||||
|
LPVOID lpEventData, LPVOID lpContext)
|
||||||
|
{
|
||||||
|
switch (dwControl)
|
||||||
|
{
|
||||||
|
case SERVICE_CONTROL_STOP:
|
||||||
|
case SERVICE_CONTROL_SHUTDOWN:
|
||||||
|
DBG1(DBG_DMN, "service is stopping, cleaning up");
|
||||||
|
if (status.dwCurrentState == SERVICE_RUNNING)
|
||||||
|
{
|
||||||
|
charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL,
|
||||||
|
dwControl);
|
||||||
|
}
|
||||||
|
/* signal main thread to clean up */
|
||||||
|
SetEvent(event);
|
||||||
|
return NO_ERROR;
|
||||||
|
case SERVICE_CONTROL_INTERROGATE:
|
||||||
|
return NO_ERROR;
|
||||||
|
default:
|
||||||
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for console program shutdown
|
||||||
|
*/
|
||||||
|
static int console_wait()
|
||||||
|
{
|
||||||
|
update_status(SERVICE_RUNNING);
|
||||||
|
|
||||||
|
if (WaitForSingleObjectEx(event, INFINITE, TRUE) != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for service shutdown
|
||||||
|
*/
|
||||||
|
static int service_wait()
|
||||||
|
{
|
||||||
|
/* service is initialized, we now accept control requests */
|
||||||
|
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||||
|
update_status(SERVICE_RUNNING);
|
||||||
|
status.dwControlsAccepted = 0;
|
||||||
|
|
||||||
|
if (WaitForSingleObjectEx(event, INFINITE, TRUE) != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and run charon using a wait function
|
||||||
|
*/
|
||||||
|
static void init_and_run(DWORD dwArgc, LPTSTR *lpszArgv, int (*wait)())
|
||||||
{
|
{
|
||||||
level_t levels[DBG_MAX];
|
level_t levels[DBG_MAX];
|
||||||
int i;
|
int i;
|
||||||
|
@ -138,11 +225,7 @@ static void init_and_run(DWORD dwArgc, LPTSTR *lpszArgv)
|
||||||
|
|
||||||
charon->start(charon);
|
charon->start(charon);
|
||||||
|
|
||||||
status.dwWin32ExitCode = 0;
|
status.dwWin32ExitCode = wait();
|
||||||
update_status(SERVICE_RUNNING);
|
|
||||||
|
|
||||||
/* main thread goes to sleep */
|
|
||||||
WaitForSingleObjectEx(event, INFINITE, TRUE);
|
|
||||||
}
|
}
|
||||||
update_status(SERVICE_STOP_PENDING);
|
update_status(SERVICE_STOP_PENDING);
|
||||||
libcharon_deinit();
|
libcharon_deinit();
|
||||||
|
@ -159,30 +242,6 @@ static void init_and_run(DWORD dwArgc, LPTSTR *lpszArgv)
|
||||||
update_status(SERVICE_STOPPED);
|
update_status(SERVICE_STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Control handler for console
|
|
||||||
*/
|
|
||||||
static BOOL console_handler(DWORD dwCtrlType)
|
|
||||||
{
|
|
||||||
switch (dwCtrlType)
|
|
||||||
{
|
|
||||||
case CTRL_C_EVENT:
|
|
||||||
case CTRL_BREAK_EVENT:
|
|
||||||
case CTRL_CLOSE_EVENT:
|
|
||||||
DBG1(DBG_DMN, "application is stopping, cleaning up");
|
|
||||||
if (status.dwCurrentState == SERVICE_RUNNING)
|
|
||||||
{
|
|
||||||
charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL,
|
|
||||||
dwCtrlType);
|
|
||||||
}
|
|
||||||
/* signal main thread to clean up */
|
|
||||||
SetEvent(event);
|
|
||||||
return TRUE;
|
|
||||||
default:
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main routine when running from console
|
* Main routine when running from console
|
||||||
*/
|
*/
|
||||||
|
@ -192,37 +251,11 @@ static void console_main(DWORD dwArgc, LPTSTR *lpszArgv)
|
||||||
|
|
||||||
if (SetConsoleCtrlHandler(console_handler, TRUE))
|
if (SetConsoleCtrlHandler(console_handler, TRUE))
|
||||||
{
|
{
|
||||||
init_and_run(dwArgc, lpszArgv);
|
init_and_run(dwArgc, lpszArgv, console_wait);
|
||||||
SetConsoleCtrlHandler(console_handler, FALSE);
|
SetConsoleCtrlHandler(console_handler, FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Service handler function
|
|
||||||
*/
|
|
||||||
static DWORD service_handler(DWORD dwControl, DWORD dwEventType,
|
|
||||||
LPVOID lpEventData, LPVOID lpContext)
|
|
||||||
{
|
|
||||||
switch (dwControl)
|
|
||||||
{
|
|
||||||
case SERVICE_CONTROL_STOP:
|
|
||||||
case SERVICE_CONTROL_SHUTDOWN:
|
|
||||||
DBG1(DBG_DMN, "service is stopping, cleaning up");
|
|
||||||
if (status.dwCurrentState == SERVICE_RUNNING)
|
|
||||||
{
|
|
||||||
charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL,
|
|
||||||
dwControl);
|
|
||||||
}
|
|
||||||
/* signal main thread to clean up */
|
|
||||||
SetEvent(event);
|
|
||||||
return NO_ERROR;
|
|
||||||
case SERVICE_CONTROL_INTERROGATE:
|
|
||||||
return NO_ERROR;
|
|
||||||
default:
|
|
||||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch the working directory to the executable directory
|
* Switch the working directory to the executable directory
|
||||||
*/
|
*/
|
||||||
|
@ -256,7 +289,6 @@ static void service_main(DWORD dwArgc, LPTSTR *lpszArgv)
|
||||||
{
|
{
|
||||||
memset(&status, 0, sizeof(status));
|
memset(&status, 0, sizeof(status));
|
||||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||||
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
|
||||||
status.dwWin32ExitCode = 1;
|
status.dwWin32ExitCode = 1;
|
||||||
|
|
||||||
handle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, service_handler, NULL);
|
handle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, service_handler, NULL);
|
||||||
|
@ -264,7 +296,7 @@ static void service_main(DWORD dwArgc, LPTSTR *lpszArgv)
|
||||||
{
|
{
|
||||||
if (switch_workingdir())
|
if (switch_workingdir())
|
||||||
{
|
{
|
||||||
init_and_run(dwArgc, lpszArgv);
|
init_and_run(dwArgc, lpszArgv, service_wait);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue