/** * 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); }