+static int hooked_api_add_verb_cb(
+ struct afb_api_x3 *api,
+ const char *verb,
+ const char *info,
+ void (*callback)(struct afb_req_x2 *req),
+ void *vcbdata,
+ const struct afb_auth *auth,
+ uint32_t session,
+ int glob)
+{
+ struct afb_export *export = from_api_x3(api);
+ int result = api_add_verb_cb(api, verb, info, callback, vcbdata, auth, session, glob);
+ return afb_hook_api_api_add_verb(export, result, verb, info, glob);
+}
+
+static int hooked_api_del_verb_cb(
+ struct afb_api_x3 *api,
+ const char *verb,
+ void **vcbdata)
+{
+ struct afb_export *export = from_api_x3(api);
+ int result = api_del_verb_cb(api, verb, vcbdata);
+ return afb_hook_api_api_del_verb(export, result, verb);
+}
+
+static int hooked_api_set_on_event_cb(
+ struct afb_api_x3 *api,
+ void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object))
+{
+ struct afb_export *export = from_api_x3(api);
+ int result = api_set_on_event_cb(api, onevent);
+ return afb_hook_api_api_set_on_event(export, result);
+}
+
+static int hooked_api_set_on_init_cb(
+ struct afb_api_x3 *api,
+ int (*oninit)(struct afb_api_x3 *api))
+{
+ struct afb_export *export = from_api_x3(api);
+ int result = api_set_on_init_cb(api, oninit);
+ return afb_hook_api_api_set_on_init(export, result);
+}
+
+static void hooked_api_seal_cb(
+ struct afb_api_x3 *api)
+{
+ struct afb_export *export = from_api_x3(api);
+ afb_hook_api_api_seal(export);
+ api_seal_cb(api);
+}
+
+static int hooked_event_handler_add_cb(
+ struct afb_api_x3 *api,
+ const char *pattern,
+ void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*),
+ void *closure)
+{
+ struct afb_export *export = from_api_x3(api);
+ int result = event_handler_add_cb(api, pattern, callback, closure);
+ return afb_hook_api_event_handler_add(export, result, pattern);
+}
+
+static int hooked_event_handler_del_cb(
+ struct afb_api_x3 *api,
+ const char *pattern,
+ void **closure)
+{
+ struct afb_export *export = from_api_x3(api);
+ int result = event_handler_del_cb(api, pattern, closure);
+ return afb_hook_api_event_handler_del(export, result, pattern);
+}
+
+static int hooked_class_provide_cb(struct afb_api_x3 *api, const char *name)
+{
+ struct afb_export *export = from_api_x3(api);
+ int result = class_provide_cb(api, name);
+ return afb_hook_api_class_provide(export, result, name);
+}
+
+static int hooked_class_require_cb(struct afb_api_x3 *api, const char *name)
+{
+ struct afb_export *export = from_api_x3(api);
+ int result = class_require_cb(api, name);
+ return afb_hook_api_class_require(export, result, name);
+}
+
+static int hooked_delete_api_cb(struct afb_api_x3 *api)
+{
+ struct afb_export *export = afb_export_addref(from_api_x3(api));
+ int result = delete_api_cb(api);
+ result = afb_hook_api_delete_api(export, result);
+ afb_export_unref(export);
+ return result;
+}
+
+static struct json_object *hooked_settings_cb(struct afb_api_x3 *api)
+{
+ struct afb_export *export = from_api_x3(api);
+ struct json_object *result = settings_cb(api);
+ result = afb_hook_api_settings(export, result);
+ return result;
+}
+
+static const struct afb_api_x3_itf hooked_api_x3_itf = {
+
+ .vverbose = hooked_vverbose_cb,
+
+ .get_event_loop = hooked_get_event_loop,
+ .get_user_bus = hooked_get_user_bus,
+ .get_system_bus = hooked_get_system_bus,
+ .rootdir_get_fd = hooked_rootdir_get_fd,
+ .rootdir_open_locale = hooked_rootdir_open_locale_cb,
+ .queue_job = hooked_queue_job_cb,
+
+ .require_api = hooked_require_api_cb,
+ .add_alias = hooked_add_alias_cb,
+
+ .event_broadcast = hooked_event_broadcast_cb,
+ .event_make = hooked_event_x2_make_cb,
+
+ .legacy_call = legacy_hooked_call_x3,
+ .legacy_call_sync = legacy_hooked_call_sync,
+
+ .api_new_api = hooked_api_new_api_cb,
+ .api_set_verbs_v2 = hooked_api_set_verbs_v2_cb,
+ .api_add_verb = hooked_api_add_verb_cb,
+ .api_del_verb = hooked_api_del_verb_cb,
+ .api_set_on_event = hooked_api_set_on_event_cb,
+ .api_set_on_init = hooked_api_set_on_init_cb,
+ .api_seal = hooked_api_seal_cb,
+ .api_set_verbs_v3 = hooked_api_set_verbs_v3_cb,
+ .event_handler_add = hooked_event_handler_add_cb,
+ .event_handler_del = hooked_event_handler_del_cb,
+
+ .call = hooked_call_x3,
+ .call_sync = hooked_call_sync_x3,
+
+ .class_provide = hooked_class_provide_cb,
+ .class_require = hooked_class_require_cb,
+
+ .delete_api = hooked_delete_api_cb,
+ .settings = hooked_settings_cb,
+};
+#endif
+
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ L I S T E N E R S
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
+
+/*
+ * Propagates the event to the service
+ */
+static void listener_of_events(void *closure, const char *event, uint16_t eventid, struct json_object *object)
+{
+ const struct globset_handler *handler;
+ void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*);
+ struct afb_export *export = from_api_x3(closure);
+
+#if WITH_AFB_HOOK
+ /* hook the event before */
+ if (export->hooksvc & afb_hook_flag_api_on_event)
+ afb_hook_api_on_event_before(export, event, eventid, object);
+#endif
+
+ /* transmit to specific handlers */
+ /* search the handler */
+ handler = export->event_handlers ? globset_match(export->event_handlers, event) : NULL;
+ if (handler) {
+ callback = handler->callback;
+#if WITH_AFB_HOOK
+ if (!(export->hooksvc & afb_hook_flag_api_on_event_handler))
+#endif
+ callback(handler->closure, event, object, to_api_x3(export));
+#if WITH_AFB_HOOK
+ else {
+ afb_hook_api_on_event_handler_before(export, event, eventid, object, handler->pattern);
+ callback(handler->closure, event, object, to_api_x3(export));
+ afb_hook_api_on_event_handler_after(export, event, eventid, object, handler->pattern);
+ }
+#endif
+ } else {
+ /* transmit to default handler */
+ if (export->on_any_event_v3)
+ export->on_any_event_v3(to_api_x3(export), event, object);
+ else if (export->on_any_event_v12)
+ export->on_any_event_v12(event, object);
+ }
+
+#if WITH_AFB_HOOK
+ /* hook the event after */
+ if (export->hooksvc & afb_hook_flag_api_on_event)
+ afb_hook_api_on_event_after(export, event, eventid, object);
+#endif
+ json_object_put(object);
+}
+
+static void listener_of_pushed_events(void *closure, const char *event, uint16_t eventid, struct json_object *object)
+{
+ listener_of_events(closure, event, eventid, object);
+}
+
+static void listener_of_broadcasted_events(void *closure, const char *event, struct json_object *object, const uuid_binary_t uuid, uint8_t hop)
+{
+ listener_of_events(closure, event, 0, object);
+}
+
+/* the interface for events */
+static const struct afb_evt_itf evt_itf = {
+ .broadcast = listener_of_broadcasted_events,
+ .push = listener_of_pushed_events
+};
+
+/* ensure an existing listener */
+static int ensure_listener(struct afb_export *export)
+{
+ if (!export->listener) {
+ export->listener = afb_evt_listener_create(&evt_itf, export);
+ if (export->listener == NULL)
+ return -1;
+ }
+ return 0;
+}
+
+int afb_export_event_handler_add(
+ struct afb_export *export,
+ const char *pattern,
+ void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*),
+ void *closure)
+{
+ int rc;
+
+ /* ensure the listener */
+ rc = ensure_listener(export);
+ if (rc < 0)
+ return rc;
+
+ /* ensure the globset for event handling */
+ if (!export->event_handlers) {
+ export->event_handlers = globset_create();
+ if (!export->event_handlers)
+ goto oom_error;
+ }
+
+ /* add the handler */
+ rc = globset_add(export->event_handlers, pattern, callback, closure);
+ if (rc == 0)
+ return 0;
+
+ if (errno == EEXIST) {
+ ERROR("[API %s] event handler %s already exists", export->api.apiname, pattern);
+ return -1;
+ }
+
+oom_error:
+ ERROR("[API %s] can't allocate event handler %s", export->api.apiname, pattern);
+ return -1;
+}
+
+int afb_export_event_handler_del(
+ struct afb_export *export,
+ const char *pattern,
+ void **closure)
+{
+ if (export->event_handlers
+ && !globset_del(export->event_handlers, pattern, closure))
+ return 0;
+
+ ERROR("[API %s] event handler %s not found", export->api.apiname, pattern);
+ errno = ENOENT;
+ return -1;
+}
+
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ M E R G E D
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
+
+static void set_interfaces(struct afb_export *export)
+{
+#if WITH_AFB_HOOK
+ export->hookditf = afb_hook_flags_api(export->api.apiname);
+ export->hooksvc = afb_hook_flags_api(export->api.apiname);
+ export->api.itf = export->hookditf|export->hooksvc ? &hooked_api_x3_itf : &api_x3_itf;
+
+ switch (export->version) {
+#if WITH_LEGACY_BINDING_V1
+ case Api_Version_1:
+ export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf;
+ break;
+#endif
+#if WITH_LEGACY_BINDING_V2
+ case Api_Version_2:
+ export->export.v2->daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf;
+ export->export.v2->service.itf = export->hooksvc ? &hooked_service_itf : &service_itf;
+ break;
+#endif
+ }
+#else
+
+ export->api.itf = &api_x3_itf;
+
+ switch (export->version) {
+#if WITH_LEGACY_BINDING_V1
+ case Api_Version_1:
+ export->export.v1.daemon.itf = &daemon_itf;
+ break;
+#endif
+#if WITH_LEGACY_BINDING_V2
+ case Api_Version_2:
+ export->export.v2->daemon.itf = &daemon_itf;
+ export->export.v2->service.itf = &service_itf;
+ break;
+#endif
+ }
+
+#endif
+}
+
+static struct afb_export *create(
+ struct afb_apiset *declare_set,
+ struct afb_apiset *call_set,
+ const char *apiname,
+ const char *path,
+ enum afb_api_version version)
+{
+ struct afb_export *export;
+ size_t lenapi;
+
+ /* session shared with other exports */