]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
add support for windows service. This now is part of inspircd itself being as we...
authorbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>
Thu, 21 Aug 2008 11:01:51 +0000 (11:01 +0000)
committerbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>
Thu, 21 Aug 2008 11:01:51 +0000 (11:01 +0000)
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@10193 e03df62e-2008-0410-955e-edbf42e46eb7

configure
include/inspircd.h
src/inspircd.cpp
win/inspircdVC80.vcproj
win/inspircd_win32wrapper.h
win/win32service.cpp [new file with mode: 0644]

index e47512a9717308530d758c4944cc93c7da55a4ff..616ebfea790f42ddd5db34bae4b7a6865959ee4b 100755 (executable)
--- a/configure
+++ b/configure
@@ -1159,6 +1159,7 @@ sub writefiles {
 #define OPTIMISATION $config{OPTIMITEMP}
 #define LIBRARYDIR "$config{LIBRARY_DIR}"
 #define SYSTEM "$incos"
+#define ENTRYPOINT int main(int argc, char** argv)
 
 EOF
 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
index 50dc5c73bbdd3ccfd3ac0e540b255909cb5ac9e8..81a9f3cbea274b9d81d405a29fcde87c99449471 100644 (file)
@@ -911,4 +911,6 @@ class CoreExport InspIRCd : public classbase
        }
 };
 
+ENTRYPOINT;
+
 #endif
index 8d3a8fc276c933530b1e60c12a7152d735ed1635..e2ed1282ceab55bfc111c3d18498aef0369925ac 100644 (file)
@@ -867,7 +867,7 @@ void InspIRCd::BufferedSocketCull()
  * An ircd in five lines! bwahahaha. ahahahahaha. ahahah *cough*.
  */
 
-int main(int argc, char ** argv)
+ENTRYPOINT
 {
        SI = new InspIRCd(argc, argv);
        mysig = &SI->s_signal;
index 3ddddf8bc95e34f5f97cc59a860168fadd1728e9..263c597ff20f9ef77ac49b4b31a3778238aa747c 100644 (file)
                                RelativePath="..\src\wildcard.cpp"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\win32service.cpp"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="..\src\xline.cpp"\r
                                >\r
index 6008828393eacccd5fa17e2459ba846846cbdb96..94f799c189829a7a8912b7e7dbb2fc4bb12d8ca9 100644 (file)
@@ -55,6 +55,9 @@
 #define DllExport __declspec(dllimport)
 #endif
 
+/* Redirect main() through a different method in win32service.cpp, to intercept service startup */
+#define ENTRYPOINT CoreExport int smain(int argc, char** argv)
+
 /* Disable the deprecation warnings.. it spams :P */
 #define _CRT_SECURE_NO_DEPRECATE
 #define _SCL_SECURE_NO_DEPRECATE
diff --git a/win/win32service.cpp b/win/win32service.cpp
new file mode 100644 (file)
index 0000000..100afba
--- /dev/null
@@ -0,0 +1,295 @@
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */\r
+\r
+#include <windows.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+extern int smain(int argc, char** argv);\r
+\r
+static SERVICE_STATUS_HANDLE serviceStatusHandle;\r
+static HANDLE hThreadEvent;\r
+static HANDLE killServiceEvent;\r
+static int serviceCurrentStatus;\r
+\r
+// This is used to define ChangeServiceConf2() as we can't link\r
+// directly against this symbol (see below where it is used)\r
+typedef BOOL (CALLBACK* SETSERVDESC)(SC_HANDLE,DWORD,LPVOID);\r
+\r
+SETSERVDESC ChangeServiceConf;         // A function pointer for dynamic linking tricks\r
+\r
+\r
+void KillService()\r
+{\r
+       /* FIXME: This should set a flag in the mainloop for shutting down */\r
+       SetEvent(hThreadEvent);\r
+       Sleep(2000);\r
+       SetEvent(killServiceEvent);\r
+}\r
+\r
+DWORD WINAPI WorkerThread(LPDWORD param)\r
+{\r
+       // *** REAL MAIN HERE ***\r
+       char modname[MAX_PATH];\r
+       GetModuleFileName(NULL, modname, sizeof(modname));\r
+       char* argv[] = { modname, "--nofork" };\r
+       smain(1, argv);\r
+       KillService();\r
+       return 0;\r
+}\r
+\r
+void StartServiceThread()\r
+{\r
+       DWORD dwd;\r
+       CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WorkerThread,NULL,0,&dwd);\r
+}\r
+\r
+\r
+BOOL UpdateSCMStatus (DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint, DWORD dwWaitHint)\r
+{\r
+       BOOL success;\r
+       SERVICE_STATUS serviceStatus;\r
+       serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;\r
+       serviceStatus.dwCurrentState = dwCurrentState;\r
+\r
+       if (dwCurrentState == SERVICE_START_PENDING)\r
+       {\r
+               serviceStatus.dwControlsAccepted = 0;\r
+       }\r
+       else\r
+       {\r
+               serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;\r
+       }\r
+\r
+       if (dwServiceSpecificExitCode == 0)\r
+       {\r
+               serviceStatus.dwWin32ExitCode = dwWin32ExitCode;\r
+       }\r
+       else\r
+       {\r
+               serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;\r
+       }\r
+       serviceStatus.dwServiceSpecificExitCode =   dwServiceSpecificExitCode;\r
+       serviceStatus.dwCheckPoint = dwCheckPoint;\r
+       serviceStatus.dwWaitHint = dwWaitHint;\r
+\r
+       success = SetServiceStatus (serviceStatusHandle, &serviceStatus);\r
+       if (!success)\r
+       {\r
+               KillService();\r
+       }\r
+       return success;\r
+}\r
+\r
+\r
+void terminateService (int code, int wincode)\r
+{\r
+       UpdateSCMStatus(SERVICE_STOPPED,wincode?wincode:ERROR_SERVICE_SPECIFIC_ERROR,(wincode)?0:code,0,0);\r
+       return;\r
+}\r
+\r
+\r
+VOID ServiceCtrlHandler (DWORD controlCode)\r
+{\r
+       switch(controlCode)\r
+       {\r
+               case SERVICE_CONTROL_INTERROGATE:\r
+               break;\r
+               case SERVICE_CONTROL_SHUTDOWN:\r
+               case SERVICE_CONTROL_STOP:\r
+                       serviceCurrentStatus = SERVICE_STOP_PENDING;\r
+                       UpdateSCMStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);\r
+                       KillService();\r
+                       UpdateSCMStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0);\r
+                       return;\r
+               default:\r
+               break;\r
+       }\r
+       UpdateSCMStatus(serviceCurrentStatus, NO_ERROR, 0, 0, 0);\r
+}\r
+\r
+\r
+VOID ServiceMain(DWORD argc, LPTSTR *argv)\r
+{\r
+       BOOL success;\r
+       DWORD type=0, size=0;\r
+\r
+       serviceStatusHandle = RegisterServiceCtrlHandler("InspIRCd", (LPHANDLER_FUNCTION)ServiceCtrlHandler);\r
+       if (!serviceStatusHandle)\r
+       {\r
+               terminateService(1,GetLastError());\r
+               return;\r
+       }\r
+\r
+       success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 1, 1000);\r
+       if (!success)\r
+       {\r
+               terminateService(2,GetLastError());\r
+               return;\r
+       }\r
+\r
+       killServiceEvent = CreateEvent(NULL,true,false,NULL);\r
+       hThreadEvent = CreateEvent(NULL,true,false,NULL);\r
+\r
+       if (!killServiceEvent || !hThreadEvent)\r
+       {\r
+               terminateService(99,GetLastError());\r
+               return;\r
+       }\r
+\r
+       success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000);\r
+       if (!success)\r
+       {\r
+               terminateService(2,GetLastError());\r
+               return;\r
+       }\r
+\r
+       StartServiceThread();\r
+       serviceCurrentStatus = SERVICE_RUNNING;\r
+       success = UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);\r
+       if (!success)\r
+       {\r
+               terminateService(6,GetLastError());\r
+               return;\r
+       }\r
+       WaitForSingleObject (killServiceEvent, INFINITE);\r
+}\r
+\r
+void InstallService(void)\r
+{\r
+       SC_HANDLE myService, scm;\r
+       SERVICE_DESCRIPTION svDesc;\r
+       HINSTANCE advapi32;\r
+\r
+       char modname[MAX_PATH];\r
+       GetModuleFileName(NULL, modname, sizeof(modname));\r
+\r
+       scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);\r
+       if (!scm)\r
+               return;\r
+\r
+       myService = CreateService(scm,"InspIRCd","Inspire IRC Daemon", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, modname, 0, 0, 0, 0, 0);\r
+\r
+       if (!myService)\r
+       {\r
+               CloseServiceHandle(scm);\r
+               return;\r
+       }\r
+\r
+       // *** Set service description ***\r
+       // this is supported from 5.0 (win2k) onwards only, so we can't link to the definition of\r
+       // this function in advapi32.lib, otherwise the program will not run on windows NT 4. We\r
+       // must use LoadLibrary and GetProcAddress to export the function name from advapi32.dll\r
+       advapi32 = LoadLibrary("advapi32.dll");\r
+       if (advapi32)\r
+       {\r
+               ChangeServiceConf = (SETSERVDESC)GetProcAddress(advapi32,"ChangeServiceConfig2A");\r
+               if (ChangeServiceConf)\r
+               {\r
+                       char desc[] = "The Inspire Internet Relay Chat Daemon hosts IRC channels and conversations. \\r
+                                     If this service is stopped, the IRC server will not run.";\r
+                       svDesc.lpDescription = desc;\r
+                       BOOL success = ChangeServiceConf(myService,SERVICE_CONFIG_DESCRIPTION, &svDesc);\r
+                       if (!success)\r
+                       {\r
+                               CloseServiceHandle(myService);\r
+                               CloseServiceHandle(scm);\r
+                               return;\r
+                       }\r
+               }\r
+               FreeLibrary(advapi32);\r
+       }\r
+\r
+       CloseServiceHandle(myService);\r
+       CloseServiceHandle(scm);\r
+}\r
+\r
+void RemoveService(void)\r
+{\r
+       SC_HANDLE myService, scm;\r
+\r
+       scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);\r
+       if (!scm)\r
+               return;\r
+\r
+       myService = OpenService(scm,"InspIRCd",SERVICE_ALL_ACCESS);\r
+       if (!myService)\r
+       {\r
+               CloseServiceHandle(scm);\r
+               return;\r
+       }\r
+\r
+       if (!DeleteService(myService))\r
+       {\r
+               CloseServiceHandle(myService);\r
+               CloseServiceHandle(scm);\r
+               return;\r
+       }\r
+\r
+       CloseServiceHandle(myService);\r
+       CloseServiceHandle(scm);\r
+}\r
+\r
+/* In windows, our main() flows through here, before calling the 'real' main, smain() in inspircd.cpp */\r
+int main(int argc, char** argv)\r
+{\r
+       /* Check for parameters */\r
+       /*if (argc > 0)\r
+       {\r
+               if (!_stricmp(argv[1], "--installservice"))\r
+               {\r
+                       InstallService();\r
+                       return 0;\r
+               }\r
+               else if (!_stricmp(argv[1], "--removeservice"))\r
+               {\r
+                       RemoveService();\r
+                       return 0;\r
+               }\r
+       }*/\r
+\r
+       /* First, check if the service is installed.\r
+        * if it is not, just call smain().\r
+        */\r
+       SC_HANDLE myService, scm;\r
+       scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);\r
+       if (scm)\r
+       {\r
+               myService = OpenService(scm,"InspIRCd",SERVICE_ALL_ACCESS);\r
+               if (!myService)\r
+               {\r
+                       /* Service not installed or no permission to modify it */\r
+                       CloseServiceHandle(scm);\r
+                       smain(argc, argv);\r
+               }\r
+       }\r
+       else\r
+       {\r
+               /* Not enough privileges to open the SCM */\r
+               smain(argc, argv);\r
+       }\r
+\r
+       CloseServiceHandle(myService);\r
+       CloseServiceHandle(scm);\r
+\r
+       /* If we get here, we know the service is installed so we can start it */\r
+\r
+       SERVICE_TABLE_ENTRY serviceTable[] =\r
+       {\r
+               {"InspIRCd", (LPSERVICE_MAIN_FUNCTION) ServiceMain },\r
+               {NULL, NULL}\r
+       };\r
+\r
+       StartServiceCtrlDispatcher(serviceTable);\r
+       return 0;\r
+}\r