mirror of
				https://github.com/PurpleI2P/i2pd.git
				synced 2025-11-04 08:30:46 +00:00 
			
		
		
		
	[win32] return back service control code (#1733)
Signed-off-by: R4SAS <r4sas@i2pmail.org>
This commit is contained in:
		
							parent
							
								
									9f1a125ed9
								
							
						
					
					
						commit
						df62b40ca7
					
				
					 4 changed files with 362 additions and 2 deletions
				
			
		
							
								
								
									
										2
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -62,7 +62,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/Win32App.cpp Win32/Win32NetState.cpp
 | 
			
		||||
	DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32Service.cpp Win32/Win32NetState.cpp
 | 
			
		||||
	include Makefile.mingw
 | 
			
		||||
else # not supported
 | 
			
		||||
	$(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
 | 
			
		||||
*
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
#include "Log.h"
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#include "Win32Service.h"
 | 
			
		||||
#ifdef WIN32_APP
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include "Win32App.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -39,6 +40,19 @@ namespace util
 | 
			
		|||
 | 
			
		||||
		if (!Daemon_Singleton::init(argc, argv))
 | 
			
		||||
			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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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…
	
	Add table
		Add a link
		
	
		Reference in a new issue