From cb8651ec68d4c2ebe7cdb7fe3b015c8f1e686244 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 11 Mar 2021 14:39:33 +0300 Subject: [PATCH] [win32] drop service code, fix start with daemon option. Throw notification when unable to parse config Signed-off-by: R4SAS --- .gitmodules | 0 Makefile | 2 +- Win32/DaemonWin32.cpp | 42 +---- Win32/Win32Service.cpp | 414 ----------------------------------------- Win32/Win32Service.h | 92 --------- daemon/Daemon.cpp | 7 +- libi2pd/Config.cpp | 20 +- 7 files changed, 21 insertions(+), 556 deletions(-) delete mode 100644 .gitmodules delete mode 100644 Win32/Win32Service.cpp delete mode 100644 Win32/Win32Service.h diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29b..00000000 diff --git a/Makefile b/Makefile index 7357f220..7ff74787 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS))) DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp include Makefile.bsd else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS))) - DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32Service.cpp Win32/Win32App.cpp Win32/Win32NetState.cpp + DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32NetState.cpp include Makefile.mingw else # not supported $(error Not supported platform) diff --git a/Win32/DaemonWin32.cpp b/Win32/DaemonWin32.cpp index 30f4f92e..6bb953e9 100644 --- a/Win32/DaemonWin32.cpp +++ b/Win32/DaemonWin32.cpp @@ -14,7 +14,6 @@ #include "Log.h" #ifdef _WIN32 -#include "Win32Service.h" #ifdef WIN32_APP #include #include "Win32App.h" @@ -35,45 +34,11 @@ namespace util i2p::log::SetThrowFunction ([](const std::string& s) { MessageBox(0, TEXT(s.c_str ()), TEXT("i2pd"), MB_ICONERROR | MB_TASKMODAL | MB_OK ); - }); + } + ); if (!Daemon_Singleton::init(argc, argv)) return false; - - std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl); - if (serviceControl == "install") - { - LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service"); - InstallService( - SERVICE_NAME, // Name of service - SERVICE_DISPLAY_NAME, // Name to display - SERVICE_START_TYPE, // Service start type - SERVICE_DEPENDENCIES, // Dependencies - SERVICE_ACCOUNT, // Service running account - SERVICE_PASSWORD // Password of the account - ); - return false; - } - else if (serviceControl == "remove") - { - LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service"); - UninstallService(SERVICE_NAME); - return false; - } - - if (isDaemon) - { - LogPrint(eLogDebug, "Daemon: running as service"); - I2PService service((PSTR)SERVICE_NAME); - if (!I2PService::Run(service)) - { - LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); - return false; - } - return false; - } - else - LogPrint(eLogDebug, "Daemon: running as user"); return true; } @@ -86,9 +51,6 @@ namespace util setlocale(LC_TIME, "C"); #ifdef WIN32_APP if (!i2p::win32::StartWin32App ()) return false; - - // override log - i2p::config::SetOption("log", std::string ("file")); #endif bool ret = Daemon_Singleton::start(); if (ret && i2p::log::Logger().GetLogType() == eLogFile) diff --git a/Win32/Win32Service.cpp b/Win32/Win32Service.cpp deleted file mode 100644 index 7a6d7abf..00000000 --- a/Win32/Win32Service.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/* -* Copyright (c) 2013-2020, The PurpleI2P Project -* -* This file is part of Purple i2pd project and licensed under BSD3 -* -* See full license text in LICENSE file at top of project tree -*/ - -#ifdef _WIN32 -#define _CRT_SECURE_NO_WARNINGS // to use freopen -#endif - -#include "Win32Service.h" -#include -//#include -#include - -#include "Daemon.h" -#include "Log.h" - -I2PService *I2PService::s_service = NULL; - -BOOL I2PService::isService() -{ - BOOL bIsService = FALSE; - HWINSTA hWinStation = GetProcessWindowStation(); - if (hWinStation != NULL) - { - USEROBJECTFLAGS uof = { 0 }; - if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0)) - { - bIsService = TRUE; - } - } - return bIsService; -} - -BOOL I2PService::Run(I2PService &service) -{ - s_service = &service; - SERVICE_TABLE_ENTRY serviceTable[] = - { - { service.m_name, ServiceMain }, - { NULL, NULL } - }; - return StartServiceCtrlDispatcher(serviceTable); -} - -void WINAPI I2PService::ServiceMain(DWORD dwArgc, PSTR *pszArgv) -{ - assert(s_service != NULL); - s_service->m_statusHandle = RegisterServiceCtrlHandler( - s_service->m_name, ServiceCtrlHandler); - if (s_service->m_statusHandle == NULL) - { - throw GetLastError(); - } - s_service->Start(dwArgc, pszArgv); -} - - -void WINAPI I2PService::ServiceCtrlHandler(DWORD dwCtrl) -{ - switch (dwCtrl) - { - case SERVICE_CONTROL_STOP: s_service->Stop(); break; - case SERVICE_CONTROL_PAUSE: s_service->Pause(); break; - case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break; - case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break; - case SERVICE_CONTROL_INTERROGATE: break; - default: break; - } -} - -I2PService::I2PService(PSTR pszServiceName, - BOOL fCanStop, - BOOL fCanShutdown, - BOOL fCanPauseContinue) -{ - m_name = (pszServiceName == NULL) ? (PSTR)"" : pszServiceName; - m_statusHandle = NULL; - m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - m_status.dwCurrentState = SERVICE_START_PENDING; - - DWORD dwControlsAccepted = 0; - if (fCanStop) - dwControlsAccepted |= SERVICE_ACCEPT_STOP; - if (fCanShutdown) - dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN; - if (fCanPauseContinue) - dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE; - - m_status.dwControlsAccepted = dwControlsAccepted; - m_status.dwWin32ExitCode = NO_ERROR; - m_status.dwServiceSpecificExitCode = 0; - m_status.dwCheckPoint = 0; - m_status.dwWaitHint = 0; - m_fStopping = FALSE; - // Create a manual-reset event that is not signaled at first to indicate - // the stopped signal of the service. - m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (m_hStoppedEvent == NULL) - { - throw GetLastError(); - } -} - -I2PService::~I2PService(void) -{ - if (m_hStoppedEvent) - { - CloseHandle(m_hStoppedEvent); - m_hStoppedEvent = NULL; - } -} - -void I2PService::Start(DWORD dwArgc, PSTR *pszArgv) -{ - try - { - SetServiceStatus(SERVICE_START_PENDING); - OnStart(dwArgc, pszArgv); - SetServiceStatus(SERVICE_RUNNING); - } - catch (DWORD dwError) - { - LogPrint(eLogError, "Win32Service Start", dwError); - SetServiceStatus(SERVICE_STOPPED, dwError); - } - catch (...) - { - LogPrint(eLogError, "Win32Service failed to start.", EVENTLOG_ERROR_TYPE); - SetServiceStatus(SERVICE_STOPPED); - } -} - -void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv) -{ - LogPrint(eLogInfo, "Win32Service in OnStart", EVENTLOG_INFORMATION_TYPE); - Daemon.start(); - //i2p::util::config::OptionParser(dwArgc, pszArgv); - //i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); - //i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), - // i2p::util::config::GetArg("-port", 17070)); - _worker = new std::thread(std::bind(&I2PService::WorkerThread, this)); -} - -void I2PService::WorkerThread() -{ - while (!m_fStopping) - { - ::Sleep(1000); // Simulate some lengthy operations. - } - // Signal the stopped event. - SetEvent(m_hStoppedEvent); -} - -void I2PService::Stop() -{ - DWORD dwOriginalState = m_status.dwCurrentState; - try - { - SetServiceStatus(SERVICE_STOP_PENDING); - OnStop(); - SetServiceStatus(SERVICE_STOPPED); - } - catch (DWORD dwError) - { - LogPrint(eLogInfo, "Win32Service Stop", dwError); - SetServiceStatus(dwOriginalState); - } - catch (...) - { - LogPrint(eLogError, "Win32Service failed to stop.", EVENTLOG_ERROR_TYPE); - SetServiceStatus(dwOriginalState); - } -} - -void I2PService::OnStop() -{ - // Log a service stop message to the Application log. - LogPrint(eLogInfo, "Win32Service in OnStop", EVENTLOG_INFORMATION_TYPE); - Daemon.stop(); - m_fStopping = TRUE; - if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0) - { - throw GetLastError(); - } - _worker->join(); - delete _worker; -} - -void I2PService::Pause() -{ - try - { - SetServiceStatus(SERVICE_PAUSE_PENDING); - OnPause(); - SetServiceStatus(SERVICE_PAUSED); - } - catch (DWORD dwError) - { - LogPrint(eLogError, "Win32Service Pause", dwError); - SetServiceStatus(SERVICE_RUNNING); - } - catch (...) - { - LogPrint(eLogError, "Win32Service failed to pause.", EVENTLOG_ERROR_TYPE); - SetServiceStatus(SERVICE_RUNNING); - } -} - -void I2PService::OnPause() -{ -} - -void I2PService::Continue() -{ - try - { - SetServiceStatus(SERVICE_CONTINUE_PENDING); - OnContinue(); - SetServiceStatus(SERVICE_RUNNING); - } - catch (DWORD dwError) - { - LogPrint(eLogError, "Win32Service Continue", dwError); - SetServiceStatus(SERVICE_PAUSED); - } - catch (...) - { - LogPrint(eLogError, "Win32Service failed to resume.", EVENTLOG_ERROR_TYPE); - SetServiceStatus(SERVICE_PAUSED); - } -} - -void I2PService::OnContinue() -{ -} - -void I2PService::Shutdown() -{ - try - { - OnShutdown(); - SetServiceStatus(SERVICE_STOPPED); - } - catch (DWORD dwError) - { - LogPrint(eLogError, "Win32Service Shutdown", dwError); - } - catch (...) - { - LogPrint(eLogError, "Win32Service failed to shut down.", EVENTLOG_ERROR_TYPE); - } -} - -void I2PService::OnShutdown() -{ -} - -void I2PService::SetServiceStatus(DWORD dwCurrentState, - DWORD dwWin32ExitCode, - DWORD dwWaitHint) -{ - static DWORD dwCheckPoint = 1; - m_status.dwCurrentState = dwCurrentState; - m_status.dwWin32ExitCode = dwWin32ExitCode; - m_status.dwWaitHint = dwWaitHint; - m_status.dwCheckPoint = - ((dwCurrentState == SERVICE_RUNNING) || - (dwCurrentState == SERVICE_STOPPED)) ? - 0 : dwCheckPoint++; - - ::SetServiceStatus(m_statusHandle, &m_status); -} - -//***************************************************************************** - -void FreeHandles(SC_HANDLE schSCManager, SC_HANDLE schService) -{ - if (schSCManager) - { - CloseServiceHandle(schSCManager); - schSCManager = NULL; - } - if (schService) - { - CloseServiceHandle(schService); - schService = NULL; - } -} - -void InstallService(PCSTR pszServiceName, PCSTR pszDisplayName, DWORD dwStartType, PCSTR pszDependencies, PCSTR pszAccount, PCSTR pszPassword) -{ - printf("Try to install Win32Service (%s).\n", pszServiceName); - - char szPath[MAX_PATH]; - SC_HANDLE schSCManager = NULL; - SC_HANDLE schService = NULL; - - if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0) - { - printf("GetModuleFileName failed w/err 0x%08lx\n", GetLastError()); - FreeHandles(schSCManager, schService); - return; - } - char SvcOpt[] = " --daemon"; - strncat(szPath, SvcOpt, strlen(SvcOpt)); - - // Open the local default service control manager database - schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); - if (schSCManager == NULL) - { - printf("OpenSCManager failed w/err 0x%08lx\n", GetLastError()); - FreeHandles(schSCManager, schService); - return; - } - - // Install the service into SCM by calling CreateService - schService = CreateService( - schSCManager, // SCManager database - pszServiceName, // Name of service - pszDisplayName, // Name to display - SERVICE_QUERY_STATUS, // Desired access - SERVICE_WIN32_OWN_PROCESS, // Service type - dwStartType, // Service start type - SERVICE_ERROR_NORMAL, // Error control type - szPath, // Service's binary - NULL, // No load ordering group - NULL, // No tag identifier - pszDependencies, // Dependencies - pszAccount, // Service running account - pszPassword // Password of the account - ); - - if (schService == NULL) - { - printf("CreateService failed w/err 0x%08lx\n", GetLastError()); - FreeHandles(schSCManager, schService); - return; - } - - printf("Win32Service is installed as %s.\n", pszServiceName); - - // Centralized cleanup for all allocated resources. - FreeHandles(schSCManager, schService); -} - -void UninstallService(PCSTR pszServiceName) -{ - printf("Try to uninstall Win32Service (%s).\n", pszServiceName); - - SC_HANDLE schSCManager = NULL; - SC_HANDLE schService = NULL; - SERVICE_STATUS ssSvcStatus = {}; - - // Open the local default service control manager database - schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); - if (schSCManager == NULL) - { - printf("OpenSCManager failed w/err 0x%08lx\n", GetLastError()); - FreeHandles(schSCManager, schService); - return; - } - - // Open the service with delete, stop, and query status permissions - schService = OpenService(schSCManager, pszServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE); - if (schService == NULL) - { - printf("OpenService failed w/err 0x%08lx\n", GetLastError()); - FreeHandles(schSCManager, schService); - return; - } - - // Try to stop the service - if (ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus)) - { - printf("Stopping %s.\n", pszServiceName); - Sleep(1000); - - while (QueryServiceStatus(schService, &ssSvcStatus)) - { - if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING) - { - printf("."); - Sleep(1000); - } - else break; - } - - if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED) - { - printf("\n%s is stopped.\n", pszServiceName); - } - else - { - printf("\n%s failed to stop.\n", pszServiceName); - } - } - - // Now remove the service by calling DeleteService. - if (!DeleteService(schService)) - { - printf("DeleteService failed w/err 0x%08lx\n", GetLastError()); - FreeHandles(schSCManager, schService); - return; - } - - printf("%s is removed.\n", pszServiceName); - - // Centralized cleanup for all allocated resources. - FreeHandles(schSCManager, schService); -} diff --git a/Win32/Win32Service.h b/Win32/Win32Service.h deleted file mode 100644 index 40fff787..00000000 --- a/Win32/Win32Service.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -* Copyright (c) 2013-2020, The PurpleI2P Project -* -* This file is part of Purple i2pd project and licensed under BSD3 -* -* See full license text in LICENSE file at top of project tree -*/ - -#ifndef WIN_32_SERVICE_H__ -#define WIN_32_SERVICE_H__ - -#include -#include - -#ifdef _WIN32 -// Internal name of the service -#define SERVICE_NAME "i2pdService" - -// Displayed name of the service -#define SERVICE_DISPLAY_NAME "i2pd router service" - -// Service start options. -#define SERVICE_START_TYPE SERVICE_DEMAND_START - -// List of service dependencies - "dep1\0dep2\0\0" -#define SERVICE_DEPENDENCIES "" - -// The name of the account under which the service should run -#define SERVICE_ACCOUNT "NT AUTHORITY\\LocalService" - -// The password to the service account name -#define SERVICE_PASSWORD NULL -#endif - -class I2PService -{ - public: - - I2PService(PSTR pszServiceName, - BOOL fCanStop = TRUE, - BOOL fCanShutdown = TRUE, - BOOL fCanPauseContinue = FALSE); - - virtual ~I2PService(void); - - static BOOL isService(); - static BOOL Run(I2PService &service); - void Stop(); - - protected: - - virtual void OnStart(DWORD dwArgc, PSTR *pszArgv); - virtual void OnStop(); - virtual void OnPause(); - virtual void OnContinue(); - virtual void OnShutdown(); - void SetServiceStatus(DWORD dwCurrentState, - DWORD dwWin32ExitCode = NO_ERROR, - DWORD dwWaitHint = 0); - - private: - - static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv); - static void WINAPI ServiceCtrlHandler(DWORD dwCtrl); - void WorkerThread(); - void Start(DWORD dwArgc, PSTR *pszArgv); - void Pause(); - void Continue(); - void Shutdown(); - static I2PService* s_service; - PSTR m_name; - SERVICE_STATUS m_status; - SERVICE_STATUS_HANDLE m_statusHandle; - - BOOL m_fStopping; - HANDLE m_hStoppedEvent; - - std::thread* _worker; -}; - -void InstallService( - PCSTR pszServiceName, - PCSTR pszDisplayName, - DWORD dwStartType, - PCSTR pszDependencies, - PCSTR pszAccount, - PCSTR pszPassword -); - -void UninstallService(PCSTR pszServiceName); - -#endif // WIN_32_SERVICE_H__ diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index cfcf1025..ecb4b59c 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -102,8 +102,13 @@ namespace util if (logclftime) i2p::log::Logger().SetTimeFormat ("[%d/%b/%Y:%H:%M:%S %z]"); +#ifdef WIN32_APP + // Win32 app with GUI supports only logging to file + logs = "file"; +#else if (isDaemon && (logs == "" || logs == "stdout")) logs = "file"; +#endif i2p::log::Logger().SetLogLevel(loglevel); if (logstream) { @@ -123,7 +128,7 @@ namespace util // use stdout -- default } - LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); + LogPrint(eLogNone, "i2pd v", VERSION, " starting"); LogPrint(eLogDebug, "FS: main config file: ", config); LogPrint(eLogDebug, "FS: data directory: ", datadir); diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index cc79c87c..cdbe1bff 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -19,6 +19,7 @@ #include "Identity.h" #include "Config.h" #include "version.h" +#include "Log.h" using namespace boost::program_options; @@ -65,7 +66,7 @@ namespace config { ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") ("ntcpproxy", value()->default_value(""), "Ignored") #ifdef _WIN32 - ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") + ("svcctl", value()->default_value(""), "Ignored") ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") #endif @@ -209,7 +210,7 @@ namespace config { ), "Reseed URLs, separated by comma") ("reseed.yggurls", value()->default_value( "http://[324:9de3:fea4:f6ac::ace]:7070/" - ), "Reseed URLs through the Yggdrasil, separated by comma") + ), "Reseed URLs through the Yggdrasil, separated by comma") ; options_description addressbook("AddressBook options"); @@ -218,12 +219,12 @@ namespace config { "http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt" ), "AddressBook subscription URL for initial setup") ("addressbook.subscriptions", value()->default_value(""), "AddressBook subscriptions URLs, separated by comma") - ("addressbook.hostsfile", value()->default_value(""), "File to dump addresses in hosts.txt format"); + ("addressbook.hostsfile", value()->default_value(""), "File to dump addresses in hosts.txt format"); options_description trust("Trust options"); trust.add_options() ("trust.enabled", value()->default_value(false), "Enable explicit trust options") - ("trust.family", value()->default_value(""), "Router Familiy to trust for first hops") + ("trust.family", value()->default_value(""), "Router Family to trust for first hops") ("trust.routers", value()->default_value(""), "Only Connect to these routers") ("trust.hidden", value()->default_value(false), "Should we hide our router from other routers?") ; @@ -281,9 +282,9 @@ namespace config { options_description meshnets("Meshnet transports options"); meshnets.add_options() ("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (deafult: false)") - ("meshnets.yggaddress", value()->default_value(""), "Yggdrasil address to publish") - ; - + ("meshnets.yggaddress", value()->default_value(""), "Yggdrasil address to publish") + ; + m_OptionsDesc .add(general) .add(limits) @@ -314,7 +315,7 @@ namespace config { try { auto style = boost::program_options::command_line_style::unix_style - | boost::program_options::command_line_style::allow_long_disguise; + | boost::program_options::command_line_style::allow_long_disguise; style &= ~ boost::program_options::command_line_style::allow_guessing; if (ignoreUnknown) store(command_line_parser(argc, argv).options(m_OptionsDesc).style (style).allow_unregistered().run(), m_Options); @@ -323,6 +324,7 @@ namespace config { } catch (boost::program_options::error& e) { + ThrowFatal ("Error while parsing arguments: ", e.what()); std::cerr << "args: " << e.what() << std::endl; exit(EXIT_FAILURE); } @@ -360,6 +362,7 @@ namespace config { if (!config.is_open()) { + ThrowFatal ("Missing or unreadable config file: ", path); std::cerr << "missing/unreadable config file: " << path << std::endl; exit(EXIT_FAILURE); } @@ -370,6 +373,7 @@ namespace config { } catch (boost::program_options::error& e) { + ThrowFatal ("Error while parsing config file: ", e.what()); std::cerr << e.what() << std::endl; exit(EXIT_FAILURE); };