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>