Annotation of embedaddon/strongswan/src/libcharon/plugins/counters/counters_listener.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2017 Tobias Brunner
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             4:  *
        !             5:  * Copyright (C) 2012 Martin Willi
        !             6:  * Copyright (C) 2012 revosec AG
        !             7:  *
        !             8:  * This program is free software; you can redistribute it and/or modify it
        !             9:  * under the terms of the GNU General Public License as published by the
        !            10:  * Free Software Foundation; either version 2 of the License, or (at your
        !            11:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            12:  *
        !            13:  * This program is distributed in the hope that it will be useful, but
        !            14:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            15:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            16:  * for more details.
        !            17:  */
        !            18: 
        !            19: #include "counters_listener.h"
        !            20: #include "counters_query.h"
        !            21: 
        !            22: #include <threading/spinlock.h>
        !            23: #include <collections/hashtable.h>
        !            24: #include <collections/array.h>
        !            25: 
        !            26: typedef struct private_counters_listener_t private_counters_listener_t;
        !            27: typedef struct private_counters_query_t private_counters_query_t;
        !            28: 
        !            29: /**
        !            30:  * Query interface
        !            31:  */
        !            32: struct private_counters_query_t {
        !            33: 
        !            34:        /**
        !            35:         * Public interface
        !            36:         */
        !            37:        counters_query_t public;
        !            38: 
        !            39:        /**
        !            40:         * Reference to this
        !            41:         */
        !            42:        private_counters_listener_t *this;
        !            43: };
        !            44: 
        !            45: /**
        !            46:  * Private data
        !            47:  */
        !            48: struct private_counters_listener_t {
        !            49: 
        !            50:        /**
        !            51:         * Public interface
        !            52:         */
        !            53:        counters_listener_t public;
        !            54: 
        !            55:        /**
        !            56:         * Query interface
        !            57:         */
        !            58:        private_counters_query_t query;
        !            59: 
        !            60:        /**
        !            61:         * Global counter values
        !            62:         */
        !            63:        uint64_t counters[COUNTER_MAX];
        !            64: 
        !            65:        /**
        !            66:         * Counters for specific connection names, char* => entry_t
        !            67:         */
        !            68:        hashtable_t *conns;
        !            69: 
        !            70:        /**
        !            71:         * Lock for counter values
        !            72:         */
        !            73:        spinlock_t *lock;
        !            74: };
        !            75: 
        !            76: /**
        !            77:  * Counters for a specific connection name
        !            78:  */
        !            79: typedef struct {
        !            80:        /** connection name */
        !            81:        char *name;
        !            82:        /** counter values for connection */
        !            83:        uint64_t counters[COUNTER_MAX];
        !            84: } entry_t;
        !            85: 
        !            86: /**
        !            87:  * Destroy named entry
        !            88:  */
        !            89: static void destroy_entry(entry_t *this)
        !            90: {
        !            91:        free(this->name);
        !            92:        free(this);
        !            93: }
        !            94: 
        !            95: /**
        !            96:  * Hashtable hash function
        !            97:  */
        !            98: static u_int hash(char *name)
        !            99: {
        !           100:        return chunk_hash(chunk_from_str(name));
        !           101: }
        !           102: 
        !           103: /**
        !           104:  * Hashtable equals function
        !           105:  */
        !           106: static bool equals(char *a, char *b)
        !           107: {
        !           108:        return streq(a, b);
        !           109: }
        !           110: 
        !           111: /**
        !           112:  * Get the name of an IKE_SA, but return NULL if it is not known yet
        !           113:  */
        !           114: static char *get_ike_sa_name(ike_sa_t *ike_sa)
        !           115: {
        !           116:        peer_cfg_t *peer_cfg;
        !           117: 
        !           118:        if (ike_sa)
        !           119:        {
        !           120:                peer_cfg = ike_sa->get_peer_cfg(ike_sa);
        !           121:                if (peer_cfg)
        !           122:                {
        !           123:                        return peer_cfg->get_name(peer_cfg);
        !           124:                }
        !           125:        }
        !           126:        return NULL;
        !           127: }
        !           128: 
        !           129: /**
        !           130:  * Increase a counter for a named entry
        !           131:  */
        !           132: static void count_named(private_counters_listener_t *this,
        !           133:                                                ike_sa_t *ike_sa, counter_type_t type)
        !           134: {
        !           135:        entry_t *entry;
        !           136:        char *name;
        !           137: 
        !           138:        name = get_ike_sa_name(ike_sa);
        !           139:        if (name)
        !           140:        {
        !           141:                entry = this->conns->get(this->conns, name);
        !           142:                if (!entry)
        !           143:                {
        !           144:                        INIT(entry,
        !           145:                                .name = strdup(name),
        !           146:                        );
        !           147:                        this->conns->put(this->conns, entry->name, entry);
        !           148:                }
        !           149:                entry->counters[type]++;
        !           150:        }
        !           151: }
        !           152: 
        !           153: METHOD(listener_t, alert, bool,
        !           154:        private_counters_listener_t *this, ike_sa_t *ike_sa,
        !           155:        alert_t alert, va_list args)
        !           156: {
        !           157:        counter_type_t type;
        !           158: 
        !           159:        switch (alert)
        !           160:        {
        !           161:                case ALERT_INVALID_IKE_SPI:
        !           162:                        type = COUNTER_IN_INVALID_IKE_SPI;
        !           163:                        break;
        !           164:                case ALERT_PARSE_ERROR_HEADER:
        !           165:                case ALERT_PARSE_ERROR_BODY:
        !           166:                        type = COUNTER_IN_INVALID;
        !           167:                        break;
        !           168:                default:
        !           169:                        return TRUE;
        !           170:        }
        !           171: 
        !           172:        this->lock->lock(this->lock);
        !           173:        this->counters[type]++;
        !           174:        count_named(this, ike_sa, type);
        !           175:        this->lock->unlock(this->lock);
        !           176: 
        !           177:        return TRUE;
        !           178: }
        !           179: 
        !           180: METHOD(listener_t, ike_rekey, bool,
        !           181:        private_counters_listener_t *this, ike_sa_t *old, ike_sa_t *new)
        !           182: {
        !           183:        counter_type_t type;
        !           184:        ike_sa_id_t *id;
        !           185: 
        !           186:        id = new->get_id(new);
        !           187:        if (id->is_initiator(id))
        !           188:        {
        !           189:                type = COUNTER_INIT_IKE_SA_REKEY;
        !           190:        }
        !           191:        else
        !           192:        {
        !           193:                type = COUNTER_RESP_IKE_SA_REKEY;
        !           194:        }
        !           195: 
        !           196:        this->lock->lock(this->lock);
        !           197:        this->counters[type]++;
        !           198:        count_named(this, old, type);
        !           199:        this->lock->unlock(this->lock);
        !           200: 
        !           201:        return TRUE;
        !           202: }
        !           203: 
        !           204: METHOD(listener_t, child_rekey, bool,
        !           205:        private_counters_listener_t *this, ike_sa_t *ike_sa,
        !           206:        child_sa_t *old, child_sa_t *new)
        !           207: {
        !           208:        this->lock->lock(this->lock);
        !           209:        this->counters[COUNTER_CHILD_SA_REKEY]++;
        !           210:        count_named(this, ike_sa, COUNTER_CHILD_SA_REKEY);
        !           211:        this->lock->unlock(this->lock);
        !           212: 
        !           213:        return TRUE;
        !           214: }
        !           215: 
        !           216: METHOD(listener_t, message_hook, bool,
        !           217:        private_counters_listener_t *this, ike_sa_t *ike_sa, message_t *message,
        !           218:        bool incoming, bool plain)
        !           219: {
        !           220:        counter_type_t type;
        !           221:        bool request;
        !           222: 
        !           223:        if ((incoming && !plain) || (!incoming && !plain))
        !           224:        {       /* handle each message only once */
        !           225:                return TRUE;
        !           226:        }
        !           227: 
        !           228:        request = message->get_request(message);
        !           229:        switch (message->get_exchange_type(message))
        !           230:        {
        !           231:                case IKE_SA_INIT:
        !           232:                        if (incoming)
        !           233:                        {
        !           234:                                type = request ? COUNTER_IN_IKE_SA_INIT_REQ
        !           235:                                                           : COUNTER_IN_IKE_SA_INIT_RSP;
        !           236:                        }
        !           237:                        else
        !           238:                        {
        !           239:                                type = request ? COUNTER_OUT_IKE_SA_INIT_REQ
        !           240:                                                           : COUNTER_OUT_IKE_SA_INIT_RES;
        !           241:                        }
        !           242:                        break;
        !           243:                case IKE_AUTH:
        !           244:                        if (incoming)
        !           245:                        {
        !           246:                                type = request ? COUNTER_IN_IKE_AUTH_REQ
        !           247:                                                           : COUNTER_IN_IKE_AUTH_RSP;
        !           248:                        }
        !           249:                        else
        !           250:                        {
        !           251:                                type = request ? COUNTER_OUT_IKE_AUTH_REQ
        !           252:                                                           : COUNTER_OUT_IKE_AUTH_RSP;
        !           253:                        }
        !           254:                        break;
        !           255:                case CREATE_CHILD_SA:
        !           256:                        if (incoming)
        !           257:                        {
        !           258:                                type = request ? COUNTER_IN_CREATE_CHILD_SA_REQ
        !           259:                                                           : COUNTER_IN_CREATE_CHILD_SA_RSP;
        !           260:                        }
        !           261:                        else
        !           262:                        {
        !           263:                                type = request ? COUNTER_OUT_CREATE_CHILD_SA_REQ
        !           264:                                                           : COUNTER_OUT_CREATE_CHILD_SA_RSP;
        !           265:                        }
        !           266:                        break;
        !           267:                case INFORMATIONAL:
        !           268:                        if (incoming)
        !           269:                        {
        !           270:                                type = request ? COUNTER_IN_INFORMATIONAL_REQ
        !           271:                                                           : COUNTER_IN_INFORMATIONAL_RSP;
        !           272:                        }
        !           273:                        else
        !           274:                        {
        !           275:                                type = request ? COUNTER_OUT_INFORMATIONAL_REQ
        !           276:                                                           : COUNTER_OUT_INFORMATIONAL_RSP;
        !           277:                        }
        !           278:                        break;
        !           279:                default:
        !           280:                        return TRUE;
        !           281:        }
        !           282: 
        !           283:        this->lock->lock(this->lock);
        !           284:        this->counters[type]++;
        !           285:        count_named(this, ike_sa, type);
        !           286:        this->lock->unlock(this->lock);
        !           287: 
        !           288:        return TRUE;
        !           289: }
        !           290: 
        !           291: CALLBACK(free_names, void,
        !           292:        array_t * names)
        !           293: {
        !           294:        array_destroy_function(names, (void*)free, NULL);
        !           295: }
        !           296: 
        !           297: METHOD(counters_query_t, get_names, enumerator_t*,
        !           298:        private_counters_query_t *query)
        !           299: {
        !           300:        private_counters_listener_t *this = query->this;
        !           301:        enumerator_t *enumerator;
        !           302:        array_t *names;
        !           303:        char *name;
        !           304: 
        !           305:        this->lock->lock(this->lock);
        !           306:        names = array_create(0, this->conns->get_count(this->conns));
        !           307:        enumerator = this->conns->create_enumerator(this->conns);
        !           308:        while (enumerator->enumerate(enumerator, &name, NULL))
        !           309:        {
        !           310:                array_insert(names, ARRAY_TAIL, strdup(name));
        !           311:        }
        !           312:        enumerator->destroy(enumerator);
        !           313:        this->lock->unlock(this->lock);
        !           314: 
        !           315:        array_sort(names, (void*)strcmp, NULL);
        !           316: 
        !           317:        return enumerator_create_cleaner(array_create_enumerator(names),
        !           318:                                                                         free_names, names);
        !           319: }
        !           320: 
        !           321: METHOD(counters_query_t, get, bool,
        !           322:        private_counters_query_t *query, counter_type_t type, char *name,
        !           323:        uint64_t *value)
        !           324: {
        !           325:        private_counters_listener_t *this = query->this;
        !           326:        uint64_t *counters = this->counters;
        !           327: 
        !           328:        this->lock->lock(this->lock);
        !           329:        if (name)
        !           330:        {
        !           331:                entry_t *entry;
        !           332: 
        !           333:                entry = this->conns->get(this->conns, name);
        !           334:                if (!entry)
        !           335:                {
        !           336:                        this->lock->unlock(this->lock);
        !           337:                        return FALSE;
        !           338:                }
        !           339:                counters = entry->counters;
        !           340:        }
        !           341:        if (value)
        !           342:        {
        !           343:                *value = counters[type];
        !           344:        }
        !           345:        this->lock->unlock(this->lock);
        !           346:        return TRUE;
        !           347: }
        !           348: 
        !           349: METHOD(counters_query_t, get_all, uint64_t*,
        !           350:        private_counters_query_t *query, char *name)
        !           351: {
        !           352:        private_counters_listener_t *this = query->this;
        !           353:        entry_t *entry;
        !           354:        uint64_t *result, *counters = this->counters;
        !           355:        counter_type_t i;
        !           356: 
        !           357:        result = calloc(COUNTER_MAX, sizeof(uint64_t));
        !           358: 
        !           359:        this->lock->lock(this->lock);
        !           360:        if (name)
        !           361:        {
        !           362:                entry = this->conns->get(this->conns, name);
        !           363:                if (!entry)
        !           364:                {
        !           365:                        this->lock->unlock(this->lock);
        !           366:                        free(result);
        !           367:                        return NULL;
        !           368:                }
        !           369:                counters = &entry->counters[0];
        !           370:        }
        !           371:        for (i = 0; i < countof(this->counters); i++)
        !           372:        {
        !           373:                result[i] = counters[i];
        !           374:        }
        !           375:        this->lock->unlock(this->lock);
        !           376:        return result;
        !           377: }
        !           378: 
        !           379: METHOD(counters_query_t, reset, void,
        !           380:        private_counters_query_t *query, char *name)
        !           381: {
        !           382:        private_counters_listener_t *this = query->this;
        !           383:        entry_t *entry = NULL;
        !           384: 
        !           385:        this->lock->lock(this->lock);
        !           386:        if (name)
        !           387:        {
        !           388:                entry = this->conns->remove(this->conns, name);
        !           389:        }
        !           390:        else
        !           391:        {
        !           392:                memset(&this->counters, 0, sizeof(this->counters));
        !           393:        }
        !           394:        this->lock->unlock(this->lock);
        !           395: 
        !           396:        if (entry)
        !           397:        {
        !           398:                destroy_entry(entry);
        !           399:        }
        !           400: }
        !           401: 
        !           402: METHOD(counters_query_t, reset_all, void,
        !           403:        private_counters_query_t *query)
        !           404: {
        !           405:        private_counters_listener_t *this = query->this;
        !           406:        hashtable_t *new_conns, *conns;
        !           407: 
        !           408:        new_conns = hashtable_create((hashtable_hash_t)hash,
        !           409:                                                                 (hashtable_equals_t)equals, 4);
        !           410: 
        !           411:        this->lock->lock(this->lock);
        !           412:        conns = this->conns;
        !           413:        this->conns = new_conns;
        !           414:        this->lock->unlock(this->lock);
        !           415: 
        !           416:        conns->destroy_function(conns, (void*)destroy_entry);
        !           417: }
        !           418: 
        !           419: METHOD(counters_listener_t, destroy, void,
        !           420:        private_counters_listener_t *this)
        !           421: {
        !           422:        lib->set(lib, "counters", NULL);
        !           423: 
        !           424:        this->conns->destroy_function(this->conns, (void*)destroy_entry);
        !           425:        this->lock->destroy(this->lock);
        !           426:        free(this);
        !           427: }
        !           428: 
        !           429: /*
        !           430:  * Described in header
        !           431:  */
        !           432: counters_listener_t *counters_listener_create()
        !           433: {
        !           434:        private_counters_listener_t *this;
        !           435: 
        !           436:        INIT(this,
        !           437:                .public = {
        !           438:                        .listener = {
        !           439:                                .alert = _alert,
        !           440:                                .ike_rekey = _ike_rekey,
        !           441:                                .child_rekey = _child_rekey,
        !           442:                                .message = _message_hook,
        !           443:                        },
        !           444:                        .destroy = _destroy,
        !           445:                },
        !           446:                .query = {
        !           447:                        .public = {
        !           448:                                .get_names = _get_names,
        !           449:                                .get = _get,
        !           450:                                .get_all = _get_all,
        !           451:                                .reset = _reset,
        !           452:                                .reset_all = _reset_all,
        !           453:                        },
        !           454:                },
        !           455:                .conns = hashtable_create((hashtable_hash_t)hash,
        !           456:                                                                  (hashtable_equals_t)equals, 4),
        !           457:                .lock = spinlock_create(),
        !           458:        );
        !           459:        this->query.this = this;
        !           460: 
        !           461:        lib->set(lib, "counters", &this->query);
        !           462: 
        !           463:        return &this->public;
        !           464: }

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