diff options
-rw-r--r-- | src/inspircd.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_xline_db.cpp | 66 | ||||
-rw-r--r-- | win/inspircd_win32wrapper.cpp | 22 | ||||
-rw-r--r-- | win/inspircd_win32wrapper.h | 15 | ||||
-rw-r--r-- | win/win32service.cpp | 442 | ||||
-rw-r--r-- | win/win32service.h | 7 |
6 files changed, 237 insertions, 317 deletions
diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 9c13887a1..a67d24a6d 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -427,7 +427,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : }; int index; - while ((c = getopt_long(argc, argv, ":f:", longopts, &index)) != -1) + while ((c = getopt_long(argc, argv, ":c:f:", longopts, &index)) != -1) { switch (c) { diff --git a/src/modules/m_xline_db.cpp b/src/modules/m_xline_db.cpp index 404bc6b02..5e83478c3 100644 --- a/src/modules/m_xline_db.cpp +++ b/src/modules/m_xline_db.cpp @@ -27,16 +27,11 @@ class ModuleXLineDB : public Module { - std::vector<XLine *> xlines; - bool reading_db; // If this is true, addlines are as a result of db reading, so don't bother flushing the db to disk. - // DO REMEMBER TO SET IT, otherwise it's annoying :P + bool dirty; std::string xlinedbpath; public: void init() { - Implementation eventlist[] = { I_OnAddLine, I_OnDelLine, I_OnExpireLine }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - /* Load the configuration * Note: * this is on purpose not in the OnRehash() method. It would be non-trivial to change the database on-the-fly. @@ -45,10 +40,13 @@ class ModuleXLineDB : public Module */ ConfigTag* Conf = ServerInstance->Config->ConfValue("xlinedb"); xlinedbpath = Conf->getString("filename", DATA_PATH "/xline.db"); - - reading_db = true; + + // Read xlines before attaching to events ReadDatabase(); - reading_db = false; + + Implementation eventlist[] = { I_OnAddLine, I_OnDelLine, I_OnExpireLine, I_OnBackgroundTimer }; + ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); + dirty = false; } virtual ~ModuleXLineDB() @@ -62,13 +60,7 @@ class ModuleXLineDB : public Module */ void OnAddLine(User* source, XLine* line) { - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Adding a line"); - xlines.push_back(line); - - if (!reading_db) - { - WriteDatabase(); - } + dirty = true; } /** Called whenever an xline is deleted. @@ -78,27 +70,21 @@ class ModuleXLineDB : public Module */ void OnDelLine(User* source, XLine* line) { - RemoveLine(line); + dirty = true; } void OnExpireLine(XLine *line) { - RemoveLine(line); + dirty = true; } - void RemoveLine(XLine *line) + void OnBackgroundTimer(time_t now) { - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Removing a line"); - for (std::vector<XLine *>::iterator i = xlines.begin(); i != xlines.end(); i++) + if (dirty) { - if ((*i) == line) - { - xlines.erase(i); - break; - } + if (WriteDatabase()) + dirty = false; } - - WriteDatabase(); } bool WriteDatabase() @@ -133,12 +119,19 @@ class ModuleXLineDB : public Module fprintf(f, "VERSION 1\n"); // Now, let's write. - XLine *line; - for (std::vector<XLine *>::iterator i = xlines.begin(); i != xlines.end(); i++) + std::vector<std::string> types = ServerInstance->XLines->GetAllTypes(); + for (std::vector<std::string>::const_iterator it = types.begin(); it != types.end(); ++it) { - line = (*i); - fprintf(f, "LINE %s %s %s %lu %lu :%s\n", line->type.c_str(), line->Displayable(), - ServerInstance->Config->ServerName.c_str(), (unsigned long)line->set_time, (unsigned long)line->duration, line->reason.c_str()); + XLineLookup* lookup = ServerInstance->XLines->GetAll(*it); + if (!lookup) + continue; // Not possible as we just obtained the list from XLineManager + + for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) + { + XLine* line = i->second; + fprintf(f, "LINE %s %s %s %lu %lu :%s\n", line->type.c_str(), line->Displayable(), + ServerInstance->Config->ServerName.c_str(), (unsigned long)line->set_time, (unsigned long)line->duration, line->reason.c_str()); + } } ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Finished writing XLines. Checking for error.."); @@ -176,7 +169,6 @@ class ModuleXLineDB : public Module { FILE *f; char linebuf[MAXBUF]; - unsigned int lineno = 0; f = fopen(xlinedbpath.c_str(), "r"); if (!f) @@ -208,16 +200,14 @@ class ModuleXLineDB : public Module c++; } - // Smart man might think of initing to 1, and moving this to the bottom. Don't. We use continue in this loop. - lineno++; // Inspired by the command parser. :) irc::tokenstream tokens(linebuf); int items = 0; - std::string command_p[MAXPARAMETERS]; + std::string command_p[7]; std::string tmp; - while (tokens.GetToken(tmp) && (items < MAXPARAMETERS)) + while (tokens.GetToken(tmp) && (items < 7)) { command_p[items] = tmp; items++; diff --git a/win/inspircd_win32wrapper.cpp b/win/inspircd_win32wrapper.cpp index a451dd0df..ebc498529 100644 --- a/win/inspircd_win32wrapper.cpp +++ b/win/inspircd_win32wrapper.cpp @@ -180,6 +180,28 @@ int getopt_long(int ___argc, char *const *___argv, const char *__shortopts, cons return 1; } +CWin32Exception::CWin32Exception() : exception() +{ + dwErrorCode = GetLastError(); + if( FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szErrorString, _countof(szErrorString), NULL) == 0 ) + sprintf_s(szErrorString, _countof(szErrorString), "Error code: %u", dwErrorCode); +} + +CWin32Exception::CWin32Exception(const CWin32Exception& other) +{ + strcpy_s(szErrorString, _countof(szErrorString), other.szErrorString); +} + +const char* CWin32Exception::what() const throw() +{ + return szErrorString; +} + +DWORD CWin32Exception::GetErrorCode() +{ + return dwErrorCode; +} + #include "../src/modules/m_spanningtree/link.h" #include "../src/modules/ssl.h" template class reference<Link>; diff --git a/win/inspircd_win32wrapper.h b/win/inspircd_win32wrapper.h index d60276b88..75404ef8b 100644 --- a/win/inspircd_win32wrapper.h +++ b/win/inspircd_win32wrapper.h @@ -186,5 +186,20 @@ void ::operator delete(void * ptr); #define DISABLE_WRITEV +#include <exception> + +class CWin32Exception : public std::exception +{ +public: + CWin32Exception(); + CWin32Exception(const CWin32Exception& other); + virtual const char* what() const throw(); + DWORD GetErrorCode(); + +private: + char szErrorString[500]; + DWORD dwErrorCode; +}; + #endif diff --git a/win/win32service.cpp b/win/win32service.cpp index 0a4b0c5b4..c34e9957d 100644 --- a/win/win32service.cpp +++ b/win/win32service.cpp @@ -21,159 +21,61 @@ #include "inspircd.h" #include "exitcodes.h" #include <windows.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> +#include <cstdlib> +#include <cstring> +#include <cstdio> #include <iostream> -static SERVICE_STATUS_HANDLE serviceStatusHandle; -static HANDLE hThreadEvent; -static HANDLE killServiceEvent; -static int serviceCurrentStatus; +static SERVICE_STATUS_HANDLE g_ServiceStatusHandle; +static SERVICE_STATUS g_ServiceStatus; +static bool g_bRunningAsService; -/** 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); - -BOOL UpdateSCMStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint, DWORD dwWaitHint); -void terminateService(int code, int wincode); - -/* 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; +struct Service_Data { + DWORD argc; + LPSTR *argv; }; -/* A function pointer for dynamic linking tricks */ -SETSERVDESC ChangeServiceConf; - -LPCSTR RetrieveLastError() -{ - static char err[100]; - DWORD LastError = GetLastError(); - if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, LastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)err, sizeof(err), 0) == 0) - snprintf(err, sizeof(err), "Error code: %d", LastError); - SetLastError(ERROR_SUCCESS); - return err; -} - -/* Returns true if this program is running as a service, false if it is running interactive */ -bool IsAService() -{ - USEROBJECTFLAGS uoflags; - HWINSTA winstation = GetProcessWindowStation(); - if (GetUserObjectInformation(winstation, UOI_FLAGS, &uoflags, sizeof(uoflags), NULL)) - return ((uoflags.dwFlags & WSF_VISIBLE) == 0); - else - return false; -} - -/* Kills the service by setting an event which the other thread picks up and exits */ -void KillService() -{ - SetEvent(hThreadEvent); - Sleep(2000); - SetEvent(killServiceEvent); -} +static Service_Data g_ServiceData; /** 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) +DWORD WINAPI WorkerThread(LPVOID param) { - char modname[MAX_PATH]; - GetModuleFileNameA(NULL, modname, sizeof(modname)); - char* argv[] = { modname, "--nofork" }; - smain(2, argv); - KillService(); + smain(g_ServiceData.argc, g_ServiceData.argv); return 0; } /* This is called when all startup is done */ void SetServiceRunning() { - if (!IsAService()) + if (!g_bRunningAsService) return; - serviceCurrentStatus = SERVICE_RUNNING; - BOOL success = UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0); - if (!success) - { - terminateService(EXIT_STATUS_UPDATESCM_FAILED, GetLastError()); - return; - } -} + g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; + g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; - -/** Starts the worker thread above */ -void StartServiceThread() -{ - HANDLE hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WorkerThread,NULL,0,NULL); - if (hThread != NULL) - CloseHandle(hThread); + if( !SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ) ) + throw CWin32Exception(); } -/** 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) +/* In windows we hook this to InspIRCd::Exit() */ +void SetServiceStopped(DWORD dwStatus) { - 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 (!g_bRunningAsService) + return; - if (dwServiceSpecificExitCode == 0) + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + if(dwStatus != EXIT_STATUS_NOERROR) { - serviceStatus.dwWin32ExitCode = dwWin32ExitCode; + g_ServiceStatus.dwServiceSpecificExitCode = dwStatus; + g_ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; } else { - serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; + g_ServiceStatus.dwWin32ExitCode = ERROR_SUCCESS; } - 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; -} - -/* In windows we hook this to InspIRCd::Exit() */ -void SetServiceStopped(int status) -{ - if (!IsAService()) - exit(status); - - /* Are we running as a service? If so, trigger the service specific exit code */ - terminateService(status, 0); - KillService(); - exit(status); + SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ); } /** This callback is called by windows when the state of the service has been changed */ @@ -181,213 +83,205 @@ 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; + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ); + 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) +VOID ServiceMain(DWORD argc, LPCSTR *argv) { - BOOL success; + g_ServiceStatusHandle = RegisterServiceCtrlHandler(TEXT("InspIRCd"), (LPHANDLER_FUNCTION)ServiceCtrlHandler); + if( !g_ServiceStatusHandle ) + return; - serviceStatusHandle = RegisterServiceCtrlHandler(TEXT("InspIRCd"), (LPHANDLER_FUNCTION)ServiceCtrlHandler); - if (!serviceStatusHandle) - { - terminateService(EXIT_STATUS_RSCH_FAILED, GetLastError()); + g_ServiceStatus.dwCheckPoint = 1; + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + g_ServiceStatus.dwWaitHint = 5000; + g_ServiceStatus.dwWin32ExitCode = NO_ERROR; + g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + + if( !SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ) ) return; - } - success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 1, 1000); - if (!success) + char szModuleName[MAX_PATH]; + if(GetModuleFileNameA(NULL, szModuleName, MAX_PATH)) { - terminateService(EXIT_STATUS_UPDATESCM_FAILED, GetLastError()); - return; - } + if(!argc) + argc = 1; - killServiceEvent = CreateEvent(NULL, true, false, NULL); - hThreadEvent = CreateEvent(NULL, true, false, NULL); + g_ServiceData.argc = argc; - if (!killServiceEvent || !hThreadEvent) - { - terminateService(EXIT_STATUS_CREATE_EVENT_FAILED, GetLastError()); - return; - } + // Note: since this memory is going to stay allocated for the rest of the execution, + // it doesn't make sense to free it, as it's going to be "freed" on process termination + try { + g_ServiceData.argv = new char*[argc]; - success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000); - if (!success) - { - terminateService(EXIT_STATUS_UPDATESCM_FAILED, GetLastError()); - return; + uint32_t allocsize = strnlen_s(szModuleName, MAX_PATH) + 1; + g_ServiceData.argv[0] = new char[allocsize]; + strcpy_s(g_ServiceData.argv[0], allocsize, szModuleName); + + for(uint32_t i = 1; i < argc; i++) + { + allocsize = strnlen_s(argv[i], MAX_PATH) + 1; + g_ServiceData.argv[i] = new char[allocsize]; + strcpy_s(g_ServiceData.argv[i], allocsize, argv[i]); + } + + *(strrchr(szModuleName, '\\') + 1) = NULL; + SetCurrentDirectoryA(szModuleName); + + HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkerThread, NULL, 0, NULL); + if (hThread != NULL) + { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + } + } + catch(...) + { + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + g_ServiceStatus.dwWin32ExitCode = ERROR_OUTOFMEMORY; + SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ); + } } + if(g_ServiceStatus.dwCurrentState == SERVICE_STOPPED) + return; - StartServiceThread(); - WaitForSingleObject (killServiceEvent, INFINITE); + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + g_ServiceStatus.dwWin32ExitCode = GetLastError(); + SetServiceStatus( g_ServiceStatusHandle, &g_ServiceStatus ); } /** Install the windows service. This requires administrator privileges. */ void InstallService() { - SC_HANDLE myService, scm; - SERVICE_DESCRIPTION svDesc; - HINSTANCE advapi32; + SC_HANDLE InspServiceHandle = 0, SCMHandle = 0; - TCHAR modname[MAX_PATH]; - GetModuleFileName(NULL, modname, sizeof(modname)); + try { + TCHAR tszBinaryPath[MAX_PATH]; + if(!GetModuleFileName(NULL, tszBinaryPath, _countof(tszBinaryPath))) + { + throw CWin32Exception(); + } - scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); - if (!scm) - { - std::cout << "Unable to open service control manager: " << RetrieveLastError() << std::endl; - return; - } + SCMHandle = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); + if (!SCMHandle) + { + throw CWin32Exception(); + } - myService = CreateService(scm,TEXT("InspIRCd"),TEXT("Inspire IRC Daemon"), SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, - SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, modname, 0, 0, 0, NULL, NULL); + InspServiceHandle = CreateService(SCMHandle, TEXT("InspIRCd"),TEXT("InspIRCd Daemon"), SERVICE_CHANGE_CONFIG, SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, tszBinaryPath, 0, 0, 0, TEXT("NT AUTHORITY\\NetworkService"), NULL); - if (!myService) - { - std::cout << "Unable to create service: " << RetrieveLastError() << std::endl; - CloseServiceHandle(scm); - return; - } + if (!InspServiceHandle) + { + throw CWin32Exception(); + } - // *** 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(TEXT("advapi32.dll")); - if (advapi32) - { - ChangeServiceConf = (SETSERVDESC)GetProcAddress(advapi32,"ChangeServiceConfig2A"); - if (ChangeServiceConf) + TCHAR tszDescription[] = TEXT("The InspIRCd service hosts IRC channels and conversations. If this service is stopped, the IRC server will be unavailable."); + SERVICE_DESCRIPTION svDescription = { tszDescription }; + if(!ChangeServiceConfig2(InspServiceHandle, SERVICE_CONFIG_DESCRIPTION, &svDescription)) { - TCHAR desc[] = TEXT("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) - { - std::cout << "Unable to set service description: " << RetrieveLastError() << std::endl; - CloseServiceHandle(myService); - CloseServiceHandle(scm); - return; - } + throw CWin32Exception(); } - FreeLibrary(advapi32); + + CloseServiceHandle(InspServiceHandle); + CloseServiceHandle(SCMHandle); + std::cout << "Service installed." << std::endl; } + catch(CWin32Exception e) + { + if(InspServiceHandle) + CloseServiceHandle(InspServiceHandle); + + if(SCMHandle) + CloseServiceHandle(SCMHandle); - std::cout << "Service installed." << std::endl; - CloseServiceHandle(myService); - CloseServiceHandle(scm); + std::cout << "Service installation failed: " << e.what() << std::endl; + } } /** Remove the windows service. This requires administrator privileges. */ -void RemoveService() +void UninstallService() { - SC_HANDLE myService, scm; + SC_HANDLE InspServiceHandle = 0, SCMHandle = 0; - scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); - if (!scm) + try { - std::cout << "Unable to open service control manager: " << RetrieveLastError() << std::endl; - return; - } + SCMHandle = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, DELETE); + if (!SCMHandle) + throw CWin32Exception(); - myService = OpenService(scm,TEXT("InspIRCd"),SERVICE_ALL_ACCESS); - if (!myService) - { - std::cout << "Unable to open service: " << RetrieveLastError() << std::endl; - CloseServiceHandle(scm); - return; - } + InspServiceHandle = OpenService(SCMHandle, TEXT("InspIRCd"), DELETE); + if (!InspServiceHandle) + throw CWin32Exception(); - if (!DeleteService(myService)) - { - std::cout << "Unable to delete service: " << RetrieveLastError() << std::endl; - CloseServiceHandle(myService); - CloseServiceHandle(scm); - return; + if (!DeleteService(InspServiceHandle) && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) + { + throw CWin32Exception(); + } + + CloseServiceHandle(InspServiceHandle); + CloseServiceHandle(SCMHandle); + std::cout << "Service removed." << std::endl; } + catch(CWin32Exception e) + { + if(InspServiceHandle) + CloseServiceHandle(InspServiceHandle); + + if(SCMHandle) + CloseServiceHandle(SCMHandle); - std::cout << "Service removed." << std::endl; - CloseServiceHandle(myService); - CloseServiceHandle(scm); + std::cout << "Service deletion failed: " << e.what() << std::endl; + } } /* In windows, our main() flows through here, before calling the 'real' main, smain() in inspircd.cpp */ -int main(int argc, char** argv) +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) + for (int i = 1; i < argc; i++) { - if (!_stricmp(argv[1], params[z].Switch)) + if(!_stricmp(argv[i], "--installservice")) + { + InstallService(); + return 0; + } + if(!_stricmp(argv[i], "--uninstallservice") || !_stricmp(argv[i], "--removeservice")) { - params[z].Handler(); + UninstallService(); 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) + SERVICE_TABLE_ENTRY serviceTable[] = { - myService = OpenService(scm,TEXT("InspIRCd"),SERVICE_ALL_ACCESS); - if (!myService) + { TEXT("InspIRCd"), (LPSERVICE_MAIN_FUNCTION)ServiceMain }, + { NULL, NULL } + }; + + g_bRunningAsService = true; + if( !StartServiceCtrlDispatcher(serviceTable) ) + { + // This error means that the program was not started as service. + if( GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ) { - /* Service not installed or no permission to modify it */ - CloseServiceHandle(scm); + g_bRunningAsService = false; return smain(argc, argv); } + else + { + return EXIT_STATUS_INTERNAL; + } } - 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. - */ - if (!IsAService()) - return smain(argc, argv); - - /* If we get here, we know the service is installed so we can start it */ - - SERVICE_TABLE_ENTRY serviceTable[] = - { - {TEXT("InspIRCd"), (LPSERVICE_MAIN_FUNCTION) ServiceMain }, - {NULL, NULL} - }; - - StartServiceCtrlDispatcher(serviceTable); return 0; } diff --git a/win/win32service.h b/win/win32service.h index b33a53c28..e4500be13 100644 --- a/win/win32service.h +++ b/win/win32service.h @@ -15,12 +15,11 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef WIN32SERVICE_H -#define WIN32SERVICE_H +#pragma once +#ifdef _WIN32 /* Hook for win32service.cpp to exit properly with the service specific error code */ -void SetServiceStopped(int status); +void SetServiceStopped(unsigned long dwStatus); /* Marks the service as running, not called until the config is parsed */ void SetServiceRunning(); |