2004-11-12 18:11:31 +00:00
|
|
|
// $Id$
|
|
|
|
//
|
2004-01-19 20:53:40 +00:00
|
|
|
// The contents of this file are subject to the BOINC Public License
|
|
|
|
// Version 1.0 (the "License"); you may not use this file except in
|
|
|
|
// compliance with the License. You may obtain a copy of the License at
|
|
|
|
// http://boinc.berkeley.edu/license_1.0.txt
|
|
|
|
//
|
|
|
|
// Software distributed under the License is distributed on an "AS IS"
|
|
|
|
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
|
|
// License for the specific language governing rights and limitations
|
|
|
|
// under the License.
|
|
|
|
//
|
|
|
|
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
|
|
|
|
//
|
|
|
|
// The Initial Developer of the Original Code is the SETI@home project.
|
|
|
|
// Portions created by the SETI@home project are Copyright (C) 2002
|
|
|
|
// University of California at Berkeley. All Rights Reserved.
|
|
|
|
//
|
|
|
|
// Contributor(s):
|
|
|
|
// Craig Link, Microsoft Corp., Service Sample Template
|
|
|
|
//
|
|
|
|
|
|
|
|
#if defined(_WIN32) && defined(_CONSOLE)
|
|
|
|
|
2004-06-16 23:24:18 +00:00
|
|
|
#include "boinc_win.h"
|
2004-01-19 20:53:40 +00:00
|
|
|
|
2004-04-29 00:57:26 +00:00
|
|
|
#include "diagnostics.h"
|
2004-02-04 19:14:39 +00:00
|
|
|
#include "util.h"
|
2004-05-05 18:43:41 +00:00
|
|
|
#include "main.h"
|
|
|
|
#include "win_service.h"
|
2004-01-19 20:53:40 +00:00
|
|
|
|
2004-04-29 00:57:26 +00:00
|
|
|
|
2004-01-19 20:53:40 +00:00
|
|
|
// internal variables
|
|
|
|
SERVICE_STATUS ssStatus; // current status of the service
|
|
|
|
SERVICE_STATUS_HANDLE sshStatusHandle;
|
|
|
|
DWORD dwErr = 0;
|
2004-02-04 19:14:39 +00:00
|
|
|
TCHAR szErr[1024];
|
2004-01-19 20:53:40 +00:00
|
|
|
|
2004-04-29 00:57:26 +00:00
|
|
|
|
2004-01-19 20:53:40 +00:00
|
|
|
//
|
|
|
|
// FUNCTION: service_main
|
|
|
|
//
|
|
|
|
// PURPOSE: To perform actual initialization of the service
|
|
|
|
//
|
|
|
|
// PARAMETERS:
|
|
|
|
// dwArgc - number of command line arguments
|
|
|
|
// lpszArgv - array of command line arguments
|
|
|
|
//
|
|
|
|
// RETURN VALUE:
|
|
|
|
// none
|
|
|
|
//
|
|
|
|
// COMMENTS:
|
|
|
|
// This routine performs the service initialization and then calls
|
|
|
|
// the user defined main() routine to perform majority
|
|
|
|
// of the work.
|
|
|
|
//
|
|
|
|
void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
|
|
|
|
{
|
2004-04-29 00:57:26 +00:00
|
|
|
TCHAR szPath[MAX_PATH-1];
|
|
|
|
|
|
|
|
|
2004-01-19 20:53:40 +00:00
|
|
|
// SERVICE_STATUS members that don't change in example
|
|
|
|
//
|
|
|
|
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
2004-04-29 00:57:26 +00:00
|
|
|
ssStatus.dwControlsAccepted = SERVICE_ACCEPTED_ACTIONS;
|
2004-01-19 20:53:40 +00:00
|
|
|
ssStatus.dwServiceSpecificExitCode = 0;
|
|
|
|
|
2004-04-29 00:57:26 +00:00
|
|
|
|
2004-01-19 20:53:40 +00:00
|
|
|
// register our service control handler:
|
|
|
|
//
|
|
|
|
sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl);
|
|
|
|
if (!sshStatusHandle)
|
|
|
|
goto cleanup;
|
|
|
|
|
2004-04-29 00:57:26 +00:00
|
|
|
if (!ReportStatus(
|
2004-01-19 20:53:40 +00:00
|
|
|
SERVICE_RUNNING, // service state
|
|
|
|
ERROR_SUCCESS, // exit code
|
|
|
|
0)) // wait hint
|
|
|
|
goto cleanup;
|
|
|
|
|
2004-04-29 00:57:26 +00:00
|
|
|
|
|
|
|
// change the current directory to the boinc install directory
|
|
|
|
if (!GetModuleFileName(NULL, szPath, (sizeof(szPath)/sizeof(TCHAR))))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
TCHAR *pszProg = strrchr(szPath, '\\');
|
|
|
|
if (pszProg) {
|
|
|
|
szPath[pszProg - szPath + 1] = 0;
|
|
|
|
SetCurrentDirectory(szPath);
|
|
|
|
}
|
|
|
|
|
2004-03-29 23:22:19 +00:00
|
|
|
dwErr = boinc_main_loop(dwArgc, lpszArgv);
|
2004-01-19 20:53:40 +00:00
|
|
|
|
2004-04-29 00:57:26 +00:00
|
|
|
|
2004-01-19 20:53:40 +00:00
|
|
|
cleanup:
|
|
|
|
|
|
|
|
// try to report the stopped status to the service control manager.
|
|
|
|
//
|
|
|
|
if (sshStatusHandle)
|
|
|
|
(VOID)ReportStatus(
|
2004-04-29 00:57:26 +00:00
|
|
|
SERVICE_STOPPED,
|
2004-01-19 20:53:40 +00:00
|
|
|
dwErr,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// FUNCTION: service_ctrl
|
|
|
|
//
|
|
|
|
// PURPOSE: This function is called by the SCM whenever
|
|
|
|
// ControlService() is called on this service.
|
|
|
|
//
|
|
|
|
// PARAMETERS:
|
|
|
|
// dwCtrlCode - type of control requested
|
|
|
|
//
|
|
|
|
// RETURN VALUE:
|
|
|
|
// none
|
|
|
|
//
|
|
|
|
// COMMENTS:
|
|
|
|
//
|
|
|
|
VOID WINAPI service_ctrl(DWORD dwCtrlCode)
|
|
|
|
{
|
|
|
|
// Handle the requested control code.
|
|
|
|
//
|
|
|
|
switch(dwCtrlCode)
|
|
|
|
{
|
|
|
|
// Stop the service.
|
|
|
|
//
|
|
|
|
// SERVICE_STOP_PENDING should be reported before
|
|
|
|
// setting the Stop Event - hServerStopEvent - in
|
|
|
|
// ServiceStop(). This avoids a race condition
|
|
|
|
// which may result in a 1053 - The Service did not respond...
|
|
|
|
// error.
|
|
|
|
case SERVICE_CONTROL_STOP:
|
|
|
|
case SERVICE_CONTROL_SHUTDOWN:
|
|
|
|
ReportStatus(SERVICE_STOP_PENDING, ERROR_SUCCESS, 10000);
|
2004-05-05 18:43:41 +00:00
|
|
|
quit_client();
|
2004-01-19 20:53:40 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Pause the service.
|
|
|
|
//
|
|
|
|
case SERVICE_CONTROL_PAUSE:
|
|
|
|
ReportStatus(SERVICE_PAUSE_PENDING, ERROR_SUCCESS, 10000);
|
2004-05-05 18:43:42 +00:00
|
|
|
suspend_client();
|
2004-01-19 20:53:40 +00:00
|
|
|
ReportStatus(SERVICE_PAUSED, ERROR_SUCCESS, 10000);
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Continue the service.
|
|
|
|
//
|
|
|
|
case SERVICE_CONTROL_CONTINUE:
|
|
|
|
ReportStatus(SERVICE_CONTINUE_PENDING, ERROR_SUCCESS, 10000);
|
2004-05-05 18:43:41 +00:00
|
|
|
resume_client();
|
2004-01-19 20:53:40 +00:00
|
|
|
ReportStatus(SERVICE_RUNNING, ERROR_SUCCESS, 10000);
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Update the service status.
|
|
|
|
//
|
|
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
// invalid control code
|
|
|
|
//
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ReportStatus(ssStatus.dwCurrentState, ERROR_SUCCESS, 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// FUNCTION: ReportStatus()
|
|
|
|
//
|
|
|
|
// PURPOSE: Sets the current status of the service and
|
|
|
|
// reports it to the Service Control Manager
|
|
|
|
//
|
|
|
|
// PARAMETERS:
|
|
|
|
// dwCurrentState - the state of the service
|
|
|
|
// dwWin32ExitCode - error code to report
|
|
|
|
// dwWaitHint - worst case estimate to next checkpoint
|
|
|
|
//
|
|
|
|
// RETURN VALUE:
|
|
|
|
// TRUE - success
|
|
|
|
// FALSE - failure
|
|
|
|
//
|
|
|
|
// COMMENTS:
|
|
|
|
//
|
|
|
|
BOOL ReportStatus(DWORD dwCurrentState,
|
|
|
|
DWORD dwWin32ExitCode,
|
|
|
|
DWORD dwWaitHint)
|
|
|
|
{
|
|
|
|
static DWORD dwCheckPoint = 1;
|
|
|
|
BOOL fResult = TRUE;
|
|
|
|
|
|
|
|
if (dwCurrentState == SERVICE_START_PENDING)
|
|
|
|
ssStatus.dwControlsAccepted = 0;
|
|
|
|
else
|
2004-04-29 00:57:26 +00:00
|
|
|
ssStatus.dwControlsAccepted = SERVICE_ACCEPTED_ACTIONS;
|
2004-01-19 20:53:40 +00:00
|
|
|
|
|
|
|
ssStatus.dwCurrentState = dwCurrentState;
|
|
|
|
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
|
|
|
|
ssStatus.dwWaitHint = dwWaitHint;
|
|
|
|
|
|
|
|
if ( ( dwCurrentState == SERVICE_RUNNING ) ||
|
|
|
|
( dwCurrentState == SERVICE_STOPPED ) )
|
|
|
|
ssStatus.dwCheckPoint = 0;
|
|
|
|
else
|
|
|
|
ssStatus.dwCheckPoint = dwCheckPoint++;
|
|
|
|
|
|
|
|
|
|
|
|
// Report the status of the service to the service control manager.
|
|
|
|
//
|
|
|
|
if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus))) {
|
|
|
|
LogEventErrorMessage(TEXT("SetServiceStatus"));
|
|
|
|
}
|
|
|
|
return fResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// FUNCTION: LogEventErrorMessage(LPTSTR lpszMsg)
|
|
|
|
//
|
|
|
|
// PURPOSE: Allows any thread to log an error message
|
|
|
|
//
|
|
|
|
// PARAMETERS:
|
|
|
|
// lpszMsg - text for message
|
|
|
|
//
|
|
|
|
// RETURN VALUE:
|
|
|
|
// none
|
|
|
|
//
|
|
|
|
// COMMENTS:
|
|
|
|
//
|
|
|
|
VOID LogEventErrorMessage(LPTSTR lpszMsg)
|
|
|
|
{
|
|
|
|
TCHAR szMsg[1024];
|
|
|
|
HANDLE hEventSource;
|
|
|
|
LPTSTR lpszStrings[2];
|
|
|
|
|
|
|
|
dwErr = GetLastError();
|
|
|
|
|
|
|
|
// Use event logging to log the error.
|
|
|
|
//
|
|
|
|
hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
|
|
|
|
|
|
|
|
_stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), dwErr);
|
|
|
|
lpszStrings[0] = szMsg;
|
|
|
|
lpszStrings[1] = lpszMsg;
|
|
|
|
|
|
|
|
if (hEventSource != NULL) {
|
|
|
|
ReportEvent(hEventSource, // handle of event source
|
|
|
|
EVENTLOG_ERROR_TYPE, // event type
|
|
|
|
0, // event category
|
2004-04-29 00:57:26 +00:00
|
|
|
1, // event ID
|
2004-01-19 20:53:40 +00:00
|
|
|
NULL, // current user's SID
|
|
|
|
2, // strings in lpszStrings
|
|
|
|
0, // no bytes of raw data
|
|
|
|
(LPCSTR*)lpszStrings, // array of error strings
|
|
|
|
NULL); // no raw data
|
|
|
|
|
|
|
|
(VOID) DeregisterEventSource(hEventSource);
|
|
|
|
}
|
2004-04-29 00:57:26 +00:00
|
|
|
}
|
2004-01-19 20:53:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// FUNCTION: LogEventWarningMessage(LPTSTR lpszMsg)
|
|
|
|
//
|
|
|
|
// PURPOSE: Allows any thread to log an warning message
|
|
|
|
//
|
|
|
|
// PARAMETERS:
|
|
|
|
// lpszMsg - text for message
|
|
|
|
//
|
|
|
|
// RETURN VALUE:
|
|
|
|
// none
|
|
|
|
//
|
|
|
|
// COMMENTS:
|
|
|
|
//
|
|
|
|
VOID LogEventWarningMessage(LPTSTR lpszMsg)
|
|
|
|
{
|
|
|
|
HANDLE hEventSource;
|
|
|
|
LPTSTR lpszStrings[2];
|
|
|
|
|
|
|
|
// Use event logging to log the error.
|
|
|
|
//
|
|
|
|
hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
|
|
|
|
|
2004-05-05 20:23:52 +00:00
|
|
|
lpszStrings[0] = lpszMsg;
|
|
|
|
lpszStrings[1] = '\0';
|
2004-01-19 20:53:40 +00:00
|
|
|
|
|
|
|
if (hEventSource != NULL) {
|
|
|
|
ReportEvent(hEventSource, // handle of event source
|
|
|
|
EVENTLOG_WARNING_TYPE,// event type
|
|
|
|
0, // event category
|
2004-04-29 00:57:26 +00:00
|
|
|
1, // event ID
|
2004-01-19 20:53:40 +00:00
|
|
|
NULL, // current user's SID
|
|
|
|
2, // strings in lpszStrings
|
|
|
|
0, // no bytes of raw data
|
|
|
|
(LPCSTR*)lpszStrings, // array of error strings
|
|
|
|
NULL); // no raw data
|
|
|
|
|
|
|
|
(VOID) DeregisterEventSource(hEventSource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// FUNCTION: LogEventInfoMessage(LPTSTR lpszMsg)
|
|
|
|
//
|
|
|
|
// PURPOSE: Allows any thread to log an info message
|
|
|
|
//
|
|
|
|
// PARAMETERS:
|
|
|
|
// lpszMsg - text for message
|
|
|
|
//
|
|
|
|
// RETURN VALUE:
|
|
|
|
// none
|
|
|
|
//
|
|
|
|
// COMMENTS:
|
|
|
|
//
|
|
|
|
VOID LogEventInfoMessage(LPTSTR lpszMsg)
|
|
|
|
{
|
|
|
|
HANDLE hEventSource;
|
|
|
|
LPTSTR lpszStrings[2];
|
|
|
|
|
|
|
|
// Use event logging to log the error.
|
|
|
|
//
|
|
|
|
hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
|
|
|
|
|
2004-05-05 20:23:52 +00:00
|
|
|
lpszStrings[0] = lpszMsg;
|
|
|
|
lpszStrings[1] = '\0';
|
2004-01-19 20:53:40 +00:00
|
|
|
|
|
|
|
if (hEventSource != NULL) {
|
|
|
|
ReportEvent(hEventSource, // handle of event source
|
|
|
|
EVENTLOG_INFORMATION_TYPE,// event type
|
|
|
|
0, // event category
|
2004-04-29 00:57:26 +00:00
|
|
|
1, // event ID
|
2004-01-19 20:53:40 +00:00
|
|
|
NULL, // current user's SID
|
|
|
|
2, // strings in lpszStrings
|
|
|
|
0, // no bytes of raw data
|
|
|
|
(LPCSTR*)lpszStrings, // array of error strings
|
|
|
|
NULL); // no raw data
|
|
|
|
|
|
|
|
(VOID) DeregisterEventSource(hEventSource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-04-29 00:57:26 +00:00
|
|
|
#endif
|
|
|
|
|