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>