From 36e53e878baaa9d56c09097ada0b7061266caff8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Wed, 26 Oct 2016 09:23:30 +0200 Subject: [PATCH] hook: adding of hook feature for requests MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- src/CMakeLists.txt | 1 + src/afb-apis.c | 2 + src/afb-config.h | 1 + src/afb-hook.c | 579 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/afb-hook.h | 96 +++++++++ src/afb-thread.c | 1 + src/main.c | 37 +++- 7 files changed, 716 insertions(+), 1 deletion(-) create mode 100644 src/afb-hook.c create mode 100644 src/afb-hook.h 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 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 + * + * 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 +#include +#include + +#include + +#include +#include + +#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 + * + * 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 @@ -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) -- 2.16.6