Annotation of embedaddon/strongswan/src/libcharon/plugins/load_tester/load_tester_control.c, revision 1.1.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>