afb-session: Add timeout features for sessions
[src/app-framework-binder.git] / src / afb-trace.c
index 5d58b2d..f0efd5f 100644 (file)
@@ -16,7 +16,6 @@
  */
 
 #define _GNU_SOURCE
-#define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
 
 #include <assert.h>
 #include <string.h>
 #include <limits.h>
 #include <unistd.h>
 #include <pthread.h>
-#include <time.h>
 
 #include <json-c/json.h>
-#include <afb/afb-binding-v2.h>
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
 
 #include "afb-hook.h"
 #include "afb-cred.h"
 #include "afb-session.h"
 #include "afb-xreq.h"
-#include "afb-ditf.h"
-#include "afb-svc.h"
+#include "afb-export.h"
 #include "afb-evt.h"
 #include "afb-trace.h"
 
 #include "wrap-json.h"
+#include "verbose.h"
 
 /*******************************************************************************/
 /*****  default names                                                      *****/
@@ -73,14 +72,13 @@ struct tag {
 /* struct for events */
 struct event {
        struct event *next;             /* link to the next event */
-       struct afb_event event;         /* the event */
+       struct afb_evtid *evtid;                /* the event */
 };
 
 /* struct for sessions */
-struct session {
-       struct session *next;           /* link to the next session */
-       struct afb_session *session;    /* the session */
-       struct afb_trace *trace;        /* the tracer */
+struct cookie {
+       struct afb_session *session;    /* the session */
+       struct afb_trace *trace;        /* the tracer */
 };
 
 /* struct for recording hooks */
@@ -89,16 +87,17 @@ struct hook {
        void *handler;                  /* the handler of the hook */
        struct event *event;            /* the associated event */
        struct tag *tag;                /* the associated tag */
-       struct session *session;        /* the associated session */
+       struct afb_session *session;    /* the associated session */
 };
 
 /* types of hooks */
 enum trace_type
 {
        Trace_Type_Xreq,        /* xreq hooks */
-       Trace_Type_Ditf,        /* ditf hooks */
-       Trace_Type_Svc,         /* svc hooks */
+       Trace_Type_Ditf,        /* export hooks */
+       Trace_Type_Svc,         /* export hooks */
        Trace_Type_Evt,         /* evt hooks */
+       Trace_Type_Global,      /* global hooks */
        Trace_Type_Count        /* count of types of hooks */
 };
 
@@ -111,7 +110,6 @@ struct afb_trace
        struct afb_session *bound;              /* bound to session */
        struct event *events;                   /* list of events */
        struct tag *tags;                       /* list of tags */
-       struct session *sessions;               /* list of tags */
        struct hook *hooks[Trace_Type_Count];   /* hooks */
 };
 
@@ -163,13 +161,11 @@ static int get_flag(const char *name, struct flag flags[], int count)
 }
 
 /* timestamp */
-static struct json_object *timestamp()
+static struct json_object *timestamp(const struct afb_hookid *hookid)
 {
        char ts[50];
-       struct timespec tv;
 
-       clock_gettime(CLOCK_MONOTONIC, &tv);
-       snprintf(ts, sizeof ts, "%llu.%06lu", (long long unsigned)tv.tv_sec, (long unsigned)(tv.tv_nsec / 1000));
+       snprintf(ts, sizeof ts, "%llu.%06lu", (long long unsigned)hookid->time.tv_sec, (long unsigned)(hookid->time.tv_nsec / 1000));
        return json_object_new_string(ts);
 }
 
@@ -184,32 +180,32 @@ static const char *verbosity_level_name(int level)
                "debug"
        };
 
-       return level >= 3 && level <= 7 ? names[level - 3] : NULL;
+       return level >= Log_Level_Error && level <= Log_Level_Debug ? names[level - Log_Level_Error] : NULL;
 }
 
 /* generic hook */
-static void emit(void *closure, unsigned hookid, const char *type, const char *fmt1, const char *fmt2, va_list ap2, ...)
+static void emit(void *closure, const struct afb_hookid *hookid, const char *type, const char *fmt1, const char *fmt2, va_list ap2, ...)
 {
        struct hook *hook = closure;
-       struct json_object *event, *data1, *data2;
+       struct json_object *data, *data1, *data2;
        va_list ap1;
 
-       data1 = data2 = event = NULL;
+       data1 = data2 = data = NULL;
        va_start(ap1, ap2);
        wrap_json_vpack(&data1, fmt1, ap1);
        va_end(ap1);
        if (fmt2)
                wrap_json_vpack(&data2, fmt2, ap2);
 
-       wrap_json_pack(&event, "{so ss ss si so so*}",
-                                       "time", timestamp(),
+       wrap_json_pack(&data, "{so ss ss si so so*}",
+                                       "time", timestamp(hookid),
                                        "tag", hook->tag->tag,
                                        "type", type,
-                                       "id", (int)(hookid & INT_MAX),
+                                       "id", (int)(hookid->id & INT_MAX),
                                        type, data1,
                                        "data", data2);
 
-       afb_evt_unhooked_push(hook->event->event, event);
+       afb_evt_evtid_push(hook->event->evtid, data);
 }
 
 /*******************************************************************************/
@@ -224,16 +220,21 @@ static struct flag xreq_flags[] = { /* must be sorted by names */
                { "common",             afb_hook_flags_req_common },
                { "context",            afb_hook_flags_req_context },
                { "context_get",        afb_hook_flag_req_context_get },
+               { "context_make",       afb_hook_flag_req_context_make },
                { "context_set",        afb_hook_flag_req_context_set },
                { "end",                afb_hook_flag_req_end },
                { "event",              afb_hook_flags_req_event },
                { "extra",              afb_hook_flags_req_extra },
                { "fail",               afb_hook_flag_req_fail },
                { "get",                afb_hook_flag_req_get },
+               { "get_application_id", afb_hook_flag_req_get_application_id },
+               { "get_uid",            afb_hook_flag_req_get_uid },
+               { "has_permission",     afb_hook_flag_req_has_permission },
                { "json",               afb_hook_flag_req_json },
                { "life",               afb_hook_flags_req_life },
                { "ref",                afb_hook_flags_req_ref },
                { "result",             afb_hook_flags_req_result },
+               { "security",           afb_hook_flags_req_security },
                { "session",            afb_hook_flags_req_session },
                { "session_close",      afb_hook_flag_req_session_close },
                { "session_set_LOA",    afb_hook_flag_req_session_set_LOA },
@@ -260,7 +261,7 @@ static int get_xreq_flag(const char *name)
        return get_flag(name, xreq_flags, (int)(sizeof xreq_flags / sizeof *xreq_flags));
 }
 
-static void hook_xreq(void *closure, unsigned hookid, const struct afb_xreq *xreq, const char *action, const char *format, ...)
+static void hook_xreq(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *action, const char *format, ...)
 {
        struct json_object *cred = NULL;
        const char *session = NULL;
@@ -281,31 +282,31 @@ static void hook_xreq(void *closure, unsigned hookid, const struct afb_xreq *xre
        va_start(ap, format);
        emit(closure, hookid, "request", "{si ss ss ss so* ss*}", format, ap,
                                        "index", xreq->hookindex,
-                                       "api", xreq->api,
-                                       "verb", xreq->verb,
+                                       "api", xreq->request.api,
+                                       "verb", xreq->request.verb,
                                        "action", action,
                                        "credentials", cred,
                                        "session", session);
        va_end(ap);
 }
 
-static void hook_xreq_begin(void *closure, unsigned hookid, const struct afb_xreq *xreq)
+static void hook_xreq_begin(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
 {
        hook_xreq(closure, hookid, xreq, "begin", NULL);
 }
 
-static void hook_xreq_end(void *closure, unsigned hookid, const struct afb_xreq *xreq)
+static void hook_xreq_end(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
 {
        hook_xreq(closure, hookid, xreq, "end", NULL);
 }
 
-static void hook_xreq_json(void *closure, unsigned hookid, const struct afb_xreq *xreq, struct json_object *obj)
+static void hook_xreq_json(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj)
 {
        hook_xreq(closure, hookid, xreq, "json", "{sO?}",
                                                "result", obj);
 }
 
-static void hook_xreq_get(void *closure, unsigned hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
+static void hook_xreq_get(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
 {
        hook_xreq(closure, hookid, xreq, "get", "{ss? ss? ss? ss?}",
                                                "query", name,
@@ -314,71 +315,71 @@ static void hook_xreq_get(void *closure, unsigned hookid, const struct afb_xreq
                                                "path", arg.path);
 }
 
-static void hook_xreq_success(void *closure, unsigned hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
+static void hook_xreq_success(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
 {
        hook_xreq(closure, hookid, xreq, "success", "{sO? ss?}",
                                                "result", obj,
                                                "info", info);
 }
 
-static void hook_xreq_fail(void *closure, unsigned hookid, const struct afb_xreq *xreq, const char *status, const char *info)
+static void hook_xreq_fail(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info)
 {
        hook_xreq(closure, hookid, xreq, "fail", "{ss? ss?}",
                                                "status", status,
                                                "info", info);
 }
 
-static void hook_xreq_context_get(void *closure, unsigned hookid, const struct afb_xreq *xreq, void *value)
+static void hook_xreq_context_get(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value)
 {
        hook_xreq(closure, hookid, xreq, "context_get", NULL);
 }
 
-static void hook_xreq_context_set(void *closure, unsigned hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
+static void hook_xreq_context_set(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
 {
        hook_xreq(closure, hookid, xreq, "context_set", NULL);
 }
 
-static void hook_xreq_addref(void *closure, unsigned hookid, const struct afb_xreq *xreq)
+static void hook_xreq_addref(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
 {
        hook_xreq(closure, hookid, xreq, "addref", NULL);
 }
 
-static void hook_xreq_unref(void *closure, unsigned hookid, const struct afb_xreq *xreq)
+static void hook_xreq_unref(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
 {
        hook_xreq(closure, hookid, xreq, "unref", NULL);
 }
 
-static void hook_xreq_session_close(void *closure, unsigned hookid, const struct afb_xreq *xreq)
+static void hook_xreq_session_close(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
 {
        hook_xreq(closure, hookid, xreq, "session_close", NULL);
 }
 
-static void hook_xreq_session_set_LOA(void *closure, unsigned hookid, const struct afb_xreq *xreq, unsigned level, int result)
+static void hook_xreq_session_set_LOA(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result)
 {
        hook_xreq(closure, hookid, xreq, "session_set_LOA", "{si si}",
                                        "level", level,
                                        "result", result);
 }
 
-static void hook_xreq_subscribe(void *closure, unsigned hookid, const struct afb_xreq *xreq, struct afb_event event, int result)
+static void hook_xreq_subscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result)
 {
        hook_xreq(closure, hookid, xreq, "subscribe", "{s{ss si} si}",
                                        "event",
-                                               "name", afb_evt_event_name(event),
-                                               "id", afb_evt_event_id(event),
+                                               "name", afb_evt_eventid_fullname(eventid),
+                                               "id", afb_evt_eventid_id(eventid),
                                        "result", result);
 }
 
-static void hook_xreq_unsubscribe(void *closure, unsigned hookid, const struct afb_xreq *xreq, struct afb_event event, int result)
+static void hook_xreq_unsubscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result)
 {
        hook_xreq(closure, hookid, xreq, "unsubscribe", "{s{ss? si} si}",
                                        "event",
-                                               "name", afb_evt_event_name(event),
-                                               "id", afb_evt_event_id(event),
+                                               "name", afb_evt_eventid_fullname(eventid),
+                                               "id", afb_evt_eventid_id(eventid),
                                        "result", result);
 }
 
-static void hook_xreq_subcall(void *closure, unsigned hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
+static void hook_xreq_subcall(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
 {
        hook_xreq(closure, hookid, xreq, "subcall", "{ss? ss? sO?}",
                                        "api", api,
@@ -386,14 +387,14 @@ static void hook_xreq_subcall(void *closure, unsigned hookid, const struct afb_x
                                        "args", args);
 }
 
-static void hook_xreq_subcall_result(void *closure, unsigned hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
+static void hook_xreq_subcall_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
 {
        hook_xreq(closure, hookid, xreq, "subcall_result", "{si sO?}",
                                        "status", status,
                                        "result", result);
 }
 
-static void hook_xreq_subcallsync(void *closure, unsigned hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
+static void hook_xreq_subcallsync(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
 {
        hook_xreq(closure, hookid, xreq, "subcallsync", "{ss? ss? sO?}",
                                        "api", api,
@@ -401,14 +402,14 @@ static void hook_xreq_subcallsync(void *closure, unsigned hookid, const struct a
                                        "args", args);
 }
 
-static void hook_xreq_subcallsync_result(void *closure, unsigned hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
+static void hook_xreq_subcallsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
 {
        hook_xreq(closure, hookid, xreq, "subcallsync_result", "{si sO?}",
                                        "status", status,
                                        "result", result);
 }
 
-static void hook_xreq_vverbose(void *closure, unsigned hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
+static void hook_xreq_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
 {
        struct json_object *pos;
        int len;
@@ -434,17 +435,17 @@ static void hook_xreq_vverbose(void *closure, unsigned hookid, const struct afb_
        free(msg);
 }
 
-static void hook_xreq_store(void *closure, unsigned hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq)
+static void hook_xreq_store(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq)
 {
        hook_xreq(closure, hookid, xreq, "store", NULL);
 }
 
-static void hook_xreq_unstore(void *closure, unsigned hookid, const struct afb_xreq *xreq)
+static void hook_xreq_unstore(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
 {
        hook_xreq(closure, hookid, xreq, "unstore", NULL);
 }
 
-static void hook_xreq_subcall_req(void *closure, unsigned hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
+static void hook_xreq_subcall_req(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
 {
        hook_xreq(closure, hookid, xreq, "subcall_req", "{ss? ss? sO?}",
                                        "api", api,
@@ -452,13 +453,47 @@ static void hook_xreq_subcall_req(void *closure, unsigned hookid, const struct a
                                        "args", args);
 }
 
-static void hook_xreq_subcall_req_result(void *closure, unsigned hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
+static void hook_xreq_subcall_req_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
 {
        hook_xreq(closure, hookid, xreq, "subcall_req_result", "{si sO?}",
                                        "status", status,
                                        "result", result);
 }
 
+static void hook_xreq_has_permission(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result)
+{
+       hook_xreq(closure, hookid, xreq, "has_permission", "{ss sb}",
+                                       "permission", permission,
+                                       "result", result);
+}
+
+static void hook_xreq_get_application_id(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result)
+{
+       hook_xreq(closure, hookid, xreq, "get_application_id", "{ss?}",
+                                       "result", result);
+}
+
+static void hook_xreq_context_make(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result)
+{
+       char pc[50], pf[50], pv[50], pr[50];
+       snprintf(pc, sizeof pc, "%p", create_value);
+       snprintf(pf, sizeof pf, "%p", free_value);
+       snprintf(pv, sizeof pv, "%p", create_closure);
+       snprintf(pr, sizeof pr, "%p", result);
+       hook_xreq(closure, hookid, xreq, "context_make", "{sb ss ss ss ss}",
+                                       "replace", replace,
+                                       "create", pc,
+                                       "free", pf,
+                                       "closure", pv,
+                                       "result", pr);
+}
+
+static void hook_xreq_get_uid(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result)
+{
+       hook_xreq(closure, hookid, xreq, "get_uid", "{si}",
+                                       "result", result);
+}
+
 static struct afb_hook_xreq_itf hook_xreq_itf = {
        .hook_xreq_begin = hook_xreq_begin,
        .hook_xreq_end = hook_xreq_end,
@@ -482,7 +517,11 @@ static struct afb_hook_xreq_itf hook_xreq_itf = {
        .hook_xreq_store = hook_xreq_store,
        .hook_xreq_unstore = hook_xreq_unstore,
        .hook_xreq_subcall_req = hook_xreq_subcall_req,
-       .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result
+       .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result,
+       .hook_xreq_has_permission = hook_xreq_has_permission,
+       .hook_xreq_get_application_id = hook_xreq_get_application_id,
+       .hook_xreq_context_make = hook_xreq_context_make,
+       .hook_xreq_get_uid = hook_xreq_get_uid,
 };
 
 /*******************************************************************************/
@@ -508,52 +547,52 @@ static struct flag ditf_flags[] = { /* must be sorted by names */
                { "vverbose",                   afb_hook_flag_ditf_vverbose },
 };
 
-/* get the ditf value for flag of 'name' */
+/* get the export value for flag of 'name' */
 static int get_ditf_flag(const char *name)
 {
        return get_flag(name, ditf_flags, (int)(sizeof ditf_flags / sizeof *ditf_flags));
 }
 
 
-static void hook_ditf(void *closure, unsigned hookid, const struct afb_ditf *ditf, const char *action, const char *format, ...)
+static void hook_ditf(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...)
 {
        va_list ap;
 
        va_start(ap, format);
        emit(closure, hookid, "daemon", "{ss ss}", format, ap,
-                                       "api", ditf->api,
+                                       "api", afb_export_apiname(export),
                                        "action", action);
        va_end(ap);
 }
 
-static void hook_ditf_event_broadcast_before(void *closure, unsigned hookid, const struct afb_ditf *ditf, const char *name, struct json_object *object)
+static void hook_ditf_event_broadcast_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object)
 {
-       hook_ditf(closure, hookid, ditf, "event_broadcast_before", "{ss sO*}",
+       hook_ditf(closure, hookid, export, "event_broadcast_before", "{ss sO*}",
                        "name", name, "data", object);
 }
 
-static void hook_ditf_event_broadcast_after(void *closure, unsigned hookid, const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
+static void hook_ditf_event_broadcast_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result)
 {
-       hook_ditf(closure, hookid, ditf, "event_broadcast_after", "{ss sO* si}",
+       hook_ditf(closure, hookid, export, "event_broadcast_after", "{ss sO* si}",
                        "name", name, "data", object, "result", result);
 }
 
-static void hook_ditf_get_event_loop(void *closure, unsigned hookid, const struct afb_ditf *ditf, struct sd_event *result)
+static void hook_ditf_get_event_loop(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result)
 {
-       hook_ditf(closure, hookid, ditf, "get_event_loop", NULL);
+       hook_ditf(closure, hookid, export, "get_event_loop", NULL);
 }
 
-static void hook_ditf_get_user_bus(void *closure, unsigned hookid, const struct afb_ditf *ditf, struct sd_bus *result)
+static void hook_ditf_get_user_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
 {
-       hook_ditf(closure, hookid, ditf, "get_user_bus", NULL);
+       hook_ditf(closure, hookid, export, "get_user_bus", NULL);
 }
 
-static void hook_ditf_get_system_bus(void *closure, unsigned hookid, const struct afb_ditf *ditf, struct sd_bus *result)
+static void hook_ditf_get_system_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
 {
-       hook_ditf(closure, hookid, ditf, "get_system_bus", NULL);
+       hook_ditf(closure, hookid, export, "get_system_bus", NULL);
 }
 
-static void hook_ditf_vverbose(void *closure, unsigned hookid, const struct afb_ditf *ditf, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
+static void hook_ditf_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
 {
        struct json_object *pos;
        int len;
@@ -570,7 +609,7 @@ static void hook_ditf_vverbose(void *closure, unsigned hookid, const struct afb_
        if (file)
                wrap_json_pack(&pos, "{ss si ss*}", "file", file, "line", line, "function", function);
 
-       hook_ditf(closure, hookid, ditf, "vverbose", "{si ss* ss? so*}",
+       hook_ditf(closure, hookid, export, "vverbose", "{si ss* ss? so*}",
                                        "level", level,
                                        "type", verbosity_level_name(level),
                                        len < 0 ? "format" : "message", len < 0 ? fmt : msg,
@@ -579,13 +618,13 @@ static void hook_ditf_vverbose(void *closure, unsigned hookid, const struct afb_
        free(msg);
 }
 
-static void hook_ditf_event_make(void *closure, unsigned hookid, const struct afb_ditf *ditf, const char *name, struct afb_event result)
+static void hook_ditf_event_make(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_eventid *result)
 {
-       hook_ditf(closure, hookid, ditf, "event_make", "{ss ss si}",
-                       "name", name, "event", afb_evt_event_name(result), "id", afb_evt_event_id(result));
+       hook_ditf(closure, hookid, export, "event_make", "{ss ss si}",
+                       "name", name, "event", afb_evt_eventid_fullname(result), "id", afb_evt_eventid_id(result));
 }
 
-static void hook_ditf_rootdir_get_fd(void *closure, unsigned hookid, const struct afb_ditf *ditf, int result)
+static void hook_ditf_rootdir_get_fd(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
 {
        char path[PATH_MAX];
 
@@ -594,12 +633,12 @@ static void hook_ditf_rootdir_get_fd(void *closure, unsigned hookid, const struc
                readlink(path, path, sizeof path);
        }
 
-       hook_ditf(closure, hookid, ditf, "rootdir_get_fd", "{ss}",
+       hook_ditf(closure, hookid, export, "rootdir_get_fd", "{ss}",
                        result < 0 ? "path" : "error",
                        result < 0 ? strerror(errno) : path);
 }
 
-static void hook_ditf_rootdir_open_locale(void *closure, unsigned hookid, const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
+static void hook_ditf_rootdir_open_locale(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result)
 {
        char path[PATH_MAX];
 
@@ -608,7 +647,7 @@ static void hook_ditf_rootdir_open_locale(void *closure, unsigned hookid, const
                readlink(path, path, sizeof path);
        }
 
-       hook_ditf(closure, hookid, ditf, "rootdir_open_locale", "{ss si ss* ss}",
+       hook_ditf(closure, hookid, export, "rootdir_open_locale", "{ss si ss* ss}",
                        "file", filename,
                        "flags", flags,
                        "locale", locale,
@@ -616,24 +655,24 @@ static void hook_ditf_rootdir_open_locale(void *closure, unsigned hookid, const
                        result < 0 ? strerror(errno) : path);
 }
 
-static void hook_ditf_queue_job(void *closure, unsigned hookid, const struct afb_ditf *ditf, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
+static void hook_ditf_queue_job(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
 {
-       hook_ditf(closure, hookid, ditf, "queue_job", "{ss}", "result", result);
+       hook_ditf(closure, hookid, export, "queue_job", "{ss}", "result", result);
 }
 
-static void hook_ditf_unstore_req(void * closure, unsigned hookid, const struct afb_ditf *ditf, struct afb_stored_req *sreq)
+static void hook_ditf_unstore_req(void * closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq)
 {
-       hook_ditf(closure, hookid, ditf, "unstore_req", NULL);
+       hook_ditf(closure, hookid, export, "unstore_req", NULL);
 }
 
-static void hook_ditf_require_api(void *closure, unsigned hookid, const struct afb_ditf *ditf, const char *name, int initialized)
+static void hook_ditf_require_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized)
 {
-       hook_ditf(closure, hookid, ditf, "require_api", "{ss sb}", "name", name, "initialized", initialized);
+       hook_ditf(closure, hookid, export, "require_api", "{ss sb}", "name", name, "initialized", initialized);
 }
 
-static void hook_ditf_require_api_result(void *closure, unsigned hookid, const struct afb_ditf *ditf, const char *name, int initialized, int result)
+static void hook_ditf_require_api_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result)
 {
-       hook_ditf(closure, hookid, ditf, "require_api_result", "{ss sb si}", "name", name, "initialized", initialized, "result", result);
+       hook_ditf(closure, hookid, export, "require_api_result", "{ss sb si}", "name", name, "initialized", initialized, "result", result);
 }
 
 static struct afb_hook_ditf_itf hook_ditf_itf = {
@@ -668,66 +707,66 @@ static struct flag svc_flags[] = { /* must be sorted by names */
                { "start_before",       afb_hook_flag_svc_start_before },
 };
 
-/* get the svc value for flag of 'name' */
+/* get the export value for flag of 'name' */
 static int get_svc_flag(const char *name)
 {
        return get_flag(name, svc_flags, (int)(sizeof svc_flags / sizeof *svc_flags));
 }
 
-static void hook_svc(void *closure, unsigned hookid, const struct afb_svc *svc, const char *action, const char *format, ...)
+static void hook_svc(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...)
 {
        va_list ap;
 
        va_start(ap, format);
        emit(closure, hookid, "service", "{ss ss}", format, ap,
-                                       "api", svc->api,
+                                       "api", afb_export_apiname(export),
                                        "action", action);
        va_end(ap);
 }
 
-static void hook_svc_start_before(void *closure, unsigned hookid, const struct afb_svc *svc)
+static void hook_svc_start_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
 {
-       hook_svc(closure, hookid, svc, "start_before", NULL);
+       hook_svc(closure, hookid, export, "start_before", NULL);
 }
 
-static void hook_svc_start_after(void *closure, unsigned hookid, const struct afb_svc *svc, int status)
+static void hook_svc_start_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status)
 {
-       hook_svc(closure, hookid, svc, "start_after", "{si}", "result", status);
+       hook_svc(closure, hookid, export, "start_after", "{si}", "result", status);
 }
 
-static void hook_svc_on_event_before(void *closure, unsigned hookid, const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
+static void hook_svc_on_event_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object)
 {
-       hook_svc(closure, hookid, svc, "on_event_before", "{ss si sO*}",
-                       "event", event, "id", eventid, "data", object);
+       hook_svc(closure, hookid, export, "on_event_before", "{ss si sO*}",
+                       "event", event, "id", evtid, "data", object);
 }
 
-static void hook_svc_on_event_after(void *closure, unsigned hookid, const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
+static void hook_svc_on_event_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object)
 {
-       hook_svc(closure, hookid, svc, "on_event_after", "{ss si sO*}",
-                       "event", event, "id", eventid, "data", object);
+       hook_svc(closure, hookid, export, "on_event_after", "{ss si sO*}",
+                       "event", event, "id", evtid, "data", object);
 }
 
-static void hook_svc_call(void *closure, unsigned hookid, const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
+static void hook_svc_call(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
 {
-       hook_svc(closure, hookid, svc, "call", "{ss ss sO*}",
+       hook_svc(closure, hookid, export, "call", "{ss ss sO*}",
                        "api", api, "verb", verb, "args", args);
 }
 
-static void hook_svc_call_result(void *closure, unsigned hookid, const struct afb_svc *svc, int status, struct json_object *result)
+static void hook_svc_call_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result)
 {
-       hook_svc(closure, hookid, svc, "call_result", "{si sO*}",
+       hook_svc(closure, hookid, export, "call_result", "{si sO*}",
                        "status", status, "result", result);
 }
 
-static void hook_svc_callsync(void *closure, unsigned hookid, const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
+static void hook_svc_callsync(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
 {
-       hook_svc(closure, hookid, svc, "callsync", "{ss ss sO*}",
+       hook_svc(closure, hookid, export, "callsync", "{ss ss sO*}",
                        "api", api, "verb", verb, "args", args);
 }
 
-static void hook_svc_callsync_result(void *closure, unsigned hookid, const struct afb_svc *svc, int status, struct json_object *result)
+static void hook_svc_callsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result)
 {
-       hook_svc(closure, hookid, svc, "callsync_result", "{si sO*}",
+       hook_svc(closure, hookid, export, "callsync_result", "{si sO*}",
                        "status", status, "result", result);
 }
 
@@ -747,16 +786,17 @@ static struct afb_hook_svc_itf hook_svc_itf = {
 /*******************************************************************************/
 
 static struct flag evt_flags[] = { /* must be sorted by names */
+               { "addref",             afb_hook_flag_evt_addref },
                { "all",                afb_hook_flags_evt_all },
                { "broadcast_after",    afb_hook_flag_evt_broadcast_after },
                { "broadcast_before",   afb_hook_flag_evt_broadcast_before },
                { "common",             afb_hook_flags_evt_common },
                { "create",             afb_hook_flag_evt_create },
-               { "drop",               afb_hook_flag_evt_drop },
                { "extra",              afb_hook_flags_evt_extra },
                { "name",               afb_hook_flag_evt_name },
                { "push_after",         afb_hook_flag_evt_push_after },
                { "push_before",        afb_hook_flag_evt_push_before },
+               { "unref",              afb_hook_flag_evt_unref },
 };
 
 /* get the evt value for flag of 'name' */
@@ -765,7 +805,7 @@ static int get_evt_flag(const char *name)
        return get_flag(name, evt_flags, (int)(sizeof evt_flags / sizeof *evt_flags));
 }
 
-static void hook_evt(void *closure, unsigned hookid, const char *evt, int id, const char *action, const char *format, ...)
+static void hook_evt(void *closure, const struct afb_hookid *hookid, const char *evt, int id, const char *action, const char *format, ...)
 {
        va_list ap;
 
@@ -777,40 +817,45 @@ static void hook_evt(void *closure, unsigned hookid, const char *evt, int id, co
        va_end(ap);
 }
 
-static void hook_evt_create(void *closure, unsigned hookid, const char *evt, int id)
+static void hook_evt_create(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
 {
        hook_evt(closure, hookid, evt, id, "create", NULL);
 }
 
-static void hook_evt_push_before(void *closure, unsigned hookid, const char *evt, int id, struct json_object *obj)
+static void hook_evt_push_before(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
 {
        hook_evt(closure, hookid, evt, id, "push_before", "{sO*}", "data", obj);
 }
 
 
-static void hook_evt_push_after(void *closure, unsigned hookid, const char *evt, int id, struct json_object *obj, int result)
+static void hook_evt_push_after(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
 {
        hook_evt(closure, hookid, evt, id, "push_after", "{sO* si}", "data", obj, "result", result);
 }
 
-static void hook_evt_broadcast_before(void *closure, unsigned hookid, const char *evt, int id, struct json_object *obj)
+static void hook_evt_broadcast_before(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
 {
        hook_evt(closure, hookid, evt, id, "broadcast_before", "{sO*}", "data", obj);
 }
 
-static void hook_evt_broadcast_after(void *closure, unsigned hookid, const char *evt, int id, struct json_object *obj, int result)
+static void hook_evt_broadcast_after(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
 {
        hook_evt(closure, hookid, evt, id, "broadcast_after", "{sO* si}", "data", obj, "result", result);
 }
 
-static void hook_evt_name(void *closure, unsigned hookid, const char *evt, int id)
+static void hook_evt_name(void *closure, const struct afb_hookid *hookid, const char *evt, int id, const char *result)
+{
+       hook_evt(closure, hookid, evt, id, "name", "{ss}", "result", result);
+}
+
+static void hook_evt_addref(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
 {
-       hook_evt(closure, hookid, evt, id, "name", NULL);
+       hook_evt(closure, hookid, evt, id, "addref", NULL);
 }
 
-static void hook_evt_drop(void *closure, unsigned hookid, const char *evt, int id)
+static void hook_evt_unref(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
 {
-       hook_evt(closure, hookid, evt, id, "drop", NULL);
+       hook_evt(closure, hookid, evt, id, "unref", NULL);
 }
 
 static struct afb_hook_evt_itf hook_evt_itf = {
@@ -820,7 +865,62 @@ static struct afb_hook_evt_itf hook_evt_itf = {
        .hook_evt_broadcast_before = hook_evt_broadcast_before,
        .hook_evt_broadcast_after = hook_evt_broadcast_after,
        .hook_evt_name = hook_evt_name,
-       .hook_evt_drop = hook_evt_drop
+       .hook_evt_addref = hook_evt_addref,
+       .hook_evt_unref = hook_evt_unref
+};
+
+/*******************************************************************************/
+/*****  trace the globals                                                  *****/
+/*******************************************************************************/
+
+static struct flag global_flags[] = { /* must be sorted by names */
+               { "all",                afb_hook_flags_global_all },
+               { "vverbose",           afb_hook_flag_global_vverbose },
+};
+
+/* get the global value for flag of 'name' */
+static int get_global_flag(const char *name)
+{
+       return get_flag(name, global_flags, (int)(sizeof global_flags / sizeof *global_flags));
+}
+
+static void hook_global(void *closure, const struct afb_hookid *hookid, const char *action, const char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+       emit(closure, hookid, "global", "{ss}", format, ap, "action", action);
+       va_end(ap);
+}
+
+static void hook_global_vverbose(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
+{
+       struct json_object *pos;
+       int len;
+       char *msg;
+       va_list ap;
+
+       pos = NULL;
+       msg = NULL;
+
+       va_copy(ap, args);
+       len = vasprintf(&msg, fmt, ap);
+       va_end(ap);
+
+       if (file)
+               wrap_json_pack(&pos, "{ss si ss*}", "file", file, "line", line, "function", function);
+
+       hook_global(closure, hookid, "vverbose", "{si ss* ss? so*}",
+                                       "level", level,
+                                       "type", verbosity_level_name(level),
+                                       len < 0 ? "format" : "message", len < 0 ? fmt : msg,
+                                       "position", pos);
+
+       free(msg);
+}
+
+static struct afb_hook_global_itf hook_global_itf = {
+       .hook_global_vverbose = hook_global_vverbose,
 };
 
 /*******************************************************************************/
@@ -859,7 +959,13 @@ abstracting[Trace_Type_Count] =
                .name = "event",
                .unref =  (void(*)(void*))afb_hook_unref_evt,
                .get_flag = get_evt_flag
-       }
+       },
+       [Trace_Type_Global] =
+       {
+               .name = "global",
+               .unref =  (void(*)(void*))afb_hook_unref_global,
+               .get_flag = get_global_flag
+       },
 };
 
 /*******************************************************************************/
@@ -867,7 +973,7 @@ abstracting[Trace_Type_Count] =
 /*******************************************************************************/
 
 /* drop hooks of 'trace' matching 'tag' and 'event' and 'session' */
-static void trace_unhook(struct afb_trace *trace, struct tag *tag, struct event *event, struct session *session)
+static void trace_unhook(struct afb_trace *trace, struct tag *tag, struct event *event, struct afb_session *session)
 {
        int i;
        struct hook *hook, **prev;
@@ -896,29 +1002,12 @@ static void trace_cleanup(struct afb_trace *trace)
        struct hook *hook;
        struct tag *tag, **ptag;
        struct event *event, **pevent;
-       struct session *session, **psession;
-
-       /* clean sessions */
-       psession = &trace->sessions;
-       while ((session = *psession)) {
-               /* search for session */
-               for (hook = NULL, i = 0 ; !hook && i < Trace_Type_Count ; i++) 
-                       for (hook = trace->hooks[i] ; hook && hook->session != session ; hook = hook->next);
-               /* keep or free whether used or not */
-               if (hook)
-                       psession = &session->next;
-               else {
-                       *psession = session->next;
-                       if (__atomic_exchange_n(&session->trace, NULL, __ATOMIC_RELAXED))
-                               afb_session_set_cookie(session->session, session, NULL, NULL);
-                       free(session);
-               }
-       }
+
        /* clean tags */
        ptag = &trace->tags;
        while ((tag = *ptag)) {
                /* search for tag */
-               for (hook = NULL, i = 0 ; !hook && i < Trace_Type_Count ; i++) 
+               for (hook = NULL, i = 0 ; !hook && i < Trace_Type_Count ; i++)
                        for (hook = trace->hooks[i] ; hook && hook->tag != tag ; hook = hook->next);
                /* keep or free whether used or not */
                if (hook)
@@ -932,32 +1021,19 @@ static void trace_cleanup(struct afb_trace *trace)
        pevent = &trace->events;
        while ((event = *pevent)) {
                /* search for event */
-               for (hook = NULL, i = 0 ; !hook && i < Trace_Type_Count ; i++) 
+               for (hook = NULL, i = 0 ; !hook && i < Trace_Type_Count ; i++)
                        for (hook = trace->hooks[i] ; hook && hook->event != event ; hook = hook->next);
                /* keep or free whether used or not */
                if (hook)
                        pevent = &event->next;
                else {
                        *pevent = event->next;
-                       afb_event_drop(event->event);
+                       afb_evt_evtid_unref(event->evtid);
                        free(event);
                }
        }
 }
 
-/* callback at end of traced session */
-static void free_session_cookie(void *cookie)
-{
-       struct session *session = cookie;
-       struct afb_trace *trace = __atomic_exchange_n(&session->trace, NULL, __ATOMIC_RELAXED);
-       if (trace) {
-               pthread_mutex_lock(&trace->mutex);
-               trace_unhook(trace, NULL, NULL, session);
-               trace_cleanup(trace);
-               pthread_mutex_unlock(&trace->mutex);
-       }
-}
-
 /*
  * Get the tag of 'name' within 'trace'.
  * If 'alloc' isn't zero, create the tag and add it.
@@ -989,18 +1065,20 @@ static struct tag *trace_get_tag(struct afb_trace *trace, const char *name, int
  */
 static struct event *trace_get_event(struct afb_trace *trace, const char *name, int alloc)
 {
+       struct afb_event e;
        struct event *event;
 
        /* search the event */
        event = trace->events;
-       while (event && strcmp(afb_event_name(event->event), name))
+       while (event && strcmp(afb_evt_evtid_name(event->evtid), name))
                event = event->next;
 
        if (!event && alloc) {
                event = malloc(sizeof * event);
                if (event) {
-                       event->event = trace->daemon->itf->event_make(trace->daemon->closure, name);
-                       if (afb_event_is_valid(event->event)) {
+                       e = afb_daemon_make_event_v1(*trace->daemon, name);
+                       event->evtid = afb_evt_eventid_to_evtid(afb_event_to_eventid(e));
+                       if (event->evtid) {
                                event->next = trace->events;
                                trace->events = event;
                        } else {
@@ -1013,41 +1091,48 @@ static struct event *trace_get_event(struct afb_trace *trace, const char *name,
 }
 
 /*
- * Get the session of 'value' within 'trace'.
- * If 'alloc' isn't zero, create the session and add it.
+ * called on session closing
  */
-static struct session *trace_get_session(struct afb_trace *trace, struct afb_session *value, int alloc)
-{
-       struct session *session;
-
-       /* search the session */
-       session = trace->sessions;
-       while (session && session->session != value)
-               session = session->next;
-
-       if (!session && alloc) {
-               session = malloc(sizeof * session);
-               if (session) {
-                       session->session = value;
-                       session->trace = NULL;
-                       session->next = trace->sessions;
-                       trace->sessions = session;
-               }
-       }
-       return session;
+static void session_closed(void *item)
+{
+       struct cookie *cookie = item;
+
+       pthread_mutex_lock(&cookie->trace->mutex);
+       trace_unhook(cookie->trace, NULL, NULL, cookie->session);
+       pthread_mutex_unlock(&cookie->trace->mutex);
+       free(cookie);
+}
+
+/*
+ * records the cookie of session for tracking close
+ */
+static void *session_open(void *closure)
+{
+       struct cookie *param = closure, *cookie;
+       cookie = malloc(sizeof *cookie);
+       if (cookie)
+               *cookie = *param;
+       return cookie;
 }
 
 /*
  * Get the session of 'uuid' within 'trace'.
  * If 'alloc' isn't zero, create the session and add it.
  */
-static struct session *trace_get_session_by_uuid(struct afb_trace *trace, const char *uuid, int alloc)
+static struct afb_session *trace_get_session_by_uuid(struct afb_trace *trace, const char *uuid, int alloc)
 {
-       struct afb_session *session;
-       int created;
+       struct cookie cookie;
 
-       session = afb_session_get(uuid, alloc ? &created : NULL);
-       return session ? trace_get_session(trace, session, alloc) : NULL;
+       if (!alloc)
+               cookie.session = afb_session_search(uuid);
+       else {
+               cookie.session = afb_session_get(uuid, AFB_SESSION_TIMEOUT_DEFAULT, NULL);
+               if (cookie.session) {
+                       cookie.trace = trace;
+                       afb_session_cookie(cookie.session, cookie.trace, session_open, session_closed, &cookie, 0);
+               }
+       }
+       return cookie.session;
 }
 
 static struct hook *trace_make_detached_hook(struct afb_trace *trace, const char *event, const char *tag)
@@ -1068,13 +1153,8 @@ static struct hook *trace_make_detached_hook(struct afb_trace *trace, const char
 
 static void trace_attach_hook(struct afb_trace *trace, struct hook *hook, enum trace_type type)
 {
-       struct session *session = hook->session;
        hook->next = trace->hooks[type];
        trace->hooks[type] = hook;
-       if (session && !session->trace) {
-               session->trace = trace;
-               afb_session_set_cookie(session->session, session, session, free_session_cookie);
-       }
 }
 
 /*******************************************************************************/
@@ -1104,7 +1184,7 @@ struct desc
 static void addhook(struct desc *desc, enum trace_type type)
 {
        struct hook *hook;
-       struct session *session;
+       struct afb_session *session;
        struct afb_session *bind;
        struct afb_trace *trace = desc->context->trace;
 
@@ -1138,7 +1218,7 @@ static void addhook(struct desc *desc, enum trace_type type)
                                free(hook);
                                return;
                        }
-                       bind = session->session;
+                       bind = session;
                }
                hook->handler = afb_hook_create_xreq(desc->api, desc->verb, bind,
                                desc->flags[type], &hook_xreq_itf, hook);
@@ -1152,6 +1232,9 @@ static void addhook(struct desc *desc, enum trace_type type)
        case Trace_Type_Evt:
                hook->handler = afb_hook_create_evt(desc->pattern, desc->flags[type], &hook_evt_itf, hook);
                break;
+       case Trace_Type_Global:
+               hook->handler = afb_hook_create_global(desc->flags[type], &hook_global_itf, hook);
+               break;
        default:
                break;
        }
@@ -1162,7 +1245,7 @@ static void addhook(struct desc *desc, enum trace_type type)
        }
 
        /* attach and activate the hook */
-       afb_req_subscribe(desc->context->req, hook->event->event);
+       afb_req_subscribe(desc->context->req, afb_evt_event_from_evtid(hook->event->evtid));
        trace_attach_hook(trace, hook, type);
 }
 
@@ -1217,17 +1300,22 @@ static void add_evt_flags(void *closure, struct json_object *object)
        add_flags(closure, object, Trace_Type_Evt);
 }
 
+static void add_global_flags(void *closure, struct json_object *object)
+{
+       add_flags(closure, object, Trace_Type_Global);
+}
+
 /* add hooks */
 static void add(void *closure, struct json_object *object)
 {
        int rc;
        struct desc desc;
-       struct json_object *request, *event, *daemon, *service, *sub;
+       struct json_object *request, *event, *daemon, *service, *sub, *global;
 
        memcpy (&desc, closure, sizeof desc);
-       request = event = daemon = service = sub = NULL;
+       request = event = daemon = service = sub = global = NULL;
 
-       rc = wrap_json_unpack(object, "{s?s s?s s?s s?s s?s s?s s?o s?o s?o s?o s?o}",
+       rc = wrap_json_unpack(object, "{s?s s?s s?s s?s s?s s?s s?o s?o s?o s?o s?o s?o}",
                        "name", &desc.name,
                        "tag", &desc.tag,
                        "api", &desc.api,
@@ -1238,6 +1326,7 @@ static void add(void *closure, struct json_object *object)
                        "daemon", &daemon,
                        "service", &service,
                        "event", &event,
+                       "global", &global,
                        "for", &sub);
 
        if (!rc) {
@@ -1264,6 +1353,9 @@ static void add(void *closure, struct json_object *object)
                if (event)
                        wrap_json_optarray_for_all(event, add_evt_flags, &desc);
 
+               if (global)
+                       wrap_json_optarray_for_all(global, add_global_flags, &desc);
+
                /* apply */
                if (sub)
                        wrap_json_optarray_for_all(sub, add, &desc);
@@ -1321,7 +1413,7 @@ static void drop_session(void *closure, struct json_object *object)
 {
        int rc;
        struct context *context = closure;
-       struct session *session;
+       struct afb_session *session;
        const char *uuid;
 
        rc = wrap_json_unpack(object, "s", &uuid);