tservice.c - mixmaster - mixmaster 3.0 patched for libressl
HTML git clone git://parazyd.org/mixmaster.git
DIR Log
DIR Files
DIR Refs
DIR README
---
tservice.c (9633B)
---
1 /* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
2
3 Mixmaster may be redistributed and modified under certain conditions.
4 This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
5 ANY KIND, either express or implied. See the file COPYRIGHT for
6 details.
7
8 Win32 Service support
9 $Id: service.c 934 2006-06-24 13:40:39Z rabbi $ */
10
11
12 #include <windows.h>
13 #include <stdio.h>
14 #include <direct.h>
15 #include <io.h>
16 #include <fcntl.h>
17
18 #include "mix3.h"
19
20 #ifdef WIN32SERVICE
21
22 #define SVCNAME "Mixmaster"
23 #define SVCDISPLAYNAME "Mixmaster Service"
24
25
26 /* internal variables */
27 static SERVICE_STATUS ssStatus;
28 static SERVICE_STATUS_HANDLE sshStatusHandle;
29 static BOOL not_service = FALSE;
30
31 static HANDLE hThread = NULL;
32 static HANDLE hMustTerminate = NULL;
33
34 /* internal function prototypes */
35 VOID WINAPI service_ctrl(DWORD ctrl_code);
36 VOID WINAPI service_main(DWORD argc, LPSTR *argv);
37 static DWORD service_run(void);
38 static void service_stop();
39 static int set_stdfiles();
40 static int install_service();
41 static int remove_service();
42 static int run_notservice(int argc, char **argv);
43 BOOL WINAPI console_ctrl_handler(DWORD ctrl_type);
44 static char *GetLastErrorText();
45 static BOOL send_status(DWORD current_state, DWORD exit_code, DWORD wait_hint, DWORD id);
46 static void event_log(DWORD id, char *eventmsg);
47
48 int mix_main(int argc, char *argv[]);
49
50
51 int main(int argc, char *argv[])
52 {
53 SERVICE_TABLE_ENTRY dispatchTable[] = {
54 {SVCNAME, (LPSERVICE_MAIN_FUNCTION)service_main},
55 {NULL, NULL} };
56
57 if ((argc > 1) && ((argv[1][0] == '-') && (argv[1][1] == '-'))) {
58 if (!_stricmp("install-svc", argv[1]+2))
59 return install_service();
60 else if (!_stricmp("remove-svc", argv[1]+2))
61 return remove_service();
62 else if (_stricmp("run-svc", argv[1]+2) && !is_nt_service())
63 return run_notservice(argc, argv);
64 } else if (!is_nt_service()) {
65 return run_notservice(argc, argv);
66 }
67 printf("mix --install-svc install the service\n");
68 printf("mix --remove-svc remove the service\n");
69 printf("mix --run-svc run as a service\n");
70 printf("mix -h view a summary of the command line options.\n");
71
72 printf("\nStartServiceCtrlDispatcher being called.\n" );
73 printf("This may take several seconds. Please wait.\n" );
74 if (!StartServiceCtrlDispatcher(dispatchTable)) {
75 printf("Service not started: StartServiceCtrlDispatcher failed.\n" );
76 event_log(1000, "Service not started: StartServiceCtrlDispatcher failed");
77 }
78 return 0;
79 } /* main */
80
81
82 VOID WINAPI service_main(DWORD argc, LPSTR *argv)
83 {
84 DWORD err = 0;
85
86 if (!(sshStatusHandle = RegisterServiceCtrlHandler(SVCNAME, service_ctrl)))
87 return;
88
89 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
90 ssStatus.dwServiceSpecificExitCode = 0;
91 if (send_status(SERVICE_START_PENDING, NO_ERROR, 1000, 1020))
92 err = service_run();
93
94 send_status(SERVICE_STOPPED, err, 0, err ? 1030 : 30);
95 } /* service_main */
96
97
98 VOID WINAPI service_ctrl(DWORD ctrl_code)
99 { /* Handle the requested control code. */
100 if (ctrl_code == SERVICE_CONTROL_STOP || ctrl_code == SERVICE_CONTROL_SHUTDOWN)
101 service_stop();
102 else
103 send_status(ssStatus.dwCurrentState, NO_ERROR, 0, 1040 + ctrl_code);
104 } /* service_ctrl */
105
106
107 static DWORD service_run(void)
108 {
109 char filename[_MAX_PATH+1];
110 char home[_MAX_PATH+1], *p;
111 char *svc_argv[2] = {filename, "-D"};
112
113 if (!hMustTerminate)
114 hMustTerminate = CreateEvent(NULL, FALSE, FALSE, NULL);
115 set_nt_exit_event(hMustTerminate);
116 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
117 &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
118
119 GetModuleFileName(NULL , filename, _MAX_PATH);
120 strcpy(home, filename);
121 if (p = strrchr(home, '\\')) {
122 *p = 0;
123 chdir(home);
124 }
125
126 if (!set_stdfiles()) {
127 event_log(1010, "stdin|stdout|stderr not created");
128 return ERROR_SERVICE_NOT_ACTIVE;
129 }
130
131 send_status(SERVICE_RUNNING, NO_ERROR, 0, 1060);
132 event_log(10, "Mixmaster Service started");
133
134 mix_main(2, svc_argv);
135 return 0;
136 } /* service_run */
137
138
139 static void service_stop(void)
140 {
141 send_status(SERVICE_STOP_PENDING, NO_ERROR, 5000, 1070);
142 if (hMustTerminate) {
143 SetEvent(hMustTerminate);
144 if (WaitForSingleObject(hThread, 4500) == WAIT_TIMEOUT) {
145 if (hThread) {
146 TerminateThread(hThread, 0);
147 event_log(1080, "Mixmaster Service terminated forcibly");
148 }
149 } else
150 event_log(20, "Mixmaster Service stopped");
151 CloseHandle(hMustTerminate);
152 hMustTerminate = NULL;
153 } else
154 if (hThread)
155 TerminateThread(hThread, 0);
156 if (hThread)
157 CloseHandle(hThread);
158 hThread = NULL;
159 ssStatus.dwCurrentState = SERVICE_STOPPED;
160 } /* service_stop */
161
162
163 static int set_stdfiles()
164 { /* needed for _popen() */
165 static DWORD std_handles[]={STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
166 FILE *stdfile[]={stdin, stdout, stderr};
167 HANDLE hStd;
168 int fh, stf_fileno;
169 FILE *fl;
170
171 AllocConsole();
172 for (stf_fileno=0; stf_fileno<=2; stf_fileno++) {
173 hStd = GetStdHandle(std_handles[stf_fileno]);
174 if (hStd == INVALID_HANDLE_VALUE)
175 return 0;
176 fh = _open_osfhandle((long)std_handles[stf_fileno], (stf_fileno ? _O_WRONLY : _O_RDONLY ) | _O_BINARY);
177 dup2(fh, stf_fileno);
178 fl = _fdopen(stf_fileno, (stf_fileno ? "wcb" : "rcb" ));
179 fflush(stdfile[stf_fileno]);
180 memcpy(stdfile[stf_fileno], fl, sizeof(FILE));
181 }
182 return 1;
183 } /* set_stdfiles */
184
185
186 static BOOL send_status(DWORD current_state, DWORD exit_code, DWORD wait_hint, DWORD id)
187 {
188 static DWORD dwCheckPoint = 1;
189 BOOL ret_val;
190
191 if (not_service)
192 return TRUE;
193
194 ssStatus.dwCurrentState = current_state;
195 ssStatus.dwWin32ExitCode = exit_code;
196 ssStatus.dwWaitHint = wait_hint;
197 ssStatus.dwControlsAccepted = (current_state == SERVICE_START_PENDING) ?
198 0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
199 ssStatus.dwCheckPoint = ((current_state == SERVICE_RUNNING) || (current_state == SERVICE_STOPPED)) ?
200 0 : dwCheckPoint++;
201
202 if (!(ret_val = SetServiceStatus(sshStatusHandle, &ssStatus)))
203 event_log(id, "SetServiceStatus failed");
204 return ret_val;
205 } /* send_status */
206
207
208 static void event_log(DWORD id, char *eventmsg)
209 {
210 HANDLE hEventSource;
211 char *pStrings[2] = {"", eventmsg};
212
213 if (not_service)
214 return;
215
216 if (id > 1000)
217 pStrings[0] = GetLastErrorText();
218
219 if (!(hEventSource = RegisterEventSource(NULL, SVCNAME)))
220 return;
221 ReportEvent(hEventSource, (WORD)((id < 1000) ? EVENTLOG_SUCCESS : EVENTLOG_ERROR_TYPE),
222 0, id, NULL, 2, 0, pStrings, NULL);
223 DeregisterEventSource(hEventSource);
224 } /* event_log */
225
226
227 static int run_notservice(int argc, char ** argv)
228 {
229 not_service = TRUE;
230 return mix_main(argc, argv);
231 } /* run_notservice */
232
233
234 static int install_service()
235 {
236 SC_HANDLE schService, schSCManager;
237 char filename[_MAX_PATH+10];
238
239 if (GetModuleFileName(NULL, filename, _MAX_PATH) == 0) {
240 printf("Unable to install Mixmaster Service: %s\n", GetLastErrorText());
241 return 1;
242 }
243 strcat(filename, " --run-svc");
244
245 if (!(schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
246 printf("OpenSCManager failed: %s\n", GetLastErrorText());
247 return 1;
248 }
249 schService = CreateService(schSCManager, SVCNAME, SVCDISPLAYNAME,
250 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
251 filename, NULL, NULL, NULL, NULL, NULL);
252
253 if (schService) {
254 printf("Mixmaster Service installed.\n");
255 CloseServiceHandle(schService);
256 } else {
257 printf("CreateService failed: %s\n", GetLastErrorText());
258 }
259
260 CloseServiceHandle(schSCManager);
261 return 0;
262 } /* install_service */
263
264
265 static int remove_service()
266 {
267 SC_HANDLE schService, schSCManager;
268 int ret_val = 0;
269
270 if (!(schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
271 printf("OpenSCManager failed: %s\n", GetLastErrorText());
272 return 1;
273 }
274 if (!(schService = OpenService(schSCManager, SVCNAME, SERVICE_ALL_ACCESS))) {
275 CloseServiceHandle(schSCManager);
276 printf("OpenService failed: %s\n", GetLastErrorText());
277 return 1;
278 }
279 /* try to stop the service */
280 if (ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus)) {
281 printf("Stopping Mixmaster Service");
282 do {
283 sleep(1);
284 printf(".");
285 QueryServiceStatus(schService, &ssStatus);
286 } while (ssStatus.dwCurrentState != SERVICE_STOP_PENDING);
287
288 if (ssStatus.dwCurrentState == SERVICE_STOPPED)
289 printf("\nMixmaster Service stopped.\n");
290 else
291 printf("\n%Mixmaster Service failed to stop.\n");
292 }
293
294 /* now remove the service */
295 if (!DeleteService(schService)) {
296 ret_val = 1;
297 printf("DeleteService failed: %s\n", GetLastErrorText());
298 } else
299 printf("Mixmaster Service removed.\n");
300
301 CloseServiceHandle(schService);
302 CloseServiceHandle(schSCManager);
303 return ret_val;
304 } /* remove_service */
305
306
307 static char *GetLastErrorText()
308 {
309 static char error_buf[256];
310 DWORD dwRet, err;
311 LPSTR lpszTemp = NULL;
312
313 dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
314 NULL, err=GetLastError(), LANG_NEUTRAL, (LPSTR)&lpszTemp, 0, NULL);
315
316 /* supplied buffer is not long enough */
317 if (!dwRet || (256 < (long)dwRet+14))
318 sprintf(error_buf, "Error (0x%x)", err);
319 else {
320 lpszTemp[lstrlen(lpszTemp)-2] = '\0';
321 /* remove cr and newline character */
322 sprintf(error_buf, "%s (0x%x)", lpszTemp, err);
323 }
324
325 if (lpszTemp)
326 LocalFree((HLOCAL)lpszTemp);
327
328 return error_buf;
329 } /* GetLastErrorText */
330
331 #endif /* WIN32SERVICE */