libstrongswan_vici_la_SOURCES = \
vici_socket.h vici_socket.c \
vici_message.h vici_message.c \
+ vici_builder.h vici_builder.c \
+ vici_dispatcher.h vici_dispatcher.c \
vici_plugin.h vici_plugin.c
libstrongswan_vici_la_LDFLAGS = -module -avoid-version
suites/test_message.c \
vici_socket.c \
vici_message.c \
+ vici_builder.c \
vici_tests.h vici_tests.c
vici_tests_CFLAGS = \
#include <test_suite.h>
#include "../vici_message.h"
+#include "../vici_builder.h"
#include <unistd.h>
}
END_TEST
+START_TEST(test_builder)
+{
+ enumerator_t *parse, *tmpl;
+ vici_message_t *m;
+ vici_builder_t *b;
+
+ b = vici_builder_create();
+ b->add(b, VICI_SECTION_START, "section1");
+ b->add(b, VICI_LIST_START, "list1");
+ b->add(b, VICI_LIST_ITEM, chunk_from_str("item1"));
+ b->add(b, VICI_LIST_ITEM, chunk_from_str("item2"));
+ b->add(b, VICI_LIST_END);
+ b->add(b, VICI_KEY_VALUE, "key1", chunk_from_str("value1"));
+ b->add(b, VICI_SECTION_END);
+ m = b->finalize(b);
+ ck_assert(m);
+ tmpl = endecode_create_enumerator(endecode_test_list);
+ parse = m->create_enumerator(m);
+ ck_assert(parse);
+
+ compare_vici(parse, tmpl);
+
+ m->destroy(m);
+ tmpl->destroy(tmpl);
+ parse->destroy(parse);
+}
+END_TEST
+
+START_TEST(test_builder_fmt)
+{
+ enumerator_t *parse, *tmpl;
+ vici_message_t *m;
+ vici_builder_t *b;
+
+ b = vici_builder_create();
+ b->begin_section(b, "section1");
+ b->begin_list(b, "list1");
+ b->add_li(b, "item%u", 1);
+ b->add_li(b, "%s%u", "item", 2);
+ b->end_list(b);
+ b->add_kv(b, "key1", "value%u", 1);
+ b->end_section(b);
+ m = b->finalize(b);
+ ck_assert(m);
+ tmpl = endecode_create_enumerator(endecode_test_list);
+ parse = m->create_enumerator(m);
+ ck_assert(parse);
+
+ compare_vici(parse, tmpl);
+
+ m->destroy(m);
+ tmpl->destroy(tmpl);
+ parse->destroy(parse);
+}
+END_TEST
+
Suite *message_suite_create()
{
Suite *s;
tcase_add_test(tc, test_vararg);
suite_add_tcase(s, tc);
+ tc = tcase_create("builder encode");
+ tcase_add_test(tc, test_builder);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("builder format encode");
+ tcase_add_test(tc, test_builder_fmt);
+ suite_add_tcase(s, tc);
+
return s;
}
--- /dev/null
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "vici_builder.h"
+
+#include <bio/bio_writer.h>
+
+typedef struct private_vici_builder_t private_vici_builder_t;
+
+/**
+ * Private data of an vici_builder_t object.
+ */
+struct private_vici_builder_t {
+
+ /**
+ * Public vici_builder_t interface.
+ */
+ vici_builder_t public;
+
+ /**
+ * Writer for elements
+ */
+ bio_writer_t *writer;
+
+ /**
+ * Errors encountered
+ */
+ u_int error;
+
+ /**
+ * Section nesting level
+ */
+ u_int section;
+
+ /**
+ * In list element?
+ */
+ bool list;
+};
+
+METHOD(vici_builder_t, add, void,
+ private_vici_builder_t *this, vici_type_t type, ...)
+{
+ va_list args;
+ char *name = NULL;
+ chunk_t value = chunk_empty;
+
+ va_start(args, type);
+ switch (type)
+ {
+ case VICI_SECTION_END:
+ case VICI_LIST_END:
+ case VICI_END:
+ break;
+ case VICI_LIST_START:
+ case VICI_SECTION_START:
+ name = va_arg(args, char*);
+ break;
+ case VICI_KEY_VALUE:
+ name = va_arg(args, char*);
+ value = va_arg(args, chunk_t);
+ break;
+ case VICI_LIST_ITEM:
+ value = va_arg(args, chunk_t);
+ break;
+ default:
+ va_end(args);
+ this->error++;
+ return;
+ }
+ va_end(args);
+
+ if (value.len > 0xffff)
+ {
+ this->error++;
+ return;
+ }
+ if (!vici_verify_type(type, this->section, this->list))
+ {
+ this->error++;
+ return;
+ }
+ if (type != VICI_END)
+ {
+ this->writer->write_uint8(this->writer, type);
+ }
+ switch (type)
+ {
+ case VICI_SECTION_START:
+ this->writer->write_data8(this->writer, chunk_from_str(name));
+ this->section++;
+ break;
+ case VICI_SECTION_END:
+ this->section--;
+ break;
+ case VICI_KEY_VALUE:
+ this->writer->write_data8(this->writer, chunk_from_str(name));
+ this->writer->write_data16(this->writer, value);
+ break;
+ case VICI_LIST_START:
+ this->writer->write_data8(this->writer, chunk_from_str(name));
+ this->list = TRUE;
+ break;
+ case VICI_LIST_ITEM:
+ this->writer->write_data16(this->writer, value);
+ break;
+ case VICI_LIST_END:
+ this->list = FALSE;
+ break;
+ default:
+ this->error++;
+ break;
+ }
+}
+
+METHOD(vici_builder_t, vadd_kv, void,
+ private_vici_builder_t *this, char *key, char *fmt, va_list args)
+{
+ char buf[2048];
+ ssize_t len;
+
+ len = vsnprintf(buf, sizeof(buf), fmt, args);
+ if (len < 0 || len >= sizeof(buf))
+ {
+ DBG1(DBG_ENC, "vici builder format buffer exceeds limit");
+ this->error++;
+ }
+ else
+ {
+ add(this, VICI_KEY_VALUE, key, chunk_create(buf, len));
+ }
+}
+
+METHOD(vici_builder_t, add_kv, void,
+ private_vici_builder_t *this, char *key, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vadd_kv(this, key, fmt, args);
+ va_end(args);
+}
+
+
+METHOD(vici_builder_t, vadd_li, void,
+ private_vici_builder_t *this, char *fmt, va_list args)
+{
+ char buf[2048];
+ ssize_t len;
+
+ len = vsnprintf(buf, sizeof(buf), fmt, args);
+ if (len < 0 || len >= sizeof(buf))
+ {
+ DBG1(DBG_ENC, "vici builder format buffer exceeds limit");
+ this->error++;
+ }
+ else
+ {
+ add(this, VICI_LIST_ITEM, chunk_create(buf, len));
+ }
+}
+
+METHOD(vici_builder_t, add_li, void,
+ private_vici_builder_t *this, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vadd_li(this, fmt, args);
+ va_end(args);
+}
+
+METHOD(vici_builder_t, begin_section, void,
+ private_vici_builder_t *this, char *name)
+{
+ add(this, VICI_SECTION_START, name);
+}
+
+METHOD(vici_builder_t, end_section, void,
+ private_vici_builder_t *this)
+{
+ add(this, VICI_SECTION_END);
+}
+
+METHOD(vici_builder_t, begin_list, void,
+ private_vici_builder_t *this, char *name)
+{
+ add(this, VICI_LIST_START, name);
+}
+
+METHOD(vici_builder_t, end_list, void,
+ private_vici_builder_t *this)
+{
+ add(this, VICI_LIST_END);
+}
+
+METHOD(vici_builder_t, finalize, vici_message_t*,
+ private_vici_builder_t *this)
+{
+ vici_message_t *product;
+
+ if (this->error || this->section || this->list)
+ {
+ DBG1(DBG_ENC, "vici builder error: %u errors (section: %u, list %u)",
+ this->error, this->section, this->list);
+ this->writer->destroy(this->writer);
+ free(this);
+ return NULL;
+ }
+ product = vici_message_create_from_data(
+ this->writer->extract_buf(this->writer), TRUE);
+ this->writer->destroy(this->writer);
+ free(this);
+ return product;
+}
+
+/**
+ * See header
+ */
+vici_builder_t *vici_builder_create()
+{
+ private_vici_builder_t *this;
+
+ INIT(this,
+ .public = {
+ .add = _add,
+ .add_kv = _add_kv,
+ .vadd_kv = _vadd_kv,
+ .add_li = _add_li,
+ .vadd_li = _vadd_li,
+ .begin_section = _begin_section,
+ .end_section = _end_section,
+ .begin_list = _begin_list,
+ .end_list = _end_list,
+ .finalize = _finalize,
+ },
+ .writer = bio_writer_create(0),
+ );
+
+ return &this->public;
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup vici_builder vici_builder
+ * @{ @ingroup vici
+ */
+
+#ifndef VICI_BUILDER_H_
+#define VICI_BUILDER_H_
+
+#include "vici_message.h"
+
+typedef struct vici_builder_t vici_builder_t;
+
+/**
+ * Build helper for vici message
+ */
+struct vici_builder_t {
+
+ /**
+ * Append a generic message element to message.
+ *
+ * The additional arguments are type specific, it may be nothing, a string,
+ * a chunk value or both.
+ *
+ * @param type element type to add
+ * @param ... additional type specific arguments
+ */
+ void (*add)(vici_builder_t *this, vici_type_t type, ...);
+
+ /**
+ * Append a key/value element using a format string.
+ *
+ * Instead of passing the type specific value as a chunk, this method
+ * takes a printf() style format string followed by its arguments. The
+ * key name for a key/value type is still a fixed string.
+ *
+ * @param key key name of the key/value to add
+ * @param fmt value format string
+ * @param ... arguments to value format string
+ */
+ void (*add_kv)(vici_builder_t *this, char *key, char *fmt, ...);
+
+ /**
+ * Append a message element using a format string and va_list.
+ *
+ * Instead of passing the type specific value as a chunk, this method
+ * takes a printf() style format string followed by its arguments. The
+ * key name for a key/value type is still a fixed string.
+ *
+ * @param key key name of the key/value to add
+ * @param fmt value format string
+ * @param args arguments to value format string
+ */
+ void (*vadd_kv)(vici_builder_t *this, char *key, char *fmt, va_list args);
+
+ /**
+ * Append a list item element using a format string.
+ *
+ * Instead of passing the type specific value as a chunk, this method
+ * takes a printf() style format string followed by its arguments.
+ *
+ * @param fmt value format string
+ * @param ... arguments to value format string
+ */
+ void (*add_li)(vici_builder_t *this, char *fmt, ...);
+
+ /**
+ * Append a list item element using a format string and va_list.
+ *
+ * Instead of passing the type specific value as a chunk, this method
+ * takes a printf() style format string followed by its arguments.
+ *
+ * @param fmt value format string
+ * @param args arguments to value format string
+ */
+ void (*vadd_li)(vici_builder_t *this, char *fmt, va_list args);
+
+ /**
+ * Begin a new section.
+ *
+ * @param name name of section to begin
+ */
+ void (*begin_section)(vici_builder_t *this, char *name);
+
+ /**
+ * End the currently open section.
+ */
+ void (*end_section)(vici_builder_t *this);
+
+ /**
+ * Begin a new list.
+ *
+ * @param name name of list to begin
+ */
+ void (*begin_list)(vici_builder_t *this, char *name);
+
+ /**
+ * End the currently open list.
+ */
+ void (*end_list)(vici_builder_t *this);
+
+ /**
+ * Finalize a vici message with all added elements, destroy builder.
+ *
+ * @return vici message, NULL on error
+ */
+ vici_message_t* (*finalize)(vici_builder_t *this);
+};
+
+/**
+ * Create a vici_builder instance.
+ */
+vici_builder_t *vici_builder_create();
+
+#endif /** VICI_BUILDER_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "vici_dispatcher.h"
+#include "vici_socket.h"
+
+#include <bio/bio_reader.h>
+#include <bio/bio_writer.h>
+#include <threading/mutex.h>
+#include <threading/condvar.h>
+#include <collections/array.h>
+#include <collections/hashtable.h>
+
+typedef struct private_vici_dispatcher_t private_vici_dispatcher_t;
+
+/**
+ * Private data of an vici_dispatcher_t object.
+ */
+struct private_vici_dispatcher_t {
+
+ /**
+ * Public vici_dispatcher_t interface.
+ */
+ vici_dispatcher_t public;
+
+ /**
+ * Socket to send/receive messages
+ */
+ vici_socket_t *socket;
+
+ /**
+ * List of registered commands (char* => command_t*)
+ */
+ hashtable_t *cmds;
+
+ /**
+ * List of known events, and registered clients (char* => event_t*)
+ */
+ hashtable_t *events;
+
+ /**
+ * Mutex to lock hashtables
+ */
+ mutex_t *mutex;
+
+ /**
+ * Condvar to signal command termination
+ */
+ condvar_t *cond;
+};
+
+/**
+ * Registered command
+ */
+typedef struct {
+ /** command name */
+ char *name;
+ /** callback for command */
+ vici_command_cb_t cb;
+ /** user data to pass to callback */
+ void *user;
+ /** command currently in use? */
+ u_int uses;
+} command_t;
+
+/**
+ * Registered event
+ */
+typedef struct {
+ /** event name */
+ char *name;
+ /** registered clients, as u_int */
+ array_t *clients;
+ /** event currently in use? */
+ u_int uses;
+} event_t;
+
+/**
+ * Send a operation code, optionally with name and message
+ */
+static void send_op(private_vici_dispatcher_t *this, u_int id,
+ vici_operation_t op, char *name, vici_message_t *message)
+{
+ bio_writer_t *writer;
+ u_int len;
+
+ len = sizeof(u_int8_t);
+ if (name)
+ {
+ len += sizeof(u_int8_t) + strlen(name);
+ }
+ if (message)
+ {
+ len += message->get_encoding(message).len;
+ }
+ writer = bio_writer_create(len);
+ writer->write_uint8(writer, op);
+ if (name)
+ {
+ writer->write_data8(writer, chunk_from_str(name));
+ }
+ if (message)
+ {
+ writer->write_data(writer, message->get_encoding(message));
+ }
+ this->socket->send(this->socket, id, writer->extract_buf(writer));
+ writer->destroy(writer);
+}
+
+/**
+ * Register client for event
+ */
+static void register_event(private_vici_dispatcher_t *this, char *name,
+ u_int id)
+{
+ event_t *event;
+
+ this->mutex->lock(this->mutex);
+ event = this->events->get(this->events, name);
+ if (event)
+ {
+ array_insert(event->clients, ARRAY_TAIL, &id);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (event)
+ {
+ send_op(this, id, VICI_EVENT_CONFIRM, NULL, NULL);
+ }
+ else
+ {
+ send_op(this, id, VICI_EVENT_UNKNOWN, NULL, NULL);
+ }
+}
+
+/**
+ * Unregister client for event
+ */
+static void unregister_event(private_vici_dispatcher_t *this, char *name,
+ u_int id)
+{
+ enumerator_t *enumerator;
+ event_t *event;
+ u_int *current;
+ bool found = FALSE;
+
+ this->mutex->lock(this->mutex);
+ event = this->events->get(this->events, name);
+ if (event)
+ {
+ enumerator = array_create_enumerator(event->clients);
+ while (enumerator->enumerate(enumerator, ¤t))
+ {
+ if (*current == id)
+ {
+ array_remove_at(event->clients, enumerator);
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (found)
+ {
+ send_op(this, id, VICI_EVENT_CONFIRM, NULL, NULL);
+ }
+ else
+ {
+ send_op(this, id, VICI_EVENT_UNKNOWN, NULL, NULL);
+ }
+}
+
+/**
+ * Process a request message
+ */
+void process_request(private_vici_dispatcher_t *this, char *name, u_int id,
+ chunk_t data)
+{
+ command_t *cmd;
+ vici_message_t *request, *response = NULL;
+
+ this->mutex->lock(this->mutex);
+ cmd = this->cmds->get(this->cmds, name);
+ if (cmd)
+ {
+ cmd->uses++;
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (cmd)
+ {
+ request = vici_message_create_from_data(data, FALSE);
+ response = cmd->cb(cmd->user, cmd->name, id, request);
+ request->destroy(request);
+
+ this->mutex->lock(this->mutex);
+ if (--cmd->uses == 0)
+ {
+ this->cond->broadcast(this->cond);
+ }
+ this->mutex->unlock(this->mutex);
+ }
+ if (response)
+ {
+ send_op(this, id, VICI_CMD_RESPONSE, NULL, response);
+ response->destroy(response);
+ }
+ else
+ {
+ send_op(this, id, VICI_CMD_UNKNOWN, NULL, NULL);
+ }
+}
+
+CALLBACK(inbound, void,
+ private_vici_dispatcher_t *this, u_int id, chunk_t data)
+{
+ bio_reader_t *reader;
+ chunk_t chunk;
+ u_int8_t type;
+ char name[257];
+
+ reader = bio_reader_create(data);
+ if (reader->read_uint8(reader, &type))
+ {
+ switch (type)
+ {
+ case VICI_EVENT_REGISTER:
+ if (reader->read_data8(reader, &chunk) &&
+ vici_stringify(chunk, name, sizeof(name)))
+ {
+ register_event(this, name, id);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "invalid vici register message");
+ }
+ break;
+ case VICI_EVENT_UNREGISTER:
+ if (reader->read_data8(reader, &chunk) &&
+ vici_stringify(chunk, name, sizeof(name)))
+ {
+ unregister_event(this, name, id);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "invalid vici unregister message");
+ }
+ break;
+ case VICI_CMD_REQUEST:
+ if (reader->read_data8(reader, &chunk) &&
+ vici_stringify(chunk, name, sizeof(name)))
+ {
+ process_request(this, name, id, reader->peek(reader));
+ }
+ else
+ {
+ DBG1(DBG_CFG, "invalid vici request message");
+ }
+ break;
+ case VICI_CMD_RESPONSE:
+ case VICI_EVENT_CONFIRM:
+ case VICI_EVENT_UNKNOWN:
+ case VICI_EVENT:
+ default:
+ DBG1(DBG_CFG, "unsupported vici operation: %u", type);
+ break;
+ }
+ }
+ else
+ {
+ DBG1(DBG_CFG, "invalid vici message");
+ }
+ reader->destroy(reader);
+}
+
+CALLBACK(connect_, void,
+ private_vici_dispatcher_t *this, u_int id)
+{
+}
+
+CALLBACK(disconnect, void,
+ private_vici_dispatcher_t *this, u_int id)
+{
+ enumerator_t *events, *ids;
+ event_t *event;
+ u_int *current;
+
+ /* deregister all clients */
+ this->mutex->lock(this->mutex);
+ events = this->events->create_enumerator(this->events);
+ while (events->enumerate(events, NULL, &event))
+ {
+ ids = array_create_enumerator(event->clients);
+ while (ids->enumerate(ids, ¤t))
+ {
+ if (id == *current)
+ {
+ array_remove_at(event->clients, ids);
+ }
+ }
+ ids->destroy(ids);
+ }
+ events->destroy(events);
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(vici_dispatcher_t, manage_command, void,
+ private_vici_dispatcher_t *this, char *name,
+ vici_command_cb_t cb, void *user)
+{
+ command_t *cmd;
+
+ this->mutex->lock(this->mutex);
+ if (cb)
+ {
+ INIT(cmd,
+ .name = strdup(name),
+ .cb = cb,
+ .user = user,
+ );
+ cmd = this->cmds->put(this->cmds, cmd->name, cmd);
+ }
+ else
+ {
+ cmd = this->cmds->remove(this->cmds, name);
+ }
+ if (cmd)
+ {
+ while (cmd->uses)
+ {
+ this->cond->wait(this->cond, this->mutex);
+ }
+ free(cmd->name);
+ free(cmd);
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(vici_dispatcher_t, manage_event, void,
+ private_vici_dispatcher_t *this, char *name, bool reg)
+{
+ event_t *event;
+
+ this->mutex->lock(this->mutex);
+ if (reg)
+ {
+ INIT(event,
+ .name = strdup(name),
+ .clients = array_create(sizeof(u_int), 0),
+ );
+ event = this->events->put(this->events, event->name, event);
+ }
+ else
+ {
+ event = this->events->remove(this->events, name);
+ }
+ if (event)
+ {
+ while (event->uses)
+ {
+ this->cond->wait(this->cond, this->mutex);
+ }
+ array_destroy(event->clients);
+ free(event->name);
+ free(event);
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(vici_dispatcher_t, raise_event, void,
+ private_vici_dispatcher_t *this, char *name, vici_message_t *message)
+{
+ enumerator_t *enumerator;
+ event_t *event;
+ u_int *id;
+
+ this->mutex->lock(this->mutex);
+ event = this->events->get(this->events, name);
+ if (event)
+ {
+ event->uses++;
+ }
+ this->mutex->unlock(this->mutex);
+
+ enumerator = array_create_enumerator(event->clients);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ send_op(this, *id, VICI_EVENT, name, message);
+ }
+ enumerator->destroy(enumerator);
+
+ this->mutex->lock(this->mutex);
+ if (--event->uses == 0)
+ {
+ this->cond->broadcast(this->cond);
+ }
+ this->mutex->unlock(this->mutex);
+
+ message->destroy(message);
+}
+
+METHOD(vici_dispatcher_t, destroy, void,
+ private_vici_dispatcher_t *this)
+{
+ DESTROY_IF(this->socket);
+ this->mutex->destroy(this->mutex);
+ this->cond->destroy(this->cond);
+ this->cmds->destroy(this->cmds);
+ this->events->destroy(this->events);
+ free(this);
+}
+
+/**
+ * See header
+ */
+vici_dispatcher_t *vici_dispatcher_create(char *uri)
+{
+ private_vici_dispatcher_t *this;
+
+ INIT(this,
+ .public = {
+ .manage_command = _manage_command,
+ .manage_event = _manage_event,
+ .raise_event = _raise_event,
+ .destroy = _destroy,
+ },
+ .cmds = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1),
+ .events = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .cond = condvar_create(CONDVAR_TYPE_DEFAULT),
+ );
+
+ this->socket = vici_socket_create(uri, inbound, connect_, disconnect, this);
+ if (!this->socket)
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ return &this->public;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup vici_dispatcher vici_dispatcher
+ * @{ @ingroup vici
+ */
+
+#ifndef VICI_DISPATCHER_H_
+#define VICI_DISPATCHER_H_
+
+#include "vici_message.h"
+
+typedef struct vici_dispatcher_t vici_dispatcher_t;
+typedef enum vici_operation_t vici_operation_t;
+
+/**
+ * Default socket URI of vici service
+ */
+#define VICI_DEFAULT_URI "unix://" IPSEC_PIDDIR "/charon.vici"
+
+/**
+ * Kind of vici operation
+ */
+enum vici_operation_t {
+ /** a named request message */
+ VICI_CMD_REQUEST,
+ /** an unnamed response message to a request */
+ VICI_CMD_RESPONSE,
+ /** unnamed response if requested command is unknown */
+ VICI_CMD_UNKNOWN,
+ /** a named event registration request */
+ VICI_EVENT_REGISTER,
+ /** a named event unregistration request */
+ VICI_EVENT_UNREGISTER,
+ /** unnamed response for successful event (un-)registration */
+ VICI_EVENT_CONFIRM,
+ /** unnamed response if event (un-)registration failed */
+ VICI_EVENT_UNKNOWN,
+ /** a named event message */
+ VICI_EVENT,
+};
+
+/**
+ * Vici command callback function
+ *
+ * @param user user data, as supplied during registration
+ * @param name name of the command it has been registered under
+ * @param id client connection identifier
+ * @param request request message data
+ * @return response message
+ */
+typedef vici_message_t* (*vici_command_cb_t)(void *user, char *name, u_int id,
+ vici_message_t *request);
+
+/**
+ * Vici command dispatcher.
+ */
+struct vici_dispatcher_t {
+
+ /**
+ * Register/Unregister a callback invoked for a specific command request.
+ *
+ * @param name name of the command
+ * @param cb callback function to register, NULL to unregister
+ * @param user user data to pass to callback
+ */
+ void (*manage_command)(vici_dispatcher_t *this, char *name,
+ vici_command_cb_t cb, void *user);
+
+ /**
+ * Register/Unregister an event type to send.
+ *
+ * The dispatcher internally manages event subscriptions. Clients registered
+ * for an event will receive such messages when the event is raised.
+ *
+ * @param name event name to manager
+ * @param reg TRUE to register, FALSE to unregister
+ */
+ void (*manage_event)(vici_dispatcher_t *this, char *name, bool reg);
+
+ /**
+ * Raise an event to all clients registered to that event.
+ *
+ * @param name event name to raise
+ * @param message event message to send, gets destroyed
+ */
+ void (*raise_event)(vici_dispatcher_t *this, char *name,
+ vici_message_t *message);
+
+ /**
+ * Destroy a vici_dispatcher_t.
+ */
+ void (*destroy)(vici_dispatcher_t *this);
+};
+
+/**
+ * Create a vici_dispatcher instance.
+ *
+ * @param uri uri for listening stream service
+ * @return dispatcher instance
+ */
+vici_dispatcher_t *vici_dispatcher_create(char *uri);
+
+#endif /** VICI_DISPATCHER_H_ @}*/
*/
#include "vici_message.h"
+#include "vici_builder.h"
#include <bio/bio_reader.h>
#include <bio/bio_writer.h>
}
/**
- * Verify the occurence of a given type for given section/list nesting
+ * See header.
*/
-static bool verify_type(vici_type_t type, int section, bool list)
+bool vici_verify_type(vici_type_t type, u_int section, bool list)
{
if (list)
{
*out = VICI_END;
return TRUE;
}
- if (!verify_type(type, this->section, this->list))
+ if (!vici_verify_type(type, this->section, this->list))
{
return FALSE;
}
}
/**
- * Write from enumerator to writer
+ * See header
*/
-static bool write_from_enumerator(bio_writer_t *writer,
- enumerator_t *enumerator)
+vici_message_t *vici_message_create_from_enumerator(enumerator_t *enumerator)
{
+ vici_builder_t *builder;
vici_type_t type;
char *name;
chunk_t value;
- int section = 0;
- bool list = FALSE;
+ builder = vici_builder_create();
while (enumerator->enumerate(enumerator, &type, &name, &value))
{
- if (!verify_type(type, section, list))
- {
- return FALSE;
- }
-
- if (type != VICI_END)
- {
- writer->write_uint8(writer, type);
- }
-
switch (type)
{
case VICI_SECTION_START:
- writer->write_data8(writer, chunk_from_str(name));
- section++;
- break;
- case VICI_SECTION_END:
- section--;
- break;
- case VICI_KEY_VALUE:
- writer->write_data8(writer, chunk_from_str(name));
- writer->write_data16(writer, value);
- break;
case VICI_LIST_START:
- writer->write_data8(writer, chunk_from_str(name));
- list = TRUE;
- break;
+ builder->add(builder, type, name);
+ continue;
+ case VICI_KEY_VALUE:
+ builder->add(builder, type, name, value);
+ continue;
case VICI_LIST_ITEM:
- writer->write_data16(writer, value);
- break;
+ builder->add(builder, type, value);
+ continue;
+ case VICI_SECTION_END:
case VICI_LIST_END:
- list = FALSE;
- break;
- case VICI_END:
- return TRUE;
default:
- return FALSE;
+ builder->add(builder, type);
+ continue;
+ case VICI_END:
+ break;
}
- }
- return FALSE;
-}
-
-/**
- * See header
- */
-vici_message_t *vici_message_create_from_enumerator(enumerator_t *enumerator)
-{
- vici_message_t *message = NULL;
- bio_writer_t *writer;
- chunk_t data;
-
- writer = bio_writer_create(0);
- if (write_from_enumerator(writer, enumerator))
- {
- data = chunk_clone(writer->get_buf(writer));
- message = vici_message_create_from_data(data, TRUE);
+ break;
}
enumerator->destroy(enumerator);
- writer->destroy(writer);
-
- return message;
-}
-
-/**
- * Enumerator for va_list arguments
- */
-typedef struct {
- /* implements enumerator */
- enumerator_t public;
- /** arguments to enumerate */
- va_list args;
- /** first type, if not yet processed */
- vici_type_t *first;
-} va_enumerator_t;
-
-METHOD(enumerator_t, va_enumerate, bool,
- va_enumerator_t *this, vici_type_t *out, char **name, chunk_t *value)
-{
- vici_type_t type;
-
- if (this->first)
- {
- type = *this->first;
- this->first = NULL;
- }
- else
- {
- type = va_arg(this->args, vici_type_t);
- }
- switch (type)
- {
- case VICI_SECTION_END:
- case VICI_LIST_END:
- case VICI_END:
- break;
- case VICI_LIST_START:
- case VICI_SECTION_START:
- *name = va_arg(this->args, char*);
- break;
- case VICI_KEY_VALUE:
- *name = va_arg(this->args, char*);
- *value = va_arg(this->args, chunk_t);
- break;
- case VICI_LIST_ITEM:
- *value = va_arg(this->args, chunk_t);
- break;
- default:
- return FALSE;
- }
- *out = type;
- return TRUE;
-}
-METHOD(enumerator_t, va_destroy, void,
- va_enumerator_t *this)
-{
- va_end(this->args);
- free(this);
+ return builder->finalize(builder);
}
/**
*/
vici_message_t *vici_message_create_from_args(vici_type_t type, ...)
{
- va_enumerator_t *enumerator;
-
- INIT(enumerator,
- .public = {
- .enumerate = (void*)_va_enumerate,
- .destroy = _va_destroy,
- },
- .first = &type,
- );
- va_start(enumerator->args, type);
+ vici_builder_t *builder;
+ va_list args;
+ char *name;
+ chunk_t value;
- return vici_message_create_from_enumerator(&enumerator->public);
+ builder = vici_builder_create();
+ va_start(args, type);
+ while (type != VICI_END)
+ {
+ switch (type)
+ {
+ case VICI_LIST_START:
+ case VICI_SECTION_START:
+ name = va_arg(args, char*);
+ builder->add(builder, type, name);
+ break;
+ case VICI_KEY_VALUE:
+ name = va_arg(args, char*);
+ value = va_arg(args, chunk_t);
+ builder->add(builder, type, name, value);
+ break;
+ case VICI_LIST_ITEM:
+ value = va_arg(args, chunk_t);
+ builder->add(builder, type, value);
+ break;
+ case VICI_SECTION_END:
+ case VICI_LIST_END:
+ default:
+ builder->add(builder, type);
+ break;
+ }
+ type = va_arg(args, vici_type_t);
+ }
+ va_end(args);
+ return builder->finalize(builder);
}
/**
* Create vici message from a variable argument list.
*
- * @param first first type beginning message
+ * @param type first type beginning message
* @param ... vici_type_t and args, terminated by VICI_END
* @return message representation, NULL on error
*/
/**
* Check if a chunk has a printable string, and print it to buf.
*
- * @param chunkt chunk containing potential string
+ * @param chunk chunk containing potential string
* @param buf buffer to write string to
* @param size size of buf
* @return TRUE if printable and string written to buf
*/
bool vici_stringify(chunk_t chunk, char *buf, size_t size);
+/**
+ * Verify the occurence of a given type for given section/list nesting
+ */
+bool vici_verify_type(vici_type_t type, u_int section, bool list);
+
#endif /** VICI_MESSAGE_H_ @}*/
*/
#include "vici_plugin.h"
+#include "vici_dispatcher.h"
#include <library.h>
+#include <daemon.h>
typedef struct private_vici_plugin_t private_vici_plugin_t;
* public functions
*/
vici_plugin_t public;
+
+ /**
+ * Dispatcher, creating socket
+ */
+ vici_dispatcher_t *dispatcher;
};
METHOD(plugin_t, get_name, char*,
static bool register_vici(private_vici_plugin_t *this,
plugin_feature_t *feature, bool reg, void *data)
{
+ if (reg)
+ {
+ char *uri;
+
+ uri = lib->settings->get_str(lib->settings, "%s.plugins.vici.socket",
+ VICI_DEFAULT_URI, lib->ns);
+ this->dispatcher = vici_dispatcher_create(uri);
+ return this->dispatcher != NULL;
+ }
+ else
+ {
+ this->dispatcher->destroy(this->dispatcher);
+ }
return TRUE;
}