Annotation of embedaddon/strongswan/src/libcharon/control/controller.c, revision 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>