mirror of https://github.com/PurpleI2P/i2pd.git
orignal
4 years ago
committed by
GitHub
39 changed files with 617 additions and 777 deletions
@ -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 <assert.h> |
|
||||||
//#include <strsafe.h>
|
|
||||||
#include <windows.h> |
|
||||||
|
|
||||||
#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); |
|
||||||
} |
|
@ -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 <thread> |
|
||||||
#include <windows.h> |
|
||||||
|
|
||||||
#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__
|
|
Loading…
Reference in new issue