Annotation of embedaddon/strongswan/src/libcharon/plugins/load_tester/load_tester_control.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2012 Martin Willi
        !             3:  * Copyright (C) 2012 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 "load_tester_control.h"
        !            17: 
        !            18: #include <sys/types.h>
        !            19: #include <sys/stat.h>
        !            20: #include <sys/socket.h>
        !            21: #include <sys/un.h>
        !            22: #include <unistd.h>
        !            23: #include <errno.h>
        !            24: 
        !            25: #include <daemon.h>
        !            26: #include <collections/hashtable.h>
        !            27: #include <threading/thread.h>
        !            28: #include <threading/mutex.h>
        !            29: #include <threading/condvar.h>
        !            30: #include <processing/jobs/callback_job.h>
        !            31: 
        !            32: typedef struct private_load_tester_control_t private_load_tester_control_t;
        !            33: typedef struct init_listener_t init_listener_t;
        !            34: 
        !            35: /**
        !            36:  * Private data of an load_tester_control_t object.
        !            37:  */
        !            38: struct private_load_tester_control_t {
        !            39: 
        !            40:        /**
        !            41:         * Public load_tester_control_t interface.
        !            42:         */
        !            43:        load_tester_control_t public;
        !            44: 
        !            45:        /**
        !            46:         * Load tester control stream service
        !            47:         */
        !            48:        stream_service_t *service;
        !            49: };
        !            50: 
        !            51: /**
        !            52:  * Listener to follow initiation progress
        !            53:  */
        !            54: struct init_listener_t {
        !            55: 
        !            56:        /**
        !            57:         * implements listener_t
        !            58:         */
        !            59:        listener_t listener;
        !            60: 
        !            61:        /**
        !            62:         * Output stream to log to
        !            63:         */
        !            64:        FILE *stream;
        !            65: 
        !            66:        /**
        !            67:         * IKE_SAs we have started to initiate
        !            68:         */
        !            69:        hashtable_t *initiated;
        !            70: 
        !            71:        /**
        !            72:         * IKE_SAs we have completed to initiate (success or failure)
        !            73:         */
        !            74:        hashtable_t *completed;
        !            75: 
        !            76:        /**
        !            77:         * Mutex to lock IKE_SA tables
        !            78:         */
        !            79:        mutex_t *mutex;
        !            80: 
        !            81:        /**
        !            82:         * Condvar to wait for completion
        !            83:         */
        !            84:        condvar_t *condvar;
        !            85: };
        !            86: 
        !            87: /**
        !            88:  * Hashtable hash function
        !            89:  */
        !            90: static u_int hash(uintptr_t id)
        !            91: {
        !            92:        return id;
        !            93: }
        !            94: 
        !            95: /**
        !            96:  * Hashtable hash function
        !            97:  */
        !            98: static bool equals(uintptr_t a, uintptr_t b)
        !            99: {
        !           100:        return a == b;
        !           101: }
        !           102: 
        !           103: METHOD(listener_t, alert, bool,
        !           104:        init_listener_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args)
        !           105: {
        !           106:        if (alert == ALERT_RETRANSMIT_SEND)
        !           107:        {
        !           108:                uintptr_t id;
        !           109:                bool match = FALSE;
        !           110: 
        !           111:                id = ike_sa->get_unique_id(ike_sa);
        !           112:                this->mutex->lock(this->mutex);
        !           113:                if (this->initiated->get(this->initiated, (void*)id))
        !           114:                {
        !           115:                        match = TRUE;
        !           116:                }
        !           117:                this->mutex->unlock(this->mutex);
        !           118: 
        !           119:                if (match)
        !           120:                {
        !           121:                        fprintf(this->stream, "*");
        !           122:                        fflush(this->stream);
        !           123:                }
        !           124:        }
        !           125:        return TRUE;
        !           126: }
        !           127: 
        !           128: METHOD(listener_t, ike_state_change, bool,
        !           129:        init_listener_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
        !           130: {
        !           131:        if (state == IKE_ESTABLISHED || state == IKE_DESTROYING)
        !           132:        {
        !           133:                uintptr_t id;
        !           134:                bool match = FALSE;
        !           135: 
        !           136:                id = ike_sa->get_unique_id(ike_sa);
        !           137:                this->mutex->lock(this->mutex);
        !           138:                if (this->initiated->get(this->initiated, (void*)id))
        !           139:                {
        !           140:                        match = !this->completed->put(this->completed, (void*)id, (void*)id);
        !           141:                }
        !           142:                this->mutex->unlock(this->mutex);
        !           143: 
        !           144:                if (match)
        !           145:                {
        !           146:                        this->condvar->signal(this->condvar);
        !           147:                        fprintf(this->stream, state == IKE_ESTABLISHED ? "+" : "-");
        !           148:                        fflush(this->stream);
        !           149:                }
        !           150:        }
        !           151:        return TRUE;
        !           152: }
        !           153: 
        !           154: /**
        !           155:  * Logging callback function used during initiate
        !           156:  */
        !           157: static bool initiate_cb(init_listener_t *this, debug_t group, level_t level,
        !           158:                                                ike_sa_t *ike_sa, const char *message)
        !           159: {
        !           160:        uintptr_t id;
        !           161: 
        !           162:        if (ike_sa)
        !           163:        {
        !           164:                id = ike_sa->get_unique_id(ike_sa);
        !           165:                this->mutex->lock(this->mutex);
        !           166:                this->initiated->put(this->initiated, (void*)id, (void*)id);
        !           167:                this->mutex->unlock(this->mutex);
        !           168: 
        !           169:                return FALSE;
        !           170:        }
        !           171: 
        !           172:        return TRUE;
        !           173: }
        !           174: 
        !           175: /**
        !           176:  * Accept connections, initiate load-test, write progress to stream
        !           177:  */
        !           178: static bool on_accept(private_load_tester_control_t *this, stream_t *io)
        !           179: {
        !           180:        init_listener_t *listener;
        !           181:        enumerator_t *enumerator;
        !           182:        peer_cfg_t *peer_cfg;
        !           183:        child_cfg_t *child_cfg;
        !           184:        u_int i, count, failed = 0, delay = 0;
        !           185:        char buf[16] = "";
        !           186:        FILE *stream;
        !           187: 
        !           188:        stream = io->get_file(io);
        !           189:        if (!stream)
        !           190:        {
        !           191:                return FALSE;
        !           192:        }
        !           193:        fflush(stream);
        !           194:        if (fgets(buf, sizeof(buf), stream) == NULL)
        !           195:        {
        !           196:                fclose(stream);
        !           197:                return FALSE;
        !           198:        }
        !           199:        if (sscanf(buf, "%u %u", &count, &delay) < 1)
        !           200:        {
        !           201:                fclose(stream);
        !           202:                return FALSE;
        !           203:        }
        !           204: 
        !           205:        INIT(listener,
        !           206:                .listener = {
        !           207:                        .ike_state_change = _ike_state_change,
        !           208:                        .alert = _alert,
        !           209:                },
        !           210:                .stream = stream,
        !           211:                .initiated = hashtable_create((void*)hash, (void*)equals, count),
        !           212:                .completed = hashtable_create((void*)hash, (void*)equals, count),
        !           213:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
        !           214:                .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
        !           215:        );
        !           216: 
        !           217:        charon->bus->add_listener(charon->bus, &listener->listener);
        !           218: 
        !           219:        for (i = 0; i < count; i++)
        !           220:        {
        !           221:                peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
        !           222:                                                                                                                  "load-test");
        !           223:                if (!peer_cfg)
        !           224:                {
        !           225:                        failed++;
        !           226:                        fprintf(stream, "!");
        !           227:                        continue;
        !           228:                }
        !           229:                enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
        !           230:                if (!enumerator->enumerate(enumerator, &child_cfg))
        !           231:                {
        !           232:                        enumerator->destroy(enumerator);
        !           233:                        peer_cfg->destroy(peer_cfg);
        !           234:                        failed++;
        !           235:                        fprintf(stream, "!");
        !           236:                        continue;
        !           237:                }
        !           238:                enumerator->destroy(enumerator);
        !           239: 
        !           240:                switch (charon->controller->initiate(charon->controller,
        !           241:                                                                                peer_cfg, child_cfg->get_ref(child_cfg),
        !           242:                                                                                (void*)initiate_cb, listener, 0, FALSE))
        !           243:                {
        !           244:                        case NEED_MORE:
        !           245:                                /* Callback returns FALSE once it got track of this IKE_SA.
        !           246:                                 * FALL */
        !           247:                        case SUCCESS:
        !           248:                                fprintf(stream, ".");
        !           249:                                break;
        !           250:                        default:
        !           251:                                fprintf(stream, "!");
        !           252:                                break;
        !           253:                }
        !           254:                if (delay)
        !           255:                {
        !           256:                        usleep(delay * 1000);
        !           257:                }
        !           258:                fflush(stream);
        !           259:        }
        !           260: 
        !           261:        listener->mutex->lock(listener->mutex);
        !           262:        while (listener->completed->get_count(listener->completed) < count - failed)
        !           263:        {
        !           264:                listener->condvar->wait(listener->condvar, listener->mutex);
        !           265:        }
        !           266:        listener->mutex->unlock(listener->mutex);
        !           267: 
        !           268:        charon->bus->remove_listener(charon->bus, &listener->listener);
        !           269: 
        !           270:        listener->initiated->destroy(listener->initiated);
        !           271:        listener->completed->destroy(listener->completed);
        !           272:        listener->mutex->destroy(listener->mutex);
        !           273:        listener->condvar->destroy(listener->condvar);
        !           274:        free(listener);
        !           275: 
        !           276:        fprintf(stream, "\n");
        !           277:        fclose(stream);
        !           278: 
        !           279:        return FALSE;
        !           280: }
        !           281: 
        !           282: METHOD(load_tester_control_t, destroy, void,
        !           283:        private_load_tester_control_t *this)
        !           284: {
        !           285:        DESTROY_IF(this->service);
        !           286:        free(this);
        !           287: }
        !           288: 
        !           289: /**
        !           290:  * See header
        !           291:  */
        !           292: load_tester_control_t *load_tester_control_create()
        !           293: {
        !           294:        private_load_tester_control_t *this;
        !           295:        char *uri;
        !           296: 
        !           297:        INIT(this,
        !           298:                .public = {
        !           299:                        .destroy = _destroy,
        !           300:                },
        !           301:        );
        !           302: 
        !           303:        uri = lib->settings->get_str(lib->settings,
        !           304:                                "%s.plugins.load-tester.socket", "unix://" LOAD_TESTER_SOCKET,
        !           305:                                lib->ns);
        !           306:        this->service = lib->streams->create_service(lib->streams, uri, 10);
        !           307:        if (this->service)
        !           308:        {
        !           309:                this->service->on_accept(this->service, (stream_service_cb_t)on_accept,
        !           310:                                                                 this, JOB_PRIO_CRITICAL, 0);
        !           311:        }
        !           312:        else
        !           313:        {
        !           314:                DBG1(DBG_CFG, "creating load-tester control socket failed");
        !           315:        }
        !           316:        return &this->public;
        !           317: }

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