|
|
/******************************************************************************
* * Copyright (c) 2000 Microsoft Corporation * * Module Name: * NTService.cpp * * Abstract: * This file contains the implementation of CNTService class. * * Revision History: * Ashish Sikka ( ashishs ) 05/08/2000 * created *****************************************************************************/
#include "precomp.h"
#include "ntservmsg.h" // generated from the MC message compiler
#ifdef THIS_FILE
#undef THIS_FILE
#endif
static char __szTraceSourceFile[] = __FILE__; #define THIS_FILE __szTraceSourceFile
#define TRACEID 8970
CNTService * g_pSRService=NULL;
#define SERVICE_WAIT_HINT 30 // seconds
extern "C" void CALLBACK StopCallback( PVOID pv, BOOLEAN TimerOrWaitFired);
//
// static variables
//
CNTService::CNTService() { TraceFunctEnter("CNTService:CNTService"); m_hEventSource = NULL;
//
// Set up the initial service status
//
m_hServiceStatus = NULL; m_Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; m_Status.dwCurrentState = SERVICE_START_PENDING; m_Status.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN; m_Status.dwWin32ExitCode = 0; m_Status.dwServiceSpecificExitCode = 0; m_Status.dwCheckPoint = 0; m_Status.dwWaitHint = 0; TraceFunctLeave(); }
CNTService::~CNTService() { TENTER("CNTService::~CNTService");
if (m_hEventSource) { ::DeregisterEventSource(m_hEventSource); }
TLEAVE(); }
//
// Logging functions
//
void CNTService::LogEvent( WORD wType, DWORD dwID, void * pRawData, DWORD dwDataSize, const WCHAR* pszS1, const WCHAR* pszS2, const WCHAR* pszS3) { TraceFunctEnter("CNTService::LogEvent"); //
// Check the event source has been registered and if
// not then register it now
//
if (!m_hEventSource) { m_hEventSource = ::RegisterEventSource(NULL, s_cszServiceName); }
SRLogEvent (m_hEventSource, wType, dwID, pRawData, dwDataSize, pszS1, pszS2, pszS3);
TraceFunctLeave(); }
//
// ServiceMain
//
//This function immediately reports the service as having started.
//However, all the initialization is done after the service is
//started. We chose to do this becuase this service may have a long
//initialization time and it may be tricky to keep giving hints to the
//SCM during this time. Also, the service does all the work itself and
//does not service any clients. So it is OK to do initialization after
//the service is reported to be started.
void CNTService::ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv) { DWORD dwRc = ERROR_SUCCESS; HANDLE hSRStopWait = NULL; TENTER("CNTService::ServiceMain()");
// Register the control request handler
m_hServiceStatus = RegisterServiceCtrlHandler(s_cszServiceName, SRServiceHandler);
if (m_hServiceStatus != NULL) { HKEY hKey = NULL; DWORD dwBreak = 0;
/*
// tell the service manager that we are starting
// Also inform the Controls accepted
m_Status.dwCheckPoint = 0; m_Status.dwWaitHint = SERVICE_WAIT_HINT*1000; SetStatus(SERVICE_START_PENDING); */ //
// Tell the service manager we are running
//
m_Status.dwCheckPoint = 0; m_Status.dwWaitHint = 0; SetStatus(SERVICE_RUNNING);
// break into debugger if need to debug
// this is controlled by setting regkey SRService\DebugBreak to 1
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, s_cszServiceRegKey, 0, KEY_READ, &hKey)) { RegReadDWORD(hKey, s_cszDebugBreak, &dwBreak); ASSERT (dwBreak != 1); RegCloseKey(hKey); } //
// do boot time tasks - including firstrun if necessary
//
g_pEventHandler = new CEventHandler; if ( ! g_pEventHandler ) { dwRc = GetLastError(); TRACE(TRACEID, "! out of memory"); goto done; }
dwRc = g_pEventHandler->OnBoot( ); if ( ERROR_SUCCESS != dwRc ) { TRACE(TRACEID, "g_pEventHandler->OnBoot : error=%ld", dwRc); goto done; }
// bind the stop event to a callback
// so that this gets called on a thread pool thread
// when the stop event is signalled
if (FALSE == RegisterWaitForSingleObject(&hSRStopWait, g_pSRConfig->m_hSRStopEvent, StopCallback, NULL, INFINITE, WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE)) { dwRc = GetLastError(); trace(0, "! RegisterWaitForSingleObject : %ld", dwRc); goto done; } } else { // There is not much we can do here if we do not have the
// Service handle. So we will just log an error and exit.
dwRc = GetLastError(); DebugTrace(TRACEID, "RegisterServiceCtrlHandler failed %d", dwRc); LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_CTRLHANDLERNOTINSTALLED); }
done: if (dwRc != ERROR_SUCCESS) { if (g_pEventHandler) { g_pEventHandler->OnStop(); delete g_pEventHandler; g_pEventHandler = NULL; } m_Status.dwWin32ExitCode = (dwRc != ERROR_SERVICE_DISABLED) ? dwRc : ERROR_SUCCESS; SetStatus(SERVICE_STOPPED);
if (dwRc != ERROR_SERVICE_DISABLED) LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_FAILEDINI, &dwRc, sizeof(dwRc)); } TLEAVE(); }
//
// SetStatus:
//
void CNTService::SetStatus(DWORD dwState) { TENTER("CNTService::SetStatus"); TRACE(TRACEID, "SetStatus(%lu, %lu)", m_hServiceStatus, dwState);
m_Status.dwCurrentState = dwState;
::SetServiceStatus(m_hServiceStatus, &m_Status);
TLEAVE(); }
void CNTService::OnStop() { TENTER("CNTService::OnStop"); // BUGBUG what happens if the service has not started completely
// yet ? We need to make sure that OnStop can only be called after
// g_pEventHandler has been initialized.
if (NULL != g_pEventHandler) { // Tell SCM we are stopping
m_Status.dwWin32ExitCode = 0; m_Status.dwCheckPoint = 0; // we will stop in half the time we took to start or lesser
m_Status.dwWaitHint = (SERVICE_WAIT_HINT/2)*1000; SetStatus(SERVICE_STOP_PENDING);
// complete all tasks
g_pEventHandler->SignalStop(); }
TLEAVE(); }
// OnInterrogate is called by the SCM to get information about the
// current status of the service. Since this must report information
// about the service immediately to the SCM, we will run this in the
// same thread on which the handler function is called.
void CNTService::OnInterrogate() { TENTER("CNTService::OnInterrogate");
// report the status
::SetServiceStatus(m_hServiceStatus, &m_Status); TLEAVE(); }
//
// Handler : static member function (callback) to handle commands from the
// service control manager
//
void WINAPI SRServiceHandler(DWORD dwOpcode) { //
// Get a pointer to the object
//
TENTER("CNTService::Handler");
TRACE(TRACEID, "CNTService::Handler(%lu)", dwOpcode);
switch (dwOpcode) { case SERVICE_CONTROL_STOP: // 1
//
// if someone disables the service explicitly
// then disable all of SR
//
if (NULL != g_pSRService) { DWORD dwStart = 0; if (ERROR_SUCCESS == GetServiceStartup(s_cszServiceName, &dwStart)) { if (dwStart == SERVICE_DISABLED || dwStart == SERVICE_DEMAND_START) { if (g_pEventHandler) g_pEventHandler->DisableSRS(NULL); break; } } else { trace(TRACEID, "! GetServiceStartup"); } }
//
// else fallover
//
case SERVICE_CONTROL_SHUTDOWN: // 5
// BUGBUG - g_pSRService should be accessed in critical section
if (NULL != g_pSRService) { g_pSRService->OnStop(); }
break;
case SERVICE_CONTROL_PAUSE: // 2
case SERVICE_CONTROL_CONTINUE: // 3
// we do not do anything here
break; case SERVICE_CONTROL_INTERROGATE: // 4
// BUGBUG - g_pSRService should be accessed in critical section
if (NULL != g_pSRService) { g_pSRService->OnInterrogate(); } break; default: break; } TLEAVE(); }
/////////////////////////////////////////////////////////////////////////////
// Exported functions
/////////////////////////////////////////////////////////////////////////////
extern "C" { VOID WINAPI ServiceMain( DWORD dwArgc, LPWSTR *lpwzArgv ) { // Initialize tracing
InitAsyncTrace();
TraceFunctEnter("ServiceMain"); g_pSRService = new CNTService(); if (NULL == g_pSRService) { // in this case we will just exit. This is because we cannot
// report any status here.
// SCM will assume that the service has failed since it did
// not call RegisterServiceCtrlHandler().
goto cleanup; } g_pEventHandler = NULL; g_pSRService->ServiceMain( dwArgc, NULL );
cleanup: TraceFunctLeave(); }
BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReserved */ ) { if (dwReason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) { } return TRUE; }
// callback for service stop event
void CALLBACK StopCallback( PVOID pv, BOOLEAN TimerOrWaitFired) { if (g_pEventHandler) { g_pEventHandler->OnStop(); delete g_pEventHandler; g_pEventHandler = NULL; }
if (g_pSRService) { g_pSRService->SetStatus(SERVICE_STOPPED); delete g_pSRService; g_pSRService = NULL; }
TermAsyncTrace(); }
}
|