|
|
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996-1998
//
// File: service.c
//
// Contents: Hydra License Server Service Control Manager Interface
//
// History: 12-09-97 HueiWang Modified from MSDN RPC Service Sample
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#include <winsock2.h>
#include <ws2tcpip.h>
#include "server.h"
#include "globals.h"
#include "init.h"
#include "postsrv.h"
#include "tlsbkup.h"
#define SERVICE_WAITHINT 60*1000 // WaitHint 1 mins.
#define SERVICE_SHUTDOWN_WAITTIME 15*60*1000 // must have shutdown already.
//---------------------------------------------------------------------------
//
// internal function prototypes
//
BOOL ReportStatusToSCMgr( DWORD, DWORD, DWORD );
DWORD ServiceStart( DWORD, LPTSTR *, BOOL bDebug=FALSE );
VOID WINAPI ServiceCtrl( DWORD );
VOID WINAPI ServiceMain( DWORD, LPTSTR * );
VOID CmdDebugService( int, char **, BOOL );
BOOL WINAPI ControlHandler( DWORD );
extern "C" VOID ServiceStop();
VOID ServicePause();
VOID ServiceContinue();
HANDLE hRpcPause=NULL;
///////////////////////////////////////////////////////////
//
// internal variables
//
SERVICE_STATUS_HANDLE sshStatusHandle; DWORD ssCurrentStatus; // current status of the service
BOOL g_bReportToSCM = TRUE;
HANDLE gSafeToTerminate=NULL;
HRESULT hrStatus = NULL;
DEFINE_GUID(TLS_WRITER_GUID, 0x5382579c, 0x98df, 0x47a7, 0xac, 0x6c, 0x98, 0xa6, 0xd7, 0x10, 0x6e, 0x9); GUID idWriter = TLS_WRITER_GUID;
CVssJetWriter *g_pWriter = NULL;
SERVICE_TABLE_ENTRY dispatchTable[] = { { _TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)ServiceMain }, { NULL, NULL } };
//-----------------------------------------------------------------
// Internal routine
//-----------------------------------------------------------------
void print_usage() { _ftprintf( stdout, _TEXT("Usage : %s can't be run as a console app\n"), _TEXT(SZAPPNAME) ); return; }
//-----------------------------------------------------------------
DWORD AddNullSessionPipe( IN LPTSTR szPipeName ) /*++
Abstract:
Add our RPC namedpipe into registry to allow unrestricted access.
Parameter:
szPipeName : name of the pipe to append.
Returns:
ERROR_SUCCESS or error code
--*/ { LPTSTR lpszKey=L"SYSTEM\\CurrentControlSet\\Services\\LanmanServer\\Parameters"; LPTSTR lpszValue=L"NullSessionPipes";
HKEY hKey; DWORD dwStatus; LPTSTR pbData=NULL, pbOrg=NULL; DWORD cbData = 0;
dwStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, lpszKey, 0, KEY_ALL_ACCESS, &hKey ); if(dwStatus != ERROR_SUCCESS) return dwStatus;
dwStatus = RegQueryValueEx( hKey, lpszValue, NULL, NULL, NULL, &cbData );
if(dwStatus != ERROR_MORE_DATA && dwStatus != ERROR_SUCCESS) return dwStatus;
// pre-allocate our pipe name
if(!(pbData = (LPTSTR)AllocateMemory(cbData + (_tcslen(szPipeName) + 1) * sizeof(TCHAR)))) return GetLastError();
dwStatus = RegQueryValueEx( hKey, lpszValue, NULL, NULL, (LPBYTE)pbData, &cbData ); BOOL bAddPipe=TRUE; pbOrg = pbData;
// check pipe name
while(*pbData) { if(!_tcsicmp(pbData, szPipeName)) { bAddPipe=FALSE; break; }
pbData += _tcslen(pbData) + 1; }
if(bAddPipe) { _tcscat(pbData, szPipeName); cbData += (_tcslen(szPipeName) + 1) * sizeof(TCHAR); dwStatus = RegSetValueEx( hKey, lpszValue, 0, REG_MULTI_SZ, (PBYTE)pbOrg, cbData ); }
FreeMemory(pbOrg); RegCloseKey(hKey);
return dwStatus; } //-----------------------------------------------------------------
void __cdecl trans_se_func( unsigned int u, _EXCEPTION_POINTERS* pExp ) /*++
--*/ { #if DBG
OutputDebugString(_TEXT("Translating SE exception...\n")); #endif
throw SE_Exception( u ); }
//-----------------------------------------------------------------
int __cdecl handle_new_failed( size_t size ) /*++
--*/ { #if DBG
OutputDebugString(_TEXT("handle_new_failed() invoked...\n")); #endif
//
// Raise exception here, STL does not check return pointer
//
RaiseException( ERROR_OUTOFMEMORY, 0, 0, NULL );
//
// stop memory allocation attemp.
//
return 0; }
//-----------------------------------------------------------------
void _cdecl main( int argc, char **argv ) /*++
Abstract
Entry point.
++*/ { // LARGE_INTEGER Time = USER_SHARED_DATA->SystemExpirationDate;
_set_new_handler(handle_new_failed); _set_new_mode(1);
gSafeToTerminate = CreateEvent( NULL, TRUE, FALSE, NULL ); if(gSafeToTerminate == NULL) { TLSLogErrorEvent(TLS_E_ALLOCATE_RESOURCE); // out of resource.
return; }
for(int i=1; i < argc; i++) { if(*argv[i] == '-' || *argv[i] == '/') { if(!_stricmp("noservice", argv[i]+1)) { g_bReportToSCM = FALSE; } else if(!_stricmp("cleanup", argv[i]+1)) { CleanSetupLicenseServer(); exit(0); } else { print_usage(); exit(0); } } }
if(g_bReportToSCM == FALSE) { CmdDebugService( argc, argv, !g_bReportToSCM ); } else if(!StartServiceCtrlDispatcher(dispatchTable)) { TLSLogErrorEvent(TLS_E_SC_CONNECT); }
WaitForSingleObject(gSafeToTerminate, INFINITE); CloseHandle(gSafeToTerminate); }
//-----------------------------------------------------------------
void WINAPI ServiceMain( IN DWORD dwArgc, IN LPTSTR *lpszArgv ) /*++
Abstract:
To perform actual initialization of the service
Parameter:
dwArgc - number of command line arguments lpszArgv - array of command line arguments
Returns:
none
++*/ { DWORD dwStatus;
// register our service control handler:
sshStatusHandle = RegisterServiceCtrlHandler( _TEXT(SZSERVICENAME), ServiceCtrl );
if (sshStatusHandle) { ssCurrentStatus=SERVICE_START_PENDING;
// report the status to the service control manager.
//
if(ReportStatusToSCMgr( SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
SERVICE_WAITHINT)) // wait hint
{ dwStatus = ServiceStart( dwArgc, lpszArgv );
if(dwStatus != ERROR_SUCCESS) { ReportStatusToSCMgr( SERVICE_STOPPED, dwStatus, 0 ); } else { ReportStatusToSCMgr( SERVICE_STOPPED, NO_ERROR, 0 ); } } } else { dwStatus = GetLastError(); TLSLogErrorEvent(TLS_E_SC_CONNECT); }
DBGPrintf( DBG_INFORMATION, DBG_FACILITY_INIT, DBGLEVEL_FUNCTION_TRACE, _TEXT("Service terminated...\n") );
return; }
//-------------------------------------------------------------
VOID WINAPI ServiceCtrl( IN DWORD dwCtrlCode ) /*+++
Abstract:
This function is called by the SCM whenever ControlService() is called on this service.
Parameter:
dwCtrlCode - type of control requested from SCM.
+++*/ { // Handle the requested control code.
//
switch(dwCtrlCode) { // Stop the service.
//
case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_STOP:
ReportStatusToSCMgr( SERVICE_STOP_PENDING, NO_ERROR, 0 ); ServiceStop(); break;
// We don't really accept pause and continue
case SERVICE_CONTROL_PAUSE: ReportStatusToSCMgr( SERVICE_PAUSED, NO_ERROR, 0 );
ServicePause(); break;
case SERVICE_CONTROL_CONTINUE: ReportStatusToSCMgr( SERVICE_RUNNING, NO_ERROR, 0 ); ServiceContinue(); break;
// Update the service status.
case SERVICE_CONTROL_INTERROGATE: ReportStatusToSCMgr( ssCurrentStatus, NO_ERROR, 0 ); break;
// invalid control code
default: break;
} }
//------------------------------------------------------------------
DWORD ServiceShutdownThread( void *p ) /*++
Abstract:
Entry point into thread that shutdown server (mainly database).
Parameter:
Ignore
++*/ { ServerShutdown();
ExitThread(ERROR_SUCCESS); return ERROR_SUCCESS; }
//------------------------------------------------------------------
DWORD RPCServiceStartThread( void *p ) /*++
Abstract:
Entry point to thread that startup RPC.
Parameter:
None.
Return:
Thread exit code.
++*/ { RPC_BINDING_VECTOR *pbindingVector = NULL; RPC_STATUS status = RPC_S_OK; WCHAR *pszEntryName = _TEXT(RPC_ENTRYNAME); DWORD dwNumSuccessRpcPro=0; do { //
// local procedure call
//
status = RpcServerUseProtseq( _TEXT(RPC_PROTOSEQLPC), RPC_C_PROTSEQ_MAX_REQS_DEFAULT, NULL // &SecurityDescriptor
); if(status == RPC_S_OK) { dwNumSuccessRpcPro++; }
//
// NT4 backward compatible issue, let NT4 termsrv serivce
// client connect so still set security descriptor
//
// 11/10/98 Tested on NT4 and NT5
//
//
// Namedpipe
//
status = RpcServerUseProtseqEp( _TEXT(RPC_PROTOSEQNP), RPC_C_PROTSEQ_MAX_REQS_DEFAULT, _TEXT(LSNAMEPIPE), NULL //&SecurityDescriptor
); if(status == RPC_S_OK) { dwNumSuccessRpcPro++; }
//
// TCP/IP
//
status = RpcServerUseProtseq( _TEXT(RPC_PROTOSEQTCP), RPC_C_PROTSEQ_MAX_REQS_DEFAULT, NULL //&SecurityDescriptor
); if(status == RPC_S_OK) { dwNumSuccessRpcPro++; }
// Must have at least one protocol.
if(dwNumSuccessRpcPro == 0) { status = TLS_E_RPC_PROTOCOL; break; }
// Get server binding handles
status = RpcServerInqBindings(&pbindingVector); if (status != RPC_S_OK) { status = TLS_E_RPC_INQ_BINDING; break; }
// Register interface(s) and binding(s) (endpoints) with
// the endpoint mapper.
status = RpcEpRegister( TermServLicensing_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector, NULL, // &export_uuid,
L"" );
if (status != RPC_S_OK) { status = TLS_E_RPC_EP_REGISTER; break; }
status = RpcServerRegisterIf( TermServLicensing_v1_0_s_ifspec, NULL, NULL); if(status != RPC_S_OK) { status = TLS_E_RPC_REG_INTERFACE; break; }
// Register interface(s) and binding(s) (endpoints) with
// the endpoint mapper.
status = RpcEpRegister( HydraLicenseService_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector, NULL, // &export_uuid,
L"");
if (status != RPC_S_OK) { status = TLS_E_RPC_EP_REGISTER; break; }
status = RpcServerRegisterIf( HydraLicenseService_v1_0_s_ifspec, NULL, NULL); if(status != RPC_S_OK) { status = TLS_E_RPC_REG_INTERFACE; break; }
// Register interface(s) and binding(s) (endpoints) with
// the endpoint mapper.
status = RpcEpRegister( TermServLicensingBackup_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector, NULL, // &export_uuid,
L"");
if (status != RPC_S_OK) { status = TLS_E_RPC_EP_REGISTER; break; }
status = RpcServerRegisterIf( TermServLicensingBackup_v1_0_s_ifspec, NULL, NULL); if(status != RPC_S_OK) { status = TLS_E_RPC_REG_INTERFACE; break; }
// Enable NT LM Security Support Provider (NtLmSsp service)
status = RpcServerRegisterAuthInfo(0, RPC_C_AUTHN_WINNT, 0, 0);
if (status != RPC_S_OK) { status = TLS_E_RPC_SET_AUTHINFO; break; }
} while(FALSE);
if(status != RPC_S_OK) { TLSLogEvent( EVENTLOG_ERROR_TYPE, TLS_E_SERVICEINIT, TLS_E_INITRPC, status );
status = TLS_E_SERVICE_STARTUP; }
ExitThread(status); return status; }
//------------------------------------------------------------------------
unsigned int __stdcall GetLServerRoleInDomain( PVOID pData ) /*++
--*/ { SERVER_ROLE_IN_DOMAIN* srvRole = (SERVER_ROLE_IN_DOMAIN *)pData;
if(pData != NULL) { *srvRole = GetServerRoleInDomain(NULL); }
_endthreadex(0); return 0; }
//------------------------------------------------------------------------
DWORD ServiceStart( IN DWORD dwArgc, IN LPTSTR *lpszArgv, IN BOOL bDebug ) /*
*/ { RPC_BINDING_VECTOR *pbindingVector = NULL; WCHAR *pszEntryName = _TEXT(RPC_ENTRYNAME); HANDLE hInitThread=NULL; HANDLE hRpcThread=NULL; HANDLE hMailslotThread=NULL; HANDLE hShutdownThread=NULL;
DWORD dump; HANDLE hEvent=NULL; DWORD dwStatus=ERROR_SUCCESS; WORD wVersionRequested; WSADATA wsaData; int err;
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, SERVICE_WAITHINT)) { // resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS; goto cleanup; }
hrStatus = CoInitializeEx (NULL, COINIT_MULTITHREADED);
if (FAILED (hrStatus)) { DBGPrintf( DBG_INFORMATION, DBG_FACILITY_INIT, DBGLEVEL_FUNCTION_DETAILSIMPLE, _TEXT("CoInitializeEx failed with error code %08x...\n"), hrStatus ); }
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, SERVICE_WAITHINT)) { // resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS; goto cleanup; }
if (SUCCEEDED (hrStatus)) { hrStatus = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL ); }
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, SERVICE_WAITHINT)) { // resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS; goto cleanup; }
if (SUCCEEDED (hrStatus)) {
g_pWriter = new CVssJetWriter;
if (NULL == g_pWriter) { DBGPrintf( DBG_INFORMATION, DBG_FACILITY_INIT, DBGLEVEL_FUNCTION_DETAILSIMPLE, _TEXT("new CVssJetWriter failed...\n") );
hrStatus = HRESULT_FROM_WIN32 (ERROR_NOT_ENOUGH_MEMORY); } }
// Report the status to the service control manager.
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, SERVICE_WAITHINT)) { // resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS; goto cleanup; }
{ DWORD dwConsole; DWORD dwDbLevel; DWORD dwType; DWORD dwSize = sizeof(dwConsole); DWORD status;
HKEY hKey=NULL;
status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, LSERVER_PARAMETERS_KEY, 0, KEY_ALL_ACCESS, &hKey);
if(status == ERROR_SUCCESS) {
if(RegQueryValueEx( hKey, LSERVER_PARAMETERS_CONSOLE, NULL, &dwType, (LPBYTE)&dwConsole, &dwSize ) != ERROR_SUCCESS) { dwConsole = 0; }
dwSize = sizeof(dwDbLevel);
if(RegQueryValueEx( hKey, LSERVER_PARAMETERS_LOGLEVEL, NULL, &dwType, (LPBYTE)&dwDbLevel, &dwSize ) == ERROR_SUCCESS) { InitDBGPrintf( dwConsole != 0, _TEXT(SZSERVICENAME), dwDbLevel ); }
RegCloseKey(hKey); } }
// Report the status to the service control manager.
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, SERVICE_WAITHINT)) { // resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS; goto cleanup; }
do {
// setup should have done this but just to make sure we have our
// pipe in NullSessionPipe to allow service to connect
AddNullSessionPipe(_TEXT(HLSPIPENAME)); AddNullSessionPipe(_TEXT(SZSERVICENAME));
wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData ); if(err != 0) { // None critical error
TLSLogWarningEvent( TLS_E_SERVICE_WSASTARTUP ); } else { char hostname[(MAXTCPNAME+1)*sizeof(TCHAR)]; err=gethostname(hostname, MAXTCPNAME*sizeof(TCHAR)); if(err == 0) { struct addrinfo *paddrinfo; struct addrinfo hints;
memset(&hints,0,sizeof(hints));
hints.ai_flags = AI_CANONNAME; hints.ai_family = PF_UNSPEC;
if (0 == getaddrinfo(hostname,NULL,&hints,&paddrinfo)) { err = (MultiByteToWideChar( GetACP(), MB_ERR_INVALID_CHARS, paddrinfo->ai_canonname, -1, g_szHostName, g_cbHostName) == 0) ? -1 : 0; } else { err = -1; }
freeaddrinfo(paddrinfo); } }
if(err != 0) { if(GetComputerName(g_szHostName, &g_cbHostName) == FALSE) { dwStatus = GetLastError();
DBGPrintf( DBG_INFORMATION, DBG_FACILITY_INIT, DBGLEVEL_FUNCTION_DETAILSIMPLE, _TEXT("GetComputerName() failed with %d...\n"), dwStatus );
// this shoule not happen...
TLSLogErrorEvent(TLS_E_INIT_GENERAL); break; } }
if(GetComputerName(g_szComputerName, &g_cbComputerName) == FALSE) { dwStatus = GetLastError();
DBGPrintf( DBG_INFORMATION, DBG_FACILITY_INIT, DBGLEVEL_FUNCTION_DETAILSIMPLE, _TEXT("GetComputerName() failed with %d...\n"), dwStatus );
// this shoule not happen...
TLSLogErrorEvent(TLS_E_INIT_GENERAL); break; }
hRpcPause=CreateEvent(NULL, TRUE, TRUE, NULL); if(!hRpcPause) { TLSLogErrorEvent(TLS_E_ALLOCATE_RESOURCE); dwStatus = TLS_E_ALLOCATE_RESOURCE; break; }
//
// start up general server and RPC initialization thread
//
hInitThread=ServerInit(bDebug); if(hInitThread==NULL) { TLSLogErrorEvent(TLS_E_SERVICE_STARTUP_CREATE_THREAD); dwStatus = TLS_E_SERVICE_STARTUP_CREATE_THREAD; break; }
dwStatus = ERROR_SUCCESS;
//
// Wait for general server init. thread to terminate
//
while(WaitForSingleObject( hInitThread, 100 ) == WAIT_TIMEOUT) { // Report the status to the service control manager.
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, SERVICE_WAITHINT)) { // resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS; break; } }
if(dwStatus != ERROR_SUCCESS) { break; }
// Check thread exit code.
GetExitCodeThread( hInitThread, &dwStatus ); if(dwStatus != ERROR_SUCCESS) { //
// Server init. thread logs its own error
//
dwStatus = TLS_E_SERVICE_STARTUP_INIT_THREAD_ERROR; break; }
CloseHandle(hInitThread); hInitThread=NULL;
// timing, if we startup RPC init thread but database init thread
// can't initialize, service will be in forever stop state.
hRpcThread=CreateThread( NULL, 0, RPCServiceStartThread, ULongToPtr(bDebug), 0, &dump ); if(hRpcThread == NULL) { TLSLogErrorEvent(TLS_E_SERVICE_STARTUP_CREATE_THREAD); dwStatus=TLS_E_SERVICE_STARTUP_CREATE_THREAD; break; }
dwStatus = ERROR_SUCCESS;
//
// Wait for RPC init. thread to terminate
//
while(WaitForSingleObject( hRpcThread, 100 ) == WAIT_TIMEOUT) { // Report the status to the service control manager.
if (!ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
SERVICE_WAITHINT)) // wait hint
{ dwStatus = TLS_E_SC_REPORT_STATUS; break; } }
if(dwStatus != ERROR_SUCCESS) { break; }
// Check thread exit code.
GetExitCodeThread(hRpcThread, &dwStatus); if(dwStatus != ERROR_SUCCESS) { dwStatus = TLS_E_SERVICE_STARTUP_RPC_THREAD_ERROR; break; }
CloseHandle(hRpcThread); hRpcThread=NULL;
//
// Tell server control manager that we are ready.
//
if (!ReportStatusToSCMgr( SERVICE_RUNNING, // service state
NO_ERROR, // exit code
SERVICE_WAITHINT // wait hint
)) { dwStatus = TLS_E_SC_REPORT_STATUS; break; }
//
// Post service init. load self-signed certificate and init. crypt.
// this is needed after reporting service running status back to
// service control manager because it may need to manually call
// StartService() to startup protected storage service.
//
if(InitCryptoAndCertificate() != ERROR_SUCCESS) { dwStatus = TLS_E_SERVICE_STARTUP_POST_INIT; break; }
TLSLogInfoEvent(TLS_I_SERVICE_START);
// RpcMgmtWaitServerListen() will block until the server has
// stopped listening. If this service had something better to
// do with this thread, it would delay this call until
// ServiceStop() had been called. (Set an event in ServiceStop()).
//
BOOL bOtherServiceStarted = FALSE;
do { WaitForSingleObject(hRpcPause, INFINITE); if(ssCurrentStatus == SERVICE_STOP_PENDING) { break; }
// Start accepting client calls.PostServiceInit
dwStatus = RpcServerListen( RPC_MINIMUMCALLTHREADS, RPC_MAXIMUMCALLTHREADS, TRUE );
if(dwStatus != RPC_S_OK) { TLSLogErrorEvent(TLS_E_RPC_LISTEN); dwStatus = TLS_E_SERVICE_RPC_LISTEN; break; }
//
// Initialize all policy module
//
if(bOtherServiceStarted == FALSE) { dwStatus = PostServiceInit(); if(dwStatus != ERROR_SUCCESS) { // faild to initialize.
break; }
//ServiceInitPolicyModule();
}
bOtherServiceStarted = TRUE;
DBGPrintf( DBG_INFORMATION, DBG_FACILITY_INIT, DBGLEVEL_FUNCTION_DETAILSIMPLE, _TEXT("Ready to accept request...\n") );
dwStatus = RpcMgmtWaitServerListen(); assert(dwStatus == RPC_S_OK); } while(TRUE);
// tell service control manager we are stopping
ReportStatusToSCMgr( SERVICE_STOP_PENDING, NO_ERROR, SERVICE_WAITHINT );
//
// Terminate - ignore all error here on
//
dwStatus = RpcServerUnregisterIf( TermServLicensingBackup_v1_0_s_ifspec, NULL, TRUE );
// tell service control manager we are stopping
ReportStatusToSCMgr( SERVICE_STOP_PENDING, NO_ERROR, SERVICE_WAITHINT );
dwStatus = RpcServerUnregisterIf( HydraLicenseService_v1_0_s_ifspec, NULL, TRUE );
// tell service control manager we are stopping
ReportStatusToSCMgr( SERVICE_STOP_PENDING, NO_ERROR, SERVICE_WAITHINT );
dwStatus = RpcServerUnregisterIf( TermServLicensing_v1_0_s_ifspec, // from rpcsvc.h
NULL, TRUE );
// tell service control manager we are stopping
ReportStatusToSCMgr( SERVICE_STOP_PENDING, NO_ERROR, SERVICE_WAITHINT );
// Remove entries from the endpoint mapper database.
dwStatus = RpcEpUnregister( HydraLicenseService_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector, NULL );
// tell service control manager we are stopping
ReportStatusToSCMgr( SERVICE_STOP_PENDING, NO_ERROR, SERVICE_WAITHINT );
// Remove entries from the endpoint mapper database.
dwStatus = RpcEpUnregister( TermServLicensing_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector, NULL );
// tell service control manager we are stopping
ReportStatusToSCMgr( SERVICE_STOP_PENDING, NO_ERROR, SERVICE_WAITHINT );
// Remove entries from the endpoint mapper database.
dwStatus = RpcEpUnregister( TermServLicensingBackup_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector, NULL );
// Get server binding handles
dwStatus = RpcServerInqBindings( &pbindingVector );
if(dwStatus == ERROR_SUCCESS) { dwStatus = RpcBindingVectorFree( &pbindingVector ); }
// Create entry name in name database first
// Only work for NT 5.0
// status = RpcNsMgmtEntryDelete(RPC_C_NS_SYNTAX_DEFAULT, pszEntryName);
// try to report the stopped status to the service control manager.
//
// Initialize Crypto.
} while(FALSE);
if(hInitThread != NULL) { CloseHandle(hInitThread); }
if(hRpcThread != NULL) { CloseHandle(hRpcThread); }
if(hMailslotThread != NULL) { CloseHandle(hMailslotThread); }
if(hEvent != NULL) { CloseHandle(hEvent); }
if(hRpcPause != NULL) { CloseHandle(hRpcPause); }
if(err == 0) { WSACleanup(); }
ReportStatusToSCMgr( SERVICE_STOP_PENDING, dwStatus, //NO_ERROR,
SERVICE_WAITHINT );
//
// Create another thread to shutdown server.
//
hShutdownThread=CreateThread( NULL, 0, ServiceShutdownThread, (VOID *)NULL, 0, &dump ); if(hShutdownThread == NULL) { // Report the status to the service control manager with
// long wait hint time.
ReportStatusToSCMgr( SERVICE_STOP_PENDING, NO_ERROR, SERVICE_SHUTDOWN_WAITTIME );
//
// can't create thread, just call shutdown directory
//
ServerShutdown(); } else { //
// report in 5 second interval to SC.
//
DWORD dwMaxWaitTime = SERVICE_SHUTDOWN_WAITTIME / 5000; DWORD dwTimes=0;
//
// Wait for general server shutdown thread to terminate
// Gives max 1 mins to shutdown
//
while(WaitForSingleObject( hShutdownThread, SC_WAITHINT ) == WAIT_TIMEOUT && dwTimes++ < dwMaxWaitTime) { // Report the status to the service control manager.
ReportStatusToSCMgr( SERVICE_STOP_PENDING, NO_ERROR, SERVICE_WAITHINT ); }
CloseHandle(hShutdownThread); }
cleanup:
if (NULL != g_pWriter) { g_pWriter->Uninitialize(); delete g_pWriter; g_pWriter = NULL; }
CoUninitialize( );
// Signal we are safe to shutting down
SetEvent(gSafeToTerminate); return dwStatus; }
//-----------------------------------------------------------------
VOID ServiceStop() /*++
++*/ { ReportStatusToSCMgr( SERVICE_STOP_PENDING, NO_ERROR, 0 );
// Stop's the server, wakes the main thread.
SetEvent(hRpcPause);
//
// Signal currently waiting RPC call to terminate
//
ServiceSignalShutdown();
// this is the actual time we receive shutdown request.
SetServiceLastShutdownTime();
(VOID)RpcMgmtStopServerListening(NULL); TLSLogInfoEvent(TLS_I_SERVICE_STOP); }
//-----------------------------------------------------------------
VOID ServicePause() /*++
++*/ { ResetEvent(hRpcPause); (VOID)RpcMgmtStopServerListening(NULL); TLSLogInfoEvent(TLS_I_SERVICE_PAUSED); }
//-----------------------------------------------------------------
VOID ServiceContinue() /*++
++*/ { SetEvent(hRpcPause); TLSLogInfoEvent(TLS_I_SERVICE_CONTINUE); }
//-----------------------------------------------------------------
BOOL ReportStatusToSCMgr( IN DWORD dwCurrentState, IN DWORD dwExitCode, IN DWORD dwWaitHint ) /*++
Abstract:
Sets the current status of the service and reports it to the Service Control Manager
Parameter:
dwCurrentState - the state of the service dwWin32ExitCode - error code to report dwWaitHint - worst case estimate to next checkpoint
Returns:
TRUE if success, FALSE otherwise
*/ { BOOL fResult=TRUE;
if(g_bReportToSCM == TRUE) { SERVICE_STATUS ssStatus; static DWORD dwCheckPoint = 1;
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
//
// global - current status of process
//
ssCurrentStatus = dwCurrentState;
if (dwCurrentState == SERVICE_START_PENDING) { ssStatus.dwControlsAccepted = 0; } else { ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_CONTROL_SHUTDOWN; }
ssStatus.dwCurrentState = dwCurrentState; if(dwExitCode != NO_ERROR) { ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; ssStatus.dwServiceSpecificExitCode = dwExitCode; } else { ssStatus.dwWin32ExitCode = dwExitCode; }
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.
//
fResult = SetServiceStatus( sshStatusHandle, &ssStatus ); if(fResult == FALSE) { DBGPrintf( DBG_INFORMATION, DBG_FACILITY_INIT, DBGLEVEL_FUNCTION_TRACE, _TEXT("Failed to set service status %d...\n"), GetLastError() );
TLSLogErrorEvent(TLS_E_SC_REPORT_STATUS); } }
return fResult; }
///////////////////////////////////////////////////////////////////
//
// The following code is for running the service as a console app
//
void CmdDebugService( IN int argc, IN char ** argv, IN BOOL bDebug ) /*
*/ { int dwArgc; LPTSTR *lpszArgv;
#ifdef UNICODE
lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) ); #else
dwArgc = (DWORD) argc; lpszArgv = argv; #endif
_tprintf( _TEXT("Debugging %s.\n"), _TEXT(SZSERVICEDISPLAYNAME) );
SetConsoleCtrlHandler( ControlHandler, TRUE );
ServiceStart( dwArgc, lpszArgv, bDebug ); }
//------------------------------------------------------------------
BOOL WINAPI ControlHandler( IN DWORD dwCtrlType ) /*++
Abstract:
Parameter:
IN dwCtrlType : control type
Return:
++*/ { switch( dwCtrlType ) { case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
_tprintf( _TEXT("Stopping %s.\n"), _TEXT(SZSERVICEDISPLAYNAME) );
ssCurrentStatus = SERVICE_STOP_PENDING; ServiceStop(); return TRUE; break;
} return FALSE; }
|