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