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

1.1       misho       1: /*
                      2:  * Copyright (C) 2014 Martin Willi
                      3:  * Copyright (C) 2014 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: /*
                     17:  * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
                     18:  *
                     19:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                     20:  * of this software and associated documentation files (the "Software"), to deal
                     21:  * in the Software without restriction, including without limitation the rights
                     22:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     23:  * copies of the Software, and to permit persons to whom the Software is
                     24:  * furnished to do so, subject to the following conditions:
                     25:  *
                     26:  * The above copyright notice and this permission notice shall be included in
                     27:  * all copies or substantial portions of the Software.
                     28:  *
                     29:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     30:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     31:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
                     32:  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     33:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     34:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     35:  * THE SOFTWARE.
                     36:  */
                     37: 
                     38: #include "vici_dispatcher.h"
                     39: #include "vici_socket.h"
                     40: 
                     41: #include <bio/bio_reader.h>
                     42: #include <bio/bio_writer.h>
                     43: #include <threading/mutex.h>
                     44: #include <threading/condvar.h>
                     45: #include <threading/thread.h>
                     46: #include <collections/array.h>
                     47: #include <collections/hashtable.h>
                     48: 
                     49: typedef struct private_vici_dispatcher_t private_vici_dispatcher_t;
                     50: 
                     51: /**
                     52:  * Private data of an vici_dispatcher_t object.
                     53:  */
                     54: struct private_vici_dispatcher_t {
                     55: 
                     56:        /**
                     57:         * Public vici_dispatcher_t interface.
                     58:         */
                     59:        vici_dispatcher_t public;
                     60: 
                     61:        /**
                     62:         * Socket to send/receive messages
                     63:         */
                     64:        vici_socket_t *socket;
                     65: 
                     66:        /**
                     67:         * List of registered commands (char* => command_t*)
                     68:         */
                     69:        hashtable_t *cmds;
                     70: 
                     71:        /**
                     72:         * List of known events, and registered clients (char* => event_t*)
                     73:         */
                     74:        hashtable_t *events;
                     75: 
                     76:        /**
                     77:         * Mutex to lock hashtables
                     78:         */
                     79:        mutex_t *mutex;
                     80: 
                     81:        /**
                     82:         * Condvar to signal command termination
                     83:         */
                     84:        condvar_t *cond;
                     85: };
                     86: 
                     87: /**
                     88:  * Registered command
                     89:  */
                     90: typedef struct {
                     91:        /** command name */
                     92:        char *name;
                     93:        /** callback for command */
                     94:        vici_command_cb_t cb;
                     95:        /** user data to pass to callback */
                     96:        void *user;
                     97:        /** command currently in use? */
                     98:        u_int uses;
                     99: } command_t;
                    100: 
                    101: /**
                    102:  * Registered event
                    103:  */
                    104: typedef struct {
                    105:        /** event name */
                    106:        char *name;
                    107:        /** registered clients, as u_int */
                    108:        array_t *clients;
                    109:        /** event currently in use? */
                    110:        u_int uses;
                    111: } event_t;
                    112: 
                    113: /**
                    114:  * Send a operation code, optionally with name and message
                    115:  */
                    116: static void send_op(private_vici_dispatcher_t *this, u_int id,
                    117:                                        vici_operation_t op, char *name, vici_message_t *message)
                    118: {
                    119:        bio_writer_t *writer;
                    120:        u_int len;
                    121: 
                    122:        len = sizeof(uint8_t);
                    123:        if (name)
                    124:        {
                    125:                len += sizeof(uint8_t) + strlen(name);
                    126:        }
                    127:        if (message)
                    128:        {
                    129:                len += message->get_encoding(message).len;
                    130:        }
                    131:        writer = bio_writer_create(len);
                    132:        writer->write_uint8(writer, op);
                    133:        if (name)
                    134:        {
                    135:                writer->write_data8(writer, chunk_from_str(name));
                    136:        }
                    137:        if (message)
                    138:        {
                    139:                writer->write_data(writer, message->get_encoding(message));
                    140:        }
                    141:        this->socket->send(this->socket, id, writer->extract_buf(writer));
                    142:        writer->destroy(writer);
                    143: }
                    144: 
                    145: /**
                    146:  * Register client for event
                    147:  */
                    148: static void register_event(private_vici_dispatcher_t *this, char *name,
                    149:                                                   u_int id)
                    150: {
                    151:        event_t *event;
                    152: 
                    153:        this->mutex->lock(this->mutex);
                    154:        while (TRUE)
                    155:        {
                    156:                event = this->events->get(this->events, name);
                    157:                if (!event)
                    158:                {
                    159:                        break;
                    160:                }
                    161:                if (!event->uses)
                    162:                {
                    163:                        array_insert(event->clients, ARRAY_TAIL, &id);
                    164:                        break;
                    165:                }
                    166:                this->cond->wait(this->cond, this->mutex);
                    167:        }
                    168:        this->mutex->unlock(this->mutex);
                    169: 
                    170:        if (event)
                    171:        {
                    172:                DBG2(DBG_CFG, "vici client %u registered for: %s", id, name);
                    173:                send_op(this, id, VICI_EVENT_CONFIRM, NULL, NULL);
                    174:        }
                    175:        else
                    176:        {
                    177:                DBG1(DBG_CFG, "vici client %u invalid registration: %s", id, name);
                    178:                send_op(this, id, VICI_EVENT_UNKNOWN, NULL, NULL);
                    179:        }
                    180: }
                    181: 
                    182: /**
                    183:  * Unregister client for event
                    184:  */
                    185: static void unregister_event(private_vici_dispatcher_t *this, char *name,
                    186:                                                         u_int id)
                    187: {
                    188:        enumerator_t *enumerator;
                    189:        event_t *event;
                    190:        u_int *current;
                    191:        bool found = FALSE;
                    192: 
                    193:        this->mutex->lock(this->mutex);
                    194:        while (TRUE)
                    195:        {
                    196:                event = this->events->get(this->events, name);
                    197:                if (!event)
                    198:                {
                    199:                        break;
                    200:                }
                    201:                if (!event->uses)
                    202:                {
                    203:                        enumerator = array_create_enumerator(event->clients);
                    204:                        while (enumerator->enumerate(enumerator, &current))
                    205:                        {
                    206:                                if (*current == id)
                    207:                                {
                    208:                                        array_remove_at(event->clients, enumerator);
                    209:                                        found = TRUE;
                    210:                                        break;
                    211:                                }
                    212:                        }
                    213:                        enumerator->destroy(enumerator);
                    214:                        break;
                    215:                }
                    216:                this->cond->wait(this->cond, this->mutex);
                    217:        }
                    218:        this->mutex->unlock(this->mutex);
                    219: 
                    220:        DBG2(DBG_CFG, "vici client %u unregistered for: %s", id, name);
                    221: 
                    222:        if (found)
                    223:        {
                    224:                send_op(this, id, VICI_EVENT_CONFIRM, NULL, NULL);
                    225:        }
                    226:        else
                    227:        {
                    228:                send_op(this, id, VICI_EVENT_UNKNOWN, NULL, NULL);
                    229:        }
                    230: }
                    231: 
                    232: /**
                    233:  * Data to release on thread cancellation
                    234:  */
                    235: typedef struct {
                    236:        private_vici_dispatcher_t *this;
                    237:        command_t *cmd;
                    238:        vici_message_t *request;
                    239: } release_data_t;
                    240: 
                    241: /**
                    242:  * Release command after execution/cancellation
                    243:  */
                    244: CALLBACK(release_command, void,
                    245:        release_data_t *release)
                    246: {
                    247:        release->request->destroy(release->request);
                    248: 
                    249:        release->this->mutex->lock(release->this->mutex);
                    250:        if (--release->cmd->uses == 0)
                    251:        {
                    252:                release->this->cond->broadcast(release->this->cond);
                    253:        }
                    254:        release->this->mutex->unlock(release->this->mutex);
                    255: 
                    256:        free(release);
                    257: }
                    258: 
                    259: /**
                    260:  * Process a request message
                    261:  */
                    262: void process_request(private_vici_dispatcher_t *this, char *name, u_int id,
                    263:                                         chunk_t data)
                    264: {
                    265:        vici_message_t *response = NULL;
                    266:        release_data_t *release;
                    267:        command_t *cmd;
                    268: 
                    269:        this->mutex->lock(this->mutex);
                    270:        cmd = this->cmds->get(this->cmds, name);
                    271:        if (cmd)
                    272:        {
                    273:                cmd->uses++;
                    274:        }
                    275:        this->mutex->unlock(this->mutex);
                    276: 
                    277:        if (cmd)
                    278:        {
                    279:                INIT(release,
                    280:                        .this = this,
                    281:                        .cmd = cmd,
                    282:                );
                    283: 
                    284:                DBG2(DBG_CFG, "vici client %u requests: %s", id, name);
                    285: 
                    286:                thread_cleanup_push(release_command, release);
                    287: 
                    288:                release->request = vici_message_create_from_data(data, FALSE);
                    289:                response = release->cmd->cb(cmd->user, cmd->name, id, release->request);
                    290: 
                    291:                thread_cleanup_pop(TRUE);
                    292: 
                    293:                if (response)
                    294:                {
                    295:                        send_op(this, id, VICI_CMD_RESPONSE, NULL, response);
                    296:                        response->destroy(response);
                    297:                }
                    298:        }
                    299:        else
                    300:        {
                    301:                DBG1(DBG_CFG, "vici client %u invalid request: %s", id, name);
                    302:                send_op(this, id, VICI_CMD_UNKNOWN, NULL, NULL);
                    303:        }
                    304: }
                    305: 
                    306: CALLBACK(inbound, void,
                    307:        private_vici_dispatcher_t *this, u_int id, chunk_t data)
                    308: {
                    309:        bio_reader_t *reader;
                    310:        chunk_t chunk;
                    311:        uint8_t type;
                    312:        char name[257];
                    313: 
                    314:        reader = bio_reader_create(data);
                    315:        if (reader->read_uint8(reader, &type))
                    316:        {
                    317:                switch (type)
                    318:                {
                    319:                        case VICI_EVENT_REGISTER:
                    320:                                if (reader->read_data8(reader, &chunk) &&
                    321:                                        vici_stringify(chunk, name, sizeof(name)))
                    322:                                {
                    323:                                        register_event(this, name, id);
                    324:                                }
                    325:                                else
                    326:                                {
                    327:                                        DBG1(DBG_CFG, "invalid vici register message");
                    328:                                }
                    329:                                break;
                    330:                        case VICI_EVENT_UNREGISTER:
                    331:                                if (reader->read_data8(reader, &chunk) &&
                    332:                                        vici_stringify(chunk, name, sizeof(name)))
                    333:                                {
                    334:                                        unregister_event(this, name, id);
                    335:                                }
                    336:                                else
                    337:                                {
                    338:                                        DBG1(DBG_CFG, "invalid vici unregister message");
                    339:                                }
                    340:                                break;
                    341:                        case VICI_CMD_REQUEST:
                    342:                                if (reader->read_data8(reader, &chunk) &&
                    343:                                        vici_stringify(chunk, name, sizeof(name)))
                    344:                                {
                    345:                                        thread_cleanup_push((void*)reader->destroy, reader);
                    346:                                        process_request(this, name, id, reader->peek(reader));
                    347:                                        thread_cleanup_pop(FALSE);
                    348:                                }
                    349:                                else
                    350:                                {
                    351:                                        DBG1(DBG_CFG, "invalid vici request message");
                    352:                                }
                    353:                                break;
                    354:                        case VICI_CMD_RESPONSE:
                    355:                        case VICI_EVENT_CONFIRM:
                    356:                        case VICI_EVENT_UNKNOWN:
                    357:                        case VICI_EVENT:
                    358:                        default:
                    359:                                DBG1(DBG_CFG, "unsupported vici operation: %u", type);
                    360:                                break;
                    361:                }
                    362:        }
                    363:        else
                    364:        {
                    365:                DBG1(DBG_CFG, "invalid vici message");
                    366:        }
                    367:        reader->destroy(reader);
                    368: }
                    369: 
                    370: CALLBACK(connect_, void,
                    371:        private_vici_dispatcher_t *this, u_int id)
                    372: {
                    373:        DBG2(DBG_CFG, "vici client %u connected", id);
                    374: }
                    375: 
                    376: CALLBACK(disconnect, void,
                    377:        private_vici_dispatcher_t *this, u_int id)
                    378: {
                    379:        enumerator_t *events, *ids;
                    380:        event_t *event;
                    381:        u_int *current;
                    382: 
                    383:        /* deregister client from all events */
                    384:        this->mutex->lock(this->mutex);
                    385:        events = this->events->create_enumerator(this->events);
                    386:        while (events->enumerate(events, NULL, &event))
                    387:        {
                    388:                while (event->uses)
                    389:                {
                    390:                        this->cond->wait(this->cond, this->mutex);
                    391:                }
                    392:                ids = array_create_enumerator(event->clients);
                    393:                while (ids->enumerate(ids, &current))
                    394:                {
                    395:                        if (id == *current)
                    396:                        {
                    397:                                array_remove_at(event->clients, ids);
                    398:                        }
                    399:                }
                    400:                ids->destroy(ids);
                    401:        }
                    402:        events->destroy(events);
                    403:        this->mutex->unlock(this->mutex);
                    404: 
                    405:        DBG2(DBG_CFG, "vici client %u disconnected", id);
                    406: }
                    407: 
                    408: METHOD(vici_dispatcher_t, manage_command, void,
                    409:        private_vici_dispatcher_t *this, char *name,
                    410:        vici_command_cb_t cb, void *user)
                    411: {
                    412:        command_t *cmd;
                    413: 
                    414:        this->mutex->lock(this->mutex);
                    415:        if (cb)
                    416:        {
                    417:                INIT(cmd,
                    418:                        .name = strdup(name),
                    419:                        .cb = cb,
                    420:                        .user = user,
                    421:                );
                    422:                cmd = this->cmds->put(this->cmds, cmd->name, cmd);
                    423:        }
                    424:        else
                    425:        {
                    426:                cmd = this->cmds->remove(this->cmds, name);
                    427:        }
                    428:        if (cmd)
                    429:        {
                    430:                while (cmd->uses)
                    431:                {
                    432:                        this->cond->wait(this->cond, this->mutex);
                    433:                }
                    434:                free(cmd->name);
                    435:                free(cmd);
                    436:        }
                    437:        this->mutex->unlock(this->mutex);
                    438: }
                    439: 
                    440: METHOD(vici_dispatcher_t, manage_event, void,
                    441:        private_vici_dispatcher_t *this, char *name, bool reg)
                    442: {
                    443:        event_t *event;
                    444: 
                    445:        this->mutex->lock(this->mutex);
                    446:        if (reg)
                    447:        {
                    448:                INIT(event,
                    449:                        .name = strdup(name),
                    450:                        .clients = array_create(sizeof(u_int), 0),
                    451:                );
                    452:                event = this->events->put(this->events, event->name, event);
                    453:        }
                    454:        else
                    455:        {
                    456:                event = this->events->remove(this->events, name);
                    457:        }
                    458:        if (event)
                    459:        {
                    460:                while (event->uses)
                    461:                {
                    462:                        this->cond->wait(this->cond, this->mutex);
                    463:                }
                    464:                array_destroy(event->clients);
                    465:                free(event->name);
                    466:                free(event);
                    467:        }
                    468:        this->mutex->unlock(this->mutex);
                    469: }
                    470: 
                    471: METHOD(vici_dispatcher_t, has_event_listeners, bool,
                    472:        private_vici_dispatcher_t *this, char *name)
                    473: {
                    474:        event_t *event;
                    475:        bool retval = FALSE;
                    476: 
                    477:        this->mutex->lock(this->mutex);
                    478:        event = this->events->get(this->events, name);
                    479:        if (event)
                    480:        {
                    481:                /* the entry might be getting destroyed, but returning
                    482:                 * false positive is not a problem as a later raise_event
                    483:                 * will check things again. */
                    484:                retval = array_count(event->clients);
                    485:        }
                    486:        this->mutex->unlock(this->mutex);
                    487: 
                    488:        return retval;
                    489: }
                    490: 
                    491: METHOD(vici_dispatcher_t, raise_event, void,
                    492:        private_vici_dispatcher_t *this, char *name, u_int id,
                    493:        vici_message_t *message)
                    494: {
                    495:        enumerator_t *enumerator;
                    496:        event_t *event;
                    497:        u_int *current;
                    498: 
                    499:        this->mutex->lock(this->mutex);
                    500:        event = this->events->get(this->events, name);
                    501:        if (event)
                    502:        {
                    503:                event->uses++;
                    504:                this->mutex->unlock(this->mutex);
                    505: 
                    506:                enumerator = array_create_enumerator(event->clients);
                    507:                while (enumerator->enumerate(enumerator, &current))
                    508:                {
                    509:                        if (id == 0 || id == *current)
                    510:                        {
                    511:                                send_op(this, *current, VICI_EVENT, name, message);
                    512:                        }
                    513:                }
                    514:                enumerator->destroy(enumerator);
                    515: 
                    516:                this->mutex->lock(this->mutex);
                    517:                if (--event->uses == 0)
                    518:                {
                    519:                        this->cond->broadcast(this->cond);
                    520:                }
                    521:        }
                    522:        this->mutex->unlock(this->mutex);
                    523: 
                    524:        message->destroy(message);
                    525: }
                    526: 
                    527: METHOD(vici_dispatcher_t, destroy, void,
                    528:        private_vici_dispatcher_t *this)
                    529: {
                    530:        DESTROY_IF(this->socket);
                    531:        this->mutex->destroy(this->mutex);
                    532:        this->cond->destroy(this->cond);
                    533:        this->cmds->destroy(this->cmds);
                    534:        this->events->destroy(this->events);
                    535:        free(this);
                    536: }
                    537: 
                    538: /**
                    539:  * See header
                    540:  */
                    541: vici_dispatcher_t *vici_dispatcher_create(char *uri)
                    542: {
                    543:        private_vici_dispatcher_t *this;
                    544: 
                    545:        INIT(this,
                    546:                .public = {
                    547:                        .manage_command = _manage_command,
                    548:                        .manage_event = _manage_event,
                    549:                        .has_event_listeners = _has_event_listeners,
                    550:                        .raise_event = _raise_event,
                    551:                        .destroy = _destroy,
                    552:                },
                    553:                .cmds = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1),
                    554:                .events = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1),
                    555:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
                    556:                .cond = condvar_create(CONDVAR_TYPE_DEFAULT),
                    557:        );
                    558: 
                    559:        this->socket = vici_socket_create(uri, inbound, connect_, disconnect, this);
                    560:        if (!this->socket)
                    561:        {
                    562:                destroy(this);
                    563:                return NULL;
                    564:        }
                    565: 
                    566:        return &this->public;
                    567: }

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