Annotation of embedaddon/strongswan/src/charon-svc/charon-svc.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2013 Martin Willi
3: * Copyright (C) 2013 revosec AG
4: *
5: * This program is free software; you can redistribute it and/or modify it
6: * under the terms of the GNU General Public License as published by the
7: * Free Software Foundation; either version 2 of the License, or (at your
8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9: *
10: * This program is distributed in the hope that it will be useful, but
11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13: * for more details.
14: */
15:
16: #include <library.h>
17: #include <daemon.h>
18:
19: #include <utils/backtrace.h>
20: #include <threading/thread.h>
21:
22: /**
23: * The name of our service, both internal and external
24: */
25: #define SERVICE_NAME "charon-svc"
26:
27: /**
28: * Current service status
29: */
30: static SERVICE_STATUS status;
31:
32: /**
33: * Handle for service status
34: */
35: static SERVICE_STATUS_HANDLE handle;
36:
37: /**
38: * Wait event for main thread
39: */
40: static HANDLE event;
41:
42: /**
43: * hook in library for debugging messages
44: */
45: extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
46:
47: /**
48: * Forward declaration
49: */
50: static DWORD WINAPI service_handler(DWORD dwControl, DWORD dwEventType,
51: LPVOID lpEventData, LPVOID lpContext);
52:
53: /**
54: * Logging hook for library logs, using stderr output
55: */
56: static void dbg_stderr(debug_t group, level_t level, char *fmt, ...)
57: {
58: va_list args;
59:
60: if (level <= 1)
61: {
62: va_start(args, fmt);
63: fprintf(stderr, "00[%N] ", debug_names, group);
64: vfprintf(stderr, fmt, args);
65: fprintf(stderr, "\n");
66: va_end(args);
67: }
68: }
69:
70: /**
71: * Log strongSwan/Windows version during startup
72: */
73: static void print_version()
74: {
75: OSVERSIONINFOEX osvie;
76:
77: memset(&osvie, 0, sizeof(osvie));
78: osvie.dwOSVersionInfoSize = sizeof(osvie);
79:
80: if (GetVersionEx((LPOSVERSIONINFO)&osvie))
81: {
82: DBG1(DBG_DMN, "Starting IKE service %s (strongSwan %s, "
83: "Windows %s %d.%d.%d (SP %d.%d)", SERVICE_NAME, VERSION,
84: osvie.wProductType == VER_NT_WORKSTATION ? "Client" : "Server",
85: osvie.dwMajorVersion, osvie.dwMinorVersion, osvie.dwBuildNumber,
86: osvie.wServicePackMajor, osvie.wServicePackMinor);
87: }
88: }
89:
90: /**
91: * Update service state to SCM, increase check point if state didn't change
92: */
93: static void update_status(DWORD state)
94: {
95: if (state == status.dwCurrentState)
96: {
97: status.dwCheckPoint++;
98: }
99: else
100: {
101: status.dwCheckPoint = 0;
102: }
103: status.dwCurrentState = state;
104: if (handle)
105: {
106: SetServiceStatus(handle, &status);
107: }
108: }
109:
110: /**
111: * Control handler for console
112: */
113: static BOOL WINAPI console_handler(DWORD dwCtrlType)
114: {
115: switch (dwCtrlType)
116: {
117: case CTRL_C_EVENT:
118: case CTRL_BREAK_EVENT:
119: case CTRL_CLOSE_EVENT:
120: DBG1(DBG_DMN, "application is stopping, cleaning up");
121: if (status.dwCurrentState == SERVICE_RUNNING)
122: {
123: charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL,
124: dwCtrlType);
125: }
126: /* signal main thread to clean up */
127: SetEvent(event);
128: return TRUE;
129: default:
130: return FALSE;
131: }
132: }
133:
134: /**
135: * Service handler function
136: */
137: static DWORD WINAPI service_handler(DWORD dwControl, DWORD dwEventType,
138: LPVOID lpEventData, LPVOID lpContext)
139: {
140: switch (dwControl)
141: {
142: case SERVICE_CONTROL_STOP:
143: case SERVICE_CONTROL_SHUTDOWN:
144: DBG1(DBG_DMN, "service is stopping, cleaning up");
145: if (status.dwCurrentState == SERVICE_RUNNING)
146: {
147: charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL,
148: dwControl);
149: }
150: /* signal main thread to clean up */
151: SetEvent(event);
152: return NO_ERROR;
153: case SERVICE_CONTROL_INTERROGATE:
154: return NO_ERROR;
155: default:
156: return ERROR_CALL_NOT_IMPLEMENTED;
157: }
158: }
159:
160: /**
161: * Wait for console program shutdown
162: */
163: static int console_wait()
164: {
165: update_status(SERVICE_RUNNING);
166:
167: if (WaitForSingleObjectEx(event, INFINITE, TRUE) != WAIT_OBJECT_0)
168: {
169: return 2;
170: }
171: return 0;
172: }
173:
174: /**
175: * Wait for service shutdown
176: */
177: static int service_wait()
178: {
179: /* service is initialized, we now accept control requests */
180: status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
181: update_status(SERVICE_RUNNING);
182: status.dwControlsAccepted = 0;
183:
184: if (WaitForSingleObjectEx(event, INFINITE, TRUE) != WAIT_OBJECT_0)
185: {
186: return 2;
187: }
188: return 0;
189: }
190:
191: /**
192: * Add namespace alias
193: */
194: static void __attribute__ ((constructor))register_namespace()
195: {
196: /* inherit settings from charon */
197: library_add_namespace("charon");
198: }
199:
200: /**
201: * Initialize and run charon using a wait function
202: */
203: static void init_and_run(DWORD dwArgc, LPTSTR *lpszArgv, int (*wait)())
204: {
205: level_t levels[DBG_MAX];
206: int i;
207:
208: for (i = 0; i < DBG_MAX; i++)
209: {
210: levels[i] = LEVEL_CTRL;
211: }
212:
213: update_status(SERVICE_START_PENDING);
214: event = CreateEvent(NULL, FALSE, FALSE, NULL);
215: if (event)
216: {
217: update_status(SERVICE_START_PENDING);
218: if (library_init(NULL, SERVICE_NAME))
219: {
220: update_status(SERVICE_START_PENDING);
221: if (libcharon_init())
222: {
223: charon->set_default_loggers(charon, levels, TRUE);
224: charon->load_loggers(charon);
225: print_version();
226: update_status(SERVICE_START_PENDING);
227: if (charon->initialize(charon, PLUGINS))
228: {
229: update_status(SERVICE_START_PENDING);
230: lib->plugins->status(lib->plugins, LEVEL_CTRL);
231:
232: charon->start(charon);
233:
234: status.dwWin32ExitCode = wait();
235: }
236: update_status(SERVICE_STOP_PENDING);
237: libcharon_deinit();
238: }
239: update_status(SERVICE_STOP_PENDING);
240: library_deinit();
241: }
242: update_status(SERVICE_STOP_PENDING);
243: CloseHandle(event);
244: }
245: update_status(SERVICE_STOPPED);
246: }
247:
248: /**
249: * Main routine when running from console
250: */
251: static void console_main(DWORD dwArgc, LPTSTR *lpszArgv)
252: {
253: status.dwWin32ExitCode = 1;
254:
255: if (SetConsoleCtrlHandler(console_handler, TRUE))
256: {
257: init_and_run(dwArgc, lpszArgv, console_wait);
258: SetConsoleCtrlHandler(console_handler, FALSE);
259: }
260: }
261:
262: /**
263: * Switch the working directory to the executable directory
264: */
265: static bool switch_workingdir()
266: {
267: CHAR path[MAX_PATH], *pos;
268: HMODULE module;
269:
270: module = GetModuleHandle(NULL);
271: if (!module)
272: {
273: return FALSE;
274: }
275: if (!GetModuleFileName(module, path, sizeof(path)))
276: {
277: return FALSE;
278: }
279: pos = strrchr(path, '\\');
280: if (!pos)
281: {
282: return FALSE;
283: }
284: *pos = 0;
285: return SetCurrentDirectory(path);
286: }
287:
288: /**
289: * Service main routine when running as service
290: */
291: static void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
292: {
293: memset(&status, 0, sizeof(status));
294: status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
295: status.dwWin32ExitCode = 1;
296:
297: handle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, service_handler, NULL);
298: if (handle)
299: {
300: if (switch_workingdir())
301: {
302: init_and_run(dwArgc, lpszArgv, service_wait);
303: }
304: }
305: }
306:
307: /**
308: * Main function, starts the service
309: */
310: int main(int argc, char *argv[])
311: {
312: SERVICE_TABLE_ENTRY services[] = {
313: {
314: .lpServiceName = SERVICE_NAME,
315: .lpServiceProc = service_main,
316: },
317: { NULL, NULL },
318: };
319: DWORD err;
320:
321: dbg = dbg_stderr;
322:
323: if (!StartServiceCtrlDispatcher(services))
324: {
325: err = GetLastError();
326: if (err == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
327: {
328: console_main(argc, argv);
329: }
330: else
331: {
332: return 2;
333: }
334: }
335: return status.dwWin32ExitCode;
336: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>