/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Copyright (C) 2016-2019 "IoT.bzh"
* Author José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* limitations under the License.
*/
+#if WITH_AFB_HOOK && WITH_AFB_TRACE
+
#define _GNU_SOURCE
#include <assert.h>
#include <pthread.h>
#include <json-c/json.h>
+#if !defined(JSON_C_TO_STRING_NOSLASHESCAPE)
+#define JSON_C_TO_STRING_NOSLASHESCAPE 0
+#endif
#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
#include "afb-hook.h"
+#include "afb-hook-flags.h"
#include "afb-cred.h"
#include "afb-session.h"
#include "afb-xreq.h"
/***** types *****/
/*******************************************************************************/
-/* structure for searching flags by names */
-struct flag
-{
- const char *name; /** the name */
- int value; /** the value */
-};
-
/* struct for tags */
struct tag {
struct tag *next; /* link to the next */
- char tag[1]; /* name of the tag */
+ char tag[]; /* name of the tag */
};
/* struct for events */
}
}
-/* get the value of the flag of 'name' in the array 'flags' of 'count elements */
-static int get_flag(const char *name, struct flag flags[], int count)
-{
- /* dichotomic search */
- int lower = 0, upper = count;
- while (lower < upper) {
- int mid = (lower + upper) >> 1;
- int cmp = strcmp(name, flags[mid].name);
- if (!cmp)
- return flags[mid].value;
- if (cmp < 0)
- upper = mid;
- else
- lower = mid + 1;
- }
- return 0;
-}
-
/* timestamp */
static struct json_object *timestamp(const struct afb_hookid *hookid)
{
- char ts[50];
-
- snprintf(ts, sizeof ts, "%llu.%06lu",
- (long long unsigned)hookid->time.tv_sec,
- (long unsigned)((hookid->time.tv_nsec + 500) / 1000));
-
- return json_object_new_double_s(0.0f, ts); /* the real value isn't used */
-#if 0
- return json_object_new_string(ts);
- return json_object_new_double_s(0f, ts); /* the real value isn't used */
-#endif
+ return json_object_new_double((double)hookid->time.tv_sec +
+ (double)hookid->time.tv_nsec * .000000001);
}
/* verbosity level name or NULL */
/***** trace the requests *****/
/*******************************************************************************/
-static struct flag xreq_flags[] = { /* must be sorted by names */
- { "addref", afb_hook_flag_req_addref },
- { "all", afb_hook_flags_req_all },
- { "args", afb_hook_flags_req_args },
- { "begin", afb_hook_flag_req_begin },
- { "common", afb_hook_flags_req_common },
- { "context", afb_hook_flags_req_context },
- { "context_get", afb_hook_flag_req_legacy_context_get },
- { "context_make", afb_hook_flag_req_context_make },
- { "context_set", afb_hook_flag_req_legacy_context_set },
- { "end", afb_hook_flag_req_end },
- { "event", afb_hook_flags_req_event },
- { "extra", afb_hook_flags_req_extra },
- { "get", afb_hook_flag_req_get },
- { "get_application_id", afb_hook_flag_req_get_application_id },
- { "get_client_info", afb_hook_flag_req_get_client_info },
- { "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 },
- { "reply", afb_hook_flag_req_reply },
- { "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 },
- { "store", afb_hook_flag_req_legacy_store },
- { "stores", afb_hook_flags_req_stores },
- { "subcall", afb_hook_flag_req_subcall },
- { "subcall_result", afb_hook_flag_req_subcall_result },
- { "subcalls", afb_hook_flags_req_subcalls },
- { "subcallsync", afb_hook_flag_req_subcallsync },
- { "subcallsync_result", afb_hook_flag_req_subcallsync_result },
- { "subscribe", afb_hook_flag_req_subscribe },
- { "unref", afb_hook_flag_req_unref },
- { "unstore", afb_hook_flag_req_legacy_unstore },
- { "unsubscribe", afb_hook_flag_req_unsubscribe },
- { "vverbose", afb_hook_flag_req_vverbose },
-};
-
-/* get the xreq value for flag of 'name' */
-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, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *action, const char *format, ...)
{
struct json_object *cred = NULL;
/***** trace the api interface *****/
/*******************************************************************************/
-#if !defined(REMOVE_LEGACY_TRACE)
-static struct flag legacy_ditf_flags[] = { /* must be sorted by names */
- { "all", afb_hook_flags_api_ditf_all },
- { "common", afb_hook_flags_api_ditf_common },
- { "event_broadcast_after", afb_hook_flag_api_event_broadcast },
- { "event_broadcast_before", afb_hook_flag_api_event_broadcast },
- { "event_make", afb_hook_flag_api_event_make },
- { "extra", afb_hook_flags_api_ditf_extra },
- { "get_event_loop", afb_hook_flag_api_get_event_loop },
- { "get_system_bus", afb_hook_flag_api_get_system_bus },
- { "get_user_bus", afb_hook_flag_api_get_user_bus },
- { "queue_job", afb_hook_flag_api_queue_job },
- { "require_api", afb_hook_flag_api_require_api },
- { "require_api_result", afb_hook_flag_api_require_api },
- { "rootdir_get_fd", afb_hook_flag_api_rootdir_get_fd },
- { "rootdir_open_locale", afb_hook_flag_api_rootdir_open_locale },
- { "unstore_req", afb_hook_flag_api_legacy_unstore_req },
- { "vverbose", afb_hook_flag_api_vverbose },
-};
-
-static struct flag legacy_svc_flags[] = { /* must be sorted by names */
- { "all", afb_hook_flags_api_svc_all },
- { "call", afb_hook_flag_api_call },
- { "call_result", afb_hook_flag_api_call },
- { "callsync", afb_hook_flag_api_callsync },
- { "callsync_result", afb_hook_flag_api_callsync },
- { "on_event_after", afb_hook_flag_api_on_event },
- { "on_event_before", afb_hook_flag_api_on_event },
- { "start_after", afb_hook_flag_api_start },
- { "start_before", afb_hook_flag_api_start },
-};
-
-/* get the export value for flag of 'name' */
-static int get_legacy_ditf_flag(const char *name)
-{
- return get_flag(name, legacy_ditf_flags, (int)(sizeof legacy_ditf_flags / sizeof *legacy_ditf_flags));
-}
-
-/* get the export value for flag of 'name' */
-static int get_legacy_svc_flag(const char *name)
-{
- return get_flag(name, legacy_svc_flags, (int)(sizeof legacy_svc_flags / sizeof *legacy_svc_flags));
-}
-#endif
-
-static struct flag api_flags[] = { /* must be sorted by names */
- { "add_alias", afb_hook_flag_api_add_alias },
- { "all", afb_hook_flags_api_all },
- { "api_add_verb", afb_hook_flag_api_api_add_verb },
- { "api", afb_hook_flags_api_api },
- { "api_del_verb", afb_hook_flag_api_api_del_verb },
- { "api_seal", afb_hook_flag_api_api_seal },
- { "api_set_on_event", afb_hook_flag_api_api_set_on_event },
- { "api_set_on_init", afb_hook_flag_api_api_set_on_init },
- { "api_set_verbs", afb_hook_flag_api_api_set_verbs },
- { "call", afb_hook_flag_api_call },
- { "callsync", afb_hook_flag_api_callsync },
- { "class_provide", afb_hook_flag_api_class_provide },
- { "class_require", afb_hook_flag_api_class_require },
- { "common", afb_hook_flags_api_common },
- { "delete_api", afb_hook_flag_api_delete_api },
- { "event", afb_hook_flags_api_event },
- { "event_broadcast", afb_hook_flag_api_event_broadcast },
- { "event_handler_add", afb_hook_flag_api_event_handler_add },
- { "event_handler_del", afb_hook_flag_api_event_handler_del },
- { "event_make", afb_hook_flag_api_event_make },
- { "extra", afb_hook_flags_api_extra },
- { "get_event_loop", afb_hook_flag_api_get_event_loop },
- { "get_system_bus", afb_hook_flag_api_get_system_bus },
- { "get_user_bus", afb_hook_flag_api_get_user_bus },
- { "legacy_unstore_req", afb_hook_flag_api_legacy_unstore_req },
- { "new_api", afb_hook_flag_api_new_api },
- { "on_event", afb_hook_flag_api_on_event },
- { "on_event_handler", afb_hook_flag_api_on_event_handler },
- { "queue_job", afb_hook_flag_api_queue_job },
- { "require_api", afb_hook_flag_api_require_api },
- { "rootdir_get_fd", afb_hook_flag_api_rootdir_get_fd },
- { "rootdir_open_locale",afb_hook_flag_api_rootdir_open_locale },
- { "start", afb_hook_flag_api_start },
- { "vverbose", afb_hook_flag_api_vverbose },
-};
-
-/* get the export value for flag of 'name' */
-static int get_api_flag(const char *name)
-{
- return get_flag(name, api_flags, (int)(sizeof api_flags / sizeof *api_flags));
-}
-
static void hook_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...)
{
va_list ap;
{
char path[PATH_MAX], proc[100];
const char *key, *val;
+ ssize_t s;
if (result >= 0) {
snprintf(proc, sizeof proc, "/proc/self/fd/%d", result);
- readlink(proc, path, sizeof path);
+ s = readlink(proc, path, sizeof path);
+ path[s < 0 ? 0 : s >= sizeof path ? sizeof path - 1 : s] = 0;
key = "path";
val = path;
} else {
{
char path[PATH_MAX], proc[100];
const char *key, *val;
+ ssize_t s;
if (result >= 0) {
snprintf(proc, sizeof proc, "/proc/self/fd/%d", result);
- readlink(proc, path, sizeof path);
+ s = readlink(proc, path, sizeof path);
+ path[s < 0 ? 0 : s >= sizeof path ? sizeof path - 1 : s] = 0;
key = "path";
val = path;
} else {
hook_api(closure, hookid, export, "delete_api", "{si}", "status", result);
}
+static void hook_api_on_event_handler_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern)
+{
+ hook_api(closure, hookid, export, "on_event_handler.before",
+ "{ss ss sO?}", "pattern", pattern, "event", event, "data", object);
+}
+
+static void hook_api_on_event_handler_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern)
+{
+ hook_api(closure, hookid, export, "on_event_handler.after",
+ "{ss ss sO?}", "pattern", pattern, "event", event, "data", object);
+}
+
+static void hook_api_settings(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object)
+{
+ hook_api(closure, hookid, export, "settings", "{sO}", "settings", object);
+}
+
static struct afb_hook_api_itf hook_api_itf = {
.hook_api_event_broadcast_before = hook_api_event_broadcast_before,
.hook_api_event_broadcast_after = hook_api_event_broadcast_after,
.hook_api_class_provide = hook_api_class_provide,
.hook_api_class_require = hook_api_class_require,
.hook_api_delete_api = hook_api_delete_api,
+ .hook_api_on_event_handler_before = hook_api_on_event_handler_before,
+ .hook_api_on_event_handler_after = hook_api_on_event_handler_after,
+ .hook_api_settings = hook_api_settings,
};
/*******************************************************************************/
/***** trace the events *****/
/*******************************************************************************/
-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 },
- { "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' */
-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, const struct afb_hookid *hookid, const char *evt, int id, const char *action, const char *format, ...)
{
va_list ap;
/***** trace the sessions *****/
/*******************************************************************************/
-static struct flag session_flags[] = { /* must be sorted by names */
- { "addref", afb_hook_flag_session_addref },
- { "all", afb_hook_flags_session_all },
- { "close", afb_hook_flag_session_close },
- { "common", afb_hook_flags_session_common },
- { "create", afb_hook_flag_session_create },
- { "destroy", afb_hook_flag_session_destroy },
- { "renew", afb_hook_flag_session_renew },
- { "unref", afb_hook_flag_session_unref },
-};
-
-/* get the session value for flag of 'name' */
-static int get_session_flag(const char *name)
-{
- return get_flag(name, session_flags, (int)(sizeof session_flags / sizeof *session_flags));
-}
-
static void hook_session(void *closure, const struct afb_hookid *hookid, struct afb_session *session, const char *action, const char *format, ...)
{
va_list ap;
va_start(ap, format);
emit(closure, hookid, "session", "{ss ss}", format, ap,
- "uuid", session,
+ "uuid", afb_session_uuid(session),
"action", action);
va_end(ap);
}
/***** 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;
{
.name = "request",
.unref = (void(*)(void*))afb_hook_unref_xreq,
- .get_flag = get_xreq_flag
+ .get_flag = afb_hook_flags_xreq_from_text
},
[Trace_Type_Api] =
{
.name = "api",
.unref = (void(*)(void*))afb_hook_unref_api,
- .get_flag = get_api_flag
+ .get_flag = afb_hook_flags_api_from_text
},
[Trace_Type_Evt] =
{
.name = "event",
.unref = (void(*)(void*))afb_hook_unref_evt,
- .get_flag = get_evt_flag
+ .get_flag = afb_hook_flags_evt_from_text
},
[Trace_Type_Session] =
{
.name = "session",
.unref = (void(*)(void*))afb_hook_unref_session,
- .get_flag = get_session_flag
+ .get_flag = afb_hook_flags_session_from_text
},
[Trace_Type_Global] =
{
.name = "global",
.unref = (void(*)(void*))afb_hook_unref_global,
- .get_flag = get_global_flag
+ .get_flag = afb_hook_flags_global_from_text
},
#if !defined(REMOVE_LEGACY_TRACE)
[Trace_Legacy_Type_Ditf] =
{
.name = "daemon",
.unref = (void(*)(void*))afb_hook_unref_api,
- .get_flag = get_legacy_ditf_flag
+ .get_flag = afb_hook_flags_legacy_ditf_from_text
},
[Trace_Legacy_Type_Svc] =
{
.name = "service",
.unref = (void(*)(void*))afb_hook_unref_api,
- .get_flag = get_legacy_svc_flag
+ .get_flag = afb_hook_flags_legacy_svc_from_text
},
#endif
};
if (!tag && alloc) {
/* creation if needed */
- tag = malloc(sizeof * tag + strlen(name));
+ tag = malloc(sizeof * tag + 1 + strlen(name));
if (tag) {
strcpy(tag->tag, name);
tag->next = trace->tags;
if (wrap_json_unpack(object, "s", &name))
ctxt_error(&desc->context->errors, "unexpected %s value %s",
abstracting[type].name,
- json_object_to_json_string(object));
+ json_object_to_json_string_ext(object, JSON_C_TO_STRING_NOSLASHESCAPE));
else {
queried = (name[0] == '*' && !name[1]) ? "all" : name;
value = abstracting[type].get_flag(queried);
wrap_json_optarray_for_all(event, add_evt_flags, &desc);
if (session)
- wrap_json_optarray_for_all(event, add_session_flags, &desc);
+ wrap_json_optarray_for_all(session, add_session_flags, &desc);
if (global)
wrap_json_optarray_for_all(global, add_global_flags, &desc);
rc = wrap_json_unpack(object, "s", &name);
if (rc)
- ctxt_error(&context->errors, "unexpected tag value %s", json_object_to_json_string(object));
+ ctxt_error(&context->errors, "unexpected tag value %s", json_object_to_json_string_ext(object, JSON_C_TO_STRING_NOSLASHESCAPE));
else {
tag = trace_get_tag(context->trace, name, 0);
if (!tag)
rc = wrap_json_unpack(object, "s", &name);
if (rc)
- ctxt_error(&context->errors, "unexpected event value %s", json_object_to_json_string(object));
+ ctxt_error(&context->errors, "unexpected event value %s", json_object_to_json_string_ext(object, JSON_C_TO_STRING_NOSLASHESCAPE));
else {
event = trace_get_event(context->trace, name, 0);
if (!event)
rc = wrap_json_unpack(object, "s", &uuid);
if (rc)
- ctxt_error(&context->errors, "unexpected session value %s", json_object_to_json_string(object));
+ ctxt_error(&context->errors, "unexpected session value %s", json_object_to_json_string_ext(object, JSON_C_TO_STRING_NOSLASHESCAPE));
else {
session = trace_get_session_by_uuid(context->trace, uuid, 0);
if (!session)
}
/* drop traces */
-extern int afb_trace_drop(afb_req_t req, struct json_object *args, struct afb_trace *trace)
+int afb_trace_drop(afb_req_t req, struct json_object *args, struct afb_trace *trace)
{
int rc;
struct context context;
free(context.errors);
return -1;
}
+
+#endif