summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/afb-monitor.c400
-rw-r--r--src/afb-monitor.h21
-rw-r--r--src/main.c3
4 files changed, 425 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fe497fc9..bec9124e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -74,6 +74,7 @@ ADD_LIBRARY(afb-lib STATIC
afb-hsrv.c
afb-hswitch.c
afb-method.c
+ afb-monitor.c
afb-msg-json.c
afb-perm.c
afb-session.c
diff --git a/src/afb-monitor.c b/src/afb-monitor.c
new file mode 100644
index 00000000..5d5c12d1
--- /dev/null
+++ b/src/afb-monitor.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <string.h>
+
+#include <json-c/json.h>
+
+#include "afb-api.h"
+#include "afb-apiset.h"
+#include "afb-ditf.h"
+#include "afb-xreq.h"
+#include "verbose.h"
+
+extern struct afb_apiset *main_apiset;
+
+/* CAUTION! KEEP VERBS SORTED */
+#define VERBS \
+ V(get) \
+ V(hook) \
+ V(set)
+
+/**
+ * Declare functions of verbs
+ */
+#define F(x) static void f_##x(struct afb_xreq *xreq)
+#define V(x) F(x);
+ VERBS
+#undef V
+
+/**
+ * Name of the known verbs
+ */
+static const struct {
+ const char *name;
+ void (*function)(struct afb_xreq*);
+} verbs[] = {
+#define V(x) { .name = #x, .function = f_##x },
+ VERBS
+#undef V
+};
+
+/**
+ * get the function of a verb
+ * @param verb the name of the verb
+ * @return the function for the verb or NULL when no verb of name exists
+ */
+static void (*lookfun(const char *verb))(struct afb_xreq*)
+{
+ int l, u, i, c;
+
+ l = 0;
+ u = (int)(sizeof verbs / sizeof *verbs);
+ while (l < u) {
+ i = (l + u) >> 1;
+ c = strcmp(verb, verbs[i].name);
+ if (c == 0)
+ return verbs[i].function;
+ if (c < 0)
+ u = i;
+ else
+ l = i + 1;
+ }
+ return NULL;
+}
+
+static void call_cb(void *closure, struct afb_xreq *xreq)
+{
+ void (*fun)(struct afb_xreq*);
+
+ fun = lookfun(xreq->verb);
+ if (!fun)
+ afb_xreq_fail_unknown_verb(xreq);
+ else
+ fun(xreq);
+}
+
+static struct afb_api_itf monitor_api_itf = {
+ .call = call_cb
+};
+
+int afb_monitor_init()
+{
+ struct afb_api api;
+ api.closure = NULL;
+ api.itf = &monitor_api_itf;
+ return afb_apiset_add(main_apiset, "monitor", api);
+}
+
+/******************************************************************************
+**** Monitoring verbosity
+******************************************************************************/
+
+static const char _debug_[] = "debug";
+static const char _info_[] = "info";
+static const char _notice_[] = "notice";
+static const char _warning_[] = "warning";
+static const char _error_[] = "error";
+
+/**
+ * Translate verbosity indication to an integer value.
+ * @param v the verbosity indication
+ * @return the verbosity level (0, 1, 2 or 3) or -1 in case of error
+ */
+static int decode_verbosity(struct json_object *v)
+{
+ const char *s;
+ int level = -1;
+ if (json_object_is_type(v, json_type_int)) {
+ level = json_object_get_int(v);
+ level = level < 0 ? 0 : level > 3 ? 3 : level;
+ } else if (json_object_is_type(v, json_type_string)) {
+ s = json_object_get_string(v);
+ switch(*s&~' ') {
+ case 'D':
+ if (!strcasecmp(s, _debug_))
+ level = 3;
+ break;
+ case 'I':
+ if (!strcasecmp(s, _info_))
+ level = 2;
+ break;
+ case 'N':
+ if (!strcasecmp(s, _notice_))
+ level = 1;
+ break;
+ case 'W':
+ if (!strcasecmp(s, _warning_))
+ level = 1;
+ break;
+ case 'E':
+ if (!strcasecmp(s, _error_))
+ level = 0;
+ break;
+ }
+ }
+ return level;
+}
+
+/**
+ * callback for setting verbosity on all apis
+ * @param set the apiset
+ * @param the name of the api to set
+ * @param closure the verbosity to set as an integer casted to a pointer
+ */
+static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, void *closure)
+{
+ afb_apiset_set_verbosity(set, name, (int)(intptr_t)closure);
+}
+
+/**
+ * set the verbosity 'level' of the api of 'name'
+ * @param name the api name or "*" for any api or NULL or "" for global verbosity
+ * @param level the verbosity level to set
+ */
+static void set_verbosity_to(const char *name, int level)
+{
+ if (!name || !name[0])
+ verbosity = level;
+ else if (name[0] == '*' && !name[1])
+ afb_apiset_enum(main_apiset, set_verbosity_to_all_cb, (void*)(intptr_t)level);
+ else
+ afb_apiset_set_verbosity(main_apiset, name, level);
+}
+
+/**
+ * Set verbosities accordling to specification in 'spec'
+ * @param spec specification of the verbosity to set
+ */
+static void set_verbosity(struct json_object *spec)
+{
+ int l;
+ struct json_object_iterator it, end;
+
+ if (json_object_is_type(spec, json_type_object)) {
+ it = json_object_iter_begin(spec);
+ end = json_object_iter_end(spec);
+ while (!json_object_iter_equal(&it, &end)) {
+ l = decode_verbosity(json_object_iter_peek_value(&it));
+ if (l >= 0)
+ set_verbosity_to(json_object_iter_peek_name(&it), l);
+ json_object_iter_next(&it);
+ }
+ } else {
+ l = decode_verbosity(spec);
+ if (l >= 0) {
+ set_verbosity_to("", l);
+ set_verbosity_to("*", l);
+ }
+ }
+}
+
+/**
+ * Translate verbosity level to a protocol indication.
+ * @param level the verbosity
+ * @return the encoded verbosity
+ */
+static struct json_object *encode_verbosity(int level)
+{
+ switch(level) {
+ case 0: return json_object_new_string(_error_);
+ case 1: return json_object_new_string(_notice_);
+ case 2: return json_object_new_string(_info_);
+ case 3: return json_object_new_string(_debug_);
+ default: return json_object_new_int(level);
+ }
+}
+
+/**
+ * callback for getting verbosity of all apis
+ * @param set the apiset
+ * @param the name of the api to set
+ * @param closure the json object to build
+ */
+static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
+{
+ struct json_object *resu = closure;
+ int l = afb_apiset_get_verbosity(set, name);
+ if (l >= 0)
+ json_object_object_add(resu, name, encode_verbosity(l));
+}
+
+/**
+ * get in resu the verbosity of the api of 'name'
+ * @param resu the json object to build
+ * @param name the api name or "*" for any api or NULL or "" for global verbosity
+ */
+static void get_verbosity_of(struct json_object *resu, const char *name)
+{
+ int l;
+ if (!name || !name[0])
+ json_object_object_add(resu, "", encode_verbosity(verbosity));
+ else if (name[0] == '*' && !name[1])
+ afb_apiset_enum(main_apiset, get_verbosity_of_all_cb, resu);
+ else {
+ l = afb_apiset_get_verbosity(main_apiset, name);
+ if (l >= 0)
+ json_object_object_add(resu, name, encode_verbosity(l));
+ }
+}
+
+/**
+ * get verbosities accordling to specification in 'spec'
+ * @param resu the json object to build
+ * @param spec specification of the verbosity to set
+ */
+static void get_verbosity(struct json_object *resu, struct json_object *spec)
+{
+ int i, n;
+ struct json_object_iterator it, end;
+
+ if (json_object_is_type(spec, json_type_object)) {
+ it = json_object_iter_begin(spec);
+ end = json_object_iter_end(spec);
+ while (!json_object_iter_equal(&it, &end)) {
+ get_verbosity_of(resu, json_object_iter_peek_name(&it));
+ json_object_iter_next(&it);
+ }
+ } else if (json_object_is_type(spec, json_type_array)) {
+ n = json_object_array_length(spec);
+ for (i = 0 ; i < n ; i++)
+ get_verbosity_of(resu, json_object_get_string(json_object_array_get_idx(spec, i)));
+ } else if (json_object_get_boolean(spec)) {
+ get_verbosity_of(resu, "");
+ get_verbosity_of(resu, "*");
+ }
+}
+
+/******************************************************************************
+**** Monitoring apis
+******************************************************************************/
+
+/**
+ * get apis accordling to specification in 'spec'
+ * @param resu the json object to build
+ * @param spec specification of the verbosity to set
+ */
+static void get_one_api(struct json_object *resu, const char *name, struct json_object *spec)
+{
+ struct json_object *o;
+ struct afb_api api;
+ int rc;
+
+ rc = afb_apiset_lookup(main_apiset, name, &api);
+ if (!rc) {
+ o = api.itf->describe ? api.itf->describe(api.closure) : NULL;
+ json_object_object_add(resu, name, o);
+ }
+}
+
+/**
+ * callback for getting verbosity of all apis
+ * @param set the apiset
+ * @param the name of the api to set
+ * @param closure the json object to build
+ */
+static void get_apis_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
+{
+ struct json_object *resu = closure;
+ get_one_api(resu, name, NULL);
+}
+
+/**
+ * get apis accordling to specification in 'spec'
+ * @param resu the json object to build
+ * @param spec specification of the verbosity to set
+ */
+static void get_apis(struct json_object *resu, struct json_object *spec)
+{
+ int i, n;
+ struct json_object_iterator it, end;
+
+ if (json_object_is_type(spec, json_type_object)) {
+ it = json_object_iter_begin(spec);
+ end = json_object_iter_end(spec);
+ while (!json_object_iter_equal(&it, &end)) {
+ get_one_api(resu, json_object_iter_peek_name(&it), json_object_iter_peek_value(&it));
+ json_object_iter_next(&it);
+ }
+ } else if (json_object_is_type(spec, json_type_array)) {
+ n = json_object_array_length(spec);
+ for (i = 0 ; i < n ; i++)
+ get_one_api(resu, json_object_get_string(json_object_array_get_idx(spec, i)), NULL);
+ } else if (json_object_get_boolean(spec)) {
+ afb_apiset_enum(main_apiset, get_apis_of_all_cb, resu);
+ }
+}
+
+/******************************************************************************
+**** Implementation monitoring verbs
+******************************************************************************/
+
+static const char _verbosity_[] = "verbosity";
+static const char _apis_[] = "apis";
+
+static void f_get(struct afb_xreq *xreq)
+{
+ struct json_object *o, *v, *r, *x;
+
+ r = json_object_new_object();
+ o = afb_xreq_json(xreq);
+
+ if (json_object_object_get_ex(o, _verbosity_, &v)) {
+ x = json_object_new_object();
+ json_object_object_add(r, _verbosity_, x);
+ get_verbosity(x, v);
+ }
+
+ if (json_object_object_get_ex(o, _apis_, &v)) {
+ x = json_object_new_object();
+ json_object_object_add(r, _apis_, x);
+ get_apis(x, v);
+ }
+
+ if (!xreq->replied)
+ afb_xreq_success(xreq, json_object_get(r), NULL);
+ json_object_put(r);
+}
+
+static void f_set(struct afb_xreq *xreq)
+{
+ struct json_object *o, *v;
+
+ o = afb_xreq_json(xreq);
+ if (json_object_object_get_ex(o, _verbosity_, &v)) {
+ set_verbosity(v);
+ }
+
+ if (!xreq->replied)
+ afb_xreq_success(xreq, NULL, NULL);
+}
+
+static void f_hook(struct afb_xreq *xreq)
+{
+ struct json_object *o, *v;
+
+ o = afb_xreq_json(xreq);
+ if (json_object_object_get_ex(o, _verbosity_, &v)) {
+ set_verbosity(v);
+ }
+
+ if (!xreq->replied)
+ afb_xreq_success(xreq, NULL, NULL);
+}
+
diff --git a/src/afb-monitor.h b/src/afb-monitor.h
new file mode 100644
index 00000000..d8827b99
--- /dev/null
+++ b/src/afb-monitor.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+extern int afb_monitor_init();
diff --git a/src/main.c b/src/main.c
index 3541e44c..0522e708 100644
--- a/src/main.c
+++ b/src/main.c
@@ -45,6 +45,7 @@
#include "afb-session.h"
#include "verbose.h"
#include "afb-common.h"
+#include "afb-monitor.h"
#include "afb-hook.h"
#include "sd-fds.h"
@@ -560,6 +561,8 @@ static void start()
ERROR("can't create main api set");
goto error;
}
+ if (afb_monitor_init() < 0) {
+ ERROR("failed to setup monitor");
goto error;
}