X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-export.c;h=800ee77bdf9ee1adadddb5776acd6faa655c233e;hb=65353dce81a629e042800bb7b86fcd869a76727e;hp=811ecb5eacdf245ea4ffb85fcf463c33ba75b865;hpb=77ca8b40f2d0c8b1cbf9960bd5a5b2aec36fef38;p=src%2Fapp-framework-binder.git diff --git a/src/afb-export.c b/src/afb-export.c index 811ecb5e..800ee77b 100644 --- a/src/afb-export.c +++ b/src/afb-export.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Copyright (C) 2015-2020 "IoT.bzh" * Author: José Bollo * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,14 +33,14 @@ #include "afb-api.h" #include "afb-apiset.h" -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 #include "afb-api-so-v1.h" #endif +#if WITH_LEGACY_BINDING_V2 #include "afb-api-so-v2.h" +#endif #include "afb-api-v3.h" #include "afb-common.h" -#include "afb-systemd.h" -#include "afb-cred.h" #include "afb-evt.h" #include "afb-export.h" #include "afb-hook.h" @@ -48,42 +48,31 @@ #include "afb-session.h" #include "afb-xreq.h" #include "afb-calls.h" +#include "afb-error-text.h" + +#include "systemd.h" #include "jobs.h" #include "verbose.h" +#include "globset.h" #include "sig-monitor.h" +#include "wrap-json.h" /************************************************************************* * internal types ************************************************************************/ -/* - * structure for handling events - */ -struct event_handler -{ - /* link to the next event handler of the list */ - struct event_handler *next; - - /* function to call on the case of the event */ - void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*); - - /* closure for the callback */ - void *closure; - - /* the handled pattern */ - char pattern[1]; -}; - /* * Actually supported versions */ enum afb_api_version { Api_Version_None = 0, -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 Api_Version_1 = 1, #endif +#if WITH_LEGACY_BINDING_V2 Api_Version_2 = 2, +#endif Api_Version_3 = 3 }; @@ -120,9 +109,11 @@ struct afb_export /* unsealed */ unsigned unsealed: 1; +#if WITH_AFB_HOOK /* hooking flags */ int hookditf; int hooksvc; +#endif /* session for service */ struct afb_session *session; @@ -137,11 +128,20 @@ struct afb_export struct afb_evt_listener *listener; /* event handler list */ - struct event_handler *event_handlers; + struct globset *event_handlers; + + /* creator if any */ + struct afb_export *creator; + + /* path indication if any */ + const char *path; + + /* settings */ + struct json_object *settings; /* internal descriptors */ union { -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 struct afb_binding_v1 *v1; #endif const struct afb_binding_v2 *v2; @@ -150,7 +150,7 @@ struct afb_export /* start function */ union { -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 int (*v1)(struct afb_service_x1); #endif int (*v2)(); @@ -163,14 +163,14 @@ struct afb_export /* exported data */ union { -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 struct afb_binding_interface_v1 v1; #endif struct afb_binding_data_v2 *v2; } export; /* initial name */ - char name[1]; + char name[]; }; /*****************************************************************************/ @@ -195,6 +195,54 @@ struct afb_api_x3 *afb_export_to_api_x3(struct afb_export *export) return to_api_x3(export); } +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + SETTINGS + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ + +static struct json_object *configuration; + +void afb_export_set_config(struct json_object *config) +{ + struct json_object *save = configuration; + configuration = json_object_get(config); + json_object_put(save); +} + +static struct json_object *make_settings(struct afb_export *export) +{ + struct json_object *result; + struct json_object *obj; + struct afb_export *iter; + char *path; + + /* clone the globals */ + if (json_object_object_get_ex(configuration, "*", &obj)) + result = wrap_json_clone(obj); + else + result = json_object_new_object(); + + /* add locals */ + if (json_object_object_get_ex(configuration, export->name, &obj)) + wrap_json_object_add(result, obj); + + /* add library path */ + for (iter = export ; iter && !iter->path ; iter = iter->creator); + if (iter) { + path = realpath(iter->path, NULL); + json_object_object_add(result, "binding-path", json_object_new_string(path)); + free(path); + } + + export->settings = result; + return result; +} + /****************************************************************************** ****************************************************************************** ****************************************************************************** @@ -216,16 +264,11 @@ static void vverbose_cb(struct afb_api_x3 *closure, int level, const char *file, if (!fmt || vasprintf(&p, fmt, args) < 0) vverbose(level, file, line, function, fmt, args); else { - verbose(level, file, line, function, "[API %s] %s", export->api.apiname, p); + verbose(level, file, line, function, (verbose_is_colorized() == 0 ? "[API %s] %s" : COLOR_API "[API %s]" COLOR_DEFAULT " %s"), export->api.apiname, p); free(p); } } -static void legacy_vverbose_v1_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *fmt, va_list args) -{ - vverbose_cb(closure, level, file, line, NULL, fmt, args); -} - static struct afb_event_x2 *event_x2_make_cb(struct afb_api_x3 *closure, const char *name) { struct afb_export *export = from_api_x3(closure); @@ -241,12 +284,6 @@ static struct afb_event_x2 *event_x2_make_cb(struct afb_api_x3 *closure, const c return afb_evt_event_x2_create2(export->api.apiname, name); } -static struct afb_event_x1 legacy_event_x1_make_cb(struct afb_api_x3 *closure, const char *name) -{ - struct afb_event_x2 *event = event_x2_make_cb(closure, name); - return afb_evt_event_from_evtid(afb_evt_event_x2_to_evtid(event)); -} - static int event_broadcast_cb(struct afb_api_x3 *closure, const char *name, struct json_object *object) { size_t plen, nlen; @@ -273,6 +310,24 @@ static int event_broadcast_cb(struct afb_api_x3 *closure, const char *name, stru return afb_evt_broadcast(event, object); } +static struct sd_event *get_event_loop(struct afb_api_x3 *closure) +{ + jobs_acquire_event_manager(); + return systemd_get_event_loop(); +} + +static struct sd_bus *get_user_bus(struct afb_api_x3 *closure) +{ + jobs_acquire_event_manager(); + return systemd_get_user_bus(); +} + +static struct sd_bus *get_system_bus(struct afb_api_x3 *closure) +{ + jobs_acquire_event_manager(); + return systemd_get_system_bus(); +} + static int rootdir_open_locale_cb(struct afb_api_x3 *closure, const char *filename, int flags, const char *locale) { return afb_common_rootdir_open_locale(filename, flags, locale); @@ -283,17 +338,19 @@ static int queue_job_cb(struct afb_api_x3 *closure, void (*callback)(int signum, return jobs_queue(group, timeout, callback, argument); } -static struct afb_req_x1 legacy_unstore_req_cb(struct afb_api_x3 *closure, struct afb_stored_req *sreq) -{ - return afb_xreq_unstore(sreq); -} - static int require_api_cb(struct afb_api_x3 *closure, const char *name, int initialized) { struct afb_export *export = from_api_x3(closure); int rc, rc2; char *iter, *end, save; + /* emit a warning about unexpected require in preinit */ + if (export->state == Api_State_Pre_Init && initialized) { + ERROR("[API %s] requiring initialized apis in pre-init is forbiden", export->api.apiname); + errno = EINVAL; + return -1; + } + /* scan the names in a local copy */ rc = 0; iter = strdupa(name); @@ -312,10 +369,20 @@ static int require_api_cb(struct afb_api_x3 *closure, const char *name, int init *end = 0; /* check the required api */ - if (export->state == Api_State_Pre_Init) - rc2 = afb_apiset_require(export->declare_set, export->api.apiname, name); - else + if (export->state == Api_State_Pre_Init) { + rc2 = afb_apiset_require(export->declare_set, export->api.apiname, iter); + if (rc2 < 0) { + if (rc == 0) + WARNING("[API %s] requiring apis pre-init may lead to unexpected result", export->api.apiname); + ERROR("[API %s] requiring api %s in pre-init failed", export->api.apiname, iter); + } + } else { rc2 = -!((initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->call_set, iter, 1)); + if (rc2 < 0) { + ERROR("[API %s] requiring api %s%s failed", export->api.apiname, + iter, initialized ? " initialized" : ""); + } + } if (rc2 < 0) rc = rc2; @@ -346,13 +413,51 @@ static struct afb_api_x3 *api_new_api_cb( void *preinit_closure) { struct afb_export *export = from_api_x3(closure); - struct afb_api_v3 *apiv3 = afb_api_v3_create(export->declare_set, export->call_set, api, info, noconcurrency, preinit, preinit_closure, 1); + struct afb_api_v3 *apiv3 = afb_api_v3_create( + export->declare_set, export->call_set, + api, info, noconcurrency, + preinit, preinit_closure, 1, + export, NULL); return apiv3 ? to_api_x3(afb_api_v3_export(apiv3)) : NULL; } -/********************************************** -* hooked flow -**********************************************/ +#if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2 + +static void legacy_vverbose_v1_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *fmt, va_list args) +{ + vverbose_cb(closure, level, file, line, NULL, fmt, args); +} + +static struct afb_event_x1 legacy_event_x1_make_cb(struct afb_api_x3 *closure, const char *name) +{ + struct afb_event_x2 *event = event_x2_make_cb(closure, name); + return afb_evt_event_from_evtid(afb_evt_event_x2_to_evtid(event)); +} + +static struct afb_req_x1 legacy_unstore_req_cb(struct afb_api_x3 *closure, struct afb_stored_req *sreq) +{ + return afb_xreq_unstore(sreq); +} + +static const struct afb_daemon_itf_x1 daemon_itf = { + .vverbose_v1 = legacy_vverbose_v1_cb, + .vverbose_v2 = vverbose_cb, + .event_make = legacy_event_x1_make_cb, + .event_broadcast = event_broadcast_cb, + .get_event_loop = get_event_loop, + .get_user_bus = get_user_bus, + .get_system_bus = get_system_bus, + .rootdir_get_fd = afb_common_rootdir_get_fd, + .rootdir_open_locale = rootdir_open_locale_cb, + .queue_job = queue_job_cb, + .unstore_req = legacy_unstore_req_cb, + .require_api = require_api_cb, + .add_alias = add_alias_cb, + .new_api = api_new_api_cb, +}; +#endif + +#if WITH_AFB_HOOK static void hooked_vverbose_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { struct afb_export *export = from_api_x3(closure); @@ -363,11 +468,6 @@ static void hooked_vverbose_cb(struct afb_api_x3 *closure, int level, const char va_end(ap); } -static void legacy_hooked_vverbose_v1_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *fmt, va_list args) -{ - hooked_vverbose_cb(closure, level, file, line, NULL, fmt, args); -} - static struct afb_event_x2 *hooked_event_x2_make_cb(struct afb_api_x3 *closure, const char *name) { struct afb_export *export = from_api_x3(closure); @@ -376,15 +476,6 @@ static struct afb_event_x2 *hooked_event_x2_make_cb(struct afb_api_x3 *closure, return r; } -static struct afb_event_x1 legacy_hooked_event_x1_make_cb(struct afb_api_x3 *closure, const char *name) -{ - struct afb_event_x2 *event = hooked_event_x2_make_cb(closure, name); - struct afb_event_x1 e; - e.closure = event; - e.itf = event ? event->itf : NULL; - return e; -} - static int hooked_event_broadcast_cb(struct afb_api_x3 *closure, const char *name, struct json_object *object) { int r; @@ -400,21 +491,30 @@ static int hooked_event_broadcast_cb(struct afb_api_x3 *closure, const char *nam static struct sd_event *hooked_get_event_loop(struct afb_api_x3 *closure) { struct afb_export *export = from_api_x3(closure); - struct sd_event *r = afb_systemd_get_event_loop(); + struct sd_event *r; + + jobs_acquire_event_manager(); + r = get_event_loop(closure); return afb_hook_api_get_event_loop(export, r); } static struct sd_bus *hooked_get_user_bus(struct afb_api_x3 *closure) { struct afb_export *export = from_api_x3(closure); - struct sd_bus *r = afb_systemd_get_user_bus(); + struct sd_bus *r; + + jobs_acquire_event_manager(); + r = get_user_bus(closure); return afb_hook_api_get_user_bus(export, r); } static struct sd_bus *hooked_get_system_bus(struct afb_api_x3 *closure) { struct afb_export *export = from_api_x3(closure); - struct sd_bus *r = afb_systemd_get_system_bus(); + struct sd_bus *r; + + jobs_acquire_event_manager(); + r = get_system_bus(closure); return afb_hook_api_get_system_bus(export, r); } @@ -439,13 +539,6 @@ static int hooked_queue_job_cb(struct afb_api_x3 *closure, void (*callback)(int return afb_hook_api_queue_job(export, callback, argument, group, timeout, r); } -static struct afb_req_x1 legacy_hooked_unstore_req_cb(struct afb_api_x3 *closure, struct afb_stored_req *sreq) -{ - struct afb_export *export = from_api_x3(closure); - afb_hook_api_legacy_unstore_req(export, sreq); - return legacy_unstore_req_cb(closure, sreq); -} - static int hooked_require_api_cb(struct afb_api_x3 *closure, const char *name, int initialized) { int result; @@ -478,25 +571,28 @@ static struct afb_api_x3 *hooked_api_new_api_cb( return result; } -/********************************************** -* vectors -**********************************************/ -static const struct afb_daemon_itf_x1 daemon_itf = { - .vverbose_v1 = legacy_vverbose_v1_cb, - .vverbose_v2 = vverbose_cb, - .event_make = legacy_event_x1_make_cb, - .event_broadcast = event_broadcast_cb, - .get_event_loop = afb_systemd_get_event_loop, - .get_user_bus = afb_systemd_get_user_bus, - .get_system_bus = afb_systemd_get_system_bus, - .rootdir_get_fd = afb_common_rootdir_get_fd, - .rootdir_open_locale = rootdir_open_locale_cb, - .queue_job = queue_job_cb, - .unstore_req = legacy_unstore_req_cb, - .require_api = require_api_cb, - .add_alias = add_alias_cb, - .new_api = api_new_api_cb, -}; +#if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2 + +static void legacy_hooked_vverbose_v1_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *fmt, va_list args) +{ + hooked_vverbose_cb(closure, level, file, line, NULL, fmt, args); +} + +static struct afb_event_x1 legacy_hooked_event_x1_make_cb(struct afb_api_x3 *closure, const char *name) +{ + struct afb_event_x2 *event = hooked_event_x2_make_cb(closure, name); + struct afb_event_x1 e; + e.closure = event; + e.itf = event ? event->itf : NULL; + return e; +} + +static struct afb_req_x1 legacy_hooked_unstore_req_cb(struct afb_api_x3 *closure, struct afb_stored_req *sreq) +{ + struct afb_export *export = from_api_x3(closure); + afb_hook_api_legacy_unstore_req(export, sreq); + return legacy_unstore_req_cb(closure, sreq); +} static const struct afb_daemon_itf_x1 hooked_daemon_itf = { .vverbose_v1 = legacy_hooked_vverbose_v1_cb, @@ -514,6 +610,9 @@ static const struct afb_daemon_itf_x1 hooked_daemon_itf = { .add_alias = hooked_add_alias_cb, .new_api = hooked_api_new_api_cb, }; +#endif + +#endif /****************************************************************************** ****************************************************************************** @@ -563,41 +662,51 @@ static int call_sync_x3( return afb_calls_call_sync(export, api, verb, args, object, error, info); } -static void legacy_call_v12( +static void legacy_call_x3( struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*), + void (*callback)(void*, int, struct json_object*, struct afb_api_x3*), void *closure) { struct afb_export *export = from_api_x3(apix3); - afb_calls_legacy_call_v12(export, api, verb, args, callback, closure); + afb_calls_legacy_call_v3(export, api, verb, args, callback, closure); } -static void legacy_call_x3( +static int legacy_call_sync( struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_api_x3*), - void *closure) + struct json_object **result) { struct afb_export *export = from_api_x3(apix3); - afb_calls_legacy_call_v3(export, api, verb, args, callback, closure); + return afb_calls_legacy_call_sync(export, api, verb, args, result); } -static int legacy_call_sync( +#if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2 + +static void legacy_call_v12( struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - struct json_object **result) + void (*callback)(void*, int, struct json_object*), + void *closure) { struct afb_export *export = from_api_x3(apix3); - return afb_calls_legacy_call_sync(export, api, verb, args, result); + afb_calls_legacy_call_v12(export, api, verb, args, callback, closure); } +/* the interface for services */ +static const struct afb_service_itf_x1 service_itf = { + .call = legacy_call_v12, + .call_sync = legacy_call_sync +}; +#endif + +#if WITH_AFB_HOOK static void hooked_call_x3( struct afb_api_x3 *apix3, const char *api, @@ -623,52 +732,51 @@ static int hooked_call_sync_x3( return afb_calls_hooked_call_sync(export, api, verb, args, object, error, info); } -static void legacy_hooked_call_v12( +static void legacy_hooked_call_x3( struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*), + void (*callback)(void*, int, struct json_object*, struct afb_api_x3*), void *closure) { struct afb_export *export = from_api_x3(apix3); - afb_calls_legacy_hooked_call_v12(export, api, verb, args, callback, closure); + afb_calls_legacy_hooked_call_v3(export, api, verb, args, callback, closure); } -static void legacy_hooked_call_x3( +static int legacy_hooked_call_sync( struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_api_x3*), - void *closure) + struct json_object **result) { struct afb_export *export = from_api_x3(apix3); - afb_calls_legacy_hooked_call_v3(export, api, verb, args, callback, closure); + return afb_calls_legacy_hooked_call_sync(export, api, verb, args, result); } -static int legacy_hooked_call_sync( +#if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2 + +static void legacy_hooked_call_v12( struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - struct json_object **result) + void (*callback)(void*, int, struct json_object*), + void *closure) { struct afb_export *export = from_api_x3(apix3); - return afb_calls_legacy_hooked_call_sync(export, api, verb, args, result); + afb_calls_legacy_hooked_call_v12(export, api, verb, args, callback, closure); } -/* the interface for services */ -static const struct afb_service_itf_x1 service_itf = { - .call = legacy_call_v12, - .call_sync = legacy_call_sync -}; - /* the interface for services */ static const struct afb_service_itf_x1 hooked_service_itf = { .call = legacy_hooked_call_v12, .call_sync = legacy_hooked_call_sync }; +#endif + +#endif /****************************************************************************** ****************************************************************************** @@ -684,6 +792,7 @@ static int api_set_verbs_v2_cb( struct afb_api_x3 *api, const struct afb_verb_v2 *verbs) { +#if WITH_LEGACY_BINDING_V2 struct afb_export *export = from_api_x3(api); if (export->unsealed) { @@ -692,6 +801,9 @@ static int api_set_verbs_v2_cb( } errno = EPERM; +#else + errno = ECANCELED; +#endif return -1; } @@ -867,6 +979,57 @@ static int delete_api_cb(struct afb_api_x3 *api) return 0; } +static struct json_object *settings_cb(struct afb_api_x3 *api) +{ + struct afb_export *export = from_api_x3(api); + struct json_object *result = export->settings; + if (!result) + result = make_settings(export); + return result; +} + +static const struct afb_api_x3_itf api_x3_itf = { + + .vverbose = (void*)vverbose_cb, + + .get_event_loop = get_event_loop, + .get_user_bus = get_user_bus, + .get_system_bus = get_system_bus, + .rootdir_get_fd = afb_common_rootdir_get_fd, + .rootdir_open_locale = rootdir_open_locale_cb, + .queue_job = queue_job_cb, + + .require_api = require_api_cb, + .add_alias = add_alias_cb, + + .event_broadcast = event_broadcast_cb, + .event_make = event_x2_make_cb, + + .legacy_call = legacy_call_x3, + .legacy_call_sync = legacy_call_sync, + + .api_new_api = api_new_api_cb, + .api_set_verbs_v2 = api_set_verbs_v2_cb, + .api_add_verb = api_add_verb_cb, + .api_del_verb = api_del_verb_cb, + .api_set_on_event = api_set_on_event_cb, + .api_set_on_init = api_set_on_init_cb, + .api_seal = api_seal_cb, + .api_set_verbs_v3 = api_set_verbs_v3_cb, + .event_handler_add = event_handler_add_cb, + .event_handler_del = event_handler_del_cb, + + .call = call_x3, + .call_sync = call_sync_x3, + + .class_provide = class_provide_cb, + .class_require = class_require_cb, + + .delete_api = delete_api_cb, + .settings = settings_cb, +}; + +#if WITH_AFB_HOOK static int hooked_api_set_verbs_v2_cb( struct afb_api_x3 *api, const struct afb_verb_v2 *verbs) @@ -980,45 +1143,13 @@ static int hooked_delete_api_cb(struct afb_api_x3 *api) return result; } -static const struct afb_api_x3_itf api_x3_itf = { - - .vverbose = (void*)vverbose_cb, - - .get_event_loop = afb_systemd_get_event_loop, - .get_user_bus = afb_systemd_get_user_bus, - .get_system_bus = afb_systemd_get_system_bus, - .rootdir_get_fd = afb_common_rootdir_get_fd, - .rootdir_open_locale = rootdir_open_locale_cb, - .queue_job = queue_job_cb, - - .require_api = require_api_cb, - .add_alias = add_alias_cb, - - .event_broadcast = event_broadcast_cb, - .event_make = event_x2_make_cb, - - .legacy_call = legacy_call_x3, - .legacy_call_sync = legacy_call_sync, - - .api_new_api = api_new_api_cb, - .api_set_verbs_v2 = api_set_verbs_v2_cb, - .api_add_verb = api_add_verb_cb, - .api_del_verb = api_del_verb_cb, - .api_set_on_event = api_set_on_event_cb, - .api_set_on_init = api_set_on_init_cb, - .api_seal = api_seal_cb, - .api_set_verbs_v3 = api_set_verbs_v3_cb, - .event_handler_add = event_handler_add_cb, - .event_handler_del = event_handler_del_cb, - - .call = call_x3, - .call_sync = call_sync_x3, - - .class_provide = class_provide_cb, - .class_require = class_require_cb, - - .delete_api = delete_api_cb, -}; +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 = { @@ -1058,7 +1189,9 @@ static const struct afb_api_x3_itf hooked_api_x3_itf = { .class_require = hooked_class_require_cb, .delete_api = hooked_delete_api_cb, + .settings = hooked_settings_cb, }; +#endif /****************************************************************************** ****************************************************************************** @@ -1073,47 +1206,64 @@ static const struct afb_api_x3_itf hooked_api_x3_itf = { /* * Propagates the event to the service */ -static void listener_of_events(void *closure, const char *event, int eventid, struct json_object *object) +static void listener_of_events(void *closure, const char *event, uint16_t eventid, struct json_object *object) { - struct event_handler *handler; + 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; - while (handler) { - if (fnmatch(handler->pattern, event, 0)) { - if (!(export->hooksvc & afb_hook_flag_api_on_event_handler)) - handler->callback(handler->closure, event, object, to_api_x3(export)); - else { - afb_hook_api_on_event_handler_before(export, event, eventid, object, handler->pattern); - handler->callback(handler->closure, event, object, to_api_x3(export)); - afb_hook_api_on_event_handler_after(export, event, eventid, object, handler->pattern); - } + 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); } - handler = handler->next; +#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); } - /* 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_events, - .push = listener_of_events + .broadcast = listener_of_broadcasted_events, + .push = listener_of_pushed_events }; /* ensure an existing listener */ @@ -1134,40 +1284,32 @@ int afb_export_event_handler_add( void *closure) { int rc; - struct event_handler *handler, **previous; + /* ensure the listener */ rc = ensure_listener(export); if (rc < 0) return rc; - /* search the handler */ - previous = &export->event_handlers; - while ((handler = *previous) && strcasecmp(handler->pattern, pattern)) - previous = &handler->next; - - /* error if found */ - if (handler) { - ERROR("[API %s] event handler %s already exists", export->api.apiname, pattern); - errno = EEXIST; - return -1; + /* ensure the globset for event handling */ + if (!export->event_handlers) { + export->event_handlers = globset_create(); + if (!export->event_handlers) + goto oom_error; } - /* create the event */ - handler = malloc(strlen(pattern) + sizeof * handler); - if (!handler) { - ERROR("[API %s] can't allocate event handler %s", export->api.apiname, pattern); - errno = ENOMEM; + /* 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; } - /* init and record */ - handler->next = NULL; - handler->callback = callback; - handler->closure = closure; - strcpy(handler->pattern, pattern); - *previous = handler; - - return 0; +oom_error: + ERROR("[API %s] can't allocate event handler %s", export->api.apiname, pattern); + return -1; } int afb_export_event_handler_del( @@ -1175,27 +1317,13 @@ int afb_export_event_handler_del( const char *pattern, void **closure) { - struct event_handler *handler, **previous; - - /* search the handler */ - previous = &export->event_handlers; - while ((handler = *previous) && strcasecmp(handler->pattern, pattern)) - previous = &handler->next; - - /* error if found */ - if (!handler) { - ERROR("[API %s] event handler %s already exists", export->api.apiname, pattern); - errno = ENOENT; - return -1; - } - - /* remove the found event */ - if (closure) - *closure = handler->closure; + if (export->event_handlers + && !globset_del(export->event_handlers, pattern, closure)) + return 0; - *previous = handler->next; - free(handler); - return 0; + ERROR("[API %s] event handler %s not found", export->api.apiname, pattern); + errno = ENOENT; + return -1; } /****************************************************************************** @@ -1208,13 +1336,56 @@ int afb_export_event_handler_del( ****************************************************************************** ******************************************************************************/ +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 */ if (common_session == NULL) { @@ -1222,13 +1393,18 @@ static struct afb_export *create( if (common_session == NULL) return NULL; } - export = calloc(1, sizeof *export + strlen(apiname)); + lenapi = strlen(apiname); + export = calloc(1, sizeof *export + 1 + lenapi + (path == apiname || !path ? 0 : 1 + strlen(path))); if (!export) errno = ENOMEM; else { export->refcount = 1; strcpy(export->name, apiname); export->api.apiname = export->name; + if (path == apiname) + export->path = export->name; + else if (path) + export->path = strcpy(&export->name[lenapi + 1], path); export->version = version; export->state = Api_State_Pre_Init; export->session = afb_session_addref(common_session); @@ -1253,18 +1429,16 @@ void afb_export_unref(struct afb_export *export) void afb_export_destroy(struct afb_export *export) { - struct event_handler *handler; - if (export) { - while ((handler = export->event_handlers)) { - export->event_handlers = handler->next; - free(handler); - } + if (export->event_handlers) + globset_destroy(export->event_handlers); if (export->listener != NULL) afb_evt_listener_unref(export->listener); afb_session_unref(export->session); afb_apiset_unref(export->declare_set); afb_apiset_unref(export->call_set); + json_object_put(export->settings); + afb_export_unref(export->creator); if (export->api.apiname != export->name) free((void*)export->api.apiname); free(export); @@ -1278,10 +1452,10 @@ struct afb_export *afb_export_create_none_for_path( int (*creator)(void*, struct afb_api_x3*), void *closure) { - struct afb_export *export = create(declare_set, call_set, path, Api_Version_None); + struct afb_export *export = create(declare_set, call_set, path, path, Api_Version_None); if (export) { afb_export_logmask_set(export, logmask); - afb_export_update_hooks(export); + set_interfaces(export); if (creator && creator(closure, to_api_x3(export)) < 0) { afb_export_unref(export); export = NULL; @@ -1290,37 +1464,38 @@ struct afb_export *afb_export_create_none_for_path( return export; } -#if defined(WITH_LEGACY_BINDING_V1) -struct afb_export *afb_export_create_v1( - struct afb_apiset *declare_set, +#if WITH_LEGACY_BINDING_V1 +struct afb_export *afb_export_create_v1(struct afb_apiset *declare_set, struct afb_apiset *call_set, const char *apiname, int (*init)(struct afb_service_x1), - void (*onevent)(const char*, struct json_object*)) + void (*onevent)(const char*, struct json_object*), + const char* path) { - struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_1); + struct afb_export *export = create(declare_set, call_set, apiname, path, Api_Version_1); if (export) { export->init.v1 = init; export->on_any_event_v12 = onevent; export->export.v1.mode = AFB_MODE_LOCAL; export->export.v1.daemon.closure = to_api_x3(export); afb_export_logmask_set(export, logmask); - afb_export_update_hooks(export); + set_interfaces(export); } return export; } #endif -struct afb_export *afb_export_create_v2( - struct afb_apiset *declare_set, +#if WITH_LEGACY_BINDING_V2 +struct afb_export *afb_export_create_v2(struct afb_apiset *declare_set, struct afb_apiset *call_set, const char *apiname, const struct afb_binding_v2 *binding, struct afb_binding_data_v2 *data, int (*init)(), - void (*onevent)(const char*, struct json_object*)) + void (*onevent)(const char*, struct json_object*), + const char* path) { - struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_2); + struct afb_export *export = create(declare_set, call_set, apiname, path, Api_Version_2); if (export) { export->init.v2 = init; export->on_any_event_v12 = onevent; @@ -1329,22 +1504,26 @@ struct afb_export *afb_export_create_v2( data->daemon.closure = to_api_x3(export); data->service.closure = to_api_x3(export); afb_export_logmask_set(export, logmask); - afb_export_update_hooks(export); + set_interfaces(export); } return export; } +#endif struct afb_export *afb_export_create_v3(struct afb_apiset *declare_set, struct afb_apiset *call_set, const char *apiname, - struct afb_api_v3 *apiv3) + struct afb_api_v3 *apiv3, + struct afb_export* creator, + const char* path) { - struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_3); + struct afb_export *export = create(declare_set, call_set, apiname, path, Api_Version_3); if (export) { export->unsealed = 1; export->desc.v3 = apiv3; + export->creator = afb_export_addref(creator); afb_export_logmask_set(export, logmask); - afb_export_update_hooks(export); + set_interfaces(export); } return export; } @@ -1374,7 +1553,7 @@ int afb_export_rename(struct afb_export *export, const char *apiname) free((void*)export->api.apiname); export->api.apiname = name; - afb_export_update_hooks(export); + set_interfaces(export); return 0; } @@ -1383,25 +1562,6 @@ const char *afb_export_apiname(const struct afb_export *export) return export->api.apiname; } -void afb_export_update_hooks(struct afb_export *export) -{ - 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 defined(WITH_LEGACY_BINDING_V1) - case Api_Version_1: - export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf; - break; -#endif - 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; - } -} - int afb_export_unshare_session(struct afb_export *export) { if (export->session == common_session) { @@ -1416,15 +1576,18 @@ int afb_export_unshare_session(struct afb_export *export) return 0; } +#if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2 int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object)) { /* check version */ switch (export->version) { -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 case Api_Version_1: #endif +#if WITH_LEGACY_BINDING_V2 case Api_Version_2: break; +#endif default: ERROR("invalid version 12 for API %s", export->api.apiname); errno = EINVAL; @@ -1434,6 +1597,7 @@ int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(con export->on_any_event_v12 = on_event; return ensure_listener(export); } +#endif int afb_export_handle_events_v3(struct afb_export *export, void (*on_event)(struct afb_api_x3 *api, const char *event, struct json_object *object)) { @@ -1462,7 +1626,7 @@ int afb_export_handle_init_v3(struct afb_export *export, int (*oninit)(struct af return 0; } -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 /* * Starts a new service (v1) */ @@ -1489,10 +1653,12 @@ void afb_export_logmask_set(struct afb_export *export, int mask) { export->api.logmask = mask; switch (export->version) { -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 case Api_Version_1: export->export.v1.verbosity = verbosity_from_mask(mask); break; #endif +#if WITH_LEGACY_BINDING_V2 case Api_Version_2: export->export.v2->verbosity = verbosity_from_mask(mask); break; +#endif } } @@ -1533,17 +1699,23 @@ static void do_init(int sig, void *closure) else { export = init->export; switch (export->version) { -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 case Api_Version_1: rc = export->init.v1 ? export->init.v1( (struct afb_service_x1){ +#if WITH_AFB_HOOK .itf = &hooked_service_itf, +#else + .itf = &service_itf, +#endif .closure = to_api_x3(export) }) : 0; break; #endif +#if WITH_LEGACY_BINDING_V2 case Api_Version_2: rc = export->init.v2 ? export->init.v2() : 0; break; +#endif case Api_Version_3: rc = export->init.v3 ? export->init.v3(to_api_x3(export)) : 0; break; @@ -1576,11 +1748,14 @@ int afb_export_start(struct afb_export *export) } /* set event handling */ +#if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2 switch (export->version) { -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 case Api_Version_1: #endif +#if WITH_LEGACY_BINDING_V2 case Api_Version_2: +#endif if (export->on_any_event_v12) { rc = afb_export_handle_events_v12(export, export->on_any_event_v12); break; @@ -1594,10 +1769,13 @@ int afb_export_start(struct afb_export *export) ERROR("Can't set event handler for %s", export->api.apiname); return -1; } +#endif +#if WITH_AFB_HOOK /* Starts the service */ if (export->hooksvc & afb_hook_flag_api_start) afb_hook_api_start_before(export); +#endif export->state = Api_State_Init; init.export = export; @@ -1605,8 +1783,10 @@ int afb_export_start(struct afb_export *export) rc = init.return_code; export->state = Api_State_Run; +#if WITH_AFB_HOOK if (export->hooksvc & afb_hook_flag_api_start) afb_hook_api_start_after(export, rc); +#endif if (rc < 0) { /* initialisation error */ @@ -1624,37 +1804,41 @@ static void api_call_cb(void *closure, struct afb_xreq *xreq) xreq->request.api = to_api_x3(export); switch (export->version) { -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 case Api_Version_1: afb_api_so_v1_process_call(export->desc.v1, xreq); break; #endif +#if WITH_LEGACY_BINDING_V2 case Api_Version_2: afb_api_so_v2_process_call(export->desc.v2, xreq); break; +#endif case Api_Version_3: afb_api_v3_process_call(export->desc.v3, xreq); break; default: - afb_xreq_reply(xreq, NULL, "bad-api-type", NULL); + afb_xreq_reply(xreq, NULL, afb_error_text_internal_error, NULL); break; } } -static struct json_object *api_describe_cb(void *closure) +static void api_describe_cb(void *closure, void (*describecb)(void *, struct json_object *), void *clocb) { struct afb_export *export = closure; struct json_object *result; switch (export->version) { -#if defined(WITH_LEGACY_BINDING_V1) +#if WITH_LEGACY_BINDING_V1 case Api_Version_1: result = afb_api_so_v1_make_description_openAPIv3(export->desc.v1, export->api.apiname); break; #endif +#if WITH_LEGACY_BINDING_V2 case Api_Version_2: result = afb_api_so_v2_make_description_openAPIv3(export->desc.v2, export->api.apiname); break; +#endif case Api_Version_3: result = afb_api_v3_make_description_openAPIv3(export->desc.v3, export->api.apiname); break; @@ -1662,7 +1846,7 @@ static struct json_object *api_describe_cb(void *closure) result = NULL; break; } - return result; + describecb(clocb, result); } static int api_service_start_cb(void *closure) @@ -1672,12 +1856,13 @@ static int api_service_start_cb(void *closure) return afb_export_start(export); } +#if WITH_AFB_HOOK static void api_update_hooks_cb(void *closure) -{ - struct afb_export *export = closure; + __attribute__((alias("set_interfaces"))); - afb_export_update_hooks(export); -} +void afb_export_update_hooks(struct afb_export *export) + __attribute__((alias("set_interfaces"))); +#endif static int api_get_logmask_cb(void *closure) { @@ -1704,7 +1889,9 @@ static struct afb_api_itf export_api_itf = { .call = api_call_cb, .service_start = api_service_start_cb, +#if WITH_AFB_HOOK .update_hooks = api_update_hooks_cb, +#endif .get_logmask = api_get_logmask_cb, .set_logmask = api_set_logmask_cb, .describe = api_describe_cb, @@ -1733,7 +1920,7 @@ int afb_export_declare(struct afb_export *export, ERROR("can't declare export %s to set %s, ABORTING it!", export->api.apiname, afb_apiset_name(export->declare_set)); - afb_export_addref(export); + afb_export_unref(export); } } @@ -1750,12 +1937,12 @@ void afb_export_undeclare(struct afb_export *export) int afb_export_subscribe(struct afb_export *export, struct afb_event_x2 *event) { - return afb_evt_event_x2_add_watch(export->listener, event); + return afb_evt_listener_watch_x2(export->listener, event); } int afb_export_unsubscribe(struct afb_export *export, struct afb_event_x2 *event) { - return afb_evt_event_x2_remove_watch(export->listener, event); + return afb_evt_listener_unwatch_x2(export->listener, event); } void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq) @@ -1765,6 +1952,6 @@ void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq) void afb_export_context_init(struct afb_export *export, struct afb_context *context) { - afb_context_init(context, export->session, NULL); + afb_context_init_validated(context, export->session, NULL, NULL); }