diff options
| author | Shauren <shauren.trinity@gmail.com> | 2024-09-15 12:40:54 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2024-09-15 12:40:54 +0200 |
| commit | 052f2d0a81460ba484c27d05fe34673cf467c75e (patch) | |
| tree | ca548c95ca2b21d5a5feb276e1bf2dc95029ca3d /src/common/Platform/Windows | |
| parent | fd0a7ba871060c895fdf701799dbf649ee697078 (diff) | |
Core/Common: Compile ServiceWin32 as part of common project instead of directly adding its source files to both server executables
Diffstat (limited to 'src/common/Platform/Windows')
| -rw-r--r-- | src/common/Platform/Windows/ServiceWin32.cpp | 256 | ||||
| -rw-r--r-- | src/common/Platform/Windows/ServiceWin32.h | 33 |
2 files changed, 289 insertions, 0 deletions
diff --git a/src/common/Platform/Windows/ServiceWin32.cpp b/src/common/Platform/Windows/ServiceWin32.cpp new file mode 100644 index 00000000000..80914d2a415 --- /dev/null +++ b/src/common/Platform/Windows/ServiceWin32.cpp @@ -0,0 +1,256 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ServiceWin32.h" +#include <array> // for std::size +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <windows.h> +#include <winsvc.h> + +namespace +{ +_TCHAR* ServiceLongName; +_TCHAR* ServiceName; +_TCHAR* ServiceDescription; +int(*ServiceEntryPoint)(int argc, char** argv); +int* ServiceStatusPtr; + +SERVICE_STATUS ServiceStatus; +SERVICE_STATUS_HANDLE ServiceStatusHandle = nullptr; +} + +typedef BOOL (WINAPI *CSD_T)(SC_HANDLE, DWORD, LPCVOID); + +void Trinity::Service::Init(_TCHAR* serviceLongName, _TCHAR* serviceName, _TCHAR* serviceDescription, int(* entryPoint)(int argc, char** argv), int* status) +{ + ServiceLongName = serviceLongName; + ServiceName = serviceName; + ServiceDescription = serviceDescription; + ServiceEntryPoint = entryPoint; + ServiceStatusPtr = status; +} + +int32 Trinity::Service::Install() +{ + SC_HANDLE serviceControlManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_CREATE_SERVICE); + + if (serviceControlManager) + { + TCHAR path[_MAX_PATH + 10]; + if (GetModuleFileName(nullptr, path, std::size(path)) > 0) + { + _tcscat(path, _T(" --service run")); + SC_HANDLE service = CreateService(serviceControlManager, + ServiceName, // name of service + ServiceLongName, // service name to display + SERVICE_ALL_ACCESS, // desired access + // service type + SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, + SERVICE_AUTO_START, // start type + SERVICE_ERROR_IGNORE, // error control type + path, // service's binary + nullptr, // no load ordering group + nullptr, // no tag identifier + nullptr, // no dependencies + nullptr, // LocalSystem account + nullptr); // no password + if (service) + { + SERVICE_DESCRIPTION sdBuf; + sdBuf.lpDescription = ServiceDescription; + ChangeServiceConfig2( + service, // handle to service + SERVICE_CONFIG_DESCRIPTION, // change: description + &sdBuf); // new data + + SC_ACTION _action[1]; + _action[0].Type = SC_ACTION_RESTART; + _action[0].Delay = 10000; + SERVICE_FAILURE_ACTIONS sfa; + ZeroMemory(&sfa, sizeof(SERVICE_FAILURE_ACTIONS)); + sfa.lpsaActions = _action; + sfa.cActions = 1; + sfa.dwResetPeriod = INFINITE; + ChangeServiceConfig2( + service, // handle to service + SERVICE_CONFIG_FAILURE_ACTIONS, // information level + &sfa); // new data + + CloseServiceHandle(service); + + } + } + CloseServiceHandle(serviceControlManager); + } + + printf("Service installed\n"); + return 0; +} + +int32 Trinity::Service::Uninstall() +{ + SC_HANDLE serviceControlManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT); + + if (serviceControlManager) + { + SC_HANDLE service = OpenService(serviceControlManager, + ServiceName, SERVICE_QUERY_STATUS | DELETE); + if (service) + { + SERVICE_STATUS serviceStatus2; + if (QueryServiceStatus(service, &serviceStatus2)) + { + if (serviceStatus2.dwCurrentState == SERVICE_STOPPED) + DeleteService(service); + } + CloseServiceHandle(service); + } + + CloseServiceHandle(serviceControlManager); + } + + printf("Service uninstalled\n"); + return 0; +} + +void WINAPI ServiceControlHandler(DWORD controlCode) +{ + switch (controlCode) + { + case SERVICE_CONTROL_INTERROGATE: + break; + + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + + *ServiceStatusPtr = 0; + return; + + case SERVICE_CONTROL_PAUSE: + *ServiceStatusPtr = 2; + ServiceStatus.dwCurrentState = SERVICE_PAUSED; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + break; + + case SERVICE_CONTROL_CONTINUE: + ServiceStatus.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + *ServiceStatusPtr = 1; + break; + + default: + if (controlCode >= 128 && controlCode <= 255) + // user defined control code + break; + else + // unrecognized control code + break; + } + + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); +} + +template<size_t size> +void TCharToChar(TCHAR const* src, char(&dst)[size]) +{ + if constexpr (std::is_same_v<TCHAR, char>) + ::strcpy_s(dst, src); + else + ::wcstombs_s(nullptr, dst, src, _TRUNCATE); +} + +void WINAPI ServiceMain(DWORD /*argc*/, TCHAR *argv[]) +{ + // initialise service status + ServiceStatus.dwServiceType = SERVICE_WIN32; + ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; + ServiceStatus.dwWin32ExitCode = NO_ERROR; + ServiceStatus.dwServiceSpecificExitCode = NO_ERROR; + ServiceStatus.dwCheckPoint = 0; + ServiceStatus.dwWaitHint = 0; + + ServiceStatusHandle = RegisterServiceCtrlHandler(ServiceName, ServiceControlHandler); + + if (ServiceStatusHandle) + { + TCHAR path[_MAX_PATH + 1]; + size_t last_slash = 0; + + size_t pathLen = GetModuleFileName(nullptr, path, std::size(path)); + for (size_t i = 0; i < pathLen; i++) + if (path[i] == '\\') + last_slash = i; + + path[last_slash] = 0; + + // service is starting + ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + + // do initialisation here + SetCurrentDirectory(path); + + // running + ServiceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + ServiceStatus.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + + //////////////////////// + // service main cycle // + //////////////////////// + + *ServiceStatusPtr = 1; + + char cArg[_MAX_PATH + 1]; + TCharToChar(argv[0], cArg); + char* cArgv[] = { cArg }; + + ServiceEntryPoint(1, cArgv); + + // service was stopped + ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + + // do cleanup here + + // service is now stopped + ServiceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + } +} + +int32 Trinity::Service::Run() +{ + SERVICE_TABLE_ENTRY serviceTable[] = + { + { ServiceName, ServiceMain }, + { nullptr, nullptr } + }; + + if (!StartServiceCtrlDispatcher(serviceTable)) + { + printf("StartService Failed. Error [%u]", uint32(::GetLastError())); + return 1; + } + return 0; +} diff --git a/src/common/Platform/Windows/ServiceWin32.h b/src/common/Platform/Windows/ServiceWin32.h new file mode 100644 index 00000000000..8602c12fedf --- /dev/null +++ b/src/common/Platform/Windows/ServiceWin32.h @@ -0,0 +1,33 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITYCORE_WIN32_SERVICE +#define TRINITYCORE_WIN32_SERVICE + +#include "Define.h" +#include <tchar.h> + +namespace Trinity::Service +{ + TC_COMMON_API void Init(_TCHAR* serviceLongName, _TCHAR* serviceName, _TCHAR* serviceDescription, + int(*entryPoint)(int argc, char** argv), int* status); + TC_COMMON_API int32 Install(); + TC_COMMON_API int32 Uninstall(); + TC_COMMON_API int32 Run(); +} + +#endif // TRINITYCORE_WIN32_SERVICE |
