diff options
-rw-r--r-- | win/win32service.cpp | 666 |
1 files changed, 333 insertions, 333 deletions
diff --git a/win/win32service.cpp b/win/win32service.cpp index c3dd9871f..0fb94f3e4 100644 --- a/win/win32service.cpp +++ b/win/win32service.cpp @@ -9,336 +9,336 @@ * the file COPYING for details. * * --------------------------------------------------- - */
-#include "inspircd_config.h"
-#include "inspircd.h"
-#include <windows.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-static SERVICE_STATUS_HANDLE serviceStatusHandle;
-static HANDLE hThreadEvent;
-static HANDLE killServiceEvent;
-static int serviceCurrentStatus;
-
-/** This is used to define ChangeServiceConf2() as we can't link
- * directly against this symbol (see below where it is used)
- */
-typedef BOOL (CALLBACK* SETSERVDESC)(SC_HANDLE,DWORD,LPVOID);
-
-/* A commandline parameter handler for service specific commandline parameters */
-typedef void (*CommandlineParameterHandler)(void);
-
-/* Represents a commandline and its handler */
-struct Commandline
-{
- const char* Switch;
- CommandlineParameterHandler Handler;
-};
-
-/* A function pointer for dynamic linking tricks */
-SETSERVDESC ChangeServiceConf;
-
-/* Kills the service by setting an event which the other thread picks up and exits */
-void KillService()
-{
- SetEvent(hThreadEvent);
- Sleep(2000);
- SetEvent(killServiceEvent);
-}
-
-/** The main part of inspircd runs within this thread function. This allows the service part to run
- * seperately on its own and to be able to kill the worker thread when its time to quit.
- */
-DWORD WINAPI WorkerThread(LPDWORD param)
-{
- char modname[MAX_PATH];
- GetModuleFileName(NULL, modname, sizeof(modname));
- char* argv[] = { modname, "--nofork", "--debug" };
- smain(3, argv);
- KillService();
- return 0;
-}
-
-/** Starts the worker thread above */
-void StartServiceThread()
-{
- DWORD dwd;
- CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WorkerThread,NULL,0,&dwd);
-}
-
-/** This function updates the status of the service in the SCM
- * (service control manager, the services.msc applet)
- */
-BOOL UpdateSCMStatus (DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint, DWORD dwWaitHint)
-{
- BOOL success;
- SERVICE_STATUS serviceStatus;
- serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- serviceStatus.dwCurrentState = dwCurrentState;
-
- if (dwCurrentState == SERVICE_START_PENDING)
- {
- serviceStatus.dwControlsAccepted = 0;
- }
- else
- {
- serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
- }
-
- if (dwServiceSpecificExitCode == 0)
- {
- serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
- }
- else
- {
- serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
- }
- serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
- serviceStatus.dwCheckPoint = dwCheckPoint;
- serviceStatus.dwWaitHint = dwWaitHint;
-
- success = SetServiceStatus (serviceStatusHandle, &serviceStatus);
- if (!success)
- {
- KillService();
- }
- return success;
-}
-
-/** This function is called by us when the service is being shut down or when it can't be started */
-void terminateService (int code, int wincode)
-{
- UpdateSCMStatus(SERVICE_STOPPED,wincode?wincode:ERROR_SERVICE_SPECIFIC_ERROR,(wincode)?0:code,0,0);
- return;
-}
-
-/** This callback is called by windows when the state of the service has been changed */
-VOID ServiceCtrlHandler (DWORD controlCode)
-{
- switch(controlCode)
- {
- case SERVICE_CONTROL_INTERROGATE:
- break;
- case SERVICE_CONTROL_SHUTDOWN:
- case SERVICE_CONTROL_STOP:
- serviceCurrentStatus = SERVICE_STOP_PENDING;
- UpdateSCMStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);
- KillService();
- UpdateSCMStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0);
- return;
- default:
- break;
- }
- UpdateSCMStatus(serviceCurrentStatus, NO_ERROR, 0, 0, 0);
-}
-
-/** This callback is called by windows when the service is started */
-VOID ServiceMain(DWORD argc, LPTSTR *argv)
-{
- BOOL success;
- DWORD type=0, size=0;
-
- serviceStatusHandle = RegisterServiceCtrlHandler("InspIRCd", (LPHANDLER_FUNCTION)ServiceCtrlHandler);
- if (!serviceStatusHandle)
- {
- terminateService(1, GetLastError());
- return;
- }
-
- success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 1, 1000);
- if (!success)
- {
- terminateService(2, GetLastError());
- return;
- }
-
- killServiceEvent = CreateEvent(NULL, true, false, NULL);
- hThreadEvent = CreateEvent(NULL, true, false, NULL);
-
- if (!killServiceEvent || !hThreadEvent)
- {
- terminateService(99, GetLastError());
- return;
- }
-
- success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000);
- if (!success)
- {
- terminateService(2, GetLastError());
- return;
- }
-
- StartServiceThread();
- serviceCurrentStatus = SERVICE_RUNNING;
- success = UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);
- if (!success)
- {
- terminateService(6, GetLastError());
- return;
- }
- WaitForSingleObject (killServiceEvent, INFINITE);
-}
-
-/** Install the windows service. This requires administrator privileges. */
-void InstallService()
-{
- SC_HANDLE myService, scm;
- SERVICE_DESCRIPTION svDesc;
- HINSTANCE advapi32;
-
- char modname[MAX_PATH];
- GetModuleFileName(NULL, modname, sizeof(modname));
-
- scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
- if (!scm)
- {
- printf("Unable to open service control manager: %s\n", dlerror());
- return;
- }
-
- myService = CreateService(scm,"InspIRCd","Inspire IRC Daemon", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
- SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, modname, 0, 0, 0, NULL, NULL);
-
- if (!myService)
- {
- printf("Unable to create service: %s\n", dlerror());
- CloseServiceHandle(scm);
- return;
- }
-
- // *** Set service description ***
- // this is supported from 5.0 (win2k) onwards only, so we can't link to the definition of
- // this function in advapi32.lib, otherwise the program will not run on windows NT 4. We
- // must use LoadLibrary and GetProcAddress to export the function name from advapi32.dll
- advapi32 = LoadLibrary("advapi32.dll");
- if (advapi32)
- {
- ChangeServiceConf = (SETSERVDESC)GetProcAddress(advapi32,"ChangeServiceConfig2A");
- if (ChangeServiceConf)
- {
- char desc[] = "The Inspire Internet Relay Chat Daemon hosts IRC channels and conversations.\
- If this service is stopped, the IRC server will not run.";
- svDesc.lpDescription = desc;
- BOOL success = ChangeServiceConf(myService,SERVICE_CONFIG_DESCRIPTION, &svDesc);
- if (!success)
- {
- printf("Unable to set service description: %s\n", dlerror());
- CloseServiceHandle(myService);
- CloseServiceHandle(scm);
- return;
- }
- }
- FreeLibrary(advapi32);
- }
-
- printf("Service installed.\n");
- CloseServiceHandle(myService);
- CloseServiceHandle(scm);
-}
-
-/** Remove the windows service. This requires administrator privileges. */
-void RemoveService()
-{
- SC_HANDLE myService, scm;
-
- scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
- if (!scm)
- {
- printf("Unable to open service control manager: %s\n", dlerror());
- return;
- }
-
- myService = OpenService(scm,"InspIRCd",SERVICE_ALL_ACCESS);
- if (!myService)
- {
- printf("Unable to open service: %s\n", dlerror());
- CloseServiceHandle(scm);
- return;
- }
-
- if (!DeleteService(myService))
- {
- printf("Unable to delete service: %s\n", dlerror());
- CloseServiceHandle(myService);
- CloseServiceHandle(scm);
- return;
- }
-
- printf("Service removed.\n");
- CloseServiceHandle(myService);
- CloseServiceHandle(scm);
-}
-
-/* In windows, our main() flows through here, before calling the 'real' main, smain() in inspircd.cpp */
-int main(int argc, char** argv)
-{
- /* List of parameters and handlers */
- Commandline params[] = {
- { "--installservice", InstallService },
- { "--removeservice", RemoveService },
- { NULL }
- };
-
- /* Check for parameters */
- if (argc > 1)
- {
- for (int z = 0; params[z].Switch; ++z)
- {
- if (!_stricmp(argv[1], params[z].Switch))
- {
- params[z].Handler();
- return 0;
- }
- }
- }
-
- /* First, check if the service is installed.
- * if it is not, or we're starting as non-administrator,
- * just call smain() and start as normal non-service
- * process.
- */
- SC_HANDLE myService, scm;
- scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
- if (scm)
- {
- myService = OpenService(scm,"InspIRCd",SERVICE_ALL_ACCESS);
- if (!myService)
- {
- /* Service not installed or no permission to modify it */
- CloseServiceHandle(scm);
- return smain(argc, argv);
- }
- }
- else
- {
- /* Not enough privileges to open the SCM */
- return smain(argc, argv);
- }
-
- CloseServiceHandle(myService);
- CloseServiceHandle(scm);
-
- /* Check if the process is running interactively. InspIRCd does not run interactively
- * as a service so if this is true, we just run the non-service inspircd.
- */
- USEROBJECTFLAGS uoflags;
- HWINSTA winstation = GetProcessWindowStation();
- if (GetUserObjectInformation(winstation, UOI_FLAGS, &uoflags, sizeof(uoflags), NULL))
- {
- if (uoflags.dwFlags == WSF_VISIBLE)
- return smain(argc, argv);
- }
-
- /* If we get here, we know the service is installed so we can start it */
-
- SERVICE_TABLE_ENTRY serviceTable[] =
- {
- {"InspIRCd", (LPSERVICE_MAIN_FUNCTION) ServiceMain },
- {NULL, NULL}
- };
-
- StartServiceCtrlDispatcher(serviceTable);
- return 0;
-}
+ */ +#include "inspircd_config.h" +#include "inspircd.h" +#include <windows.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +static SERVICE_STATUS_HANDLE serviceStatusHandle; +static HANDLE hThreadEvent; +static HANDLE killServiceEvent; +static int serviceCurrentStatus; + +/** This is used to define ChangeServiceConf2() as we can't link + * directly against this symbol (see below where it is used) + */ +typedef BOOL (CALLBACK* SETSERVDESC)(SC_HANDLE,DWORD,LPVOID); + +/* A commandline parameter handler for service specific commandline parameters */ +typedef void (*CommandlineParameterHandler)(void); + +/* Represents a commandline and its handler */ +struct Commandline +{ + const char* Switch; + CommandlineParameterHandler Handler; +}; + +/* A function pointer for dynamic linking tricks */ +SETSERVDESC ChangeServiceConf; + +/* Kills the service by setting an event which the other thread picks up and exits */ +void KillService() +{ + SetEvent(hThreadEvent); + Sleep(2000); + SetEvent(killServiceEvent); +} + +/** The main part of inspircd runs within this thread function. This allows the service part to run + * seperately on its own and to be able to kill the worker thread when its time to quit. + */ +DWORD WINAPI WorkerThread(LPDWORD param) +{ + char modname[MAX_PATH]; + GetModuleFileName(NULL, modname, sizeof(modname)); + char* argv[] = { modname, "--nofork", "--debug" }; + smain(3, argv); + KillService(); + return 0; +} + +/** Starts the worker thread above */ +void StartServiceThread() +{ + DWORD dwd; + CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WorkerThread,NULL,0,&dwd); +} + +/** This function updates the status of the service in the SCM + * (service control manager, the services.msc applet) + */ +BOOL UpdateSCMStatus (DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint, DWORD dwWaitHint) +{ + BOOL success; + SERVICE_STATUS serviceStatus; + serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + serviceStatus.dwCurrentState = dwCurrentState; + + if (dwCurrentState == SERVICE_START_PENDING) + { + serviceStatus.dwControlsAccepted = 0; + } + else + { + serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + } + + if (dwServiceSpecificExitCode == 0) + { + serviceStatus.dwWin32ExitCode = dwWin32ExitCode; + } + else + { + serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; + } + serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode; + serviceStatus.dwCheckPoint = dwCheckPoint; + serviceStatus.dwWaitHint = dwWaitHint; + + success = SetServiceStatus (serviceStatusHandle, &serviceStatus); + if (!success) + { + KillService(); + } + return success; +} + +/** This function is called by us when the service is being shut down or when it can't be started */ +void terminateService (int code, int wincode) +{ + UpdateSCMStatus(SERVICE_STOPPED,wincode?wincode:ERROR_SERVICE_SPECIFIC_ERROR,(wincode)?0:code,0,0); + return; +} + +/** This callback is called by windows when the state of the service has been changed */ +VOID ServiceCtrlHandler (DWORD controlCode) +{ + switch(controlCode) + { + case SERVICE_CONTROL_INTERROGATE: + break; + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + serviceCurrentStatus = SERVICE_STOP_PENDING; + UpdateSCMStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000); + KillService(); + UpdateSCMStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0); + return; + default: + break; + } + UpdateSCMStatus(serviceCurrentStatus, NO_ERROR, 0, 0, 0); +} + +/** This callback is called by windows when the service is started */ +VOID ServiceMain(DWORD argc, LPTSTR *argv) +{ + BOOL success; + DWORD type=0, size=0; + + serviceStatusHandle = RegisterServiceCtrlHandler("InspIRCd", (LPHANDLER_FUNCTION)ServiceCtrlHandler); + if (!serviceStatusHandle) + { + terminateService(1, GetLastError()); + return; + } + + success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 1, 1000); + if (!success) + { + terminateService(2, GetLastError()); + return; + } + + killServiceEvent = CreateEvent(NULL, true, false, NULL); + hThreadEvent = CreateEvent(NULL, true, false, NULL); + + if (!killServiceEvent || !hThreadEvent) + { + terminateService(99, GetLastError()); + return; + } + + success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000); + if (!success) + { + terminateService(2, GetLastError()); + return; + } + + StartServiceThread(); + serviceCurrentStatus = SERVICE_RUNNING; + success = UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0); + if (!success) + { + terminateService(6, GetLastError()); + return; + } + WaitForSingleObject (killServiceEvent, INFINITE); +} + +/** Install the windows service. This requires administrator privileges. */ +void InstallService() +{ + SC_HANDLE myService, scm; + SERVICE_DESCRIPTION svDesc; + HINSTANCE advapi32; + + char modname[MAX_PATH]; + GetModuleFileName(NULL, modname, sizeof(modname)); + + scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + if (!scm) + { + printf("Unable to open service control manager: %s\n", dlerror()); + return; + } + + myService = CreateService(scm,"InspIRCd","Inspire IRC Daemon", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, modname, 0, 0, 0, NULL, NULL); + + if (!myService) + { + printf("Unable to create service: %s\n", dlerror()); + CloseServiceHandle(scm); + return; + } + + // *** Set service description *** + // this is supported from 5.0 (win2k) onwards only, so we can't link to the definition of + // this function in advapi32.lib, otherwise the program will not run on windows NT 4. We + // must use LoadLibrary and GetProcAddress to export the function name from advapi32.dll + advapi32 = LoadLibrary("advapi32.dll"); + if (advapi32) + { + ChangeServiceConf = (SETSERVDESC)GetProcAddress(advapi32,"ChangeServiceConfig2A"); + if (ChangeServiceConf) + { + char desc[] = "The Inspire Internet Relay Chat Daemon hosts IRC channels and conversations.\ + If this service is stopped, the IRC server will not run."; + svDesc.lpDescription = desc; + BOOL success = ChangeServiceConf(myService,SERVICE_CONFIG_DESCRIPTION, &svDesc); + if (!success) + { + printf("Unable to set service description: %s\n", dlerror()); + CloseServiceHandle(myService); + CloseServiceHandle(scm); + return; + } + } + FreeLibrary(advapi32); + } + + printf("Service installed.\n"); + CloseServiceHandle(myService); + CloseServiceHandle(scm); +} + +/** Remove the windows service. This requires administrator privileges. */ +void RemoveService() +{ + SC_HANDLE myService, scm; + + scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + if (!scm) + { + printf("Unable to open service control manager: %s\n", dlerror()); + return; + } + + myService = OpenService(scm,"InspIRCd",SERVICE_ALL_ACCESS); + if (!myService) + { + printf("Unable to open service: %s\n", dlerror()); + CloseServiceHandle(scm); + return; + } + + if (!DeleteService(myService)) + { + printf("Unable to delete service: %s\n", dlerror()); + CloseServiceHandle(myService); + CloseServiceHandle(scm); + return; + } + + printf("Service removed.\n"); + CloseServiceHandle(myService); + CloseServiceHandle(scm); +} + +/* In windows, our main() flows through here, before calling the 'real' main, smain() in inspircd.cpp */ +int main(int argc, char** argv) +{ + /* List of parameters and handlers */ + Commandline params[] = { + { "--installservice", InstallService }, + { "--removeservice", RemoveService }, + { NULL } + }; + + /* Check for parameters */ + if (argc > 1) + { + for (int z = 0; params[z].Switch; ++z) + { + if (!_stricmp(argv[1], params[z].Switch)) + { + params[z].Handler(); + return 0; + } + } + } + + /* First, check if the service is installed. + * if it is not, or we're starting as non-administrator, + * just call smain() and start as normal non-service + * process. + */ + SC_HANDLE myService, scm; + scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + if (scm) + { + myService = OpenService(scm,"InspIRCd",SERVICE_ALL_ACCESS); + if (!myService) + { + /* Service not installed or no permission to modify it */ + CloseServiceHandle(scm); + return smain(argc, argv); + } + } + else + { + /* Not enough privileges to open the SCM */ + return smain(argc, argv); + } + + CloseServiceHandle(myService); + CloseServiceHandle(scm); + + /* Check if the process is running interactively. InspIRCd does not run interactively + * as a service so if this is true, we just run the non-service inspircd. + */ + USEROBJECTFLAGS uoflags; + HWINSTA winstation = GetProcessWindowStation(); + if (GetUserObjectInformation(winstation, UOI_FLAGS, &uoflags, sizeof(uoflags), NULL)) + { + if (uoflags.dwFlags == WSF_VISIBLE) + return smain(argc, argv); + } + + /* If we get here, we know the service is installed so we can start it */ + + SERVICE_TABLE_ENTRY serviceTable[] = + { + {"InspIRCd", (LPSERVICE_MAIN_FUNCTION) ServiceMain }, + {NULL, NULL} + }; + + StartServiceCtrlDispatcher(serviceTable); + return 0; +} |