summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2016-10-26 09:23:30 +0200
committerJosé Bollo <jose.bollo@iot.bzh>2016-10-28 14:20:43 +0200
commit36e53e878baaa9d56c09097ada0b7061266caff8 (patch)
tree48e7fde72d264eacf1197d8871023d2a00adabbd
parent91d08eedaa810edfd38dcb8ce67c66813e5e3dce (diff)
hook: adding of hook feature for requests
The current implementation is for hooking requests. It allows implementation of command line option for debugging. Further development is needed to also handle events and service API. Also a binding for debugging would be cool. Change-Id: Ib1ac4711180db7b4097ed92ebbbf1a1a9fd2cc1c Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/afb-apis.c2
-rw-r--r--src/afb-config.h1
-rw-r--r--src/afb-hook.c579
-rw-r--r--src/afb-hook.h96
-rw-r--r--src/afb-thread.c1
-rw-r--r--src/main.c37
7 files changed, 716 insertions, 1 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 94e0a930..d396aef9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -40,6 +40,7 @@ ADD_LIBRARY(afb-lib STATIC
afb-common.c
afb-context.c
afb-evt.c
+ afb-hook.c
afb-hreq.c
afb-hsrv.c
afb-hswitch.c
diff --git a/src/afb-apis.c b/src/afb-apis.c
index c251aa7a..a4087838 100644
--- a/src/afb-apis.c
+++ b/src/afb-apis.c
@@ -26,6 +26,7 @@
#include "verbose.h"
#include "afb-apis.h"
#include "afb-context.h"
+#include "afb-hook.h"
#include <afb/afb-req-itf.h>
struct api_desc {
@@ -123,6 +124,7 @@ void afb_apis_call(struct afb_req req, struct afb_context *context, const char *
int i;
const struct api_desc *a;
+ req = afb_hook_req_call(req, context, api, lenapi, verb, lenverb);
a = apis_array;
for (i = 0 ; i < apis_count ; i++, a++) {
if (a->namelen == lenapi && !strncasecmp(a->name, api, lenapi)) {
diff --git a/src/afb-config.h b/src/afb-config.h
index b430cb0d..cc8e8c2f 100644
--- a/src/afb-config.h
+++ b/src/afb-config.h
@@ -58,6 +58,7 @@ struct afb_config
int nbSessionMax; // max count of sessions
int mode; // mode of listening
int aliascount;
+ int tracereq;
struct afb_config_item *items;
struct {
char *url;
diff --git a/src/afb-hook.c b/src/afb-hook.c
new file mode 100644
index 00000000..2dfd1b1e
--- /dev/null
+++ b/src/afb-hook.c
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) 2016 "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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <json-c/json.h>
+
+#include <afb/afb-req-itf.h>
+#include <afb/afb-event-itf.h>
+
+#include "afb-context.h"
+#include "afb-hook.h"
+#include "session.h"
+#include "verbose.h"
+
+/*
+ * Trace
+ */
+struct afb_hook {
+ struct afb_hook *next; /* next hook */
+ unsigned refcount; /* reference count */
+ char *api;
+ char *verb;
+ struct AFB_clientCtx *session;
+ unsigned flags; /* hook flags */
+ struct afb_hook_req_itf *reqitf;
+ void *closure;
+};
+
+struct hook_req_observer {
+ struct afb_hook *hook;
+ struct hook_req_observer *next;
+};
+
+/*
+ * Structure recording a request to hook
+ */
+struct afb_hook_req {
+ struct hook_req_observer *observers; /* observers */
+ struct afb_context *context; /* context of the request */
+ struct afb_req req; /* the request hookd */
+ unsigned refcount; /* reference count proxy for request */
+ char name[1]; /* hook info for the request */
+};
+
+/*
+ * Structure for handling subcalls callbacks
+ */
+struct hook_subcall {
+ struct afb_hook_req *tr; /* hookd request */
+ void (*callback)(void*, int, struct json_object*); /* client callback */
+ void *cb_closure; /* cient closure */
+};
+
+static unsigned hook_count = 0;
+
+static struct afb_hook *list_of_hooks = NULL;
+
+/******************************************************************************
+ * section: default callbacks for tracing requests
+ *****************************************************************************/
+
+static void _hook_(const struct afb_hook_req *tr, const char *format, ...)
+{
+ int len;
+ char *buffer;
+ va_list ap;
+
+ va_start(ap, format);
+ len = vasprintf(&buffer, format, ap);
+ va_end(ap);
+
+ if (len < 0)
+ NOTICE("tracing %s allocation error", tr->name);
+ else {
+ NOTICE("hook %s %s", tr->name, buffer);
+ free(buffer);
+ }
+}
+
+static void hook_req_begin_default_cb(void * closure, const struct afb_hook_req *tr)
+{
+ _hook_(tr, "BEGIN");
+}
+
+static void hook_req_end_default_cb(void * closure, const struct afb_hook_req *tr)
+{
+ _hook_(tr, "END");
+}
+
+static void hook_req_json_default_cb(void * closure, const struct afb_hook_req *tr, struct json_object *obj)
+{
+ _hook_(tr, "json() -> %s", json_object_to_json_string(obj));
+}
+
+static void hook_req_get_default_cb(void * closure, const struct afb_hook_req *tr, const char *name, struct afb_arg arg)
+{
+ _hook_(tr, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
+}
+
+static void hook_req_success_default_cb(void * closure, const struct afb_hook_req *tr, struct json_object *obj, const char *info)
+{
+ _hook_(tr, "success(%s, %s)", json_object_to_json_string(obj), info);
+}
+
+static void hook_req_fail_default_cb(void * closure, const struct afb_hook_req *tr, const char *status, const char *info)
+{
+ _hook_(tr, "fail(%s, %s)", status, info);
+}
+
+static void hook_req_raw_default_cb(void * closure, const struct afb_hook_req *tr, const char *buffer, size_t size)
+{
+ _hook_(tr, "raw() -> %.*s", (int)size, buffer);
+}
+
+static void hook_req_send_default_cb(void * closure, const struct afb_hook_req *tr, const char *buffer, size_t size)
+{
+ _hook_(tr, "send(%.*s)", (int)size, buffer);
+}
+
+static void hook_req_context_get_default_cb(void * closure, const struct afb_hook_req *tr, void *value)
+{
+ _hook_(tr, "context_get() -> %p", value);
+}
+
+static void hook_req_context_set_default_cb(void * closure, const struct afb_hook_req *tr, void *value, void (*free_value)(void*))
+{
+ _hook_(tr, "context_set(%p, %p)", value, free_value);
+}
+
+static void hook_req_addref_default_cb(void * closure, const struct afb_hook_req *tr)
+{
+ _hook_(tr, "addref()");
+}
+
+static void hook_req_unref_default_cb(void * closure, const struct afb_hook_req *tr)
+{
+ _hook_(tr, "unref()");
+}
+
+static void hook_req_session_close_default_cb(void * closure, const struct afb_hook_req *tr)
+{
+ _hook_(tr, "session_close()");
+}
+
+static void hook_req_session_set_LOA_default_cb(void * closure, const struct afb_hook_req *tr, unsigned level, int result)
+{
+ _hook_(tr, "session_set_LOA(%u) -> %d", level, result);
+}
+
+static void hook_req_subscribe_default_cb(void * closure, const struct afb_hook_req *tr, struct afb_event event, int result)
+{
+ _hook_(tr, "subscribe(%s:%p) -> %d", afb_event_name(event), event.closure, result);
+}
+
+static void hook_req_unsubscribe_default_cb(void * closure, const struct afb_hook_req *tr, struct afb_event event, int result)
+{
+ _hook_(tr, "unsubscribe(%s:%p) -> %d", afb_event_name(event), event.closure, result);
+}
+
+static void hook_req_subcall_default_cb(void * closure, const struct afb_hook_req *tr, const char *api, const char *verb, struct json_object *args)
+{
+ _hook_(tr, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
+}
+
+static void hook_req_subcall_result_default_cb(void * closure, const struct afb_hook_req *tr, int status, struct json_object *result)
+{
+ _hook_(tr, " ...subcall... -> %d: %s", status, json_object_to_json_string(result));
+}
+
+static struct afb_hook_req_itf hook_req_default_itf = {
+ .hook_req_begin = hook_req_begin_default_cb,
+ .hook_req_end = hook_req_end_default_cb,
+ .hook_req_json = hook_req_json_default_cb,
+ .hook_req_get = hook_req_get_default_cb,
+ .hook_req_success = hook_req_success_default_cb,
+ .hook_req_fail = hook_req_fail_default_cb,
+ .hook_req_raw = hook_req_raw_default_cb,
+ .hook_req_send = hook_req_send_default_cb,
+ .hook_req_context_get = hook_req_context_get_default_cb,
+ .hook_req_context_set = hook_req_context_set_default_cb,
+ .hook_req_addref = hook_req_addref_default_cb,
+ .hook_req_unref = hook_req_unref_default_cb,
+ .hook_req_session_close = hook_req_session_close_default_cb,
+ .hook_req_session_set_LOA = hook_req_session_set_LOA_default_cb,
+ .hook_req_subscribe = hook_req_subscribe_default_cb,
+ .hook_req_unsubscribe = hook_req_unsubscribe_default_cb,
+ .hook_req_subcall = hook_req_subcall_default_cb,
+ .hook_req_subcall_result = hook_req_subcall_result_default_cb,
+};
+
+/******************************************************************************
+ * section: macro for tracing requests
+ *****************************************************************************/
+
+#define TRACE_REQX(what,tr) do{\
+ struct hook_req_observer *observer = tr->observers;\
+ while (observer != NULL) {\
+ struct afb_hook *hook = observer->hook;\
+ observer = observer->next;\
+ if (hook->reqitf && hook->reqitf->hook_req_##what)\
+ hook->reqitf->hook_req_##what(hook->closure, tr);\
+ }\
+ }while(0)
+
+#define TRACE_REQ_(what,tr) do{\
+ struct hook_req_observer *observer = tr->observers;\
+ while (observer != NULL) {\
+ struct afb_hook *hook = observer->hook;\
+ observer = observer->next;\
+ if ((hook->flags & afb_hook_flag_req_##what) && hook->reqitf && hook->reqitf->hook_req_##what)\
+ hook->reqitf->hook_req_##what(hook->closure, tr);\
+ }\
+ }while(0)
+
+#define TRACE_REQ(what,tr,...) do{\
+ struct hook_req_observer *observer = tr->observers;\
+ while (observer != NULL) {\
+ struct afb_hook *hook = observer->hook;\
+ observer = observer->next;\
+ if ((hook->flags & afb_hook_flag_req_##what) && hook->reqitf && hook->reqitf->hook_req_##what)\
+ hook->reqitf->hook_req_##what(hook->closure, tr, __VA_ARGS__);\
+ }\
+ }while(0)
+
+/******************************************************************************
+ * section: afb_hook_req handling
+ *****************************************************************************/
+
+static void hook_req_addref(struct afb_hook_req *tr)
+{
+ tr->refcount++;
+}
+
+static void hook_req_unref(struct afb_hook_req *tr)
+{
+ struct hook_req_observer *o1, *o2;
+ if (!--tr->refcount) {
+ TRACE_REQX(end, tr);
+ afb_req_unref(tr->req);
+ o1 = tr->observers;
+ while(o1) {
+ afb_hook_unref(o1->hook);
+ o2 = o1->next;
+ free(o1);
+ o1 = o2;
+ }
+ free(tr);
+ }
+}
+
+static struct afb_hook_req *hook_req_create(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb)
+{
+ unsigned id;
+ struct afb_hook_req *tr;
+
+ tr = malloc(sizeof *tr + 8 + lenapi + lenverb);
+ if (tr != NULL) {
+ /* get the call id */
+ id = ++hook_count;
+ if (id == 1000000)
+ id = hook_count = 1;
+
+ /* init hook */
+ tr->observers = NULL;
+ tr->refcount = 1;
+ tr->context = context;
+ tr->req = req;
+ afb_req_addref(req);
+ snprintf(tr->name, 9 + lenapi + lenverb, "%06d:%.*s/%.*s", id, (int)lenapi, api, (int)lenverb, verb);
+ }
+ return tr;
+}
+
+static void hook_req_add_observer(struct afb_hook_req *tr, struct afb_hook *hook)
+{
+ struct hook_req_observer *observer;
+
+ observer = malloc(sizeof *observer);
+ if (observer) {
+ observer->hook = afb_hook_addref(hook);
+ observer->next = tr->observers;
+ tr->observers = observer;
+ }
+}
+
+/******************************************************************************
+ * section: hooks for tracing requests
+ *****************************************************************************/
+
+static struct json_object *req_hook_json(void *closure)
+{
+ struct afb_hook_req *tr = closure;
+ struct json_object *r;
+
+ r = afb_req_json(tr->req);
+ TRACE_REQ(json, tr, r);
+ return r;
+}
+
+static struct afb_arg req_hook_get(void *closure, const char *name)
+{
+ struct afb_hook_req *tr = closure;
+ struct afb_arg a;
+
+ a = afb_req_get(tr->req, name);
+ TRACE_REQ(get, tr, name, a);
+ return a;
+}
+
+static void req_hook_success(void *closure, struct json_object *obj, const char *info)
+{
+ struct afb_hook_req *tr = closure;
+
+ TRACE_REQ(success, tr, obj, info);
+ afb_req_success(tr->req, obj, info);
+ hook_req_unref(tr);
+}
+
+static void req_hook_fail(void *closure, const char *status, const char *info)
+{
+ struct afb_hook_req *tr = closure;
+
+ TRACE_REQ(fail, tr, status, info);
+ afb_req_fail(tr->req, status, info);
+ hook_req_unref(tr);
+}
+
+static const char *req_hook_raw(void *closure, size_t *size)
+{
+ struct afb_hook_req *tr = closure;
+ const char *r;
+ size_t s;
+
+ r = afb_req_raw(tr->req, &s);
+ TRACE_REQ(raw, tr, r, s);
+ if (size)
+ *size = s;
+ return r;
+}
+
+static void req_hook_send(void *closure, const char *buffer, size_t size)
+{
+ struct afb_hook_req *tr = closure;
+
+ TRACE_REQ(send, tr, buffer, size);
+ afb_req_send(tr->req, buffer, size);
+}
+
+static void *req_hook_context_get(void *closure)
+{
+ struct afb_hook_req *tr = closure;
+ void *r;
+
+ r = afb_req_context_get(tr->req);
+ TRACE_REQ(context_get, tr, r);
+
+ return r;
+}
+
+static void req_hook_context_set(void *closure, void *value, void (*free_value)(void*))
+{
+ struct afb_hook_req *tr = closure;
+
+ TRACE_REQ(context_set, tr, value, free_value);
+ afb_req_context_set(tr->req, value, free_value);
+}
+
+static void req_hook_addref(void *closure)
+{
+ struct afb_hook_req *tr = closure;
+
+ TRACE_REQ_(addref, tr);
+ hook_req_addref(tr);
+}
+
+static void req_hook_unref(void *closure)
+{
+ struct afb_hook_req *tr = closure;
+
+ TRACE_REQ_(unref, tr);
+ hook_req_unref(tr);
+}
+
+static void req_hook_session_close(void *closure)
+{
+ struct afb_hook_req *tr = closure;
+
+ TRACE_REQ_(session_close, tr);
+ afb_req_session_close(tr->req);
+}
+
+static int req_hook_session_set_LOA(void *closure, unsigned level)
+{
+ struct afb_hook_req *tr = closure;
+ int r;
+
+ r = afb_req_session_set_LOA(tr->req, level);
+ TRACE_REQ(session_set_LOA, tr, level, r);
+ return r;
+}
+
+static int req_hook_subscribe(void *closure, struct afb_event event)
+{
+ struct afb_hook_req *tr = closure;
+ int r;
+
+ r = afb_req_subscribe(tr->req, event);
+ TRACE_REQ(subscribe, tr, event, r);
+ return r;
+}
+
+static int req_hook_unsubscribe(void *closure, struct afb_event event)
+{
+ struct afb_hook_req *tr = closure;
+ int r;
+
+ r = afb_req_unsubscribe(tr->req, event);
+ TRACE_REQ(unsubscribe, tr, event, r);
+ return r;
+}
+
+static void req_hook_subcall_result(void *closure, int status, struct json_object *result)
+{
+ struct hook_subcall *sc = closure;
+ struct hook_subcall s = *sc;
+
+ free(sc);
+ TRACE_REQ(subcall_result, s.tr, status, result);
+ hook_req_unref(s.tr);
+ s.callback(s.cb_closure, status, result);
+}
+
+static void req_hook_subcall(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
+{
+ struct afb_hook_req *tr = closure;
+ struct hook_subcall *sc;
+
+ TRACE_REQ(subcall, tr, api, verb, args);
+ sc = malloc(sizeof *sc);
+ if (sc) {
+ sc->tr = tr;
+ sc->callback = callback;
+ sc->cb_closure = cb_closure;
+ hook_req_addref(tr);
+ cb_closure = sc;
+ callback = req_hook_subcall_result;
+ }
+ afb_req_subcall(tr->req, api, verb, args, callback, cb_closure);
+}
+
+static struct afb_req_itf req_hook_itf = {
+ .json = req_hook_json,
+ .get = req_hook_get,
+ .success = req_hook_success,
+ .fail = req_hook_fail,
+ .raw = req_hook_raw,
+ .send = req_hook_send,
+ .context_get = req_hook_context_get,
+ .context_set = req_hook_context_set,
+ .addref = req_hook_addref,
+ .unref = req_hook_unref,
+ .session_close = req_hook_session_close,
+ .session_set_LOA = req_hook_session_set_LOA,
+ .subscribe = req_hook_subscribe,
+ .unsubscribe = req_hook_unsubscribe,
+ .subcall = req_hook_subcall
+};
+
+/******************************************************************************
+ * section:
+ *****************************************************************************/
+
+struct afb_req afb_hook_req_call(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb)
+{
+ int add;
+ struct afb_hook_req *tr;
+ struct afb_hook *hook;
+
+ hook = list_of_hooks;
+ if (hook) {
+ tr = NULL;
+ do {
+ add = (hook->flags & afb_hook_flags_req_all) != 0
+ && (!hook->session || hook->session == context->session)
+ && (!hook->api || !(memcmp(hook->api, api, lenapi) || hook->api[lenapi]))
+ && (!hook->verb || !(memcmp(hook->verb, verb, lenverb) || hook->verb[lenverb]));
+ if (add) {
+ if (!tr)
+ tr = hook_req_create(req, context, api, lenapi, verb, lenverb);
+ if (tr)
+ hook_req_add_observer(tr, hook);
+ }
+ hook = hook->next;
+ } while(hook);
+ if (tr) {
+ req.closure = tr;
+ req.itf = &req_hook_itf;
+ TRACE_REQX(begin, tr);
+ }
+ }
+
+ return req;
+}
+
+struct afb_hook *afb_hook_req_create(const char *api, const char *verb, struct AFB_clientCtx *session, unsigned flags, struct afb_hook_req_itf *itf, void *closure)
+{
+ struct afb_hook *hook;
+
+ hook = malloc(sizeof *hook);
+ if (hook == NULL)
+ return NULL;
+
+ hook->api = api ? strdup(api) : NULL;
+ hook->verb = verb ? strdup(verb) : NULL;
+ hook->session = session ? ctxClientAddRef(session) : NULL;
+
+ if ((api && !hook->api) || (verb && !hook->verb)) {
+ free(hook->api);
+ free(hook->verb);
+ if (hook->session)
+ ctxClientUnref(hook->session);
+ free(hook);
+ return NULL;
+ }
+
+ hook->refcount = 1;
+ hook->flags = flags;
+ hook->reqitf = itf ? itf : &hook_req_default_itf;
+ hook->closure = closure;
+
+ hook->next = list_of_hooks;
+ list_of_hooks = hook;
+ return hook;
+}
+
+struct afb_hook *afb_hook_addref(struct afb_hook *hook)
+{
+ hook->refcount++;
+ return hook;
+}
+
+void afb_hook_unref(struct afb_hook *hook)
+{
+ if (!--hook->refcount) {
+ /* unlink */
+ struct afb_hook **prv = &list_of_hooks;
+ while (*prv && *prv != hook)
+ prv = &(*prv)->next;
+ if(*prv)
+ *prv = hook->next;
+
+ /* free */
+ free(hook->api);
+ free(hook->verb);
+ if (hook->session)
+ ctxClientUnref(hook->session);
+ free(hook);
+ }
+}
+
diff --git a/src/afb-hook.h b/src/afb-hook.h
new file mode 100644
index 00000000..e13aa1b1
--- /dev/null
+++ b/src/afb-hook.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 "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
+
+/* individual flags */
+#define afb_hook_flag_req_json 1
+#define afb_hook_flag_req_get 2
+#define afb_hook_flag_req_success 4
+#define afb_hook_flag_req_fail 8
+#define afb_hook_flag_req_raw 16
+#define afb_hook_flag_req_send 32
+#define afb_hook_flag_req_context_get 64
+#define afb_hook_flag_req_context_set 128
+#define afb_hook_flag_req_addref 256
+#define afb_hook_flag_req_unref 512
+#define afb_hook_flag_req_session_close 1024
+#define afb_hook_flag_req_session_set_LOA 2048
+#define afb_hook_flag_req_subscribe 4096
+#define afb_hook_flag_req_unsubscribe 8192
+#define afb_hook_flag_req_subcall 16384
+#define afb_hook_flag_req_subcall_result 32768
+
+/* common flags */
+#define afb_hook_flags_req_args (afb_hook_flag_req_json|afb_hook_flag_req_get)
+#define afb_hook_flags_req_result (afb_hook_flag_req_success|afb_hook_flag_req_fail)
+#define afb_hook_flags_req_session (afb_hook_flag_req_session_close|afb_hook_flag_req_session_set_LOA)
+#define afb_hook_flags_req_event (afb_hook_flag_req_subscribe|afb_hook_flag_req_unsubscribe)
+#define afb_hook_flags_req_subcall (afb_hook_flag_req_subcall|afb_hook_flag_req_subcall_result)
+
+/* extra flags */
+#define afb_hook_flags_req_ref (afb_hook_flag_req_addref|afb_hook_flag_req_unref)
+#define afb_hook_flags_req_context (afb_hook_flag_req_context_get|afb_hook_flag_req_context_set)
+
+/* internal flags */
+#define afb_hook_flags_req_internal (afb_hook_flag_req_raw|afb_hook_flag_req_send)
+
+/* predefined groups */
+#define afb_hook_flags_req_common (afb_hook_flags_req_args|afb_hook_flags_req_result|afb_hook_flags_req_session|afb_hook_flags_req_event|afb_hook_flags_req_subcall)
+#define afb_hook_flags_req_extra (afb_hook_flags_req_common|afb_hook_flags_req_ref|afb_hook_flags_req_context)
+#define afb_hook_flags_req_all (afb_hook_flags_req_extra|afb_hook_flags_req_internal)
+
+struct req;
+struct afb_context;
+struct json_object;
+struct afb_arg;
+struct afb_event;
+struct AFB_clientCtx;
+
+struct afb_hook;
+struct afb_hook_req;
+
+struct afb_hook_req_itf {
+ /* life cycle of the request (no flag, always called) */
+ void (*hook_req_begin)(void * closure, const struct afb_hook_req *tr);
+ void (*hook_req_end)(void * closure, const struct afb_hook_req *tr);
+
+ /* hook of actions on the request, subject to flags */
+ void (*hook_req_json)(void * closure, const struct afb_hook_req *tr, struct json_object *obj);
+ void (*hook_req_get)(void * closure, const struct afb_hook_req *tr, const char *name, struct afb_arg arg);
+ void (*hook_req_success)(void * closure, const struct afb_hook_req *tr, struct json_object *obj, const char *info);
+ void (*hook_req_fail)(void * closure, const struct afb_hook_req *tr, const char *status, const char *info);
+ void (*hook_req_raw)(void * closure, const struct afb_hook_req *tr, const char *buffer, size_t size);
+ void (*hook_req_send)(void * closure, const struct afb_hook_req *tr, const char *buffer, size_t size);
+ void (*hook_req_context_get)(void * closure, const struct afb_hook_req *tr, void *value);
+ void (*hook_req_context_set)(void * closure, const struct afb_hook_req *tr, void *value, void (*free_value)(void*));
+ void (*hook_req_addref)(void * closure, const struct afb_hook_req *tr);
+ void (*hook_req_unref)(void * closure, const struct afb_hook_req *tr);
+ void (*hook_req_session_close)(void * closure, const struct afb_hook_req *tr);
+ void (*hook_req_session_set_LOA)(void * closure, const struct afb_hook_req *tr, unsigned level, int result);
+ void (*hook_req_subscribe)(void * closure, const struct afb_hook_req *tr, struct afb_event event, int result);
+ void (*hook_req_unsubscribe)(void * closure, const struct afb_hook_req *tr, struct afb_event event, int result);
+ void (*hook_req_subcall)(void * closure, const struct afb_hook_req *tr, const char *api, const char *verb, struct json_object *args);
+ void (*hook_req_subcall_result)(void * closure, const struct afb_hook_req *tr, int status, struct json_object *result);
+};
+
+extern struct afb_req afb_hook_req_call(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb);
+
+extern struct afb_hook *afb_hook_req_create(const char *api, const char *verb, struct AFB_clientCtx *session, unsigned flags, struct afb_hook_req_itf *itf, void *closure);
+extern struct afb_hook *afb_hook_addref(struct afb_hook *spec);
+extern void afb_hook_unref(struct afb_hook *spec);
+
diff --git a/src/afb-thread.c b/src/afb-thread.c
index 5ce09300..201e1373 100644
--- a/src/afb-thread.c
+++ b/src/afb-thread.c
@@ -293,6 +293,7 @@ void afb_thread_call(struct afb_req req, void (*callback)(struct afb_req req), i
job->callback = callback;
job->req = req;
job->timeout = timeout;
+ job->blocked = 0;
job->group = group;
afb_req_addref(req);
job_add(job);
diff --git a/src/main.c b/src/main.c
index 38598189..58c0d8ec 100644
--- a/src/main.c
+++ b/src/main.c
@@ -43,6 +43,7 @@
#include "session.h"
#include "verbose.h"
#include "afb-common.h"
+#include "afb-hook.h"
#include <afb/afb-binding.h>
@@ -50,6 +51,11 @@
#error "you should define BINDING_INSTALL_DIR"
#endif
+#define TRACEREQ_NO 0
+#define TRACEREQ_COMMON 1
+#define TRACEREQ_EXTRA 2
+#define TRACEREQ_ALL 3
+
#define AFB_VERSION "0.5"
// Define command line option
@@ -88,6 +94,8 @@
#define SET_ROOT_HTTP 26
+#define SET_TRACEREQ 27
+
// Command line structure hold cli --command + help text
typedef struct {
int val; // command number within application
@@ -99,7 +107,7 @@ typedef struct {
// Supported option
static AFB_options cliOptions [] = {
- {SET_VERBOSE ,0,"verbose" , "Verbose Mode"},
+ {SET_VERBOSE ,0,"verbose" , "Verbose Mode, repeat to increase verbosity"},
{SET_FORGROUND ,0,"foreground" , "Get all in foreground mode"},
{SET_BACKGROUND ,0,"daemon" , "Get all in background mode"},
@@ -134,6 +142,8 @@ static AFB_options cliOptions [] = {
{SET_SESSIONMAX ,1,"session-max" , "max count of session simultaneously [default 10]"},
+ {SET_TRACEREQ ,1,"tracereq" , "log the requests: no, common, extra, all"},
+
{0, 0, NULL, NULL}
};
@@ -410,6 +420,15 @@ static void parse_arguments(int argc, char *argv[], struct afb_config *config)
add_item(config, optc, optarg);
break;
+ case SET_TRACEREQ:
+ if (optarg == 0) goto needValueForOption;
+ if (!strcmp(optarg, "no")) config->tracereq = TRACEREQ_NO;
+ else if (!strcmp(optarg, "common")) config->tracereq = TRACEREQ_COMMON;
+ else if (!strcmp(optarg, "extra")) config->tracereq = TRACEREQ_EXTRA;
+ else if (!strcmp(optarg, "all")) config->tracereq = TRACEREQ_ALL;
+ else goto badMode;
+ break;
+
case DISPLAY_VERSION:
if (optarg != 0) goto noValueForOption;
printVersion(stdout);
@@ -687,6 +706,22 @@ int main(int argc, char *argv[]) {
/* ignore any SIGPIPE */
signal(SIGPIPE, SIG_IGN);
+ /* install trace of requests */
+ switch(config->tracereq) {
+ default:
+ case TRACEREQ_NO:
+ break;
+ case TRACEREQ_COMMON:
+ afb_hook_req_create(NULL, NULL, NULL, afb_hook_flags_req_common, NULL, NULL);
+ break;
+ case TRACEREQ_EXTRA:
+ afb_hook_req_create(NULL, NULL, NULL, afb_hook_flags_req_extra, NULL, NULL);
+ break;
+ case TRACEREQ_ALL:
+ afb_hook_req_create(NULL, NULL, NULL, afb_hook_flags_req_all, NULL, NULL);
+ break;
+ }
+
/* start the HTTP server */
hsrv = start_http_server(config);
if (hsrv == NULL)