Annotation of embedaddon/strongswan/src/libcharon/control/controller.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2011-2019 Tobias Brunner
                      3:  * Copyright (C) 2007-2011 Martin Willi
                      4:  * Copyright (C) 2011 revosec AG
                      5:  * HSR Hochschule fuer Technik Rapperswil
                      6:  *
                      7:  * This program is free software; you can redistribute it and/or modify it
                      8:  * under the terms of the GNU General Public License as published by the
                      9:  * Free Software Foundation; either version 2 of the License, or (at your
                     10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     11:  *
                     12:  * This program is distributed in the hope that it will be useful, but
                     13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     15:  * for more details.
                     16:  */
                     17: 
                     18: #include "controller.h"
                     19: 
                     20: #include <sys/types.h>
                     21: #include <dirent.h>
                     22: #include <sys/stat.h>
                     23: 
                     24: #include <daemon.h>
                     25: #include <library.h>
                     26: #include <threading/thread.h>
                     27: #include <threading/spinlock.h>
                     28: #include <threading/semaphore.h>
                     29: 
                     30: typedef struct private_controller_t private_controller_t;
                     31: typedef struct interface_listener_t interface_listener_t;
                     32: typedef struct interface_logger_t interface_logger_t;
                     33: 
                     34: /**
                     35:  * Private data of an stroke_t object.
                     36:  */
                     37: struct private_controller_t {
                     38: 
                     39:        /**
                     40:         * Public part of stroke_t object.
                     41:         */
                     42:        controller_t public;
                     43: };
                     44: 
                     45: /**
                     46:  * helper struct for the logger interface
                     47:  */
                     48: struct interface_logger_t {
                     49:        /**
                     50:         * public logger interface
                     51:         */
                     52:        logger_t public;
                     53: 
                     54:        /**
                     55:         * reference to the listener
                     56:         */
                     57:        interface_listener_t *listener;
                     58: 
                     59:        /**
                     60:         *  interface callback (listener gets redirected to here)
                     61:         */
                     62:        controller_cb_t callback;
                     63: 
                     64:        /**
                     65:         * user parameter to pass to callback
                     66:         */
                     67:        void *param;
                     68: };
                     69: 
                     70: /**
                     71:  * helper struct to map listener callbacks to interface callbacks
                     72:  */
                     73: struct interface_listener_t {
                     74: 
                     75:        /**
                     76:         * public bus listener interface
                     77:         */
                     78:        listener_t public;
                     79: 
                     80:        /**
                     81:         * logger interface
                     82:         */
                     83:        interface_logger_t logger;
                     84: 
                     85:        /**
                     86:         * status of the operation, return to method callers
                     87:         */
                     88:        status_t status;
                     89: 
                     90:        /**
                     91:         * child configuration, used for initiate
                     92:         */
                     93:        child_cfg_t *child_cfg;
                     94: 
                     95:        /**
                     96:         * peer configuration, used for initiate
                     97:         */
                     98:        peer_cfg_t *peer_cfg;
                     99: 
                    100:        /**
                    101:         * IKE_SA to handle
                    102:         */
                    103:        ike_sa_t *ike_sa;
                    104: 
                    105:        /**
                    106:         * unique ID, used for various methods
                    107:         */
                    108:        uint32_t id;
                    109: 
                    110:        /**
                    111:         * semaphore to implement wait_for_listener()
                    112:         */
                    113:        semaphore_t *done;
                    114: 
                    115:        /**
                    116:         * spinlock to update the IKE_SA handle properly
                    117:         */
                    118:        spinlock_t *lock;
                    119: 
                    120:        union {
                    121:                /**
                    122:                 * whether to check limits during initiation
                    123:                 */
                    124:                bool limits;
                    125: 
                    126:                /**
                    127:                 * whether to force termination
                    128:                 */
                    129:                bool force;
                    130:        } options;
                    131: };
                    132: 
                    133: 
                    134: typedef struct interface_job_t interface_job_t;
                    135: 
                    136: /**
                    137:  * job for asynchronous listen operations
                    138:  */
                    139: struct interface_job_t {
                    140: 
                    141:        /**
                    142:         * job interface
                    143:         */
                    144:        job_t public;
                    145: 
                    146:        /**
                    147:         * associated listener
                    148:         */
                    149:        interface_listener_t listener;
                    150: 
                    151:        /**
                    152:         * the job is reference counted as the thread executing a job as well as
                    153:         * the thread waiting in wait_for_listener() require it but either of them
                    154:         * could be done first
                    155:         */
                    156:        refcount_t refcount;
                    157: };
                    158: 
                    159: /**
                    160:  * This function wakes a thread that is waiting in wait_for_listener(),
                    161:  * either from a listener or from a job.
                    162:  */
                    163: static inline bool listener_done(interface_listener_t *listener)
                    164: {
                    165:        if (listener->done)
                    166:        {
                    167:                listener->done->post(listener->done);
                    168:        }
                    169:        return FALSE;
                    170: }
                    171: 
                    172: /**
                    173:  * thread_cleanup_t handler to unregister a listener.
                    174:  */
                    175: static void listener_unregister(interface_listener_t *listener)
                    176: {
                    177:        charon->bus->remove_listener(charon->bus, &listener->public);
                    178:        charon->bus->remove_logger(charon->bus, &listener->logger.public);
                    179: }
                    180: 
                    181: /**
                    182:  * Registers the listener, executes the job and then waits synchronously until
                    183:  * the listener is done or the timeout occurred.
                    184:  *
                    185:  * @note Use 'return listener_done(listener)' to properly unregister a listener
                    186:  *
                    187:  * @param listener  listener to register
                    188:  * @param job       job to execute asynchronously when registered, or NULL
                    189:  * @param timeout   max timeout in ms to listen for events, 0 to disable
                    190:  * @return          TRUE if timed out
                    191:  */
                    192: static bool wait_for_listener(interface_job_t *job, u_int timeout)
                    193: {
                    194:        interface_listener_t *listener = &job->listener;
                    195:        bool old, timed_out = FALSE;
                    196: 
                    197:        /* avoid that the job is destroyed too early */
                    198:        ref_get(&job->refcount);
                    199: 
                    200:        listener->done = semaphore_create(0);
                    201: 
                    202:        charon->bus->add_logger(charon->bus, &listener->logger.public);
                    203:        charon->bus->add_listener(charon->bus, &listener->public);
                    204:        lib->processor->queue_job(lib->processor, &job->public);
                    205: 
                    206:        thread_cleanup_push((thread_cleanup_t)listener_unregister, listener);
                    207:        old = thread_cancelability(TRUE);
                    208:        if (timeout)
                    209:        {
                    210:                timed_out = listener->done->timed_wait(listener->done, timeout);
                    211:        }
                    212:        else
                    213:        {
                    214:                listener->done->wait(listener->done);
                    215:        }
                    216:        thread_cancelability(old);
                    217:        thread_cleanup_pop(TRUE);
                    218:        return timed_out;
                    219: }
                    220: 
                    221: METHOD(logger_t, listener_log, void,
                    222:        interface_logger_t *this, debug_t group, level_t level, int thread,
                    223:        ike_sa_t *ike_sa, const char *message)
                    224: {
                    225:        ike_sa_t *target;
                    226: 
                    227:        this->listener->lock->lock(this->listener->lock);
                    228:        target = this->listener->ike_sa;
                    229:        this->listener->lock->unlock(this->listener->lock);
                    230: 
                    231:        if (target == ike_sa)
                    232:        {
                    233:                if (!this->callback(this->param, group, level, ike_sa, message))
                    234:                {
                    235:                        this->listener->status = NEED_MORE;
                    236:                        listener_done(this->listener);
                    237:                }
                    238:        }
                    239: }
                    240: 
                    241: METHOD(logger_t, listener_get_level, level_t,
                    242:        interface_logger_t *this, debug_t group)
                    243: {
                    244:        /* in order to allow callback listeners to decide what they want to log
                    245:         * we request any log message, but only if we actually want logging */
                    246:        return this->callback == controller_cb_empty ? LEVEL_SILENT : LEVEL_PRIVATE;
                    247: }
                    248: 
                    249: METHOD(job_t, get_priority_medium, job_priority_t,
                    250:        job_t *this)
                    251: {
                    252:        return JOB_PRIO_MEDIUM;
                    253: }
                    254: 
                    255: METHOD(listener_t, ike_state_change, bool,
                    256:        interface_listener_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
                    257: {
                    258:        ike_sa_t *target;
                    259: 
                    260:        this->lock->lock(this->lock);
                    261:        target = this->ike_sa;
                    262:        this->lock->unlock(this->lock);
                    263: 
                    264:        if (target == ike_sa)
                    265:        {
                    266:                switch (state)
                    267:                {
                    268:                        case IKE_ESTABLISHED:
                    269:                        {
                    270: #ifdef ME
                    271:                                peer_cfg_t *peer_cfg = ike_sa->get_peer_cfg(ike_sa);
                    272: #endif /* ME */
                    273:                                /* we're done if we didn't initiate a CHILD_SA */
                    274:                                if (!this->child_cfg
                    275: #ifdef ME
                    276:                                        /* the same is always true for mediation connections */
                    277:                                        || peer_cfg->is_mediation(peer_cfg)
                    278: #endif /* ME */
                    279:                                        )
                    280:                                {
                    281:                                        this->status = SUCCESS;
                    282:                                        return listener_done(this);
                    283:                                }
                    284:                                break;
                    285:                        }
                    286:                        case IKE_DESTROYING:
                    287:                                return listener_done(this);
                    288:                        default:
                    289:                                break;
                    290:                }
                    291:        }
                    292:        return TRUE;
                    293: }
                    294: 
                    295: METHOD(listener_t, ike_state_change_terminate, bool,
                    296:        interface_listener_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
                    297: {
                    298:        ike_sa_t *target;
                    299: 
                    300:        this->lock->lock(this->lock);
                    301:        target = this->ike_sa;
                    302:        this->lock->unlock(this->lock);
                    303: 
                    304:        if (target == ike_sa)
                    305:        {
                    306:                switch (state)
                    307:                {
                    308:                        case IKE_DESTROYING:
                    309:                                this->status = SUCCESS;
                    310:                                return listener_done(this);
                    311:                        default:
                    312:                                break;
                    313:                }
                    314:        }
                    315:        return TRUE;
                    316: }
                    317: 
                    318: METHOD(listener_t, child_state_change, bool,
                    319:        interface_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
                    320:        child_sa_state_t state)
                    321: {
                    322:        ike_sa_t *target;
                    323: 
                    324:        this->lock->lock(this->lock);
                    325:        target = this->ike_sa;
                    326:        this->lock->unlock(this->lock);
                    327: 
                    328:        if (target == ike_sa)
                    329:        {
                    330:                switch (state)
                    331:                {
                    332:                        case CHILD_INSTALLED:
                    333:                                this->status = SUCCESS;
                    334:                                return listener_done(this);
                    335:                        case CHILD_DESTROYING:
                    336:                                switch (child_sa->get_state(child_sa))
                    337:                                {
                    338:                                        case CHILD_RETRYING:
                    339:                                                /* retrying with a different DH group; survive another
                    340:                                                 * initiation round */
                    341:                                                this->status = NEED_MORE;
                    342:                                                return TRUE;
                    343:                                        case CHILD_CREATED:
                    344:                                                if (this->status == NEED_MORE)
                    345:                                                {
                    346:                                                        this->status = FAILED;
                    347:                                                        return TRUE;
                    348:                                                }
                    349:                                                break;
                    350:                                        default:
                    351:                                                break;
                    352:                                }
                    353:                                return listener_done(this);
                    354:                        default:
                    355:                                break;
                    356:                }
                    357:        }
                    358:        return TRUE;
                    359: }
                    360: 
                    361: METHOD(listener_t, child_state_change_terminate, bool,
                    362:        interface_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
                    363:        child_sa_state_t state)
                    364: {
                    365:        ike_sa_t *target;
                    366: 
                    367:        this->lock->lock(this->lock);
                    368:        target = this->ike_sa;
                    369:        this->lock->unlock(this->lock);
                    370: 
                    371:        if (target == ike_sa)
                    372:        {
                    373:                switch (state)
                    374:                {
                    375:                        case CHILD_DESTROYING:
                    376:                                switch (child_sa->get_state(child_sa))
                    377:                                {
                    378:                                        case CHILD_DELETED:
                    379:                                                /* proper delete */
                    380:                                                this->status = SUCCESS;
                    381:                                                break;
                    382:                                        default:
                    383:                                                break;
                    384:                                }
                    385:                                return listener_done(this);
                    386:                        default:
                    387:                                break;
                    388:                }
                    389:        }
                    390:        return TRUE;
                    391: }
                    392: 
                    393: METHOD(job_t, destroy_job, void,
                    394:        interface_job_t *this)
                    395: {
                    396:        if (ref_put(&this->refcount))
                    397:        {
                    398:                this->listener.lock->destroy(this->listener.lock);
                    399:                DESTROY_IF(this->listener.done);
                    400:                free(this);
                    401:        }
                    402: }
                    403: 
                    404: METHOD(controller_t, create_ike_sa_enumerator, enumerator_t*,
                    405:        private_controller_t *this, bool wait)
                    406: {
                    407:        return charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager,
                    408:                                                                                                         wait);
                    409: }
                    410: 
                    411: METHOD(job_t, initiate_execute, job_requeue_t,
                    412:        interface_job_t *job)
                    413: {
                    414:        ike_sa_t *ike_sa;
                    415:        interface_listener_t *listener = &job->listener;
                    416:        peer_cfg_t *peer_cfg = listener->peer_cfg;
                    417: 
                    418:        ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
                    419:                                                                                                                peer_cfg);
                    420:        if (!ike_sa)
                    421:        {
                    422:                DESTROY_IF(listener->child_cfg);
                    423:                peer_cfg->destroy(peer_cfg);
                    424:                listener->status = FAILED;
                    425:                listener_done(listener);
                    426:                return JOB_REQUEUE_NONE;
                    427:        }
                    428:        listener->lock->lock(listener->lock);
                    429:        listener->ike_sa = ike_sa;
                    430:        listener->lock->unlock(listener->lock);
                    431: 
                    432:        if (ike_sa->get_peer_cfg(ike_sa) == NULL)
                    433:        {
                    434:                ike_sa->set_peer_cfg(ike_sa, peer_cfg);
                    435:        }
                    436:        peer_cfg->destroy(peer_cfg);
                    437: 
                    438:        if (listener->options.limits && ike_sa->get_state(ike_sa) == IKE_CREATED)
                    439:        {       /* only check if we are not reusing an IKE_SA */
                    440:                u_int half_open, limit_half_open, limit_job_load;
                    441: 
                    442:                half_open = charon->ike_sa_manager->get_half_open_count(
                    443:                                                                                charon->ike_sa_manager, NULL, FALSE);
                    444:                limit_half_open = lib->settings->get_int(lib->settings,
                    445:                                                                                "%s.init_limit_half_open", 0, lib->ns);
                    446:                limit_job_load = lib->settings->get_int(lib->settings,
                    447:                                                                                "%s.init_limit_job_load", 0, lib->ns);
                    448:                if (limit_half_open && half_open >= limit_half_open)
                    449:                {
                    450:                        DBG1(DBG_IKE, "abort IKE_SA initiation, half open IKE_SA count of "
                    451:                                 "%d exceeds limit of %d", half_open, limit_half_open);
                    452:                        charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
                    453:                                                                                                                ike_sa);
                    454:                        DESTROY_IF(listener->child_cfg);
                    455:                        listener->status = INVALID_STATE;
                    456:                        listener_done(listener);
                    457:                        return JOB_REQUEUE_NONE;
                    458:                }
                    459:                if (limit_job_load)
                    460:                {
                    461:                        u_int jobs = 0, i;
                    462: 
                    463:                        for (i = 0; i < JOB_PRIO_MAX; i++)
                    464:                        {
                    465:                                jobs += lib->processor->get_job_load(lib->processor, i);
                    466:                        }
                    467:                        if (jobs > limit_job_load)
                    468:                        {
                    469:                                DBG1(DBG_IKE, "abort IKE_SA initiation, job load of %d exceeds "
                    470:                                         "limit of %d", jobs, limit_job_load);
                    471:                                charon->ike_sa_manager->checkin_and_destroy(
                    472:                                                                                                charon->ike_sa_manager, ike_sa);
                    473:                                DESTROY_IF(listener->child_cfg);
                    474:                                listener->status = INVALID_STATE;
                    475:                                listener_done(listener);
                    476:                                return JOB_REQUEUE_NONE;
                    477:                        }
                    478:                }
                    479:        }
                    480: 
                    481:        if (ike_sa->initiate(ike_sa, listener->child_cfg, 0, NULL, NULL) == SUCCESS)
                    482:        {
                    483:                if (!listener->logger.callback)
                    484:                {
                    485:                        listener->status = SUCCESS;
                    486:                }
                    487:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    488:        }
                    489:        else
                    490:        {
                    491:                listener->status = FAILED;
                    492:                charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
                    493:                                                                                                        ike_sa);
                    494:        }
                    495:        return JOB_REQUEUE_NONE;
                    496: }
                    497: 
                    498: METHOD(controller_t, initiate, status_t,
                    499:        private_controller_t *this, peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
                    500:        controller_cb_t callback, void *param, u_int timeout, bool limits)
                    501: {
                    502:        interface_job_t *job;
                    503:        status_t status;
                    504: 
                    505:        INIT(job,
                    506:                .listener = {
                    507:                        .public = {
                    508:                                .ike_state_change = _ike_state_change,
                    509:                                .child_state_change = _child_state_change,
                    510:                        },
                    511:                        .logger = {
                    512:                                .public = {
                    513:                                        .log = _listener_log,
                    514:                                        .get_level = _listener_get_level,
                    515:                                },
                    516:                                .callback = callback,
                    517:                                .param = param,
                    518:                        },
                    519:                        .status = FAILED,
                    520:                        .child_cfg = child_cfg,
                    521:                        .peer_cfg = peer_cfg,
                    522:                        .lock = spinlock_create(),
                    523:                        .options.limits = limits,
                    524:                },
                    525:                .public = {
                    526:                        .execute = _initiate_execute,
                    527:                        .get_priority = _get_priority_medium,
                    528:                        .destroy = _destroy_job,
                    529:                },
                    530:                .refcount = 1,
                    531:        );
                    532:        job->listener.logger.listener = &job->listener;
                    533:        thread_cleanup_push((void*)destroy_job, job);
                    534: 
                    535:        if (callback == NULL)
                    536:        {
                    537:                initiate_execute(job);
                    538:        }
                    539:        else
                    540:        {
                    541:                if (wait_for_listener(job, timeout))
                    542:                {
                    543:                        job->listener.status = OUT_OF_RES;
                    544:                }
                    545:        }
                    546:        status = job->listener.status;
                    547:        thread_cleanup_pop(TRUE);
                    548:        return status;
                    549: }
                    550: 
                    551: METHOD(job_t, terminate_ike_execute, job_requeue_t,
                    552:        interface_job_t *job)
                    553: {
                    554:        interface_listener_t *listener = &job->listener;
                    555:        uint32_t unique_id = listener->id;
                    556:        ike_sa_t *ike_sa;
                    557: 
                    558:        ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
                    559:                                                                                                        unique_id);
                    560:        if (!ike_sa)
                    561:        {
                    562:                DBG1(DBG_IKE, "unable to terminate IKE_SA: ID %d not found", unique_id);
                    563:                listener->status = NOT_FOUND;
                    564:                /* release listener */
                    565:                listener_done(listener);
                    566:                return JOB_REQUEUE_NONE;
                    567:        }
                    568:        listener->lock->lock(listener->lock);
                    569:        listener->ike_sa = ike_sa;
                    570:        listener->lock->unlock(listener->lock);
                    571: 
                    572:        if (ike_sa->delete(ike_sa, listener->options.force) != DESTROY_ME)
                    573:        {       /* delete queued */
                    574:                listener->status = FAILED;
                    575:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    576:        }
                    577:        else
                    578:        {
                    579:                if (!listener->logger.callback)
                    580:                {
                    581:                        listener->status = SUCCESS;
                    582:                }
                    583:                charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
                    584:                                                                                                        ike_sa);
                    585:        }
                    586:        return JOB_REQUEUE_NONE;
                    587: }
                    588: 
                    589: METHOD(controller_t, terminate_ike, status_t,
                    590:        controller_t *this, uint32_t unique_id, bool force,
                    591:        controller_cb_t callback, void *param, u_int timeout)
                    592: {
                    593:        interface_job_t *job;
                    594:        status_t status;
                    595: 
                    596:        INIT(job,
                    597:                .listener = {
                    598:                        .public = {
                    599:                                .ike_state_change = _ike_state_change_terminate,
                    600:                        },
                    601:                        .logger = {
                    602:                                .public = {
                    603:                                        .log = _listener_log,
                    604:                                        .get_level = _listener_get_level,
                    605:                                },
                    606:                                .callback = callback,
                    607:                                .param = param,
                    608:                        },
                    609:                        .status = FAILED,
                    610:                        .id = unique_id,
                    611:                        .lock = spinlock_create(),
                    612:                },
                    613:                .public = {
                    614:                        .execute = _terminate_ike_execute,
                    615:                        .get_priority = _get_priority_medium,
                    616:                        .destroy = _destroy_job,
                    617:                },
                    618:                .refcount = 1,
                    619:        );
                    620:        job->listener.logger.listener = &job->listener;
                    621:        thread_cleanup_push((void*)destroy_job, job);
                    622: 
                    623:        if (callback == NULL)
                    624:        {
                    625:                job->listener.options.force = force;
                    626:                terminate_ike_execute(job);
                    627:        }
                    628:        else
                    629:        {
                    630:                if (!timeout)
                    631:                {
                    632:                        job->listener.options.force = force;
                    633:                }
                    634:                if (wait_for_listener(job, timeout))
                    635:                {
                    636:                        job->listener.status = OUT_OF_RES;
                    637: 
                    638:                        if (force)
                    639:                        {       /* force termination once timeout is reached */
                    640:                                job->listener.options.force = TRUE;
                    641:                                terminate_ike_execute(job);
                    642:                        }
                    643:                }
                    644:        }
                    645:        status = job->listener.status;
                    646:        thread_cleanup_pop(TRUE);
                    647:        return status;
                    648: }
                    649: 
                    650: METHOD(job_t, terminate_child_execute, job_requeue_t,
                    651:        interface_job_t *job)
                    652: {
                    653:        interface_listener_t *listener = &job->listener;
                    654:        uint32_t id = listener->id;
                    655:        child_sa_t *child_sa;
                    656:        ike_sa_t *ike_sa;
                    657: 
                    658:        ike_sa = charon->child_sa_manager->checkout_by_id(charon->child_sa_manager,
                    659:                                                                                                          id, &child_sa);
                    660:        if (!ike_sa)
                    661:        {
                    662:                DBG1(DBG_IKE, "unable to terminate, CHILD_SA with ID %d not found", id);
                    663:                listener->status = NOT_FOUND;
                    664:                /* release listener */
                    665:                listener_done(listener);
                    666:                return JOB_REQUEUE_NONE;
                    667:        }
                    668:        listener->lock->lock(listener->lock);
                    669:        listener->ike_sa = ike_sa;
                    670:        listener->lock->unlock(listener->lock);
                    671: 
                    672:        if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa),
                    673:                                        child_sa->get_spi(child_sa, TRUE), FALSE) != DESTROY_ME)
                    674:        {
                    675:                if (!listener->logger.callback)
                    676:                {
                    677:                        listener->status = SUCCESS;
                    678:                }
                    679:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    680:        }
                    681:        else
                    682:        {
                    683:                listener->status = FAILED;
                    684:                charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
                    685:                                                                                                        ike_sa);
                    686:        }
                    687:        return JOB_REQUEUE_NONE;
                    688: }
                    689: 
                    690: METHOD(controller_t, terminate_child, status_t,
                    691:        controller_t *this, uint32_t unique_id,
                    692:        controller_cb_t callback, void *param, u_int timeout)
                    693: {
                    694:        interface_job_t *job;
                    695:        status_t status;
                    696: 
                    697:        INIT(job,
                    698:                .listener = {
                    699:                        .public = {
                    700:                                .ike_state_change = _ike_state_change_terminate,
                    701:                                .child_state_change = _child_state_change_terminate,
                    702:                        },
                    703:                        .logger = {
                    704:                                .public = {
                    705:                                        .log = _listener_log,
                    706:                                        .get_level = _listener_get_level,
                    707:                                },
                    708:                                .callback = callback,
                    709:                                .param = param,
                    710:                        },
                    711:                        .status = FAILED,
                    712:                        .id = unique_id,
                    713:                        .lock = spinlock_create(),
                    714:                },
                    715:                .public = {
                    716:                        .execute = _terminate_child_execute,
                    717:                        .get_priority = _get_priority_medium,
                    718:                        .destroy = _destroy_job,
                    719:                },
                    720:                .refcount = 1,
                    721:        );
                    722:        job->listener.logger.listener = &job->listener;
                    723:        thread_cleanup_push((void*)destroy_job, job);
                    724: 
                    725:        if (callback == NULL)
                    726:        {
                    727:                terminate_child_execute(job);
                    728:        }
                    729:        else
                    730:        {
                    731:                if (wait_for_listener(job, timeout))
                    732:                {
                    733:                        job->listener.status = OUT_OF_RES;
                    734:                }
                    735:        }
                    736:        status = job->listener.status;
                    737:        thread_cleanup_pop(TRUE);
                    738:        return status;
                    739: }
                    740: 
                    741: /**
                    742:  * See header
                    743:  */
                    744: bool controller_cb_empty(void *param, debug_t group, level_t level,
                    745:                                                 ike_sa_t *ike_sa, const char *message)
                    746: {
                    747:        return TRUE;
                    748: }
                    749: 
                    750: METHOD(controller_t, destroy, void,
                    751:        private_controller_t *this)
                    752: {
                    753:        free(this);
                    754: }
                    755: 
                    756: /*
                    757:  * Described in header-file
                    758:  */
                    759: controller_t *controller_create(void)
                    760: {
                    761:        private_controller_t *this;
                    762: 
                    763:        INIT(this,
                    764:                .public = {
                    765:                        .create_ike_sa_enumerator = _create_ike_sa_enumerator,
                    766:                        .initiate = _initiate,
                    767:                        .terminate_ike = _terminate_ike,
                    768:                        .terminate_child = _terminate_child,
                    769:                        .destroy = _destroy,
                    770:                },
                    771:        );
                    772: 
                    773:        return &this->public;
                    774: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>