vici: Provide a command dispatcher handling request and event registration
This commit is contained in:
@@ -16,6 +16,8 @@ endif
|
|||||||
libstrongswan_vici_la_SOURCES = \
|
libstrongswan_vici_la_SOURCES = \
|
||||||
vici_socket.h vici_socket.c \
|
vici_socket.h vici_socket.c \
|
||||||
vici_message.h vici_message.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
|
vici_plugin.h vici_plugin.c
|
||||||
|
|
||||||
libstrongswan_vici_la_LDFLAGS = -module -avoid-version
|
libstrongswan_vici_la_LDFLAGS = -module -avoid-version
|
||||||
@@ -29,6 +31,7 @@ vici_tests_SOURCES = \
|
|||||||
suites/test_message.c \
|
suites/test_message.c \
|
||||||
vici_socket.c \
|
vici_socket.c \
|
||||||
vici_message.c \
|
vici_message.c \
|
||||||
|
vici_builder.c \
|
||||||
vici_tests.h vici_tests.c
|
vici_tests.h vici_tests.c
|
||||||
|
|
||||||
vici_tests_CFLAGS = \
|
vici_tests_CFLAGS = \
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <test_suite.h>
|
#include <test_suite.h>
|
||||||
|
|
||||||
#include "../vici_message.h"
|
#include "../vici_message.h"
|
||||||
|
#include "../vici_builder.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@@ -247,6 +248,62 @@ START_TEST(test_vararg)
|
|||||||
}
|
}
|
||||||
END_TEST
|
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 *message_suite_create()
|
||||||
{
|
{
|
||||||
Suite *s;
|
Suite *s;
|
||||||
@@ -262,5 +319,13 @@ Suite *message_suite_create()
|
|||||||
tcase_add_test(tc, test_vararg);
|
tcase_add_test(tc, test_vararg);
|
||||||
suite_add_tcase(s, tc);
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* 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_ @}*/
|
||||||
@@ -0,0 +1,455 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* 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_ @}*/
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "vici_message.h"
|
#include "vici_message.h"
|
||||||
|
#include "vici_builder.h"
|
||||||
|
|
||||||
#include <bio/bio_reader.h>
|
#include <bio/bio_reader.h>
|
||||||
#include <bio/bio_writer.h>
|
#include <bio/bio_writer.h>
|
||||||
@@ -65,9 +66,9 @@ bool vici_stringify(chunk_t chunk, char *buf, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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)
|
if (list)
|
||||||
{
|
{
|
||||||
@@ -133,7 +134,7 @@ METHOD(enumerator_t, parse_enumerate, bool,
|
|||||||
*out = VICI_END;
|
*out = VICI_END;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (!verify_type(type, this->section, this->list))
|
if (!vici_verify_type(type, this->section, this->list))
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -250,138 +251,44 @@ vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup)
|
|||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Write from enumerator to writer
|
|
||||||
*/
|
|
||||||
static bool write_from_enumerator(bio_writer_t *writer,
|
|
||||||
enumerator_t *enumerator)
|
|
||||||
{
|
|
||||||
vici_type_t type;
|
|
||||||
char *name;
|
|
||||||
chunk_t value;
|
|
||||||
int section = 0;
|
|
||||||
bool list = FALSE;
|
|
||||||
|
|
||||||
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;
|
|
||||||
case VICI_LIST_ITEM:
|
|
||||||
writer->write_data16(writer, value);
|
|
||||||
break;
|
|
||||||
case VICI_LIST_END:
|
|
||||||
list = FALSE;
|
|
||||||
break;
|
|
||||||
case VICI_END:
|
|
||||||
return TRUE;
|
|
||||||
default:
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See header
|
* See header
|
||||||
*/
|
*/
|
||||||
vici_message_t *vici_message_create_from_enumerator(enumerator_t *enumerator)
|
vici_message_t *vici_message_create_from_enumerator(enumerator_t *enumerator)
|
||||||
{
|
{
|
||||||
vici_message_t *message = NULL;
|
vici_builder_t *builder;
|
||||||
bio_writer_t *writer;
|
vici_type_t type;
|
||||||
chunk_t data;
|
char *name;
|
||||||
|
chunk_t value;
|
||||||
|
|
||||||
writer = bio_writer_create(0);
|
builder = vici_builder_create();
|
||||||
if (write_from_enumerator(writer, enumerator))
|
while (enumerator->enumerate(enumerator, &type, &name, &value))
|
||||||
{
|
{
|
||||||
data = chunk_clone(writer->get_buf(writer));
|
switch (type)
|
||||||
message = vici_message_create_from_data(data, TRUE);
|
{
|
||||||
|
case VICI_SECTION_START:
|
||||||
|
case VICI_LIST_START:
|
||||||
|
builder->add(builder, type, name);
|
||||||
|
continue;
|
||||||
|
case VICI_KEY_VALUE:
|
||||||
|
builder->add(builder, type, name, value);
|
||||||
|
continue;
|
||||||
|
case VICI_LIST_ITEM:
|
||||||
|
builder->add(builder, type, value);
|
||||||
|
continue;
|
||||||
|
case VICI_SECTION_END:
|
||||||
|
case VICI_LIST_END:
|
||||||
|
default:
|
||||||
|
builder->add(builder, type);
|
||||||
|
continue;
|
||||||
|
case VICI_END:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
writer->destroy(writer);
|
|
||||||
|
|
||||||
return message;
|
return builder->finalize(builder);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -389,16 +296,39 @@ METHOD(enumerator_t, va_destroy, void,
|
|||||||
*/
|
*/
|
||||||
vici_message_t *vici_message_create_from_args(vici_type_t type, ...)
|
vici_message_t *vici_message_create_from_args(vici_type_t type, ...)
|
||||||
{
|
{
|
||||||
va_enumerator_t *enumerator;
|
vici_builder_t *builder;
|
||||||
|
va_list args;
|
||||||
|
char *name;
|
||||||
|
chunk_t value;
|
||||||
|
|
||||||
INIT(enumerator,
|
builder = vici_builder_create();
|
||||||
.public = {
|
va_start(args, type);
|
||||||
.enumerate = (void*)_va_enumerate,
|
while (type != VICI_END)
|
||||||
.destroy = _va_destroy,
|
{
|
||||||
},
|
switch (type)
|
||||||
.first = &type,
|
{
|
||||||
);
|
case VICI_LIST_START:
|
||||||
va_start(enumerator->args, type);
|
case VICI_SECTION_START:
|
||||||
|
name = va_arg(args, char*);
|
||||||
return vici_message_create_from_enumerator(&enumerator->public);
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ vici_message_t *vici_message_create_from_enumerator(enumerator_t *enumerator);
|
|||||||
/**
|
/**
|
||||||
* Create vici message from a variable argument list.
|
* 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
|
* @param ... vici_type_t and args, terminated by VICI_END
|
||||||
* @return message representation, NULL on error
|
* @return message representation, NULL on error
|
||||||
*/
|
*/
|
||||||
@@ -115,11 +115,16 @@ vici_message_t *vici_message_create_from_args(vici_type_t type, ...);
|
|||||||
/**
|
/**
|
||||||
* Check if a chunk has a printable string, and print it to buf.
|
* 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 buf buffer to write string to
|
||||||
* @param size size of buf
|
* @param size size of buf
|
||||||
* @return TRUE if printable and string written to buf
|
* @return TRUE if printable and string written to buf
|
||||||
*/
|
*/
|
||||||
bool vici_stringify(chunk_t chunk, char *buf, size_t size);
|
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_ @}*/
|
#endif /** VICI_MESSAGE_H_ @}*/
|
||||||
|
|||||||
@@ -14,8 +14,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "vici_plugin.h"
|
#include "vici_plugin.h"
|
||||||
|
#include "vici_dispatcher.h"
|
||||||
|
|
||||||
#include <library.h>
|
#include <library.h>
|
||||||
|
#include <daemon.h>
|
||||||
|
|
||||||
typedef struct private_vici_plugin_t private_vici_plugin_t;
|
typedef struct private_vici_plugin_t private_vici_plugin_t;
|
||||||
|
|
||||||
@@ -28,6 +30,11 @@ struct private_vici_plugin_t {
|
|||||||
* public functions
|
* public functions
|
||||||
*/
|
*/
|
||||||
vici_plugin_t public;
|
vici_plugin_t public;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatcher, creating socket
|
||||||
|
*/
|
||||||
|
vici_dispatcher_t *dispatcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
METHOD(plugin_t, get_name, char*,
|
METHOD(plugin_t, get_name, char*,
|
||||||
@@ -42,6 +49,19 @@ METHOD(plugin_t, get_name, char*,
|
|||||||
static bool register_vici(private_vici_plugin_t *this,
|
static bool register_vici(private_vici_plugin_t *this,
|
||||||
plugin_feature_t *feature, bool reg, void *data)
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user