Return to charon-svc.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / charon-svc |
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: }