Annotation of embedaddon/strongswan/src/charon-svc/charon-svc.c, revision 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>