mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 13:27:17 +01:00
[win32] return back service control code (#1733)
Signed-off-by: R4SAS <r4sas@i2pmail.org>
This commit is contained in:
parent
9f1a125ed9
commit
df62b40ca7
2
Makefile
2
Makefile
|
@ -62,7 +62,7 @@ else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
|
||||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||||
include Makefile.bsd
|
include Makefile.bsd
|
||||||
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
|
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
|
||||||
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32NetState.cpp
|
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32Service.cpp Win32/Win32NetState.cpp
|
||||||
include Makefile.mingw
|
include Makefile.mingw
|
||||||
else # not supported
|
else # not supported
|
||||||
$(error Not supported platform)
|
$(error Not supported platform)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
#include "Win32Service.h"
|
||||||
#ifdef WIN32_APP
|
#ifdef WIN32_APP
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "Win32App.h"
|
#include "Win32App.h"
|
||||||
|
@ -39,6 +40,19 @@ namespace util
|
||||||
|
|
||||||
if (!Daemon_Singleton::init(argc, argv))
|
if (!Daemon_Singleton::init(argc, argv))
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
283
Win32/Win32Service.cpp
Normal file
283
Win32/Win32Service.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
63
Win32/Win32Service.h
Normal file
63
Win32/Win32Service.h
Normal file
|
@ -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 a new issue