Annotation of embedaddon/strongswan/src/libcharon/plugins/vici/vici_attribute.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2014-2016 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * Copyright (C) 2014 Martin Willi
                      6:  * Copyright (C) 2014 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 "vici_attribute.h"
                     20: #include "vici_builder.h"
                     21: 
                     22: #include <daemon.h>
                     23: #include <collections/hashtable.h>
                     24: #include <collections/array.h>
                     25: #include <threading/rwlock.h>
                     26: #include <attributes/mem_pool.h>
                     27: 
                     28: typedef struct private_vici_attribute_t private_vici_attribute_t;
                     29: 
                     30: /**
                     31:  * private data of vici_attribute
                     32:  */
                     33: struct private_vici_attribute_t {
                     34: 
                     35:        /**
                     36:         * public functions
                     37:         */
                     38:        vici_attribute_t public;
                     39: 
                     40:        /**
                     41:         * vici connection dispatcher
                     42:         */
                     43:        vici_dispatcher_t *dispatcher;
                     44: 
                     45:        /**
                     46:         * Configured pools, as char* => pool_t
                     47:         */
                     48:        hashtable_t *pools;
                     49: 
                     50:        /**
                     51:         * rwlock to lock access to pools
                     52:         */
                     53:        rwlock_t *lock;
                     54: };
                     55: 
                     56: /**
                     57:  * Single configuration attribute with type
                     58:  */
                     59: typedef struct {
                     60:        /** type of attribute */
                     61:        configuration_attribute_type_t type;
                     62:        /** attribute value */
                     63:        chunk_t value;
                     64: } attribute_t;
                     65: 
                     66: /**
                     67:  * Clean up an attribute
                     68:  */
                     69: static void attribute_destroy(attribute_t *attr)
                     70: {
                     71:        free(attr->value.ptr);
                     72:        free(attr);
                     73: }
                     74: 
                     75: /**
                     76:  * Pool instances with associated attributes
                     77:  */
                     78: typedef struct {
                     79:        /** in-memory virtual IP pool */
                     80:        mem_pool_t *vips;
                     81:        /** configuration attributes, as attribute_t */
                     82:        array_t *attrs;
                     83: } pool_t;
                     84: 
                     85: /**
                     86:  * Clean up a pool instance
                     87:  */
                     88: static void pool_destroy(pool_t *pool)
                     89: {
                     90:        DESTROY_IF(pool->vips);
                     91:        array_destroy_function(pool->attrs, (void*)attribute_destroy, NULL);
                     92:        free(pool);
                     93: }
                     94: 
                     95: /**
                     96:  * Find an existing or not yet existing lease
                     97:  */
                     98: static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools,
                     99:                                                 identification_t *id, host_t *requested,
                    100:                                                 mem_pool_op_t op, host_t *peer)
                    101: {
                    102:        enumerator_t *enumerator;
                    103:        host_t *addr = NULL;
                    104:        pool_t *pool;
                    105:        char *name;
                    106: 
                    107:        enumerator = pools->create_enumerator(pools);
                    108:        while (enumerator->enumerate(enumerator, &name))
                    109:        {
                    110:                pool = this->pools->get(this->pools, name);
                    111:                if (pool)
                    112:                {
                    113:                        addr = pool->vips->acquire_address(pool->vips, id, requested,
                    114:                                                                                           op, peer);
                    115:                        if (addr)
                    116:                        {
                    117:                                break;
                    118:                        }
                    119:                }
                    120:        }
                    121:        enumerator->destroy(enumerator);
                    122: 
                    123:        return addr;
                    124: }
                    125: 
                    126: METHOD(attribute_provider_t, acquire_address, host_t*,
                    127:        private_vici_attribute_t *this, linked_list_t *pools, ike_sa_t *ike_sa,
                    128:        host_t *requested)
                    129: {
                    130:        identification_t *id;
                    131:        host_t *addr, *peer;
                    132: 
                    133:        id = ike_sa->get_other_eap_id(ike_sa);
                    134:        peer = ike_sa->get_other_host(ike_sa);
                    135: 
                    136:        this->lock->read_lock(this->lock);
                    137: 
                    138:        addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING, peer);
                    139:        if (!addr)
                    140:        {
                    141:                addr = find_addr(this, pools, id, requested, MEM_POOL_NEW, peer);
                    142:                if (!addr)
                    143:                {
                    144:                        addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN, peer);
                    145:                }
                    146:        }
                    147: 
                    148:        this->lock->unlock(this->lock);
                    149: 
                    150:        return addr;
                    151: }
                    152: 
                    153: METHOD(attribute_provider_t, release_address, bool,
                    154:        private_vici_attribute_t *this, linked_list_t *pools, host_t *address,
                    155:        ike_sa_t *ike_sa)
                    156: {
                    157:        enumerator_t *enumerator;
                    158:        identification_t *id;
                    159:        bool found = FALSE;
                    160:        pool_t *pool;
                    161:        char *name;
                    162: 
                    163:        id = ike_sa->get_other_eap_id(ike_sa);
                    164: 
                    165:        this->lock->read_lock(this->lock);
                    166: 
                    167:        enumerator = pools->create_enumerator(pools);
                    168:        while (enumerator->enumerate(enumerator, &name))
                    169:        {
                    170:                pool = this->pools->get(this->pools, name);
                    171:                if (pool)
                    172:                {
                    173:                        found = pool->vips->release_address(pool->vips, address, id);
                    174:                        if (found)
                    175:                        {
                    176:                                break;
                    177:                        }
                    178:                }
                    179:        }
                    180:        enumerator->destroy(enumerator);
                    181: 
                    182:        this->lock->unlock(this->lock);
                    183: 
                    184:        return found;
                    185: }
                    186: 
                    187: CALLBACK(attr_filter, bool,
                    188:        void *data, enumerator_t *orig, va_list args)
                    189: {
                    190:        attribute_t *attr;
                    191:        configuration_attribute_type_t *type;
                    192:        chunk_t *value;
                    193: 
                    194:        VA_ARGS_VGET(args, type, value);
                    195: 
                    196:        if (orig->enumerate(orig, &attr))
                    197:        {
                    198:                *type = attr->type;
                    199:                *value = attr->value;
                    200:                return TRUE;
                    201:        }
                    202:        return FALSE;
                    203: }
                    204: 
                    205: /**
                    206:  * Create nested inner enumerator over pool attributes
                    207:  */
                    208: CALLBACK(create_nested, enumerator_t*,
                    209:        pool_t *pool, void *this)
                    210: {
                    211:        return enumerator_create_filter(array_create_enumerator(pool->attrs),
                    212:                                                                        attr_filter, NULL, NULL);
                    213: }
                    214: 
                    215: /**
                    216:  * Data associated to nested enumerator cleanup
                    217:  */
                    218: typedef struct {
                    219:        private_vici_attribute_t *this;
                    220:        linked_list_t *list;
                    221: } nested_data_t;
                    222: 
                    223: /**
                    224:  * Clean up nested enumerator data
                    225:  */
                    226: CALLBACK(nested_cleanup, void,
                    227:        nested_data_t *data)
                    228: {
                    229:        data->this->lock->unlock(data->this->lock);
                    230:        data->list->destroy(data->list);
                    231:        free(data);
                    232: }
                    233: 
                    234: /**
                    235:  * Check if any of vips is from pool
                    236:  */
                    237: static bool have_vips_from_pool(mem_pool_t *pool, linked_list_t *vips)
                    238: {
                    239:        enumerator_t *enumerator;
                    240:        host_t *host;
                    241:        chunk_t start, end, current;
                    242:        uint32_t size;
                    243:        bool found = FALSE;
                    244: 
                    245:        host = pool->get_base(pool);
                    246:        start = host->get_address(host);
                    247: 
                    248:        if (start.len >= sizeof(size))
                    249:        {
                    250:                end = chunk_clone(start);
                    251: 
                    252:                /* mem_pool is currently limited to 2^31 addresses, so 32-bit
                    253:                 * calculations should be sufficient. */
                    254:                size = untoh32(start.ptr + start.len - sizeof(size));
                    255:                htoun32(end.ptr + end.len - sizeof(size), size + pool->get_size(pool));
                    256: 
                    257:                enumerator = vips->create_enumerator(vips);
                    258:                while (enumerator->enumerate(enumerator, &host))
                    259:                {
                    260:                        current = host->get_address(host);
                    261:                        if (chunk_compare(current, start) >= 0 &&
                    262:                                chunk_compare(current, end) < 0)
                    263:                        {
                    264:                                found = TRUE;
                    265:                                break;
                    266:                        }
                    267:                }
                    268:                enumerator->destroy(enumerator);
                    269: 
                    270:                free(end.ptr);
                    271:        }
                    272:        return found;
                    273: }
                    274: 
                    275: METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
                    276:        private_vici_attribute_t *this, linked_list_t *pools,
                    277:        ike_sa_t *ike_sa, linked_list_t *vips)
                    278: {
                    279:        enumerator_t *enumerator;
                    280:        nested_data_t *data;
                    281:        pool_t *pool;
                    282:        char *name;
                    283: 
                    284:        INIT(data,
                    285:                .this = this,
                    286:                .list = linked_list_create(),
                    287:        );
                    288: 
                    289:        this->lock->read_lock(this->lock);
                    290: 
                    291:        enumerator = pools->create_enumerator(pools);
                    292:        while (enumerator->enumerate(enumerator, &name))
                    293:        {
                    294:                pool = this->pools->get(this->pools, name);
                    295:                if (pool && have_vips_from_pool(pool->vips, vips))
                    296:                {
                    297:                        data->list->insert_last(data->list, pool);
                    298:                }
                    299:        }
                    300:        enumerator->destroy(enumerator);
                    301: 
                    302:        return enumerator_create_nested(data->list->create_enumerator(data->list),
                    303:                                                                        create_nested, data, nested_cleanup);
                    304: }
                    305: 
                    306: /**
                    307:  * Merge a pool configuration with existing ones
                    308:  */
                    309: static bool merge_pool(private_vici_attribute_t *this, pool_t *new)
                    310: {
                    311:        mem_pool_t *tmp;
                    312:        host_t *base;
                    313:        pool_t *old;
                    314:        const char *name;
                    315:        u_int size;
                    316: 
                    317:        name = new->vips->get_name(new->vips);
                    318:        base = new->vips->get_base(new->vips);
                    319:        size = new->vips->get_size(new->vips);
                    320: 
                    321:        old = this->pools->remove(this->pools, name);
                    322:        if (!old)
                    323:        {
                    324:                this->pools->put(this->pools, name, new);
                    325:                DBG1(DBG_CFG, "added vici pool %s: %H, %u entries", name, base, size);
                    326:                return TRUE;
                    327:        }
                    328: 
                    329:        if (base->ip_equals(base, old->vips->get_base(old->vips)) &&
                    330:                size == old->vips->get_size(old->vips))
                    331:        {
                    332:                /* no changes in pool, so keep existing, but use new attributes */
                    333:                DBG1(DBG_CFG, "updated vici pool %s: %H, %u entries", name, base, size);
                    334:                tmp = new->vips;
                    335:                new->vips = old->vips;
                    336:                old->vips = tmp;
                    337:                this->pools->put(this->pools, new->vips->get_name(new->vips), new);
                    338:                pool_destroy(old);
                    339:                return TRUE;
                    340:        }
                    341:        if (old->vips->get_online(old->vips) == 0)
                    342:        {
                    343:                /* can replace old pool, no online leases */
                    344:                DBG1(DBG_CFG, "replaced vici pool %s: %H, %u entries", name, base, size);
                    345:                this->pools->put(this->pools, name, new);
                    346:                pool_destroy(old);
                    347:                return TRUE;
                    348:        }
                    349:        /* have online leases, unable to replace, TODO: migrate leases? */
                    350:        DBG1(DBG_CFG, "vici pool %s has %u online leases, unable to replace",
                    351:                 name, old->vips->get_online(old->vips));
                    352:        this->pools->put(this->pools, old->vips->get_name(old->vips), old);
                    353:        return FALSE;
                    354: }
                    355: 
                    356: /**
                    357:  * Create a (error) reply message
                    358:  */
                    359: static vici_message_t* create_reply(char *fmt, ...)
                    360: {
                    361:        vici_builder_t *builder;
                    362:        va_list args;
                    363: 
                    364:        builder = vici_builder_create();
                    365:        builder->add_kv(builder, "success", fmt ? "no" : "yes");
                    366:        if (fmt)
                    367:        {
                    368:                va_start(args, fmt);
                    369:                builder->vadd_kv(builder, "errmsg", fmt, args);
                    370:                va_end(args);
                    371:        }
                    372:        return builder->finalize(builder);
                    373: }
                    374: 
                    375: /**
                    376:  * Parse a range definition of an address pool
                    377:  */
                    378: static mem_pool_t *create_pool_range(char *name, char *buf)
                    379: {
                    380:        mem_pool_t *pool;
                    381:        host_t *from, *to;
                    382: 
                    383:        if (!host_create_from_range(buf, &from, &to))
                    384:        {
                    385:                return NULL;
                    386:        }
                    387:        pool = mem_pool_create_range(name, from, to);
                    388:        from->destroy(from);
                    389:        to->destroy(to);
                    390:        return pool;
                    391: }
                    392: 
                    393: /**
                    394:  * Parse callback data, passed to each callback
                    395:  */
                    396: typedef struct {
                    397:        private_vici_attribute_t *this;
                    398:        vici_message_t *reply;
                    399: } request_data_t;
                    400: 
                    401: /**
                    402:  * Data associated to a pool load
                    403:  */
                    404: typedef struct {
                    405:        request_data_t *request;
                    406:        char *name;
                    407:        pool_t *pool;
                    408: } load_data_t;
                    409: 
                    410: CALLBACK(pool_li, bool,
                    411:        load_data_t *data, vici_message_t *message, char *name, chunk_t value)
                    412: {
                    413:        struct {
                    414:                char *name;
                    415:                configuration_attribute_type_t v4;
                    416:                configuration_attribute_type_t v6;
                    417:        } keys[] = {
                    418:                {"address",                     INTERNAL_IP4_ADDRESS,   INTERNAL_IP6_ADDRESS    },
                    419:                {"dns",                         INTERNAL_IP4_DNS,               INTERNAL_IP6_DNS                },
                    420:                {"nbns",                        INTERNAL_IP4_NBNS,              INTERNAL_IP6_NBNS               },
                    421:                {"dhcp",                        INTERNAL_IP4_DHCP,              INTERNAL_IP6_DHCP               },
                    422:                {"netmask",                     INTERNAL_IP4_NETMASK,   INTERNAL_IP6_NETMASK    },
                    423:                {"server",                      INTERNAL_IP4_SERVER,    INTERNAL_IP6_SERVER             },
                    424:                {"subnet",                      INTERNAL_IP4_SUBNET,    INTERNAL_IP6_SUBNET             },
                    425:                {"split_include",       UNITY_SPLIT_INCLUDE,    UNITY_SPLIT_INCLUDE             },
                    426:                {"split_exclude",       UNITY_LOCAL_LAN,                UNITY_LOCAL_LAN                 },
                    427:        };
                    428:        char buf[256];
                    429:        int i, index = -1, mask = -1, type = 0;
                    430:        chunk_t encoding;
                    431:        attribute_t *attr;
                    432:        host_t *host = NULL;
                    433: 
                    434:        for (i = 0; i < countof(keys); i++)
                    435:        {
                    436:                if (streq(name, keys[i].name))
                    437:                {
                    438:                        index = i;
                    439:                        break;
                    440:                }
                    441:        }
                    442:        if (index == -1)
                    443:        {
                    444:                type = atoi(name);
                    445:                if (!type)
                    446:                {
                    447:                        data->request->reply = create_reply("invalid attribute: %s", name);
                    448:                        return FALSE;
                    449:                }
                    450:        }
                    451: 
                    452:        if (vici_stringify(value, buf, sizeof(buf)))
                    453:        {
                    454:                if (strchr(buf, '/'))
                    455:                {
                    456:                        host = host_create_from_subnet(buf, &mask);
                    457:                }
                    458:                else
                    459:                {
                    460:                        host = host_create_from_string(buf, 0);
                    461:                }
                    462:        }
                    463:        if (host)
                    464:        {
                    465:                if (index != -1)
                    466:                {
                    467:                        switch (host->get_family(host))
                    468:                        {
                    469:                                case AF_INET:
                    470:                                        type = keys[index].v4;
                    471:                                        break;
                    472:                                case AF_INET6:
                    473:                                default:
                    474:                                        type = keys[index].v6;
                    475:                                        break;
                    476:                        }
                    477:                }
                    478:                if (mask == -1)
                    479:                {
                    480:                        encoding = chunk_clone(host->get_address(host));
                    481:                }
                    482:                else
                    483:                {
                    484:                        if (host->get_family(host) == AF_INET)
                    485:                        {       /* IPv4 attributes contain a subnet mask */
                    486:                                uint32_t netmask = 0;
                    487: 
                    488:                                if (mask)
                    489:                                {       /* shifting uint32_t by 32 or more is undefined */
                    490:                                        mask = 32 - mask;
                    491:                                        netmask = htonl((0xFFFFFFFF >> mask) << mask);
                    492:                                }
                    493:                                encoding = chunk_cat("cc", host->get_address(host),
                    494:                                                                         chunk_from_thing(netmask));
                    495:                        }
                    496:                        else
                    497:                        {       /* IPv6 addresses the prefix only */
                    498:                                encoding = chunk_cat("cc", host->get_address(host),
                    499:                                                                         chunk_from_chars(mask));
                    500:                        }
                    501:                }
                    502:                host->destroy(host);
                    503:        }
                    504:        else
                    505:        {
                    506:                if (index != -1)
                    507:                {
                    508:                        data->request->reply = create_reply("invalid attribute value "
                    509:                                                                                                "for %s", name);
                    510:                        return FALSE;
                    511:                }
                    512:                /* use raw binary data for numbered attributes */
                    513:                encoding = chunk_clone(value);
                    514:        }
                    515:        INIT(attr,
                    516:                .type = type,
                    517:                .value = encoding,
                    518:        );
                    519:        array_insert_create(&data->pool->attrs, ARRAY_TAIL, attr);
                    520:        return TRUE;
                    521: }
                    522: 
                    523: CALLBACK(pool_kv, bool,
                    524:        load_data_t *data, vici_message_t *message, char *name, chunk_t value)
                    525: {
                    526:        if (streq(name, "addrs"))
                    527:        {
                    528:                char buf[128];
                    529:                mem_pool_t *pool;
                    530:                host_t *base = NULL;
                    531:                int bits;
                    532: 
                    533:                if (data->pool->vips)
                    534:                {
                    535:                        data->request->reply = create_reply("multiple addrs defined");
                    536:                        return FALSE;
                    537:                }
                    538:                if (!vici_stringify(value, buf, sizeof(buf)))
                    539:                {
                    540:                        data->request->reply = create_reply("invalid addrs value");
                    541:                        return FALSE;
                    542:                }
                    543:                pool = create_pool_range(data->name, buf);
                    544:                if (!pool)
                    545:                {
                    546:                        base = host_create_from_subnet(buf, &bits);
                    547:                        if (base)
                    548:                        {
                    549:                                pool = mem_pool_create(data->name, base, bits);
                    550:                                base->destroy(base);
                    551:                        }
                    552:                }
                    553:                if (!pool)
                    554:                {
                    555:                        data->request->reply = create_reply("invalid addrs value: %s", buf);
                    556:                        return FALSE;
                    557:                }
                    558:                data->pool->vips = pool;
                    559:                return TRUE;
                    560:        }
                    561:        data->request->reply = create_reply("invalid attribute: %s", name);
                    562:        return FALSE;
                    563: }
                    564: 
                    565: CALLBACK(pool_sn, bool,
                    566:        request_data_t *request, vici_message_t *message,
                    567:        vici_parse_context_t *ctx, char *name)
                    568: {
                    569:        load_data_t data = {
                    570:                .request = request,
                    571:                .name = name,
                    572:        };
                    573:        bool merged;
                    574: 
                    575:        INIT(data.pool);
                    576: 
                    577:        if (!message->parse(message, ctx, NULL, pool_kv, pool_li, &data))
                    578:        {
                    579:                pool_destroy(data.pool);
                    580:                return FALSE;
                    581:        }
                    582: 
                    583:        if (!data.pool->vips)
                    584:        {
                    585:                request->reply = create_reply("missing addrs for pool '%s'", name);
                    586:                pool_destroy(data.pool);
                    587:                return FALSE;
                    588:        }
                    589: 
                    590:        request->this->lock->write_lock(request->this->lock);
                    591:        merged = merge_pool(request->this, data.pool);
                    592:        request->this->lock->unlock(request->this->lock);
                    593: 
                    594:        if (!merged)
                    595:        {
                    596:                request->reply = create_reply("vici pool %s has online leases, "
                    597:                                                                          "unable to replace", name);
                    598:                pool_destroy(data.pool);
                    599:        }
                    600:        return merged;
                    601: }
                    602: 
                    603: CALLBACK(load_pool, vici_message_t*,
                    604:        private_vici_attribute_t *this, char *name, u_int id,
                    605:        vici_message_t *message)
                    606: {
                    607:        request_data_t request = {
                    608:                .this = this,
                    609:        };
                    610: 
                    611:        if (!message->parse(message, NULL, pool_sn, NULL, NULL, &request))
                    612:        {
                    613:                if (request.reply)
                    614:                {
                    615:                        return request.reply;
                    616:                }
                    617:                return create_reply("parsing request failed");
                    618:        }
                    619:        return create_reply(NULL);
                    620: }
                    621: 
                    622: CALLBACK(unload_pool, vici_message_t*,
                    623:        private_vici_attribute_t *this, char *name, u_int id,
                    624:        vici_message_t *message)
                    625: {
                    626:        vici_message_t *reply;
                    627:        u_int online;
                    628:        pool_t *pool;
                    629: 
                    630:        name = message->get_str(message, NULL, "name");
                    631:        if (!name)
                    632:        {
                    633:                return create_reply("missing pool name to unload");
                    634:        }
                    635: 
                    636:        this->lock->write_lock(this->lock);
                    637: 
                    638:        pool = this->pools->remove(this->pools, name);
                    639:        if (pool)
                    640:        {
                    641:                online = pool->vips->get_online(pool->vips);
                    642:                if (online)
                    643:                {
                    644:                        DBG1(DBG_CFG, "vici pool %s has %u online leases, unable to unload",
                    645:                                 name, online);
                    646:                        reply = create_reply("%s has online leases, unable to unload", name);
                    647:                        this->pools->put(this->pools, pool->vips->get_name(pool->vips), pool);
                    648:                }
                    649:                else
                    650:                {
                    651:                        DBG1(DBG_CFG, "unloaded vici pool %s", name);
                    652:                        reply = create_reply(NULL);
                    653:                        pool_destroy(pool);
                    654:                }
                    655:        }
                    656:        else
                    657:        {
                    658:                reply = create_reply("%s not found", name);
                    659:        }
                    660: 
                    661:        this->lock->unlock(this->lock);
                    662: 
                    663:        return reply;
                    664: }
                    665: 
                    666: CALLBACK(get_pools, vici_message_t*,
                    667:        private_vici_attribute_t *this, char *name, u_int id,
                    668:        vici_message_t *message)
                    669: {
                    670:        vici_builder_t *builder;
                    671:        enumerator_t *enumerator, *leases;
                    672:        mem_pool_t *vips;
                    673:        pool_t *pool;
                    674:        identification_t *uid;
                    675:        host_t *lease;
                    676:        bool list_leases, on;
                    677:        char buf[32], *filter;
                    678:        int i;
                    679: 
                    680:        list_leases = message->get_bool(message, FALSE, "leases");
                    681:        filter = message->get_str(message, NULL, "name");
                    682: 
                    683:        builder = vici_builder_create();
                    684: 
                    685:        this->lock->read_lock(this->lock);
                    686:        enumerator = this->pools->create_enumerator(this->pools);
                    687:        while (enumerator->enumerate(enumerator, &name, &pool))
                    688:        {
                    689:                if (filter && !streq(name, filter))
                    690:                {
                    691:                        continue;
                    692:                }
                    693: 
                    694:                vips = pool->vips;
                    695: 
                    696:                builder->begin_section(builder, name);
                    697: 
                    698:                builder->add_kv(builder, "base", "%H", vips->get_base(vips));
                    699:                builder->add_kv(builder, "size", "%u", vips->get_size(vips));
                    700:                builder->add_kv(builder, "online", "%u", vips->get_online(vips));
                    701:                builder->add_kv(builder, "offline", "%u", vips->get_offline(vips));
                    702: 
                    703:                if (list_leases)
                    704:                {
                    705:                        i = 0;
                    706:                        builder->begin_section(builder, "leases");
                    707:                        leases = vips->create_lease_enumerator(vips);
                    708:                        while (leases->enumerate(leases, &uid, &lease, &on))
                    709:                        {
                    710:                                snprintf(buf, sizeof(buf), "%d", i++);
                    711:                                builder->begin_section(builder, buf);
                    712:                                builder->add_kv(builder, "address", "%H", lease);
                    713:                                builder->add_kv(builder, "identity", "%Y", uid);
                    714:                                builder->add_kv(builder, "status", on ? "online" : "offline");
                    715:                                builder->end_section(builder);
                    716:                        }
                    717:                        leases->destroy(leases);
                    718:                        builder->end_section(builder);
                    719:                }
                    720:                builder->end_section(builder);
                    721:        }
                    722:        enumerator->destroy(enumerator);
                    723:        this->lock->unlock(this->lock);
                    724: 
                    725:        return builder->finalize(builder);
                    726: }
                    727: 
                    728: static void manage_command(private_vici_attribute_t *this,
                    729:                                                   char *name, vici_command_cb_t cb, bool reg)
                    730: {
                    731:        this->dispatcher->manage_command(this->dispatcher, name,
                    732:                                                                         reg ? cb : NULL, this);
                    733: }
                    734: 
                    735: /**
                    736:  * (Un-)register dispatcher functions
                    737:  */
                    738: static void manage_commands(private_vici_attribute_t *this, bool reg)
                    739: {
                    740:        manage_command(this, "load-pool", load_pool, reg);
                    741:        manage_command(this, "unload-pool", unload_pool, reg);
                    742:        manage_command(this, "get-pools", get_pools, reg);
                    743: }
                    744: 
                    745: METHOD(vici_attribute_t, destroy, void,
                    746:        private_vici_attribute_t *this)
                    747: {
                    748:        enumerator_t *enumerator;
                    749:        pool_t *pool;
                    750: 
                    751:        manage_commands(this, FALSE);
                    752: 
                    753:        enumerator = this->pools->create_enumerator(this->pools);
                    754:        while (enumerator->enumerate(enumerator, NULL, &pool))
                    755:        {
                    756:                pool_destroy(pool);
                    757:        }
                    758:        enumerator->destroy(enumerator);
                    759:        this->pools->destroy(this->pools);
                    760:        this->lock->destroy(this->lock);
                    761:        free(this);
                    762: }
                    763: 
                    764: /*
                    765:  * see header file
                    766:  */
                    767: vici_attribute_t *vici_attribute_create(vici_dispatcher_t *dispatcher)
                    768: {
                    769:        private_vici_attribute_t *this;
                    770: 
                    771:        INIT(this,
                    772:                .public = {
                    773:                        .provider = {
                    774:                                .acquire_address = _acquire_address,
                    775:                                .release_address = _release_address,
                    776:                                .create_attribute_enumerator = _create_attribute_enumerator,
                    777:                        },
                    778:                        .destroy = _destroy,
                    779:                },
                    780:                .dispatcher = dispatcher,
                    781:                .pools = hashtable_create(hashtable_hash_str, hashtable_equals_str, 4),
                    782:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                    783:        );
                    784: 
                    785:        manage_commands(this, TRUE);
                    786: 
                    787:        return &this->public;
                    788: }

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