diff --git a/spectrum/src/CMakeLists.txt b/spectrum/src/CMakeLists.txt index 2dd5b0da..fb38f5f0 100644 --- a/spectrum/src/CMakeLists.txt +++ b/spectrum/src/CMakeLists.txt @@ -1,13 +1,13 @@ cmake_minimum_required(VERSION 2.6) FILE(GLOB SRC *.cpp) -# if (WIN32) -# FILE(GLOB WIN_SRC win32/*.cpp) -# include_directories(win32) -# ADD_EXECUTABLE(spectrum2 ${SRC} ${WIN_SRC}) -# else() +if (WIN32) +FILE(GLOB WIN_SRC win32/*.cpp) +include_directories(win32) +ADD_EXECUTABLE(spectrum2 ${SRC} ${WIN_SRC}) +else() ADD_EXECUTABLE(spectrum2 ${SRC}) -# endif() +endif() diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 2ae15fdc..4fada002 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -33,7 +33,7 @@ #else #include #define getpid _getpid -// #include "win32/SpectrumService.h" +#include "win32/ServiceWrapper.h" #endif #include @@ -45,6 +45,13 @@ DEFINE_LOGGER(logger, "Spectrum"); Swift::SimpleEventLoop *eventLoop_ = NULL; Component *component_ = NULL; UserManager *userManager_ = NULL; +Config *config_ = NULL; + +void stop() { + userManager_->removeAllUsers(false); + component_->stop(); + eventLoop_->stop(); +} static void stop_spectrum() { userManager_->removeAllUsers(false); @@ -125,7 +132,7 @@ static void daemonize(const char *cwd, const char *lock_file) { int main(int argc, char **argv) { Config config(argc, argv); - + config_ = &config; boost::program_options::variables_map vm; bool no_daemon = false; std::string config_file; @@ -160,9 +167,9 @@ int main(int argc, char **argv) ("version,v", "Shows Spectrum version") ; #ifdef WIN32 -// desc.add_options() -// ("install-service,i", "Install spectrum as Windows service") -// ("uninstall-service,u", "Uninstall Windows service"); + desc.add_options() + ("install-service,i", "Install spectrum as Windows service") + ("uninstall-service,u", "Uninstall Windows service"); #endif try { @@ -192,18 +199,17 @@ int main(int argc, char **argv) no_daemon = true; } #ifdef WIN32 -#if 0 if (vm.count("install-service")) { - SpectrumService ntservice; + ServiceWrapper ntservice("Spectrum2"); if (!ntservice.IsInstalled()) { // determine the name of the currently executing file char szFilePath[MAX_PATH]; - GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); + GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath)); std::string exe_file(szFilePath); std::string config_file = exe_file.replace(exe_file.end() - 4, exe_file.end(), ".cfg"); std::string service_path = std::string(szFilePath) + std::string(" --config ") + config_file; - if (ntservice.Install(service_path.c_str())) { + if (ntservice.Install((char *)service_path.c_str())) { std::cout << "Successfully installed" << std::endl; return 0; } else { @@ -216,9 +222,9 @@ int main(int argc, char **argv) } } if (vm.count("uninstall-service")) { - SpectrumService ntservice; + ServiceWrapper ntservice("Spectrum2"); if (ntservice.IsInstalled()) { - if (ntservice.Remove()) { + if (ntservice.UnInstall()) { std::cout << "Successfully removed" << std::endl; return 0; } else { @@ -229,8 +235,7 @@ int main(int argc, char **argv) std::cout << "Service not installed" << std::endl; return 1; } - } -#endif + } #endif } catch (std::runtime_error& e) @@ -310,36 +315,49 @@ int main(int argc, char **argv) // removeOldIcons(CONFIG_STRING(&config, "service.working_dir") + "/icons"); } #endif +#ifdef WIN32 + ServiceWrapper ntservice("Spectrum2"); + if (ntservice.IsInstalled()) { + ntservice.RunService(); + } else { + mainloop(); + } +#else + mainloop(); +#endif +} - Logging::initMainLogging(&config); +int mainloop() { + + Logging::initMainLogging(config_); #ifndef WIN32 - if (!CONFIG_STRING(&config, "service.group").empty() ||!CONFIG_STRING(&config, "service.user").empty() ) { + if (!CONFIG_STRING(config_, "service.group").empty() ||!CONFIG_STRING(config_, "service.user").empty() ) { struct rlimit limit; getrlimit(RLIMIT_CORE, &limit); - if (!CONFIG_STRING(&config, "service.group").empty()) { + if (!CONFIG_STRING(config_, "service.group").empty()) { struct group *gr; - if ((gr = getgrnam(CONFIG_STRING(&config, "service.group").c_str())) == NULL) { - std::cerr << "Invalid service.group name " << CONFIG_STRING(&config, "service.group") << "\n"; + if ((gr = getgrnam(CONFIG_STRING(config_, "service.group").c_str())) == NULL) { + std::cerr << "Invalid service.group name " << CONFIG_STRING(config_, "service.group") << "\n"; return 1; } - if (((setgid(gr->gr_gid)) != 0) || (initgroups(CONFIG_STRING(&config, "service.user").c_str(), gr->gr_gid) != 0)) { - std::cerr << "Failed to set service.group name " << CONFIG_STRING(&config, "service.group") << " - " << gr->gr_gid << ":" << strerror(errno) << "\n"; + if (((setgid(gr->gr_gid)) != 0) || (initgroups(CONFIG_STRING(config_, "service.user").c_str(), gr->gr_gid) != 0)) { + std::cerr << "Failed to set service.group name " << CONFIG_STRING(config_, "service.group") << " - " << gr->gr_gid << ":" << strerror(errno) << "\n"; return 1; } } - if (!CONFIG_STRING(&config, "service.user").empty()) { + if (!CONFIG_STRING(config_, "service.user").empty()) { struct passwd *pw; - if ((pw = getpwnam(CONFIG_STRING(&config, "service.user").c_str())) == NULL) { - std::cerr << "Invalid service.user name " << CONFIG_STRING(&config, "service.user") << "\n"; + if ((pw = getpwnam(CONFIG_STRING(config_, "service.user").c_str())) == NULL) { + std::cerr << "Invalid service.user name " << CONFIG_STRING(config_, "service.user") << "\n"; return 1; } if ((setuid(pw->pw_uid)) != 0) { - std::cerr << "Failed to set service.user name " << CONFIG_STRING(&config, "service.user") << " - " << pw->pw_uid << ":" << strerror(errno) << "\n"; + std::cerr << "Failed to set service.user name " << CONFIG_STRING(config_, "service.user") << " - " << pw->pw_uid << ":" << strerror(errno) << "\n"; return 1; } } @@ -355,14 +373,14 @@ int main(int argc, char **argv) Swift::SimpleEventLoop eventLoop; Swift::BoostNetworkFactories *factories = new Swift::BoostNetworkFactories(&eventLoop); - UserRegistry userRegistry(&config, factories); + UserRegistry userRegistry(config_, factories); - Component transport(&eventLoop, factories, &config, NULL, &userRegistry); + Component transport(&eventLoop, factories, config_, NULL, &userRegistry); component_ = &transport; // Logger logger(&transport); std::string error; - StorageBackend *storageBackend = StorageBackend::createBackend(&config, error); + StorageBackend *storageBackend = StorageBackend::createBackend(config_, error); if (storageBackend == NULL) { if (!error.empty()) { std::cerr << error << "\n"; @@ -393,7 +411,7 @@ int main(int argc, char **argv) FileTransferManager ftManager(&transport, &userManager); - NetworkPluginServer plugin(&transport, &config, &userManager, &ftManager, &discoItemsResponder); + NetworkPluginServer plugin(&transport, config_, &userManager, &ftManager, &discoItemsResponder); plugin.start(); AdminInterface adminInterface(&transport, &userManager, &plugin, storageBackend, userRegistration); diff --git a/spectrum/src/win32/ServiceWrapper.cpp b/spectrum/src/win32/ServiceWrapper.cpp new file mode 100644 index 00000000..adb988d2 --- /dev/null +++ b/spectrum/src/win32/ServiceWrapper.cpp @@ -0,0 +1,120 @@ +#include "ServiceWrapper.h" + + +LPSTR ServiceName; +SERVICE_STATUS ServiceStatus; +SERVICE_STATUS_HANDLE ServiceStatusHandle; + +bool doAction (int action, int desiredAccess, LPSTR path = NULL); + +enum actions { + DO_INSTALL, DO_DELETE, DO_CHECK +}; + + +ServiceWrapper::ServiceWrapper(LPSTR serviceName) +{ + ServiceName = serviceName; + ServiceStatusHandle = 0; +} + +ServiceWrapper::~ServiceWrapper(void) +{ +} + +bool ServiceWrapper::Install(LPSTR commandLine) { + return doAction(DO_INSTALL, SC_MANAGER_ALL_ACCESS, commandLine); +} + +bool ServiceWrapper::UnInstall() { + return doAction(DO_DELETE, SC_MANAGER_ALL_ACCESS); +} + +bool ServiceWrapper::IsInstalled() { + return doAction(DO_CHECK, SC_MANAGER_CONNECT); +} + +bool doAction(int action, int desiredAccess, LPSTR path) { + SC_HANDLE scm = OpenSCManager(NULL, NULL, desiredAccess); + SC_HANDLE service = NULL; + if (!scm) return FALSE; + + switch(action) { + case DO_INSTALL: + service = CreateServiceA( + scm, + ServiceName, + ServiceName, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_DEMAND_START, + SERVICE_ERROR_NORMAL, + path, + NULL, + NULL, + NULL, + NULL, + NULL + ); + return (service != NULL); + break; + case DO_DELETE: + service = OpenServiceA(scm, ServiceName, DELETE); + if (service == NULL) + return FALSE; + if (DeleteService(service)) + return TRUE; + break; + case DO_CHECK: + service = OpenServiceA(scm, ServiceName, SERVICE_QUERY_STATUS); + return (service != NULL); + default: + return FALSE; + } + CloseServiceHandle(service); + CloseServiceHandle(scm); + return FALSE; +} + +void WINAPI ServiceControlHandler(DWORD controlCode) { + switch (controlCode) { + case SERVICE_CONTROL_INTERROGATE: + break; + case SERVICE_CONTROL_STOP: + ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + break; + default: + break; + } + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + stop(); +} + +void WINAPI ServiceMain(DWORD argc, LPSTR *argv) { + ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStatus.dwServiceSpecificExitCode = NO_ERROR; + + ServiceStatusHandle = RegisterServiceCtrlHandlerA(ServiceName, ServiceControlHandler); + if (ServiceStatusHandle) { + ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + ServiceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + ServiceStatus.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + mainloop(); + ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + ServiceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + } +} + +void ServiceWrapper::RunService() { + SERVICE_TABLE_ENTRYA serviceTable[] = { + { ServiceName, ServiceMain }, + { NULL, NULL} + }; + + StartServiceCtrlDispatcherA(serviceTable); +} \ No newline at end of file diff --git a/spectrum/src/win32/ServiceWrapper.h b/spectrum/src/win32/ServiceWrapper.h new file mode 100644 index 00000000..9ee2fb0d --- /dev/null +++ b/spectrum/src/win32/ServiceWrapper.h @@ -0,0 +1,19 @@ +#pragma once +#include "transport/config.h" +#include +#include + +class ServiceWrapper +{ +public: + ServiceWrapper(LPSTR serviceName); + ~ServiceWrapper(void); + bool Install(LPSTR commandLine); + bool UnInstall(); + bool IsInstalled(); + void RunService(); +}; + +int mainloop(); +void stop(); + diff --git a/spectrum/src/win32/SpectrumService.cpp b/spectrum/src/win32/SpectrumService.cpp deleted file mode 100644 index 1fbcacd3..00000000 --- a/spectrum/src/win32/SpectrumService.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "SpectrumService.h" - -SpectrumService::SpectrumService(void) { - serviceName = "Spectrum2"; - displayName = "Spectrum2 XMPP Transport"; - username = NULL; - password = NULL; -} - -SpectrumService::~SpectrumService(void) {} - -void SpectrumService::Stop() { - ReportStatus((DWORD)SERVICE_STOP_PENDING); -} - -void SpectrumService::Run(DWORD argc, LPTSTR *argv) { - ReportStatus((DWORD)SERVICE_RUNNING); - main(argc, argv); -} \ No newline at end of file diff --git a/spectrum/src/win32/SpectrumService.h b/spectrum/src/win32/SpectrumService.h deleted file mode 100644 index 404b1057..00000000 --- a/spectrum/src/win32/SpectrumService.h +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "WindowsService.h" - -class SpectrumService : public WindowsService { - -public: - SpectrumService(void); - ~SpectrumService(void); -protected: - void Stop(); - void Run(DWORD argc, LPTSTR *argv); -}; - -int main(int argc, char **argv); \ No newline at end of file diff --git a/spectrum/src/win32/WindowsService.cpp b/spectrum/src/win32/WindowsService.cpp deleted file mode 100644 index 0a749378..00000000 --- a/spectrum/src/win32/WindowsService.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include -#include -#include ".\windowsservice.h" - -static WindowsService *gService; - -WindowsService::WindowsService(void) : - statusCheckpoint(0), - serviceName(NULL), - inited(false), - dwAcceptedControls(SERVICE_ACCEPT_STOP), - debugging(false) -{ - gService= this; - status.dwServiceType= SERVICE_WIN32_OWN_PROCESS; - status.dwServiceSpecificExitCode= 0; -} - -WindowsService::~WindowsService(void) -{ -} - -BOOL WindowsService::Install(const char *szFilePath) -{ - bool ret_val= false; - SC_HANDLE newService; - SC_HANDLE scm; - - if (IsInstalled()) return true; - - // open a connection to the SCM - if (!(scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE))) - return false; - - newService= CreateService(scm, serviceName, displayName, - SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, - SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - szFilePath, NULL, NULL, NULL, username, - password); - - if (newService) - { - CloseServiceHandle(newService); - ret_val= true; - } - - CloseServiceHandle(scm); - return ret_val; -} - -BOOL WindowsService::Init() -{ - assert(serviceName != NULL); - - if (inited) return true; - - SERVICE_TABLE_ENTRY stb[] = - { - { (LPSTR)serviceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain}, - { NULL, NULL } - }; - inited= true; - return StartServiceCtrlDispatcher(stb); //register with the Service Manager -} - -BOOL WindowsService::Remove() -{ - bool ret_val= false; - - if (! IsInstalled()) - return true; - - // open a connection to the SCM - SC_HANDLE scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE); - if (! scm) - return false; - - SC_HANDLE service= OpenService(scm, serviceName, DELETE); - if (service) - { - if (DeleteService(service)) - ret_val= true; - DWORD dw= ::GetLastError(); - CloseServiceHandle(service); - } - - CloseServiceHandle(scm); - return ret_val; -} - -BOOL WindowsService::IsInstalled() -{ - BOOL ret_val= FALSE; - - SC_HANDLE scm= ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); - SC_HANDLE serv_handle= ::OpenService(scm, serviceName, SERVICE_QUERY_STATUS); - - ret_val= serv_handle != NULL; - - ::CloseServiceHandle(serv_handle); - ::CloseServiceHandle(scm); - - return ret_val; -} - -void WindowsService::SetAcceptedControls(DWORD acceptedControls) -{ - dwAcceptedControls= acceptedControls; -} - - -BOOL WindowsService::ReportStatus(DWORD currentState, DWORD waitHint, - DWORD dwError) -{ - if(debugging) return TRUE; - - if(currentState == SERVICE_START_PENDING) - status.dwControlsAccepted= 0; - else - status.dwControlsAccepted= dwAcceptedControls; - - status.dwCurrentState= currentState; - status.dwWin32ExitCode= dwError != 0 ? - ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR; - status.dwWaitHint= waitHint; - status.dwServiceSpecificExitCode= dwError; - - if(currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED) - { - status.dwCheckPoint= 0; - statusCheckpoint= 0; - } - else - status.dwCheckPoint= ++statusCheckpoint; - - // Report the status of the service to the service control manager. - BOOL result= SetServiceStatus(statusHandle, &status); - if (!result) - Log("ReportStatus failed"); - - return result; -} - -void WindowsService::RegisterAndRun(DWORD argc, LPTSTR *argv) -{ - statusHandle= ::RegisterServiceCtrlHandler(serviceName, ControlHandler); - if (statusHandle && ReportStatus(SERVICE_START_PENDING)) - Run(argc, argv); - ReportStatus(SERVICE_STOPPED); -} - -void WindowsService::HandleControlCode(DWORD opcode) -{ - // Handle the requested control code. - switch(opcode) { - case SERVICE_CONTROL_STOP: - // Stop the service. - status.dwCurrentState= SERVICE_STOP_PENDING; - Stop(); - break; - - case SERVICE_CONTROL_PAUSE: - status.dwCurrentState= SERVICE_PAUSE_PENDING; - Pause(); - break; - - case SERVICE_CONTROL_CONTINUE: - status.dwCurrentState= SERVICE_CONTINUE_PENDING; - Continue(); - break; - - case SERVICE_CONTROL_SHUTDOWN: - Shutdown(); - break; - - case SERVICE_CONTROL_INTERROGATE: - ReportStatus(status.dwCurrentState); - break; - - default: - // invalid control code - break; - } -} - -void WINAPI WindowsService::ServiceMain(DWORD argc, LPTSTR *argv) -{ - assert(gService != NULL); - - // register our service control handler: - gService->RegisterAndRun(argc, argv); -} - -void WINAPI WindowsService::ControlHandler(DWORD opcode) -{ - assert(gService != NULL); - - return gService->HandleControlCode(opcode); -} diff --git a/spectrum/src/win32/WindowsService.h b/spectrum/src/win32/WindowsService.h deleted file mode 100644 index 55e91d8b..00000000 --- a/spectrum/src/win32/WindowsService.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#pragma once - -class WindowsService -{ -protected: - bool inited; - const char *serviceName; - const char *displayName; - const char *username; - const char *password; - SERVICE_STATUS_HANDLE statusHandle; - DWORD statusCheckpoint; - SERVICE_STATUS status; - DWORD dwAcceptedControls; - bool debugging; - -public: - WindowsService(void); - ~WindowsService(void); - - BOOL Install(const char *szFilePath); - BOOL Remove(); - BOOL Init(); - BOOL IsInstalled(); - void SetAcceptedControls(DWORD acceptedControls); - void Debug(bool debugFlag) { debugging= debugFlag; } - -public: - static void WINAPI ServiceMain(DWORD argc, LPTSTR *argv); - static void WINAPI ControlHandler(DWORD CtrlType); - -protected: - virtual void Run(DWORD argc, LPTSTR *argv)= 0; - virtual void Stop() {} - virtual void Shutdown() {} - virtual void Pause() {} - virtual void Continue() {} - virtual void Log(const char *msg) {} - - BOOL ReportStatus(DWORD currentStatus, DWORD waitHint= 3000, DWORD dwError=0); - void HandleControlCode(DWORD opcode); - void RegisterAndRun(DWORD argc, LPTSTR *argv); -};