diff options
author | Matthew Newhook <matthew@zeroc.com> | 2007-02-28 09:49:22 +0000 |
---|---|---|
committer | Matthew Newhook <matthew@zeroc.com> | 2007-02-28 09:49:22 +0000 |
commit | 6b880991ccad39ab5189558c99016add754fea4a (patch) | |
tree | 2bb643f7dffef7dda5f1b92539330b61cecf459a /cpp/src/Ice/Service.cpp | |
parent | Fixed bug 1952 (diff) | |
download | ice-6b880991ccad39ab5189558c99016add754fea4a.tar.bz2 ice-6b880991ccad39ab5189558c99016add754fea4a.tar.xz ice-6b880991ccad39ab5189558c99016add754fea4a.zip |
http://bugzilla.zeroc.com/bugzilla/show_bug.cgi?id=1722,
http://bugzilla.zeroc.com/bugzilla/show_bug.cgi?id=1721,
http://bugzilla.zeroc.com/bugzilla/show_bug.cgi?id=1926
Diffstat (limited to 'cpp/src/Ice/Service.cpp')
-rwxr-xr-x | cpp/src/Ice/Service.cpp | 353 |
1 files changed, 272 insertions, 81 deletions
diff --git a/cpp/src/Ice/Service.cpp b/cpp/src/Ice/Service.cpp index a5690ba166c..75277c7cf62 100755 --- a/cpp/src/Ice/Service.cpp +++ b/cpp/src/Ice/Service.cpp @@ -21,7 +21,7 @@ #ifdef _WIN32 # include <winsock2.h> -# include <Ice/EventLoggerI.h> +# include <Ice/EventLoggerMsg.h> #else # include <Ice/Logger.h> # include <Ice/Network.h> @@ -32,6 +32,7 @@ #endif using namespace std; +using namespace Ice; Ice::Service* Ice::Service::_instance = 0; static IceUtil::CtrlCHandler* _ctrlCHandler = 0; @@ -71,7 +72,7 @@ Ice_Service_CtrlHandler(DWORD ctrl) service->control(ctrl); } -namespace Ice +namespace { class ServiceStatusManager : public IceUtil::Monitor<IceUtil::Mutex> @@ -130,9 +131,180 @@ private: bool _stopped; }; -} +static ServiceStatusManager* serviceStatusManager; + +static IceUtil::StaticMutex outputMutex = ICE_STATIC_MUTEX_INITIALIZER; + +class SMEventLoggerI : public Ice::Logger +{ + static string + mangleService(string name) + { + // + // The application name cannot contain backslashes. + // + string::size_type pos = 0; + while((pos = name.find('\\', pos)) != string::npos) + { + name[pos] = '/'; + } + return name; + } + + static string + createKey(string name) + { + // + // The registry key is: + // + // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application. + // + return "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\" + mangleService(name); + } + +public: + + SMEventLoggerI(const string& service) + { + _source = RegisterEventSource(0, mangleService(service).c_str()); + if(_source == 0) + { + SyscallException ex(__FILE__, __LINE__); + ex.error = GetLastError(); + throw ex; + } + } + + ~SMEventLoggerI() + { + assert(_source != 0); + DeregisterEventSource(_source); + } + + static void + addKeys(const string& service) + { + HKEY hKey; + DWORD d; + LONG err = RegCreateKeyEx(HKEY_LOCAL_MACHINE, createKey(service).c_str(), 0, "REG_SZ", + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, &d); + if(err != ERROR_SUCCESS) + { + SyscallException ex(__FILE__, __LINE__); + ex.error = err; + throw ex; + } -static Ice::ServiceStatusManager* serviceStatusManager; + // + // Get the filename of this DLL. + // + char path[_MAX_PATH]; + assert(_module != 0); + if(!GetModuleFileName(_module, path, _MAX_PATH)) + { + RegCloseKey(hKey); + SyscallException ex(__FILE__, __LINE__); + ex.error = GetLastError(); + throw ex; + } + + // + // The event resources are bundled into this DLL, therefore + // the "EventMessageFile" key should contain the path to this + // DLL. + // + err = RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ, + reinterpret_cast<unsigned char*>(path), static_cast<DWORD>(strlen(path) + 1)); + if(err == ERROR_SUCCESS) + { + // + // The "TypesSupported" key indicates the supported event + // types. + // + DWORD typesSupported = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; + err = RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD, + reinterpret_cast<unsigned char*>(&typesSupported), sizeof(typesSupported)); + } + if(err != ERROR_SUCCESS) + { + RegCloseKey(hKey); + SyscallException ex(__FILE__, __LINE__); + ex.error = err; + throw ex; + } + + RegCloseKey(hKey); + } + + static void + removeKeys(const string& theService) + { + LONG err = RegDeleteKey(HKEY_LOCAL_MACHINE, createKey(theService).c_str()); + if(err != ERROR_SUCCESS) + { + SyscallException ex(__FILE__, __LINE__); + ex.error = err; + throw ex; + } + } + + virtual void + print(const string& message) + { + const char* str[1]; + str[0] = message.c_str(); + // We ignore any failures from ReportEvent since there isn't + // anything we can do about it. + ReportEvent(_source, EVENTLOG_INFORMATION_TYPE, 0, EVENT_LOGGER_MSG, 0, 1, 0, str, 0); + } + + void + trace(const string& category, const string& message) + { + string s; + if(!category.empty()) + { + s = category; + s.append(": "); + } + s.append(message); + + const char* str[1]; + str[0] = s.c_str(); + ReportEvent(_source, EVENTLOG_INFORMATION_TYPE, 0, EVENT_LOGGER_MSG, 0, 1, 0, str, 0); + } + + virtual void + warning(const string& message) + { + const char* str[1]; + str[0] = message.c_str(); + ReportEvent(_source, EVENTLOG_WARNING_TYPE, 0, EVENT_LOGGER_MSG, 0, 1, 0, str, 0); + } + + virtual void + error(const string& message) + { + const char* str[1]; + str[0] = message.c_str(); + ReportEvent(_source, EVENTLOG_ERROR_TYPE, 0, EVENT_LOGGER_MSG, 0, 1, 0, str, 0); + } + + static void + setModuleHandle(HMODULE module) + { + _module = module; + } + +private: + + HANDLE _source; + static HMODULE _module; +}; + +HMODULE SMEventLoggerI::_module = 0; + +} #endif @@ -205,49 +377,6 @@ Ice::Service::main(int& argc, char* argv[], const InitializationData& initData) { if(strcmp(argv[idx], "--service") == 0) { - // - // When running as a service, we need a logger to use for reporting any - // failures that occur prior to initializing a communicator. After we have - // a communicator, we can use the configured logger instead. If a logger - // is defined in InitializationData, we'll use that. Otherwise, we create - // a temporary event logger. - // - // We postpone the initialization of the communicator until serviceMain so - // that we can incorporate the executable's arguments and the service's - // arguments into one vector. - // - _logger = initData.logger; - if(!_logger) - { - try - { - // - // Use the executable name as the source for the temporary logger. - // - string loggerName = _name; - transform(loggerName.begin(), loggerName.end(), loggerName.begin(), ::tolower); - string::size_type pos = loggerName.find_last_of("\\/"); - if(pos != string::npos) - { - loggerName.erase(0, pos + 1); // Remove leading path. - } - pos = loggerName.rfind(".exe"); - if(pos != string::npos) - { - loggerName.erase(pos, loggerName.size() - pos); // Remove .exe extension. - } - - _logger = new EventLoggerI(loggerName); - } - catch(const IceUtil::Exception& ex) - { - ostringstream ostr; - ostr << ex; - error("unable to create EventLogger:\n" + ostr.str()); - return EXIT_FAILURE; - } - } - if(idx + 1 >= argc) { error("service name argument expected for `" + string(argv[idx]) + "'"); @@ -256,6 +385,18 @@ Ice::Service::main(int& argc, char* argv[], const InitializationData& initData) name = argv[idx + 1]; + // + // The logger for the process is either the configured + // logger, or an event logger using the service name. + // + // We postpone the initialization of the communicator + // until serviceMain so that we can incorporate the + // executable's arguments and the service's arguments into + // one vector. + // + _logger = (initData.logger) ? initData.logger : new SMEventLoggerI(name); + setProcessLogger(_logger); + for(int i = idx; i + 2 < argc; ++i) { argv[i] = argv[i + 2]; @@ -373,11 +514,36 @@ Ice::Service::main(int& argc, char* argv[], const InitializationData& initData) { args.push_back(argv[idx]); } - return installService(name, display, executable, args); + try + { + // + // Add the registry keys for the event logger if + // initData.logger is empty (which is the case if the + // user wants to use the service default logger). + // + return installService(!initData.logger, name, display, executable, args); + } + catch(const Ice::Exception& ex) + { + ostringstream ostr; + ostr << ex; + error(ostr.str()); + return EXIT_FAILURE; + } } else if(op == "--uninstall") { - return uninstallService(name); + try + { + return uninstallService(!initData.logger, name); + } + catch(const Ice::Exception& ex) + { + ostringstream ostr; + ostr << ex; + error(ostr.str()); + return EXIT_FAILURE; + } } else if(op == "--start") { @@ -644,7 +810,7 @@ Ice::Service::configureService(const string& name) } int -Ice::Service::installService(const string& name, const string& display, const string& executable, +Ice::Service::installService(bool useEventLogger, const string& name, const string& display, const string& executable, const vector<string>& args) { string disp, exec; @@ -662,7 +828,7 @@ Ice::Service::installService(const string& name, const string& display, const st // Use this executable if none is specified. // char buf[_MAX_PATH]; - if(GetModuleFileName(NULL, buf, _MAX_PATH) == 0) + if(GetModuleFileName(0, buf, _MAX_PATH) == 0) { error("unable to obtain file name of executable"); return EXIT_FAILURE; @@ -701,8 +867,8 @@ Ice::Service::installService(const string& name, const string& display, const st } } - SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if(hSCM == NULL) + SC_HANDLE hSCM = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); + if(hSCM == 0) { syserror("failure in OpenSCManager"); return EXIT_FAILURE; @@ -716,13 +882,13 @@ Ice::Service::installService(const string& name, const string& display, const st SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, command.c_str(), - NULL, - NULL, - NULL, - NULL, - NULL); + 0, + 0, + 0, + 0, + 0); - if(hService == NULL) + if(hService == 0) { syserror("unable to install service `" + name + "'"); CloseServiceHandle(hSCM); @@ -732,21 +898,31 @@ Ice::Service::installService(const string& name, const string& display, const st CloseServiceHandle(hSCM); CloseServiceHandle(hService); + // + // Add the registry keys for the event logger if _logger is + // empty (which is the case if the user wants to use + // the service default logger). + // + if(useEventLogger) + { + SMEventLoggerI::addKeys(name); + } + return EXIT_SUCCESS; } int -Ice::Service::uninstallService(const string& name) +Ice::Service::uninstallService(bool useEventLogger, const string& name) { - SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if(hSCM == NULL) + SC_HANDLE hSCM = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); + if(hSCM == 0) { syserror("failure in OpenSCManager"); return EXIT_FAILURE; } SC_HANDLE hService = OpenService(hSCM, name.c_str(), SERVICE_ALL_ACCESS); - if(hService == NULL) + if(hService == 0) { syserror("unable to open service `" + name + "'"); CloseServiceHandle(hSCM); @@ -766,21 +942,29 @@ Ice::Service::uninstallService(const string& name) CloseServiceHandle(hSCM); CloseServiceHandle(hService); + // + // Rrmove the registry keys for the event logger if necessary. + // + if(useEventLogger) + { + SMEventLoggerI::removeKeys(name); + } + return EXIT_SUCCESS; } int Ice::Service::startService(const string& name, const vector<string>& args) { - SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if(hSCM == NULL) + SC_HANDLE hSCM = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); + if(hSCM == 0) { syserror("failure in OpenSCManager"); return EXIT_FAILURE; } SC_HANDLE hService = OpenService(hSCM, name.c_str(), SERVICE_ALL_ACCESS); - if(hService == NULL) + if(hService == 0) { syserror("unable to open service `" + name + "'"); CloseServiceHandle(hSCM); @@ -788,9 +972,10 @@ Ice::Service::startService(const string& name, const vector<string>& args) } // - // Create argument vector. Note that StartService() automatically adds the service name - // in argv[0], so the argv that is passed to StartService() must *not* include the - // the service name in argv[0]. + // Create argument vector. Note that StartService() automatically + // adds the service name in argv[0], so the argv that is passed to + // StartService() must *not* include the the service name in + // argv[0]. // const int argc = static_cast<int>(args.size()); LPCSTR* argv = new LPCSTR[argc]; @@ -855,15 +1040,15 @@ Ice::Service::startService(const string& name, const vector<string>& args) int Ice::Service::stopService(const string& name) { - SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if(hSCM == NULL) + SC_HANDLE hSCM = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); + if(hSCM == 0) { syserror("failure in OpenSCManager"); return EXIT_FAILURE; } SC_HANDLE hService = OpenService(hSCM, name.c_str(), SERVICE_ALL_ACCESS); - if(hService == NULL) + if(hService == 0) { syserror("unable to open service `" + name + "'"); CloseServiceHandle(hSCM); @@ -910,6 +1095,12 @@ Ice::Service::stopService(const string& name) return EXIT_SUCCESS; } +void +Ice::Service::setModuleHandle(HMODULE module) +{ + SMEventLoggerI::setModuleHandle(module); +} + #else void @@ -976,12 +1167,12 @@ Ice::Service::syserror(const string& msg) DWORD ok = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, + 0, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR)&lpMsgBuf, 0, - NULL); + 0); if(ok) { LPCTSTR str = (LPCTSTR)lpMsgBuf; @@ -1118,7 +1309,7 @@ Ice::Service::runService(int argc, char* argv[], const InitializationData& initD SERVICE_TABLE_ENTRY ste[] = { { const_cast<char*>(_name.c_str()), Ice_Service_ServiceMain }, - { NULL, NULL }, + { 0, 0 }, }; // @@ -1425,7 +1616,7 @@ Ice::Service::control(int ctrl) } } -Ice::ServiceStatusManager::ServiceStatusManager(SERVICE_STATUS_HANDLE handle) : +ServiceStatusManager::ServiceStatusManager(SERVICE_STATUS_HANDLE handle) : _handle(handle), _stopped(false) { _status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; @@ -1437,7 +1628,7 @@ Ice::ServiceStatusManager::ServiceStatusManager(SERVICE_STATUS_HANDLE handle) : } void -Ice::ServiceStatusManager::startUpdate(DWORD state) +ServiceStatusManager::startUpdate(DWORD state) { Lock sync(*this); @@ -1454,7 +1645,7 @@ Ice::ServiceStatusManager::startUpdate(DWORD state) } void -Ice::ServiceStatusManager::stopUpdate() +ServiceStatusManager::stopUpdate() { IceUtil::ThreadPtr thread; @@ -1477,7 +1668,7 @@ Ice::ServiceStatusManager::stopUpdate() } void -Ice::ServiceStatusManager::changeStatus(DWORD state, DWORD controlsAccepted) +ServiceStatusManager::changeStatus(DWORD state, DWORD controlsAccepted) { Lock sync(*this); @@ -1488,7 +1679,7 @@ Ice::ServiceStatusManager::changeStatus(DWORD state, DWORD controlsAccepted) } void -Ice::ServiceStatusManager::reportStatus() +ServiceStatusManager::reportStatus() { Lock sync(*this); @@ -1496,7 +1687,7 @@ Ice::ServiceStatusManager::reportStatus() } void -Ice::ServiceStatusManager::run() +ServiceStatusManager::run() { Lock sync(*this); |