mirror of https://github.com/PurpleI2P/i2pd.git
R4SAS
3 years ago
4 changed files with 362 additions and 2 deletions
@ -0,0 +1,283 @@
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, 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 |
||||
*/ |
||||
|
||||
#include "Win32Service.h" |
||||
#include <assert.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 error: ", 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(); |
||||
_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 error: ", 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 error: ", 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 error: ", 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 error: ", 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; |
||||
} |
||||
} |
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, 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> |
||||
|
||||
#define SERVICE_NAME "i2pdService" |
||||
|
||||
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; |
||||
}; |
||||
|
||||
#endif // WIN_32_SERVICE_H__
|
Loading…
Reference in new issue