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