/**
* Windows Service Application f�r den Monitor, basierend auf
* http://weblogs.asp.net/kennykerr/archive/2004/05/18/134342.aspx
*/
#include <assert.h>
#include <iostream>
#include <stdlib.h>
#include "../convert.h"
#include "MonitorService.h"
#include "../MonitorLogging.h"
#ifdef WIN32
#define sleep Sleep
#endif
using namespace std ;
MonitorService* MonitorService::m_service = 0;
MonitorService::MonitorService(Monitor* monitor)
{
m_handle = 0;
m_monitor = monitor;
m_service = this;
m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_status.dwCurrentState = SERVICE_START_PENDING;
m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
m_installServiceName="monitord" ;
m_installServiceDisplayName="monitord" ;
}
MonitorService::~MonitorService()
{
}
void MonitorService::Stop()
{
m_service->UpdateState(SERVICE_STOP_PENDING);
m_monitor->m_bWantStop = true;
m_service->m_debugFile << "Warte auf beenden des monitord" << endl ;
m_monitor->m_SignalStopped->WaitForSignal() ;
Sleep(2000) ;
m_service->UpdateState(SERVICE_STOPPED);
m_service->m_debugFile << "monitord Signal empfangen" << endl ;
Sleep(1000) ;
}
/**
* Provides the main entry point for an executable that
* contains a single service. Loads the service into
* memory so it can be started. This method blocks until
* the service has stopped.
*/
void MonitorService::Run()
{
assert (0 != m_service);
SERVICE_TABLE_ENTRY serviceTable[] =
{
// Even though the service name is ignored for own process services,
// it must be a valid string and cannot be 0.
{ "", (LPSERVICE_MAIN_FUNCTION)ServiceMain },
// Designates the end of table.
{ 0, 0 }
};
if (!::StartServiceCtrlDispatcher(serviceTable))
{
char msg[1024];
snprintf (msg, 1024, "Fehler bei Dispatcher-Registrierung, siehe net helpmsg %ld", GetLastError());
ThrowMonitorServiceException(msg);
}
}
/**
* The starting point for the service.
*
* @param argc number of arguments in arguments
* @param argv array of string pointers containing the arguments
*/
void WINAPI MonitorService::ServiceMain(DWORD argc, PSTR* argv)
{
//
// Since there's no way to inform the SCM of failure before a successful
// call to RegisterServiceCtrlHandler, if an error occurs before we have
// a service status handle we don't catch any exceptions and let the
// process terminate. The SCM will diligently log this event.
//
FILE_LOG(logINFO) << "ServiceMain Startet" ;
assert (0 != m_service);
if (1 != argc || 0 == argv || 0 == argv[0])
{
// FIXME AtlThrow(E_INVALIDARG);
}
m_service->m_serviceName = argv[0];
m_service->m_handle = ::RegisterServiceCtrlHandler(m_service->m_serviceName.c_str(), Handler);
if (0 == m_service->m_handle)
{
// FIXME AtlThrowLastWin32();
//m_service->m_debugFile << "Handler registiert ?=N�" << endl ;
}
m_service->UpdateState(SERVICE_START_PENDING);
sleep(100) ;
m_service->UpdateState(SERVICE_RUNNING);
/**
* now we can call the m_monitor mainloop und wait until the SCM
* tells us to stop (via Handler)
*/
m_service->m_monitor->MainLoop();
m_service->Stop() ;
}
/**
* The handler function called by the control dispatcher when an event occurs.
*/
void WINAPI MonitorService::Handler(DWORD control)
{
#ifdef _DEBUG
FILE_LOG(logINFO) << "Handler: empfangen:" << control << ".." << m_service ;
#endif
//assert (0 == m_service);
switch (control)
{
case SERVICE_CONTROL_CONTINUE :
{
m_service->UpdateState(SERVICE_CONTINUE_PENDING);
//m_service->Start(control);
m_service->UpdateState(SERVICE_RUNNING);
break;
}
case SERVICE_CONTROL_PAUSE :
{
m_service->UpdateState(SERVICE_PAUSE_PENDING);
//m_service->Stop();
m_service->UpdateState(SERVICE_PAUSED);
break;
}
case SERVICE_CONTROL_SHUTDOWN :
case SERVICE_CONTROL_STOP :
{
FILE_LOG(logINFO) << "ServiceMain stopping ... " ;
m_service->Stop();
break;
}
}
}
/**
* Updates the current state and exit code of the service
* and notifies the service control manager of the change.
*/
void MonitorService::UpdateState(DWORD state, HRESULT errorCode)
{
#ifdef _DEBUG
FILE_LOG(logDEBUG) << "Updatestatus ..." ;
#endif
//assert (0 != m_service);
m_status.dwCurrentState = state;
if (FAILED(errorCode))
{
if (FACILITY_WIN32 == HRESULT_FACILITY(errorCode))
{
m_status.dwWin32ExitCode = errorCode & ~0x80070000;
}
else
{
m_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
m_status.dwServiceSpecificExitCode = errorCode;
}
}
if (!::SetServiceStatus(m_handle,
&m_status))
{
// FIXME AtlThrowLastWin32();
}
FILE_LOG(logDEBUG) << "Updatestatus ... done" ;
}
bool MonitorService::InstallService()
{
// Get this exes full pathname
TCHAR szAppPath[_MAX_PATH];
GetModuleFileName(NULL, szAppPath, _MAX_PATH);
std::string sServiceCommandline ;
sServiceCommandline=szAppPath ;
sServiceCommandline+=" --service" ;
// Versuche die aktuell genutzte Configdatei als Parameter zu hinterlegen
if (m_monitor->m_MonitorConfig.m_ConfigFile == "monitord.xml") {
// default
TCHAR szConfigPath[_MAX_PATH];
strncpy(szConfigPath,szAppPath,_MAX_PATH) ;
char* pos=strrchr(szConfigPath, '\\') ;
if (pos)
{
*pos='\0' ;
string configFile=std::string(" -c ") + szConfigPath+"\\monitord.xml" ;
// << "configFile:" << configFile << endl ;
sServiceCommandline+=configFile ;
}
} else {
sServiceCommandline += std::string(" -c ");
sServiceCommandline += m_monitor->m_MonitorConfig.m_ConfigFile;
}
//Open up the SCM requesting Creation rights
SC_HANDLE hSCM = ::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
SC_HANDLE hService ;
if (hSCM==NULL)
{
// FIXME: TRACE(_T("Failed in call to open SCM in Install, GetLastError:%d\n"), ::GetLastError());
return FALSE;
}
//Create the new service entry in the SCM database
hService = ::CreateService( hSCM,
m_installServiceName.c_str(),
m_installServiceDisplayName.c_str(),
0,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
sServiceCommandline.c_str(),
NULL,
NULL,
NULL,
NULL,
NULL);
if (hService == NULL)
{
//FIXME:
//TRACE(_T("Failed in call to CreateService in Create, GetLastError:%d\n"), ::GetLastError());
} else
{
::CloseServiceHandle(hService);
}
if (hSCM!=NULL)
{
::CloseServiceHandle(hSCM);
}
return (hService != NULL);
}
bool MonitorService::UnInstallService()
{
bool bSuccess=false ;
SC_HANDLE hSCM = ::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT);
if (hSCM==NULL)
{
// FIXME: TRACE(_T("Failed in call to open SCM in Install, GetLastError:%d\n"), ::GetLastError());
return FALSE;
}
SC_HANDLE hService = ::OpenService(hSCM, m_installServiceName.c_str(), DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
if (hService != NULL)
{
bSuccess = ::DeleteService(hService);
::CloseServiceHandle(hService);
}
if (hSCM!=NULL)
{
::CloseServiceHandle(hSCM);
}
return (bSuccess);
}