Annotation of embedaddon/strongswan/src/libcharon/plugins/vici/libvici.c, revision 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: #include "libvici.h"
        !            17: #include "vici_builder.h"
        !            18: #include "vici_dispatcher.h"
        !            19: #include "vici_socket.h"
        !            20: 
        !            21: #include <library.h>
        !            22: #include <threading/mutex.h>
        !            23: #include <threading/condvar.h>
        !            24: #include <collections/hashtable.h>
        !            25: 
        !            26: #include <errno.h>
        !            27: 
        !            28: /**
        !            29:  * Event registration
        !            30:  */
        !            31: typedef struct {
        !            32:        /** name of event */
        !            33:        char *name;
        !            34:        /** callback function */
        !            35:        vici_event_cb_t cb;
        !            36:        /** user data for callback */
        !            37:        void *user;
        !            38: } event_t;
        !            39: 
        !            40: /**
        !            41:  * Wait state signaled by asynchronous on_read callback
        !            42:  */
        !            43: typedef enum {
        !            44:        WAIT_IDLE = 0,
        !            45:        WAIT_SUCCESS,
        !            46:        WAIT_FAILURE,
        !            47:        WAIT_READ_ERROR,
        !            48: } wait_state_t;
        !            49: 
        !            50: /**
        !            51:  * Private vici connection contex.
        !            52:  */
        !            53: struct vici_conn_t {
        !            54:        /** connection stream */
        !            55:        stream_t *stream;
        !            56:        /** event registrations, as char* => event_t */
        !            57:        hashtable_t *events;
        !            58:        /** connection lock */
        !            59:        mutex_t *mutex;
        !            60:        /** condvar to signal incoming response */
        !            61:        condvar_t *cond;
        !            62:        /** queued response message */
        !            63:        chunk_t queue;
        !            64:        /** asynchronous read error */
        !            65:        int error;
        !            66:        /** wait state */
        !            67:        wait_state_t wait;
        !            68: };
        !            69: 
        !            70: /**
        !            71:  * Private vici request message.
        !            72:  */
        !            73: struct vici_req_t {
        !            74:        /** connection context */
        !            75:        vici_conn_t *conn;
        !            76:        /** name of request message */
        !            77:        char *name;
        !            78:        /** message builder */
        !            79:        vici_builder_t *b;
        !            80: };
        !            81: 
        !            82: /**
        !            83:  * Private vici response/event message.
        !            84:  */
        !            85: struct vici_res_t {
        !            86:        /** response message */
        !            87:        vici_message_t *message;
        !            88:        /** allocated strings */
        !            89:        linked_list_t *strings;
        !            90:        /** item enumerator */
        !            91:        enumerator_t *enumerator;
        !            92:        /** currently enumerating type */
        !            93:        vici_type_t type;
        !            94:        /** currently enumerating name */
        !            95:        char *name;
        !            96:        /** currently enumerating value */
        !            97:        chunk_t value;
        !            98:        /** section nesting level of callback parser */
        !            99:        int level;
        !           100: };
        !           101: 
        !           102: /**
        !           103:  * Signal wait result for waiting user thread
        !           104:  */
        !           105: static bool wait_result(vici_conn_t *conn, wait_state_t wait)
        !           106: {
        !           107:        conn->mutex->lock(conn->mutex);
        !           108:        conn->wait = wait;
        !           109:        conn->mutex->unlock(conn->mutex);
        !           110:        conn->cond->signal(conn->cond);
        !           111:        return FALSE;
        !           112: }
        !           113: 
        !           114: /**
        !           115:  * Signal wait error result for waiting user thread
        !           116:  */
        !           117: static bool read_error(vici_conn_t *conn, int err)
        !           118: {
        !           119:        conn->error = err;
        !           120:        return wait_result(conn, WAIT_READ_ERROR);
        !           121: }
        !           122: 
        !           123: /**
        !           124:  * Handle a command response message
        !           125:  */
        !           126: static bool handle_response(vici_conn_t *conn, uint32_t len)
        !           127: {
        !           128:        chunk_t buf;
        !           129: 
        !           130:        buf = chunk_alloc(len);
        !           131:        if (!conn->stream->read_all(conn->stream, buf.ptr, buf.len))
        !           132:        {
        !           133:                free(buf.ptr);
        !           134:                return read_error(conn, errno);
        !           135:        }
        !           136:        conn->queue = buf;
        !           137:        return wait_result(conn, WAIT_SUCCESS);
        !           138: }
        !           139: 
        !           140: /**
        !           141:  * Dispatch received event message
        !           142:  */
        !           143: static bool handle_event(vici_conn_t *conn, uint32_t len)
        !           144: {
        !           145:        vici_message_t *message;
        !           146:        event_t *event;
        !           147:        uint8_t namelen;
        !           148:        char name[257], *buf;
        !           149: 
        !           150:        if (len < sizeof(namelen))
        !           151:        {
        !           152:                return read_error(conn, EBADMSG);
        !           153:        }
        !           154:        if (!conn->stream->read_all(conn->stream, &namelen, sizeof(namelen)))
        !           155:        {
        !           156:                return read_error(conn, errno);
        !           157:        }
        !           158:        if (namelen > len - sizeof(namelen))
        !           159:        {
        !           160:                return read_error(conn, EBADMSG);
        !           161:        }
        !           162:        if (!conn->stream->read_all(conn->stream, name, namelen))
        !           163:        {
        !           164:                return read_error(conn, errno);
        !           165:        }
        !           166:        name[namelen] = '\0';
        !           167:        len -= sizeof(namelen) + namelen;
        !           168:        buf = malloc(len);
        !           169:        if (!conn->stream->read_all(conn->stream, buf, len))
        !           170:        {
        !           171:                free(buf);
        !           172:                return read_error(conn, errno);
        !           173:        }
        !           174:        message = vici_message_create_from_data(chunk_create(buf, len), TRUE);
        !           175: 
        !           176:        conn->mutex->lock(conn->mutex);
        !           177:        event = conn->events->get(conn->events, name);
        !           178:        if (event)
        !           179:        {
        !           180:                vici_res_t res = {
        !           181:                        .message = message,
        !           182:                        .enumerator = message->create_enumerator(message),
        !           183:                        .strings = linked_list_create(),
        !           184:                };
        !           185: 
        !           186:                event->cb(event->user, name, &res);
        !           187: 
        !           188:                res.enumerator->destroy(res.enumerator);
        !           189:                res.strings->destroy_function(res.strings, free);
        !           190:        }
        !           191:        conn->mutex->unlock(conn->mutex);
        !           192: 
        !           193:        message->destroy(message);
        !           194: 
        !           195:        return TRUE;
        !           196: }
        !           197: 
        !           198: CALLBACK(on_read, bool,
        !           199:        vici_conn_t *conn, stream_t *stream)
        !           200: {
        !           201:        uint32_t len;
        !           202:        uint8_t op;
        !           203:        ssize_t hlen;
        !           204: 
        !           205:        hlen = stream->read(stream, &len, sizeof(len), FALSE);
        !           206:        if (hlen <= 0)
        !           207:        {
        !           208:                if (errno == EWOULDBLOCK)
        !           209:                {
        !           210:                        return TRUE;
        !           211:                }
        !           212:                return read_error(conn, errno);
        !           213:        }
        !           214:        if (hlen < sizeof(len))
        !           215:        {
        !           216:                if (!stream->read_all(stream, ((void*)&len) + hlen, sizeof(len) - hlen))
        !           217:                {
        !           218:                        return read_error(conn, errno);
        !           219:                }
        !           220:        }
        !           221: 
        !           222:        len = ntohl(len);
        !           223:        if (len > VICI_MESSAGE_SIZE_MAX)
        !           224:        {
        !           225:                return read_error(conn, EBADMSG);
        !           226:        }
        !           227:        if (len-- < sizeof(op))
        !           228:        {
        !           229:                return read_error(conn, EBADMSG);
        !           230:        }
        !           231:        if (!stream->read_all(stream, &op, sizeof(op)))
        !           232:        {
        !           233:                return read_error(conn, errno);
        !           234:        }
        !           235:        switch (op)
        !           236:        {
        !           237:                case VICI_EVENT:
        !           238:                        return handle_event(conn, len);
        !           239:                case VICI_CMD_RESPONSE:
        !           240:                        return handle_response(conn, len);
        !           241:                case VICI_EVENT_CONFIRM:
        !           242:                        return wait_result(conn, WAIT_SUCCESS);
        !           243:                case VICI_CMD_UNKNOWN:
        !           244:                case VICI_EVENT_UNKNOWN:
        !           245:                        return wait_result(conn, WAIT_FAILURE);
        !           246:                case VICI_CMD_REQUEST:
        !           247:                case VICI_EVENT_REGISTER:
        !           248:                case VICI_EVENT_UNREGISTER:
        !           249:                default:
        !           250:                        return read_error(conn, EBADMSG);
        !           251:        }
        !           252: }
        !           253: 
        !           254: vici_conn_t* vici_connect(char *uri)
        !           255: {
        !           256:        vici_conn_t *conn;
        !           257:        stream_t *stream;
        !           258: 
        !           259:        stream = lib->streams->connect(lib->streams, uri ?: VICI_DEFAULT_URI);
        !           260:        if (!stream)
        !           261:        {
        !           262:                return NULL;
        !           263:        }
        !           264: 
        !           265:        INIT(conn,
        !           266:                .stream = stream,
        !           267:                .events = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1),
        !           268:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
        !           269:                .cond = condvar_create(CONDVAR_TYPE_DEFAULT),
        !           270:        );
        !           271: 
        !           272:        stream->on_read(stream, on_read, conn);
        !           273: 
        !           274:        return conn;
        !           275: }
        !           276: 
        !           277: void vici_disconnect(vici_conn_t *conn)
        !           278: {
        !           279:        enumerator_t *enumerator;
        !           280:        event_t *event;
        !           281: 
        !           282:        conn->stream->destroy(conn->stream);
        !           283:        enumerator = conn->events->create_enumerator(conn->events);
        !           284:        while (enumerator->enumerate(enumerator, NULL, &event))
        !           285:        {
        !           286:                free(event->name);
        !           287:                free(event);
        !           288:        }
        !           289:        enumerator->destroy(enumerator);
        !           290:        conn->events->destroy(conn->events);
        !           291:        conn->mutex->destroy(conn->mutex);
        !           292:        conn->cond->destroy(conn->cond);
        !           293:        free(conn);
        !           294: }
        !           295: 
        !           296: vici_req_t* vici_begin(char *name)
        !           297: {
        !           298:        vici_req_t *req;
        !           299: 
        !           300:        INIT(req,
        !           301:                .name = strdup(name),
        !           302:                .b = vici_builder_create(),
        !           303:        );
        !           304: 
        !           305:        return req;
        !           306: }
        !           307: 
        !           308: void vici_begin_section(vici_req_t *req, char *name)
        !           309: {
        !           310:        req->b->add(req->b, VICI_SECTION_START, name);
        !           311: }
        !           312: 
        !           313: void vici_end_section(vici_req_t *req)
        !           314: {
        !           315:        req->b->add(req->b, VICI_SECTION_END);
        !           316: }
        !           317: 
        !           318: void vici_add_key_value(vici_req_t *req, char *key, void *buf, int len)
        !           319: {
        !           320:        req->b->add(req->b, VICI_KEY_VALUE, key, chunk_create(buf, len));
        !           321: }
        !           322: 
        !           323: void vici_add_key_valuef(vici_req_t *req, char *key, char *fmt, ...)
        !           324: {
        !           325:        va_list args;
        !           326: 
        !           327:        va_start(args, fmt);
        !           328:        req->b->vadd_kv(req->b, key, fmt, args);
        !           329:        va_end(args);
        !           330: }
        !           331: 
        !           332: void vici_begin_list(vici_req_t *req, char *name)
        !           333: {
        !           334:        req->b->add(req->b, VICI_LIST_START, name);
        !           335: }
        !           336: 
        !           337: void vici_add_list_item(vici_req_t *req, void *buf, int len)
        !           338: {
        !           339:        req->b->add(req->b, VICI_LIST_ITEM, chunk_create(buf, len));
        !           340: }
        !           341: 
        !           342: void vici_add_list_itemf(vici_req_t *req, char *fmt, ...)
        !           343: {
        !           344:        va_list args;
        !           345: 
        !           346:        va_start(args, fmt);
        !           347:        req->b->vadd_li(req->b, fmt, args);
        !           348:        va_end(args);
        !           349: }
        !           350: 
        !           351: void vici_end_list(vici_req_t *req)
        !           352: {
        !           353:        req->b->add(req->b, VICI_LIST_END);
        !           354: }
        !           355: 
        !           356: vici_res_t* vici_submit(vici_req_t *req, vici_conn_t *conn)
        !           357: {
        !           358:        vici_message_t *message;
        !           359:        vici_res_t *res;
        !           360:        chunk_t data;
        !           361:        uint32_t len;
        !           362:        uint8_t namelen, op;
        !           363: 
        !           364:        message = req->b->finalize(req->b);
        !           365:        if (!message)
        !           366:        {
        !           367:                errno = EINVAL;
        !           368:                return NULL;
        !           369:        }
        !           370: 
        !           371:        op = VICI_CMD_REQUEST;
        !           372:        namelen = strlen(req->name);
        !           373:        data = message->get_encoding(message);
        !           374:        len = htonl(sizeof(op) + sizeof(namelen) + namelen + data.len);
        !           375: 
        !           376:        if (!conn->stream->write_all(conn->stream, &len, sizeof(len)) ||
        !           377:                !conn->stream->write_all(conn->stream, &op, sizeof(op)) ||
        !           378:                !conn->stream->write_all(conn->stream, &namelen, sizeof(namelen)) ||
        !           379:                !conn->stream->write_all(conn->stream, req->name, namelen) ||
        !           380:                !conn->stream->write_all(conn->stream, data.ptr, data.len))
        !           381:        {
        !           382:                free(req->name);
        !           383:                free(req);
        !           384:                message->destroy(message);
        !           385:                return NULL;
        !           386:        }
        !           387:        free(req->name);
        !           388:        free(req);
        !           389:        message->destroy(message);
        !           390: 
        !           391:        message = NULL;
        !           392:        conn->mutex->lock(conn->mutex);
        !           393:        while (conn->wait == WAIT_IDLE)
        !           394:        {
        !           395:                conn->cond->wait(conn->cond, conn->mutex);
        !           396:        }
        !           397:        switch (conn->wait)
        !           398:        {
        !           399:                case WAIT_SUCCESS:
        !           400:                        message = vici_message_create_from_data(conn->queue, TRUE);
        !           401:                        conn->queue = chunk_empty;
        !           402:                        break;
        !           403:                case WAIT_READ_ERROR:
        !           404:                        errno = conn->error;
        !           405:                        break;
        !           406:                case WAIT_FAILURE:
        !           407:                default:
        !           408:                        errno = ENOENT;
        !           409:                        break;
        !           410:        }
        !           411:        conn->wait = WAIT_IDLE;
        !           412:        conn->mutex->unlock(conn->mutex);
        !           413: 
        !           414:        conn->stream->on_read(conn->stream, on_read, conn);
        !           415: 
        !           416:        if (message)
        !           417:        {
        !           418:                INIT(res,
        !           419:                        .message = message,
        !           420:                        .enumerator = message->create_enumerator(message),
        !           421:                        .strings = linked_list_create(),
        !           422:                );
        !           423:                return res;
        !           424:        }
        !           425:        return NULL;
        !           426: }
        !           427: 
        !           428: void vici_free_req(vici_req_t *req)
        !           429: {
        !           430:        free(req->name);
        !           431:        req->b->destroy(req->b);
        !           432:        free(req);
        !           433: }
        !           434: 
        !           435: int vici_dump(vici_res_t *res, char *label, int pretty, FILE *out)
        !           436: {
        !           437:        if (res->message->dump(res->message, label, pretty, out))
        !           438:        {
        !           439:                return 0;
        !           440:        }
        !           441:        errno = EBADMSG;
        !           442:        return 1;
        !           443: }
        !           444: 
        !           445: vici_parse_t vici_parse(vici_res_t *res)
        !           446: {
        !           447:        if (!res->enumerator->enumerate(res->enumerator,
        !           448:                                                                        &res->type, &res->name, &res->value))
        !           449:        {
        !           450:                return VICI_PARSE_ERROR;
        !           451:        }
        !           452:        switch (res->type)
        !           453:        {
        !           454:                case VICI_END:
        !           455:                        return VICI_PARSE_END;
        !           456:                case VICI_SECTION_START:
        !           457:                        return VICI_PARSE_BEGIN_SECTION;
        !           458:                case VICI_SECTION_END:
        !           459:                        return VICI_PARSE_END_SECTION;
        !           460:                case VICI_LIST_START:
        !           461:                        return VICI_PARSE_BEGIN_LIST;
        !           462:                case VICI_LIST_ITEM:
        !           463:                        return VICI_PARSE_LIST_ITEM;
        !           464:                case VICI_LIST_END:
        !           465:                        return VICI_PARSE_END_LIST;
        !           466:                case VICI_KEY_VALUE:
        !           467:                        return VICI_PARSE_KEY_VALUE;
        !           468:                default:
        !           469:                        return VICI_PARSE_ERROR;
        !           470:        }
        !           471: }
        !           472: 
        !           473: char* vici_parse_name(vici_res_t *res)
        !           474: {
        !           475:        char *name;
        !           476: 
        !           477:        switch (res->type)
        !           478:        {
        !           479:                case VICI_SECTION_START:
        !           480:                case VICI_LIST_START:
        !           481:                case VICI_KEY_VALUE:
        !           482:                        name = strdup(res->name);
        !           483:                        res->strings->insert_last(res->strings, name);
        !           484:                        return name;
        !           485:                default:
        !           486:                        errno = EINVAL;
        !           487:                        return NULL;
        !           488:        }
        !           489: }
        !           490: 
        !           491: int vici_parse_name_eq(vici_res_t *res, char *name)
        !           492: {
        !           493:        switch (res->type)
        !           494:        {
        !           495:                case VICI_SECTION_START:
        !           496:                case VICI_LIST_START:
        !           497:                case VICI_KEY_VALUE:
        !           498:                        return streq(name, res->name) ? 1 : 0;
        !           499:                default:
        !           500:                        return 0;
        !           501:        }
        !           502: }
        !           503: 
        !           504: void* vici_parse_value(vici_res_t *res, int *len)
        !           505: {
        !           506:        switch (res->type)
        !           507:        {
        !           508:                case VICI_LIST_ITEM:
        !           509:                case VICI_KEY_VALUE:
        !           510:                        *len = res->value.len;
        !           511:                        return res->value.ptr;
        !           512:                default:
        !           513:                        *len = 0;
        !           514:                        errno = EINVAL;
        !           515:                        return NULL;
        !           516:        }
        !           517: }
        !           518: 
        !           519: char* vici_parse_value_str(vici_res_t *res)
        !           520: {
        !           521:        char *val;
        !           522: 
        !           523:        switch (res->type)
        !           524:        {
        !           525:                case VICI_LIST_ITEM:
        !           526:                case VICI_KEY_VALUE:
        !           527:                        if (!chunk_printable(res->value, NULL, 0))
        !           528:                        {
        !           529:                                errno = EBADMSG;
        !           530:                                return NULL;
        !           531:                        }
        !           532:                        val = strndup(res->value.ptr, res->value.len);
        !           533:                        res->strings->insert_last(res->strings, val);
        !           534:                        return val;
        !           535:                default:
        !           536:                        errno = EINVAL;
        !           537:                        return NULL;
        !           538:        }
        !           539: }
        !           540: 
        !           541: int vici_parse_cb(vici_res_t *res, vici_parse_section_cb_t section,
        !           542:                                  vici_parse_value_cb_t kv, vici_parse_value_cb_t li,
        !           543:                                  void *user)
        !           544: {
        !           545:        char *name, *list = NULL;
        !           546:        void *value;
        !           547:        int base, len, ret;
        !           548: 
        !           549:        base = res->level;
        !           550: 
        !           551:        while (TRUE)
        !           552:        {
        !           553:                switch (vici_parse(res))
        !           554:                {
        !           555:                        case VICI_PARSE_KEY_VALUE:
        !           556:                                if (res->level == base)
        !           557:                                {
        !           558:                                        if (kv)
        !           559:                                        {
        !           560:                                                name = vici_parse_name(res);
        !           561:                                                value = vici_parse_value(res, &len);
        !           562:                                                if (name && value)
        !           563:                                                {
        !           564:                                                        ret = kv(user, res, name, value, len);
        !           565:                                                        if (ret)
        !           566:                                                        {
        !           567:                                                                return ret;
        !           568:                                                        }
        !           569:                                                }
        !           570:                                        }
        !           571:                                }
        !           572:                                break;
        !           573:                        case VICI_PARSE_BEGIN_SECTION:
        !           574:                                if (res->level++ == base)
        !           575:                                {
        !           576:                                        if (section)
        !           577:                                        {
        !           578:                                                name = vici_parse_name(res);
        !           579:                                                if (name)
        !           580:                                                {
        !           581:                                                        ret = section(user, res, name);
        !           582:                                                        if (ret)
        !           583:                                                        {
        !           584:                                                                return ret;
        !           585:                                                        }
        !           586:                                                }
        !           587:                                        }
        !           588:                                }
        !           589:                                break;
        !           590:                        case VICI_PARSE_END_SECTION:
        !           591:                                if (res->level-- == base)
        !           592:                                {
        !           593:                                        return 0;
        !           594:                                }
        !           595:                                break;
        !           596:                        case VICI_PARSE_END:
        !           597:                                res->level = 0;
        !           598:                                return 0;
        !           599:                        case VICI_PARSE_BEGIN_LIST:
        !           600:                                if (res->level == base)
        !           601:                                {
        !           602:                                        list = vici_parse_name(res);
        !           603:                                }
        !           604:                                break;
        !           605:                        case VICI_PARSE_LIST_ITEM:
        !           606:                                if (list && li)
        !           607:                                {
        !           608:                                        value = vici_parse_value(res, &len);
        !           609:                                        if (value)
        !           610:                                        {
        !           611:                                                ret = li(user, res, list, value, len);
        !           612:                                                if (ret)
        !           613:                                                {
        !           614:                                                        return ret;
        !           615:                                                }
        !           616:                                        }
        !           617:                                }
        !           618:                                break;
        !           619:                        case VICI_PARSE_END_LIST:
        !           620:                                if (res->level == base)
        !           621:                                {
        !           622:                                        list = NULL;
        !           623:                                }
        !           624:                                break;
        !           625:                        case VICI_PARSE_ERROR:
        !           626:                                res->level = 0;
        !           627:                                errno = EBADMSG;
        !           628:                                return 1;
        !           629:                }
        !           630:        }
        !           631: }
        !           632: 
        !           633: void* vici_find(vici_res_t *res, int *len, char *fmt, ...)
        !           634: {
        !           635:        va_list args;
        !           636:        chunk_t value;
        !           637: 
        !           638:        va_start(args, fmt);
        !           639:        value = res->message->vget_value(res->message, chunk_empty, fmt, args);
        !           640:        va_end(args);
        !           641: 
        !           642:        *len = value.len;
        !           643:        return value.ptr;
        !           644: }
        !           645: 
        !           646: char* vici_find_str(vici_res_t *res, char *def, char *fmt, ...)
        !           647: {
        !           648:        va_list args;
        !           649:        char *str;
        !           650: 
        !           651:        va_start(args, fmt);
        !           652:        str = res->message->vget_str(res->message, def, fmt, args);
        !           653:        va_end(args);
        !           654: 
        !           655:        return str;
        !           656: }
        !           657: 
        !           658: int vici_find_int(vici_res_t *res, int def, char *fmt, ...)
        !           659: {
        !           660:        va_list args;
        !           661:        int val;
        !           662: 
        !           663:        va_start(args, fmt);
        !           664:        val = res->message->vget_int(res->message, def, fmt, args);
        !           665:        va_end(args);
        !           666: 
        !           667:        return val;
        !           668: }
        !           669: 
        !           670: void vici_free_res(vici_res_t *res)
        !           671: {
        !           672:        res->strings->destroy_function(res->strings, free);
        !           673:        res->message->destroy(res->message);
        !           674:        res->enumerator->destroy(res->enumerator);
        !           675:        free(res);
        !           676: }
        !           677: 
        !           678: int vici_register(vici_conn_t *conn, char *name, vici_event_cb_t cb, void *user)
        !           679: {
        !           680:        event_t *event;
        !           681:        uint32_t len;
        !           682:        uint8_t namelen, op;
        !           683:        int ret = 1;
        !           684: 
        !           685:        op = cb ? VICI_EVENT_REGISTER : VICI_EVENT_UNREGISTER;
        !           686:        namelen = strlen(name);
        !           687:        len = htonl(sizeof(op) + sizeof(namelen) + namelen);
        !           688:        if (!conn->stream->write_all(conn->stream, &len, sizeof(len)) ||
        !           689:                !conn->stream->write_all(conn->stream, &op, sizeof(op)) ||
        !           690:                !conn->stream->write_all(conn->stream, &namelen, sizeof(namelen)) ||
        !           691:                !conn->stream->write_all(conn->stream, name, namelen))
        !           692:        {
        !           693:                return 1;
        !           694:        }
        !           695: 
        !           696:        conn->mutex->lock(conn->mutex);
        !           697:        while (conn->wait == WAIT_IDLE)
        !           698:        {
        !           699:                conn->cond->wait(conn->cond, conn->mutex);
        !           700:        }
        !           701:        switch (conn->wait)
        !           702:        {
        !           703:                case WAIT_SUCCESS:
        !           704:                        ret = 0;
        !           705:                        break;
        !           706:                case WAIT_READ_ERROR:
        !           707:                        errno = conn->error;
        !           708:                        break;
        !           709:                case WAIT_FAILURE:
        !           710:                default:
        !           711:                        errno = ENOENT;
        !           712:                        break;
        !           713:        }
        !           714:        conn->wait = WAIT_IDLE;
        !           715:        conn->mutex->unlock(conn->mutex);
        !           716: 
        !           717:        conn->stream->on_read(conn->stream, on_read, conn);
        !           718: 
        !           719:        if (ret == 0)
        !           720:        {
        !           721:                conn->mutex->lock(conn->mutex);
        !           722:                if (cb)
        !           723:                {
        !           724:                        INIT(event,
        !           725:                                .name = strdup(name),
        !           726:                                .cb = cb,
        !           727:                                .user = user,
        !           728:                        );
        !           729:                        event = conn->events->put(conn->events, event->name, event);
        !           730:                }
        !           731:                else
        !           732:                {
        !           733:                        event = conn->events->remove(conn->events, name);
        !           734:                }
        !           735:                conn->mutex->unlock(conn->mutex);
        !           736: 
        !           737:                if (event)
        !           738:                {
        !           739:                        free(event->name);
        !           740:                        free(event);
        !           741:                }
        !           742:        }
        !           743:        return ret;
        !           744: }
        !           745: 
        !           746: void vici_init()
        !           747: {
        !           748:        library_init(NULL, "vici");
        !           749:        if (lib->processor->get_total_threads(lib->processor) < 4)
        !           750:        {
        !           751:                dbg_default_set_level(0);
        !           752:                lib->processor->set_threads(lib->processor, 4);
        !           753:                dbg_default_set_level(1);
        !           754:        }
        !           755: }
        !           756: 
        !           757: void vici_deinit()
        !           758: {
        !           759:        lib->processor->cancel(lib->processor);
        !           760:        library_deinit();
        !           761: }

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