]> git.pond.sub.org Git - empserver/commitdiff
(main,close_files,loc_NT_Term,empth_exit):
authorRon Koenderink <rkoenderink@yahoo.ca>
Tue, 21 Dec 2004 03:10:30 +0000 (03:10 +0000)
committerRon Koenderink <rkoenderink@yahoo.ca>
Tue, 21 Dec 2004 03:10:30 +0000 (03:10 +0000)
Add Windows Service to the server.
This includes adding install service and remove service option.
Move the start code from main to separate function.
Make close_files() and loc_NT_Term() global.
Move disassoc() to be earlier in the startup sequence.

include/prototypes.h
include/service.h [new file with mode: 0644]
src/lib/empthread/ntthread.c
src/lib/gen/Makefile
src/lib/gen/service.c [new file with mode: 0644]
src/server/main.c

index 3df917ca95fd0a7fa67fbd3406ed7423b143529f..3caf3ba60d4f0e28c6bec82cbc665cc442544016 100644 (file)
 #include "commodity.h"
 
 /* src/server/main.c */
+extern void close_files(void);
 extern void panic(int sig);
 extern void shutdwn(int sig);
+extern void start_server(int, char *);
+#if defined(_WIN32)
+extern void loc_NTTerm(void);
+#endif
 
 /*****************************************************************************
  * src/lib/ * / *.c 
@@ -270,6 +275,10 @@ extern int command(void);
 /* recvclient.c */
 extern int recvclient(s_char *, int);
 
+/* service.c */
+extern int service_stopped(void);
+/* more in service.h */
+
 /*
  * src/lib/subs/ *.c 
  */
diff --git a/include/service.h b/include/service.h
new file mode 100644 (file)
index 0000000..b31d986
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  Empire - A multi-player, client/server Internet based war game.
+ *  Copyright (C) 1986-2004, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *                           Ken Stevens, Steve McClure
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  ---
+ *
+ *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
+ *  related information and legal notices. It is expected that any future
+ *  projects/authors will amend these files as needed.
+ *
+ *  ---
+ *
+ *  server.h: Windows services support
+ * 
+ *  Known contributors to this file:
+ *     Ron Koenderink, 2004
+ */
+
+#ifndef SERVICE_H
+#define SERVICE_H
+
+extern int install_service(char *program_name);
+extern int remove_service(void);
+extern void WINAPI service_main(DWORD argc, LPTSTR *argv);
+#endif
index 0d3f66bbef938e962807d7d23d1c6482faee9c58..5ef4ae4eccb866859d2969c2a395e28ee014d952 100644 (file)
@@ -468,13 +468,19 @@ empth_exit(void)
     loc_debug("empth_exit");
 
     if (pThread->bMainThread) {
-       char buf[20];
        /* The main line.  Wait forever. */
        while (1) {
-           printf("\nEmpire Server>");
-           fgets(buf, sizeof(buf), stdin);
-           if (!strnicmp(buf, "quit", 4))
-               shutdwn(0);
+           if (!debug) {
+               if (service_stopped())
+                   shutdwn(0);
+               Sleep(3);
+           } else {
+               char buf[20];
+               printf("\nEmpire Server>");
+               fgets(buf, sizeof(buf), stdin);
+               if (!strnicmp(buf, "quit", 4))
+                   shutdwn(0);
+           }
        }
     } else {
        TlsSetValue(loc_GVAR.dwTLSIndex, NULL);
index 98970838aaf809c82c9cdde53fc962c236c0678c..b5b6b285ac17aafb01417d5375069701dbd79c45 100644 (file)
@@ -45,7 +45,7 @@ NTOBJS = chance.obj copy.obj disassoc.obj \
        emp_config.obj getstarg.obj getstring.obj \
        io.obj ioqueue.obj mapdist.obj minmax.obj \
        numstr.obj onearg.obj parse.obj plur.obj queue.obj round.obj \
-       scthash.obj strdup.obj getopt.obj
+       scthash.obj strdup.obj getopt.obj service.obj
 
 all: $(LIB)
 
diff --git a/src/lib/gen/service.c b/src/lib/gen/service.c
new file mode 100644 (file)
index 0000000..0bf8026
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ *  Empire - A multi-player, client/server Internet based war game.
+ *  Copyright (C) 1986-2004, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *                           Ken Stevens, Steve McClure
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  ---
+ *
+ *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
+ *  related information and legal notices. It is expected that any future
+ *  projects/authors will amend these files as needed.
+ *
+ *  ---
+ *
+ *  service.c: Windows services support
+ * 
+ *  Known contributors to this file:
+ *     Ron Koenderink, 2004
+ */
+
+#include <windows.h>
+#include <winsock.h>
+#include <process.h>
+#include <stdio.h>
+
+#include "prototypes.h"
+#include "service.h"
+#include "../gen/getopt.h"
+#include "optlist.h"
+
+#define SERVICE_NAME "Empire Server"
+
+int
+install_service(char *program_name)
+{
+    char strDir[1024];
+    HANDLE schSCManager,schService;
+    LPCTSTR lpszBinaryPathName;
+    SERVICE_DESCRIPTION sdBuf;
+
+    if (strrchr(program_name,'\\') == NULL) {
+       GetCurrentDirectory(1024,strDir);
+       strcat(strDir, "\\");
+       strcat(strDir, program_name);
+    } else
+       strcpy(strDir, program_name);
+
+    schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
+
+    if (schSCManager == NULL) {
+        logerror("install_service failed to open Service Control Manager"); 
+        printf("Install service: failed to open Service Control Manager.\n"); 
+       return EXIT_FAILURE;
+    }
+
+    lpszBinaryPathName = strDir;
+
+    schService = CreateService(schSCManager,
+       SERVICE_NAME,
+       SERVICE_NAME,                   /* service name to display */
+        SERVICE_ALL_ACCESS,            /* desired access */
+        SERVICE_WIN32_OWN_PROCESS,     /* service type */
+        SERVICE_AUTO_START,            /* start type */
+        SERVICE_ERROR_NORMAL,          /* error control type */
+        lpszBinaryPathName,            /* service's binary */
+        NULL,                          /* no load ordering group */
+        NULL,                          /* no tag identifier */
+        NULL,                          /* database service dependency */
+        NULL,                          /* LocalSystem account */
+        NULL);                         /* no password */
+    if (schService == NULL) {
+       logerror("install_service failed to create service");
+       printf("Install service: failed to create service.\n");
+        return EXIT_FAILURE;
+    }
+    sdBuf.lpDescription = "Server for Empire game";
+
+    if(!ChangeServiceConfig2(
+          schService,                 /* handle to service */
+          SERVICE_CONFIG_DESCRIPTION, /* change: description */
+          &sdBuf)) {                  /* value: new description */
+        logerror("install_service failed to set the description");
+        printf("Install service: failed to set the description.\n");
+    }
+
+    logerror("install_service successfully created the service");
+    printf("Service installed.\n");
+    CloseServiceHandle(schService);
+    return EXIT_SUCCESS;
+}
+
+int
+remove_service(void)
+{
+    HANDLE schSCManager;
+    SC_HANDLE hService;
+
+    schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
+
+    if (schSCManager == NULL) {
+        logerror("remove_service failed to open Service Control Manager"); 
+        printf("remove service: failed to open Service Control Manager.\n"); 
+       return EXIT_FAILURE;
+    }
+
+    hService = OpenService(schSCManager,SERVICE_NAME,SERVICE_ALL_ACCESS);
+
+    if (hService == NULL) {
+        logerror("remove_service failed to open service");
+        printf("Remove service: failed to open service.\n");
+       return EXIT_FAILURE;
+    }
+
+    if (DeleteService(hService) == 0) {
+        logerror("remove_service failed to remove service");
+        printf("Remove service: failed to remove service.\n"); 
+       return EXIT_FAILURE;
+    }
+
+    if (CloseServiceHandle(hService) == 0) {
+        logerror("remove_service failed to close service"); 
+        printf("Remove service: failed to close service.\n"); 
+        return EXIT_FAILURE;
+    } else {
+        logerror("remove_service successfully removed service");
+        printf("Service removed.\n"); 
+        return EXIT_SUCCESS;
+    }
+}
+
+static SERVICE_STATUS          service_status; 
+static SERVICE_STATUS_HANDLE   service_status_handle; 
+
+void WINAPI
+service_ctrl_handler(DWORD Opcode) 
+{ 
+    DWORD status; 
+    switch(Opcode) 
+    { 
+        case SERVICE_CONTROL_PAUSE: 
+            service_status.dwCurrentState = SERVICE_PAUSED;
+           logerror("Pausing the service not supported");
+            break; 
+        case SERVICE_CONTROL_CONTINUE: 
+           logerror("Continuing the service not supported");
+            service_status.dwCurrentState = SERVICE_RUNNING; 
+            break; 
+        case SERVICE_CONTROL_STOP: 
+            service_status.dwWin32ExitCode = 0; 
+            service_status.dwCurrentState  = SERVICE_STOPPED; 
+            service_status.dwCheckPoint    = 0; 
+            service_status.dwWaitHint      = 0; 
+            if (!SetServiceStatus (service_status_handle, 
+                &service_status)) { 
+                status = GetLastError(); 
+                logerror("Error while stopping service SetServiceStatus"
+                   " error %ld", status); 
+            } 
+            logerror("Service stopped"); 
+            return; 
+        case SERVICE_CONTROL_INTERROGATE: 
+        /* Fall through to send current status.  */
+            break; 
+        default: 
+            logerror("Unrecognized opcode %ld in ServiceCtrlHandler", 
+                Opcode); 
+    } 
+    /* Send current status. */
+    if (!SetServiceStatus (service_status_handle,  &service_status)) { 
+        status = GetLastError(); 
+        logerror("SetServiceStatus error %ld",status); 
+    } 
+    return; 
+} 
+
+void WINAPI
+service_main(DWORD argc, LPTSTR *argv)
+{ 
+    char *config_file = NULL;
+    int op;
+    s_char tbuf[256];
+    DWORD status;
+
+    while ((op = getopt(argc, argv, "D:e:")) != EOF) {
+       switch (op) {
+       case 'D':
+           datadir = optarg;
+           break;
+       case 'e':
+           config_file = optarg;
+           break;
+       }
+    }
+
+    if (config_file == NULL) {
+       sprintf(tbuf, "%s/econfig", datadir);
+       config_file = tbuf;
+    }
+
+    service_status.dwServiceType        = SERVICE_WIN32; 
+    service_status.dwCurrentState       = SERVICE_START_PENDING; 
+    service_status.dwControlsAccepted   = SERVICE_ACCEPT_STOP; 
+    service_status.dwWin32ExitCode      = 0; 
+    service_status.dwServiceSpecificExitCode = 0; 
+    service_status.dwCheckPoint         = 0; 
+    service_status.dwWaitHint           = 0; 
+    service_status_handle = RegisterServiceCtrlHandler(
+        SERVICE_NAME, service_ctrl_handler);
+    if (service_status_handle == (SERVICE_STATUS_HANDLE)0) { 
+        logerror("RegisterServiceCtrlHandler failed %d\n", GetLastError()); 
+        return; 
+    }
+    /* Initialization code goes here. */
+    start_server(0, config_file); 
+    /* Initialization complete - report running status. */
+    service_status.dwCurrentState       = SERVICE_RUNNING; 
+    service_status.dwCheckPoint         = 0; 
+    service_status.dwWaitHint           = 0; 
+    if (!SetServiceStatus (service_status_handle, &service_status)) { 
+        status = GetLastError();
+        logerror("SetServiceStatus error %ld\n",status);
+    }
+
+    empth_exit();
+
+/* We should never get here.  But, just in case... */
+    close_files();
+
+    loc_NTTerm();
+
+    // This is where the service does its work.
+    logerror("Returning the Main Thread \n",0);
+    return;
+}
+
+int
+service_stopped(void)
+{
+    if (service_status.dwCurrentState == SERVICE_STOPPED)
+       return 1;
+    else
+       return 0;
+}
index f7e76f52292a67434cc5cf44e14a3111e277bfa4..a3a3264f7c35da345e0f91e95b9ab3d03158b783 100644 (file)
@@ -49,6 +49,7 @@
 #include <winsock.h>
 #include <process.h>
 #include "../lib/gen/getopt.h"
+#include "service.h"
 #endif
 
 #include "misc.h"
 
 static void nullify_objects(void);
 static void init_files(void);
-static void close_files(void);
 
 #if defined(_WIN32)
 static void loc_NTInit(void);
-static void loc_NTTerm(void);
 #endif
 
 static int mainpid = 0;
@@ -89,7 +88,9 @@ static void
 print_usage(char *program_name)
 {
 #if defined(_WIN32)
-    printf("Usage: %s -D datadir -e config_file -d\n", program_name);
+    printf("Usage: %s -i -r -D datadir -e config_file -d\n", program_name);
+    printf("-i install service\n");
+    printf("-r remove service\n");
 #else
     printf("Usage: %s -D datadir -e config_file -d -p -s\n", program_name);
     printf("-p print flag\n");
@@ -102,25 +103,30 @@ int
 main(int argc, char **argv)
 {
     int flags = 0;
+#if defined(_WIN32)
+    int install_service_set = 0;
+    int remove_service_set = 0;
+    int datadir_set = 0;
+#endif
     int op;
     char *config_file = NULL;
     s_char tbuf[256];
-#ifdef POSIXSIGNALS
-    struct sigaction act;
-#endif /* POSIXSIGNALS */
 
     loginit("server");
 
     mainpid = getpid();
 
 #if defined(_WIN32)
-    while ((op = getopt(argc, argv, "D:de:h")) != EOF) {
+    while ((op = getopt(argc, argv, "D:de:irh")) != EOF) {
 #else
     while ((op = getopt(argc, argv, "D:de:psh")) != EOF) {
 #endif
        switch (op) {
        case 'D':
            datadir = optarg;
+#if defined(_WIN32)
+           datadir_set++;
+#endif
            break;
        case 'd':
            debug++;
@@ -128,7 +134,14 @@ main(int argc, char **argv)
        case 'e':
            config_file = optarg;
            break;
-#if !defined(_WIN32)
+#if defined(_WIN32)
+       case 'i':
+           install_service_set++;
+           break;
+       case 'r':
+           remove_service_set++;
+           break;
+#else
        case 'p':
            flags |= EMPTH_PRINT;
            break;
@@ -139,10 +152,31 @@ main(int argc, char **argv)
        case 'h':
        default:
            print_usage(argv[0]);
-           return 0;
+           return EXIT_FAILURE;
        }
     }
 
+#if defined(_WIN32)
+    if ((debug || datadir_set || config_file != NULL) &&
+       (install_service_set || remove_service_set)) {
+       logerror("Can't use -d or -D or -e with either "
+           "-r or -i options when starting the server");
+       printf("Can't use -d or -D or -e with either -r "
+           "or -i options\n");
+       exit(EXIT_FAILURE);
+    }
+    if (install_service_set && remove_service_set) {
+       logerror("Can't use both -r and -i options when starting "
+           "the server");
+       printf("Can't use both -r and -i options\n");
+       exit(EXIT_FAILURE);
+    }
+    if (install_service_set)
+        return install_service(argv[0]);
+    if (remove_service_set)
+        return remove_service();
+#endif /* _WIN32 */
+
     if (config_file == NULL) {
        sprintf(tbuf, "%s/econfig", datadir);
        config_file = tbuf;
@@ -151,6 +185,46 @@ main(int argc, char **argv)
     logerror("------------------------------------------------------");
     logerror("Empire server (pid %d) started", (int)getpid());
 
+#if defined(_WIN32)
+    if (debug == 0) {
+       SERVICE_TABLE_ENTRY DispatchTable[]={{"Empire Server", service_main},{NULL, NULL}};
+       if (StartServiceCtrlDispatcher(DispatchTable))
+           return 0;
+       else
+           if (GetLastError() != ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
+                   logerror("Failed to dispatch service (%d)", GetLastError());
+                   printf("Failed to dispatch service (%d)\n", GetLastError());
+                   exit(EXIT_FAILURE);
+           } else  /* start in the foreground */
+               debug = 1;
+    }
+#else
+    if (debug == 0 && flags == 0) {
+       disassoc();
+    }
+#endif
+
+    start_server(flags, config_file);
+
+    empth_exit();
+
+/* We should never get here.  But, just in case... */
+    close_files();
+
+#if defined(_WIN32)
+    loc_NTTerm();
+#endif
+    return EXIT_SUCCESS;
+}
+
+
+void
+start_server(int flags, char *config_file)
+{
+#ifdef POSIXSIGNALS
+    struct sigaction act;
+#endif /* POSIXSIGNALS */
+
 #if defined(_WIN32)
     loc_NTInit();
 #endif
@@ -167,9 +241,6 @@ main(int argc, char **argv)
     act.sa_flags = SA_SIGINFO;
 #endif
     sigemptyset(&act.sa_mask);
-    if (debug == 0 && flags == 0) {
-       disassoc();
-    }
     act.sa_handler = shutdwn;
     /* pthreads on Linux use SIGUSR1 (*shrug*) so only catch it if not on
        a Linux box running POSIX threads -- STM */
@@ -187,7 +258,6 @@ main(int argc, char **argv)
     sigaction(SIGPIPE, &act, NULL);
 #else
     if (debug == 0 && flags == 0) {
-       disassoc();
        /* pthreads on Linux use SIGUSR1 (*shrug*) so only catch it if not on
           a Linux box running POSIX threads -- STM */
 #if !(defined(__linux__) && defined(_EMPTH_POSIX))
@@ -243,16 +313,6 @@ main(int argc, char **argv)
     }
     sprintf(argv[0], "%s (main pid: %d)", tbuf, getpid());
 #endif
-
-    empth_exit();
-
-/* We should never get here.  But, just in case... */
-    close_files();
-
-#if defined(_WIN32)
-    loc_NTTerm();
-#endif
-    return 0;
 }
 
 static void
@@ -275,7 +335,7 @@ init_files(void)
     ef_open(EF_LOST, O_RDWR, 0);
 }
 
-static void
+void
 close_files(void)
 {
     ef_close(EF_NATION);
@@ -483,7 +543,7 @@ loc_NTInit()
 #endif
 
 #if defined(_WIN32)
-static void
+void
 loc_NTTerm()
 {
     WSACleanup();