2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
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>.
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
19 #include <utils/backtrace.h>
20 #include <threading/thread.h>
23 * The name of our service, both internal and external
25 #define SERVICE_NAME "charon-svc"
28 * Current service status
30 static SERVICE_STATUS status
;
33 * Handle for service status
35 static SERVICE_STATUS_HANDLE handle
;
38 * Wait event for main thread
43 * hook in library for debugging messages
45 extern void (*dbg
) (debug_t group
, level_t level
, char *fmt
, ...);
50 static DWORD WINAPI
service_handler(DWORD dwControl
, DWORD dwEventType
,
51 LPVOID lpEventData
, LPVOID lpContext
);
54 * Logging hook for library logs, using stderr output
56 static void dbg_stderr(debug_t group
, level_t level
, char *fmt
, ...)
63 fprintf(stderr
, "00[%N] ", debug_names
, group
);
64 vfprintf(stderr
, fmt
, args
);
65 fprintf(stderr
, "\n");
71 * Log strongSwan/Windows version during startup
73 static void print_version()
75 OSVERSIONINFOEX osvie
;
77 memset(&osvie
, 0, sizeof(osvie
));
78 osvie
.dwOSVersionInfoSize
= sizeof(osvie
);
80 if (GetVersionEx((LPOSVERSIONINFO
)&osvie
))
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
);
91 * Update service state to SCM, increase check point if state didn't change
93 static void update_status(DWORD state
)
95 if (state
== status
.dwCurrentState
)
97 status
.dwCheckPoint
++;
101 status
.dwCheckPoint
= 0;
103 status
.dwCurrentState
= state
;
106 SetServiceStatus(handle
, &status
);
111 * Control handler for console
113 static BOOL WINAPI
console_handler(DWORD dwCtrlType
)
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
)
123 charon
->bus
->alert(charon
->bus
, ALERT_SHUTDOWN_SIGNAL
,
126 /* signal main thread to clean up */
135 * Service handler function
137 static DWORD WINAPI
service_handler(DWORD dwControl
, DWORD dwEventType
,
138 LPVOID lpEventData
, LPVOID lpContext
)
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
)
147 charon
->bus
->alert(charon
->bus
, ALERT_SHUTDOWN_SIGNAL
,
150 /* signal main thread to clean up */
153 case SERVICE_CONTROL_INTERROGATE
:
156 return ERROR_CALL_NOT_IMPLEMENTED
;
161 * Wait for console program shutdown
163 static int console_wait()
165 update_status(SERVICE_RUNNING
);
167 if (WaitForSingleObjectEx(event
, INFINITE
, TRUE
) != WAIT_OBJECT_0
)
175 * Wait for service shutdown
177 static int service_wait()
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;
184 if (WaitForSingleObjectEx(event
, INFINITE
, TRUE
) != WAIT_OBJECT_0
)
192 * Add namespace alias
194 static void __attribute__ ((constructor
))register_namespace()
196 /* inherit settings from charon */
197 library_add_namespace("charon");
201 * Initialize and run charon using a wait function
203 static void init_and_run(DWORD dwArgc
, LPTSTR
*lpszArgv
, int (*wait
)())
205 level_t levels
[DBG_MAX
];
208 for (i
= 0; i
< DBG_MAX
; i
++)
210 levels
[i
] = LEVEL_CTRL
;
213 update_status(SERVICE_START_PENDING
);
214 event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
217 update_status(SERVICE_START_PENDING
);
218 if (library_init(NULL
, SERVICE_NAME
))
220 update_status(SERVICE_START_PENDING
);
221 if (libcharon_init())
223 charon
->load_loggers(charon
, levels
, TRUE
);
225 update_status(SERVICE_START_PENDING
);
226 if (charon
->initialize(charon
, PLUGINS
))
228 update_status(SERVICE_START_PENDING
);
229 lib
->plugins
->status(lib
->plugins
, LEVEL_CTRL
);
231 charon
->start(charon
);
233 status
.dwWin32ExitCode
= wait();
235 update_status(SERVICE_STOP_PENDING
);
238 update_status(SERVICE_STOP_PENDING
);
241 update_status(SERVICE_STOP_PENDING
);
244 update_status(SERVICE_STOPPED
);
248 * Main routine when running from console
250 static void console_main(DWORD dwArgc
, LPTSTR
*lpszArgv
)
252 status
.dwWin32ExitCode
= 1;
254 if (SetConsoleCtrlHandler(console_handler
, TRUE
))
256 init_and_run(dwArgc
, lpszArgv
, console_wait
);
257 SetConsoleCtrlHandler(console_handler
, FALSE
);
262 * Switch the working directory to the executable directory
264 static bool switch_workingdir()
266 CHAR path
[MAX_PATH
], *pos
;
269 module
= GetModuleHandle(NULL
);
274 if (!GetModuleFileName(module
, path
, sizeof(path
)))
278 pos
= strrchr(path
, '\\');
284 return SetCurrentDirectory(path
);
288 * Service main routine when running as service
290 static void WINAPI
service_main(DWORD dwArgc
, LPTSTR
*lpszArgv
)
292 memset(&status
, 0, sizeof(status
));
293 status
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
294 status
.dwWin32ExitCode
= 1;
296 handle
= RegisterServiceCtrlHandlerEx(SERVICE_NAME
, service_handler
, NULL
);
299 if (switch_workingdir())
301 init_and_run(dwArgc
, lpszArgv
, service_wait
);
307 * Main function, starts the service
309 int main(int argc
, char *argv
[])
311 SERVICE_TABLE_ENTRY services
[] = {
313 .lpServiceName
= SERVICE_NAME
,
314 .lpServiceProc
= service_main
,
322 if (!StartServiceCtrlDispatcher(services
))
324 err
= GetLastError();
325 if (err
== ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
)
327 console_main(argc
, argv
);
334 return status
.dwWin32ExitCode
;