diff options
author | 2017-06-01 12:34:29 +0200 | |
---|---|---|
committer | 2017-06-01 12:34:29 +0200 | |
commit | b67e18b39830a01750721787bf3bdc5d71983144 (patch) | |
tree | 20104692fd55fcb27b3a20aae0b144bb64286150 /src | |
parent | 4dc768d67031aa99e2b885a0df7e643fdd1fa80c (diff) |
Add hooking for events
Change-Id: If5fe736e04c9f4298302c3cbba568f1d6346ee67
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
Diffstat (limited to 'src')
-rw-r--r-- | src/afb-config.c | 17 | ||||
-rw-r--r-- | src/afb-config.h | 1 | ||||
-rw-r--r-- | src/afb-evt.c | 75 | ||||
-rw-r--r-- | src/afb-evt.h | 1 | ||||
-rw-r--r-- | src/afb-hook.c | 309 | ||||
-rw-r--r-- | src/afb-hook.h | 57 | ||||
-rw-r--r-- | src/main.c | 2 |
7 files changed, 435 insertions, 27 deletions
diff --git a/src/afb-config.c b/src/afb-config.c index dc3388e4..98dd4e55 100644 --- a/src/afb-config.c +++ b/src/afb-config.c @@ -87,6 +87,7 @@ #define ADD_CALL 'c' #define SET_TRACEDITF 'D' +#define SET_TRACEEVT 'E' #define SET_EXEC 'e' #define DISPLAY_HELP 'h' #define SET_QUIET 'q' @@ -99,7 +100,7 @@ #define SET_VERBOSE 'v' #define SET_WORK_DIR 'w' -#define SHORTOPTS "c:D:ehqrT:t:u:Vvw:" +#define SHORTOPTS "c:D:E:ehqrT:t:u:Vvw:" // Command line structure hold cli --command + help text typedef struct { @@ -154,6 +155,8 @@ static AFB_options cliOptions[] = { {SET_TRACEREQ, 1, "tracereq", "Log the requests: no, common, extra, all"}, {SET_TRACEDITF, 1, "traceditf", "Log the requests: no, common, extra, all"}, {SET_TRACESVC, 1, "tracesvc", "Log the requests: no, all"}, + {SET_TRACEEVT, 1, "traceevt", "Log the requests: no, common, extra, all"}, + {ADD_CALL, 1, "call", "call at start format of val: API/VERB:json-args"}, {SET_NO_HTTPD, 0, "no-httpd", "Forbids HTTP service"}, @@ -192,6 +195,14 @@ static struct enumdesc tracesvc_desc[] = { { NULL, 0 } }; +static struct enumdesc traceevt_desc[] = { + { "no", 0 }, + { "common", afb_hook_flags_evt_common }, + { "extra", afb_hook_flags_evt_extra }, + { "all", afb_hook_flags_evt_all }, + { NULL, 0 } +}; + static struct enumdesc mode_desc[] = { { "local", AFB_MODE_LOCAL }, { "remote", AFB_MODE_REMOTE }, @@ -518,6 +529,10 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) config->tracesvc = argvalenum(optc, tracesvc_desc); break; + case SET_TRACEEVT: + config->traceevt = argvalenum(optc, traceevt_desc); + break; + case SET_NO_HTTPD: noarg(optc); config->noHttpd = 1; diff --git a/src/afb-config.h b/src/afb-config.h index acf1f38f..4ff5d141 100644 --- a/src/afb-config.h +++ b/src/afb-config.h @@ -57,6 +57,7 @@ struct afb_config { int tracereq; int traceditf; int tracesvc; + int traceevt; int noHttpd; }; diff --git a/src/afb-evt.c b/src/afb-evt.c index 7b7ce4f3..d80af045 100644 --- a/src/afb-evt.c +++ b/src/afb-evt.c @@ -28,6 +28,7 @@ #include <afb/afb-event-itf.h> #include "afb-evt.h" +#include "afb-hook.h" #include "verbose.h" struct afb_evt_watch; @@ -70,6 +71,9 @@ struct afb_evt_event { /* id of the event */ int id; + /* hooking */ + int hookflags; + /* mutex of the event */ pthread_mutex_t mutex; @@ -123,41 +127,56 @@ static int event_id_counter = 0; static int event_id_wrapped = 0; /* - * Broadcasts the event 'evt' with its 'object' - * 'object' is released (like json_object_put) - * Returns the count of listener that received the event. - */ -static int evt_broadcast(struct afb_evt_event *evt, struct json_object *object) -{ - return afb_evt_broadcast(evt->name, object); -} - -/* - * Broadcasts the 'event' with its 'object' - * 'object' is released (like json_object_put) + * Broadcasts the 'event' of 'id' with its 'obj' + * 'obj' is released (like json_object_put) + * calls hooks if hookflags isn't 0 * Returns the count of listener having receive the event. */ -int afb_evt_broadcast(const char *event, struct json_object *object) +static int broadcast(const char *event, struct json_object *obj, int id, int hookflags) { int result; struct afb_evt_listener *listener; + if (hookflags & afb_hook_flag_evt_broadcast_before) + afb_hook_evt_broadcast_before(event, id, obj); result = 0; pthread_mutex_lock(&listeners_mutex); listener = listeners; while(listener) { if (listener->itf->broadcast != NULL) { - listener->itf->broadcast(listener->closure, event, 0, json_object_get(object)); + listener->itf->broadcast(listener->closure, event, id, json_object_get(obj)); result++; } listener = listener->next; } pthread_mutex_unlock(&listeners_mutex); - json_object_put(object); + if (hookflags & afb_hook_flag_evt_broadcast_after) + afb_hook_evt_broadcast_after(event, id, obj, result); + json_object_put(obj); return result; } /* + * Broadcasts the event 'evt' with its 'object' + * 'object' is released (like json_object_put) + * Returns the count of listener that received the event. + */ +static int evt_broadcast(struct afb_evt_event *evt, struct json_object *object) +{ + return broadcast(evt->name, object, evt->id, evt->hookflags); +} + +/* + * Broadcasts the 'event' with its 'object' + * 'object' is released (like json_object_put) + * Returns the count of listener having receive the event. + */ +int afb_evt_broadcast(const char *event, struct json_object *object) +{ + return broadcast(event, object, 0, -1); +} + +/* * Pushes the event 'evt' with 'obj' to its listeners * 'obj' is released (like json_object_put) * Returns the count of listener taht received the event. @@ -170,6 +189,8 @@ static int evt_push(struct afb_evt_event *evt, struct json_object *obj) result = 0; pthread_mutex_lock(&evt->mutex); + if (evt->hookflags & afb_hook_flag_evt_push_before) + afb_hook_evt_push_before(evt->name, evt->id, obj); watch = evt->watchs; while(watch) { listener = watch->listener; @@ -180,6 +201,8 @@ static int evt_push(struct afb_evt_event *evt, struct json_object *obj) } watch = watch->next_by_event; } + if (evt->hookflags & afb_hook_flag_evt_push_after) + afb_hook_evt_push_after(evt->name, evt->id, obj, result); pthread_mutex_unlock(&evt->mutex); json_object_put(obj); return result; @@ -190,6 +213,8 @@ static int evt_push(struct afb_evt_event *evt, struct json_object *obj) */ static const char *evt_name(struct afb_evt_event *evt) { + if (evt->hookflags & afb_hook_flag_evt_name) + afb_hook_evt_name(evt->name, evt->id); return evt->name; } @@ -256,6 +281,10 @@ static void evt_destroy(struct afb_evt_event *evt) pthread_mutex_unlock(&listener->mutex); } + /* hook */ + if (evt->hookflags & afb_hook_flag_evt_drop) + afb_hook_evt_drop(evt->name, evt->id); + /* free */ pthread_mutex_destroy(&evt->mutex); free(evt); @@ -303,6 +332,9 @@ struct afb_event afb_evt_create_event(const char *name) evt->id = event_id_counter; pthread_mutex_init(&evt->mutex, NULL); events = evt; + evt->hookflags = afb_hook_flags_evt(evt->name); + if (evt->hookflags & afb_hook_flag_evt_create) + afb_hook_evt_create(evt->name, evt->id); pthread_mutex_unlock(&events_mutex); /* returns the event */ @@ -497,3 +529,16 @@ int afb_evt_remove_watch(struct afb_evt_listener *listener, struct afb_event eve return -1; } +/* + * update the hooks for events + */ +void afb_evt_update_hooks() +{ + struct afb_evt_event *evt; + + pthread_mutex_lock(&events_mutex); + for (evt = events ; evt ; evt = evt->next) + evt->hookflags = afb_hook_flags_evt(evt->name); + pthread_mutex_unlock(&events_mutex); +} + diff --git a/src/afb-evt.h b/src/afb-evt.h index 5b96b93e..2c8da613 100644 --- a/src/afb-evt.h +++ b/src/afb-evt.h @@ -44,3 +44,4 @@ extern int afb_evt_event_id(struct afb_event event); extern int afb_evt_add_watch(struct afb_evt_listener *listener, struct afb_event event); extern int afb_evt_remove_watch(struct afb_evt_listener *listener, struct afb_event event); +extern void afb_evt_update_hooks(); diff --git a/src/afb-hook.c b/src/afb-hook.c index 6afcd2fb..aa66b5de 100644 --- a/src/afb-hook.c +++ b/src/afb-hook.c @@ -23,6 +23,7 @@ #include <string.h> #include <pthread.h> #include <unistd.h> +#include <fnmatch.h> #include <json-c/json.h> @@ -36,6 +37,7 @@ #include "afb-xreq.h" #include "afb-ditf.h" #include "afb-svc.h" +#include "afb-evt.h" #include "verbose.h" /** @@ -182,12 +184,12 @@ static void hook_xreq_session_set_LOA_default_cb(void * closure, const struct af static void hook_xreq_subscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result) { - _hook_xreq_(xreq, "subscribe(%s:%p) -> %d", afb_event_name(event), event.closure, result); + _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_event_name(event), afb_evt_event_id(event), result); } static void hook_xreq_unsubscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result) { - _hook_xreq_(xreq, "unsubscribe(%s:%p) -> %d", afb_event_name(event), event.closure, result); + _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_event_name(event), afb_evt_event_id(event), result); } static void hook_xreq_subcall_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) @@ -553,7 +555,7 @@ static void hook_ditf_vverbose_cb(void*closure, const struct afb_ditf *ditf, int static void hook_ditf_event_make_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct afb_event result) { - _hook_ditf_(ditf, "event_make(%s) -> %s:%p", name, afb_event_name(result), result.closure); + _hook_ditf_(ditf, "event_make(%s) -> %s:%d", name, afb_evt_event_name(result), afb_evt_event_id(result)); } static void hook_ditf_rootdir_get_fd_cb(void *closure, const struct afb_ditf *ditf, int result) @@ -981,3 +983,304 @@ void afb_hook_unref_svc(struct afb_hook_svc *hook) } } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/********************************************************* +* section hooking evt (event interface) +*********************************************************/ + +/** + * Definition of a hook for evt + */ +struct afb_hook_evt { + struct afb_hook_evt *next; /**< next hook */ + unsigned refcount; /**< reference count */ + char *pattern; /**< event pattern name hooked or NULL for any */ + unsigned flags; /**< hook flags */ + struct afb_hook_evt_itf *itf; /**< interface of hook */ + void *closure; /**< closure for callbacks */ +}; + +/* list of hooks for evt */ +static struct afb_hook_evt *list_of_evt_hooks = NULL; + + +/****************************************************************************** + * section: default callbacks for tracing service interface (evt) + *****************************************************************************/ + +static void _hook_evt_(const char *evt, int id, 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("hook evt-%s:%d allocation error for %s", evt, id, format); + else { + NOTICE("hook evt-%s:%d %s", evt, id, buffer); + free(buffer); + } +} + +static void hook_evt_create_default_cb(void *closure, const char *evt, int id) +{ + _hook_evt_(evt, id, "create"); +} + +static void hook_evt_push_before_default_cb(void *closure, const char *evt, int id, struct json_object *obj) +{ + _hook_evt_(evt, id, "push.before(%s)", json_object_to_json_string(obj)); +} + + +static void hook_evt_push_after_default_cb(void *closure, const char *evt, int id, struct json_object *obj, int result) +{ + _hook_evt_(evt, id, "push.after(%s) -> %d", json_object_to_json_string(obj), result); +} + +static void hook_evt_broadcast_before_default_cb(void *closure, const char *evt, int id, struct json_object *obj) +{ + _hook_evt_(evt, id, "broadcast.before(%s)", json_object_to_json_string(obj)); +} + +static void hook_evt_broadcast_after_default_cb(void *closure, const char *evt, int id, struct json_object *obj, int result) +{ + _hook_evt_(evt, id, "broadcast.after(%s) -> %d", json_object_to_json_string(obj), result); +} + +static void hook_evt_name_default_cb(void *closure, const char *evt, int id) +{ + _hook_evt_(evt, id, "name"); +} + +static void hook_evt_drop_default_cb(void *closure, const char *evt, int id) +{ + _hook_evt_(evt, id, "drop"); +} + +static struct afb_hook_evt_itf hook_evt_default_itf = { + .hook_evt_create = hook_evt_create_default_cb, + .hook_evt_push_before = hook_evt_push_before_default_cb, + .hook_evt_push_after = hook_evt_push_after_default_cb, + .hook_evt_broadcast_before = hook_evt_broadcast_before_default_cb, + .hook_evt_broadcast_after = hook_evt_broadcast_after_default_cb, + .hook_evt_name = hook_evt_name_default_cb, + .hook_evt_drop = hook_evt_drop_default_cb +}; + +/****************************************************************************** + * section: hooks for tracing service interface (evt) + *****************************************************************************/ + +#define _HOOK_EVT_(what,...) \ + struct afb_hook_evt *hook; \ + pthread_rwlock_rdlock(&rwlock); \ + hook = list_of_evt_hooks; \ + while (hook) { \ + if (hook->itf->hook_evt_##what \ + && (hook->flags & afb_hook_flag_evt_##what) != 0 \ + && (!hook->pattern || !fnmatch(hook->pattern, evt, FNM_CASEFOLD))) { \ + hook->itf->hook_evt_##what(hook->closure, __VA_ARGS__); \ + } \ + hook = hook->next; \ + } \ + pthread_rwlock_unlock(&rwlock); + +void afb_hook_evt_create(const char *evt, int id) +{ + _HOOK_EVT_(create, evt, id); +} + +void afb_hook_evt_push_before(const char *evt, int id, struct json_object *obj) +{ + _HOOK_EVT_(push_before, evt, id, obj); +} + +int afb_hook_evt_push_after(const char *evt, int id, struct json_object *obj, int result) +{ + _HOOK_EVT_(push_after, evt, id, obj, result); + return result; +} + +void afb_hook_evt_broadcast_before(const char *evt, int id, struct json_object *obj) +{ + _HOOK_EVT_(broadcast_before, evt, id, obj); +} + +int afb_hook_evt_broadcast_after(const char *evt, int id, struct json_object *obj, int result) +{ + _HOOK_EVT_(broadcast_after, evt, id, obj, result); + return result; +} + +void afb_hook_evt_name(const char *evt, int id) +{ + _HOOK_EVT_(name, evt, id); +} + +void afb_hook_evt_drop(const char *evt, int id) +{ + _HOOK_EVT_(drop, evt, id); +} + +/****************************************************************************** + * section: hooking services (evt) + *****************************************************************************/ + +int afb_hook_flags_evt(const char *name) +{ + int flags; + struct afb_hook_evt *hook; + + pthread_rwlock_rdlock(&rwlock); + flags = 0; + hook = list_of_evt_hooks; + while (hook) { + if (!name || !hook->pattern || !fnmatch(hook->pattern, name, FNM_CASEFOLD)) + flags |= hook->flags; + hook = hook->next; + } + pthread_rwlock_unlock(&rwlock); + return flags; +} + +struct afb_hook_evt *afb_hook_create_evt(const char *pattern, int flags, struct afb_hook_evt_itf *itf, void *closure) +{ + struct afb_hook_evt *hook; + + /* alloc the result */ + hook = calloc(1, sizeof *hook); + if (hook == NULL) + return NULL; + + /* get a copy of the names */ + hook->pattern = pattern ? strdup(pattern) : NULL; + if (pattern && !hook->pattern) { + free(hook); + return NULL; + } + + /* initialise the rest */ + hook->refcount = 1; + hook->flags = flags; + hook->itf = itf ? itf : &hook_evt_default_itf; + hook->closure = closure; + + /* record the hook */ + pthread_rwlock_wrlock(&rwlock); + hook->next = list_of_evt_hooks; + list_of_evt_hooks = hook; + pthread_rwlock_unlock(&rwlock); + + /* returns it */ + return hook; +} + +struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook) +{ + pthread_rwlock_wrlock(&rwlock); + hook->refcount++; + pthread_rwlock_unlock(&rwlock); + return hook; +} + +void afb_hook_unref_evt(struct afb_hook_evt *hook) +{ + struct afb_hook_evt **prv; + + if (hook) { + pthread_rwlock_wrlock(&rwlock); + if (--hook->refcount) + hook = NULL; + else { + /* unlink */ + prv = &list_of_evt_hooks; + while (*prv && *prv != hook) + prv = &(*prv)->next; + if(*prv) + *prv = hook->next; + } + pthread_rwlock_unlock(&rwlock); + if (hook) { + /* free */ + free(hook->pattern); + free(hook); + } + } +} + +#if 0 +#define afb_hook_flag_evt_create 0x000001 +#define afb_hook_flag_evt_push_before 0x000002 +#define afb_hook_flag_evt_push_after 0x000004 +#define afb_hook_flag_evt_broadcast_before 0x000008 +#define afb_hook_flag_evt_broadcast_after 0x000010 +#define afb_hook_flag_evt_drop 0x000020 +#define afb_hook_flag_evt_name 0x000040 + +struct afb_hook_evt_itf { + void (*hook_evt_create)(void *closure, const char *evt); + void (*hook_evt_push_before)(void *closure, const char *evt); + void (*hook_evt_push_after)(void *closure, const char *evt, int result); + void (*hook_evt_broadcast_before)(void *closure, const char *evt); + void (*hook_evt_broadcast_after)(void *closure, const char *evt, int result); + void (*hook_evt_drop)(void *closure, const char *evt); + void (*hook_evt_name)(void *closure, const char *evt); +}; + +extern void afb_hook_evt_create(const char *evt); +extern void afb_hook_evt_push_before(const char *evt); +extern int afb_hook_evt_push_after(const char *evt, int result); +extern void afb_hook_evt_broadcast_before(const char *evt); +extern int afb_hook_evt_broadcast_after(const char *evt, int result); +extern void afb_hook_evt_drop(const char *evt); +extern void afb_hook_evt_name(const char *evt); + +extern int afb_hook_flags_evt(const char *name); +extern struct afb_hook_evt *afb_hook_create_evt(const char *name, int flags, struct afb_hook_evt_itf *itf, void *closure); +extern struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook); +extern void afb_hook_unref_evt(struct afb_hook_evt *hook); +#endif diff --git a/src/afb-hook.h b/src/afb-hook.h index c1ff8476..91736386 100644 --- a/src/afb-hook.h +++ b/src/afb-hook.h @@ -187,14 +187,14 @@ extern void afb_hook_unref_ditf(struct afb_hook_ditf *hook); * section hooking svc (service interface) *********************************************************/ -#define afb_hook_flag_svc_start_before 0x000001 -#define afb_hook_flag_svc_start_after 0x000002 -#define afb_hook_flag_svc_on_event_before 0x000004 -#define afb_hook_flag_svc_on_event_after 0x000008 -#define afb_hook_flag_svc_call 0x000010 -#define afb_hook_flag_svc_call_result 0x000020 -#define afb_hook_flag_svc_callsync 0x000040 -#define afb_hook_flag_svc_callsync_result 0x000080 +#define afb_hook_flag_svc_start_before 0x000001 +#define afb_hook_flag_svc_start_after 0x000002 +#define afb_hook_flag_svc_on_event_before 0x000004 +#define afb_hook_flag_svc_on_event_after 0x000008 +#define afb_hook_flag_svc_call 0x000010 +#define afb_hook_flag_svc_call_result 0x000020 +#define afb_hook_flag_svc_callsync 0x000040 +#define afb_hook_flag_svc_callsync_result 0x000080 #define afb_hook_flags_svc_all (afb_hook_flag_svc_start_before|afb_hook_flag_svc_start_after\ |afb_hook_flag_svc_on_event_before|afb_hook_flag_svc_on_event_after\ @@ -226,3 +226,44 @@ extern struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, stru extern struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook); extern void afb_hook_unref_svc(struct afb_hook_svc *hook); +/********************************************************* +* section hooking evt (event interface) +*********************************************************/ + +#define afb_hook_flag_evt_create 0x000001 +#define afb_hook_flag_evt_push_before 0x000002 +#define afb_hook_flag_evt_push_after 0x000004 +#define afb_hook_flag_evt_broadcast_before 0x000008 +#define afb_hook_flag_evt_broadcast_after 0x000010 +#define afb_hook_flag_evt_name 0x000020 +#define afb_hook_flag_evt_drop 0x000040 + +#define afb_hook_flags_evt_common (afb_hook_flag_evt_push_before|afb_hook_flag_evt_broadcast_before) +#define afb_hook_flags_evt_extra (afb_hook_flags_evt_common\ + |afb_hook_flag_evt_push_after|afb_hook_flag_evt_broadcast_after\ + |afb_hook_flag_evt_create|afb_hook_flag_evt_drop) +#define afb_hook_flags_evt_all (afb_hook_flags_evt_extra|afb_hook_flag_evt_name) + +struct afb_hook_evt_itf { + void (*hook_evt_create)(void *closure, const char *evt, int id); + void (*hook_evt_push_before)(void *closure, const char *evt, int id, struct json_object *obj); + void (*hook_evt_push_after)(void *closure, const char *evt, int id, struct json_object *obj, int result); + void (*hook_evt_broadcast_before)(void *closure, const char *evt, int id, struct json_object *obj); + void (*hook_evt_broadcast_after)(void *closure, const char *evt, int id, struct json_object *obj, int result); + void (*hook_evt_name)(void *closure, const char *evt, int id); + void (*hook_evt_drop)(void *closure, const char *evt, int id); +}; + +extern void afb_hook_evt_create(const char *evt, int id); +extern void afb_hook_evt_push_before(const char *evt, int id, struct json_object *obj); +extern int afb_hook_evt_push_after(const char *evt, int id, struct json_object *obj, int result); +extern void afb_hook_evt_broadcast_before(const char *evt, int id, struct json_object *obj); +extern int afb_hook_evt_broadcast_after(const char *evt, int id, struct json_object *obj, int result); +extern void afb_hook_evt_name(const char *evt, int id); +extern void afb_hook_evt_drop(const char *evt, int id); + +extern int afb_hook_flags_evt(const char *name); +extern struct afb_hook_evt *afb_hook_create_evt(const char *name, int flags, struct afb_hook_evt_itf *itf, void *closure); +extern struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook); +extern void afb_hook_unref_evt(struct afb_hook_evt *hook); + @@ -573,6 +573,8 @@ static void start() afb_hook_create_ditf(NULL, config->traceditf, NULL, NULL); if (config->tracesvc) afb_hook_create_svc(NULL, config->tracesvc, NULL, NULL); + if (config->traceevt) + afb_hook_create_evt(NULL, config->traceevt, NULL, NULL); /* load bindings */ apiset_start_list(config->dbus_clients, afb_api_dbus_add_client, "the afb-dbus client"); |