File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / charon-svc / charon-svc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:43 2020 UTC (4 years, 3 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    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>