]> git.pond.sub.org Git - empserver/blob - src/lib/w32/service.c
Update copyright notice
[empserver] / src / lib / w32 / service.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2009, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  service.c: Windows services support
29  *
30  *  Known contributors to this file:
31  *     Ron Koenderink, 2004
32  */
33
34 #include <config.h>
35
36 /*
37  * For WIN32 in empthread.h, winsock2.h is included which interfers
38  * with including windows.h, use sys/socket.h instead to prevent a
39  * problem
40  */
41 #include <sys/socket.h>
42
43 #include "service.h"
44 #include "empthread.h"
45 #include "prototypes.h"
46
47 int
48 install_service(char *program_name, char *service_name, char *config_file)
49 {
50     HANDLE schSCManager,schService;
51     SERVICE_DESCRIPTION sdBuf;
52
53     if (config_file != NULL)
54         snprintf(&program_name[strlen(program_name)], _MAX_PATH-strlen(program_name), " -e %s",
55             config_file);
56
57     if (service_name == NULL)
58         service_name = DEFAULT_SERVICE_NAME;
59     else if (service_name[0] == '\0')
60         service_name = DEFAULT_SERVICE_NAME;
61
62     schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
63
64     if (schSCManager == NULL) {
65         fprintf(stderr, "install_service failed to open Service Control Manager\n");
66         return EXIT_FAILURE;
67     }
68
69     schService = CreateService(schSCManager,
70         service_name,
71         service_name,                   /* service name to display */
72         SERVICE_ALL_ACCESS,             /* desired access */
73         SERVICE_WIN32_OWN_PROCESS,      /* service type */
74         SERVICE_AUTO_START,             /* start type */
75         SERVICE_ERROR_NORMAL,           /* error control type */
76         program_name,                   /* service's binary */
77         NULL,                           /* no load ordering group */
78         NULL,                           /* no tag identifier */
79         NULL,                           /* database service dependency */
80         NULL,                           /* LocalSystem account */
81         NULL);                          /* no password */
82
83     if (schService == NULL) {
84         fprintf(stderr, "install_service failed to create service %s\n", service_name);
85         return EXIT_FAILURE;
86     }
87     sdBuf.lpDescription = "Server for Empire game";
88
89     if(!ChangeServiceConfig2(
90           schService,                 /* handle to service */
91           SERVICE_CONFIG_DESCRIPTION, /* change: description */
92           &sdBuf)) {                  /* value: new description */
93         fprintf(stderr, "install_service failed to set the description\n");
94     }
95
96     printf("Service %s installed.\n", service_name);
97     CloseServiceHandle(schService);
98     return EXIT_SUCCESS;
99 }
100
101 int
102 remove_service(char *service_name)
103 {
104     HANDLE schSCManager;
105     SC_HANDLE hService;
106
107     if (service_name == NULL)
108         service_name = DEFAULT_SERVICE_NAME;
109     else if (service_name[0] == '\0')
110         service_name = DEFAULT_SERVICE_NAME;
111
112     schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
113
114     if (schSCManager == NULL) {
115         fprintf(stderr, "remove_service failed to open Service Control Manager\n");
116         return EXIT_FAILURE;
117     }
118
119     hService = OpenService(schSCManager, service_name, SERVICE_ALL_ACCESS);
120
121     if (hService == NULL) {
122         fprintf(stderr, "remove_service failed to open service %s\n", service_name);
123         return EXIT_FAILURE;
124     }
125
126     if (DeleteService(hService) == 0) {
127         fprintf(stderr, "remove_service failed to remove service %s\n", service_name);
128         return EXIT_FAILURE;
129     }
130
131     if (CloseServiceHandle(hService) == 0) {
132         fprintf(stderr, "remove_service failed to close service %s\n", service_name);
133         return EXIT_FAILURE;
134     } else {
135         printf("Service %s removed.\n", service_name);
136         return EXIT_SUCCESS;
137     }
138 }
139
140 static SERVICE_STATUS           service_status;
141 static SERVICE_STATUS_HANDLE    service_status_handle;
142
143 static void WINAPI
144 service_ctrl_handler(DWORD Opcode)
145 {
146     switch(Opcode) {
147         case SERVICE_CONTROL_PAUSE:
148             service_status.dwCurrentState = SERVICE_PAUSED;
149             logerror("Pausing the service not supported");
150             break;
151
152         case SERVICE_CONTROL_CONTINUE:
153             logerror("Continuing the service not supported");
154             service_status.dwCurrentState = SERVICE_RUNNING;
155             break;
156
157         case SERVICE_CONTROL_STOP:
158             logerror("Service stopping");
159             empth_request_shutdown();
160             return;
161
162         case SERVICE_CONTROL_INTERROGATE:
163         /* Fall through to send current status.  */
164             break;
165
166         default:
167             logerror("Unrecognized opcode %ld in ServiceCtrlHandler",
168                 Opcode);
169     }
170
171     /* Send current status. */
172     if (!SetServiceStatus (service_status_handle,  &service_status))
173         logerror("SetServiceStatus error %ld",GetLastError());
174     return;
175 }
176
177 void WINAPI
178 service_main(DWORD argc, LPTSTR *argv)
179 {
180     int sig;
181
182     service_status.dwServiceType        = SERVICE_WIN32;
183     service_status.dwCurrentState       = SERVICE_START_PENDING;
184     service_status.dwControlsAccepted   = SERVICE_ACCEPT_STOP;
185     service_status.dwWin32ExitCode      = 0;
186     service_status.dwServiceSpecificExitCode = 0;
187     service_status.dwCheckPoint         = 0;
188     service_status.dwWaitHint           = 0;
189
190     service_status_handle = RegisterServiceCtrlHandler(
191         DEFAULT_SERVICE_NAME, service_ctrl_handler);
192
193     if (service_status_handle == (SERVICE_STATUS_HANDLE)0) {
194         logerror("RegisterServiceCtrlHandler failed %lu\n", GetLastError());
195         finish_server();
196         return;
197     }
198
199     start_server(0);
200
201     /* Initialization complete - report running status. */
202     service_status.dwCurrentState       = SERVICE_RUNNING;
203     service_status.dwCheckPoint         = 0;
204     service_status.dwWaitHint           = 0;
205
206     if (!SetServiceStatus (service_status_handle, &service_status)) {
207         logerror("SetServiceStatus error %ld\n", GetLastError());
208     }
209
210     sig = empth_wait_for_signal();
211
212     shutdwn(sig);
213
214     CANT_REACH();
215     finish_server();
216 }
217
218 void
219 stop_service(void)
220 {
221     logerror("Service stopped");
222     service_status.dwWin32ExitCode = 0;
223     service_status.dwCurrentState  = SERVICE_STOPPED;
224     service_status.dwCheckPoint    = 0;
225     service_status.dwWaitHint      = 0;
226
227     if (!SetServiceStatus (service_status_handle, &service_status))
228         logerror("Error while stopping service SetServiceStatus"
229             " error %ld", GetLastError());
230 }