X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-export.c;h=800ee77bdf9ee1adadddb5776acd6faa655c233e;hb=65353dce81a629e042800bb7b86fcd869a76727e;hp=840bd9190331dc8a1f96289ed252c678eba23bad;hpb=a3245aed48dca435b437089bc81353da352fc0ce;p=src%2Fapp-framework-binder.git diff --git a/src/afb-export.c b/src/afb-export.c index 840bd919..800ee77b 100644 --- a/src/afb-export.c +++ b/src/afb-export.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016, 2017 "IoT.bzh" + * Copyright (C) 2015-2020 "IoT.bzh" * Author: José Bollo * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,37 +20,65 @@ #include #include #include +#include +#include #include +#if !defined(JSON_C_TO_STRING_NOSLASHESCAPE) +#define JSON_C_TO_STRING_NOSLASHESCAPE 0 +#endif #define AFB_BINDING_VERSION 0 #include #include "afb-api.h" #include "afb-apiset.h" -#include "afb-api-dyn.h" +#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-cred.h" #include "afb-evt.h" #include "afb-export.h" #include "afb-hook.h" #include "afb-msg-json.h" #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 and structures + * internal types ************************************************************************/ +/* + * Actually supported versions + */ enum afb_api_version { - Api_Version_Dyn = 0, + Api_Version_None = 0, +#if WITH_LEGACY_BINDING_V1 Api_Version_1 = 1, +#endif +#if WITH_LEGACY_BINDING_V2 Api_Version_2 = 2, +#endif + Api_Version_3 = 3 }; +/* + * The states of exported APIs + */ enum afb_api_state { Api_State_Pre_Init, @@ -58,13 +86,16 @@ enum afb_api_state Api_State_Run }; +/* + * structure of the exported API + */ struct afb_export { /* keep it first */ - struct afb_dynapi dynapi; + struct afb_api_x3 api; - /* name of the api */ - char *apiname; + /* reference count */ + int refcount; /* version of the api */ unsigned version: 4; @@ -72,124 +103,206 @@ struct afb_export /* current state */ unsigned state: 4; + /* declared */ + unsigned declared: 1; + + /* unsealed */ + unsigned unsealed: 1; + +#if WITH_AFB_HOOK /* hooking flags */ int hookditf; int hooksvc; - - /* dynamic api */ - struct afb_api_dyn *apidyn; +#endif /* session for service */ struct afb_session *session; - /* apiset for service */ - struct afb_apiset *apiset; + /* apiset the API is declared in */ + struct afb_apiset *declare_set; + + /* apiset for calls */ + struct afb_apiset *call_set; /* event listener for service or NULL */ struct afb_evt_listener *listener; + /* event handler list */ + 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 WITH_LEGACY_BINDING_V1 + struct afb_binding_v1 *v1; +#endif + const struct afb_binding_v2 *v2; + struct afb_api_v3 *v3; + } desc; + /* start function */ union { - int (*v1)(struct afb_service); +#if WITH_LEGACY_BINDING_V1 + int (*v1)(struct afb_service_x1); +#endif int (*v2)(); - int (*vdyn)(struct afb_dynapi *dynapi); + int (*v3)(struct afb_api_x3 *api); } init; /* event handling */ - union { - void (*v12)(const char *event, struct json_object *object); - void (*vdyn)(struct afb_dynapi *dynapi, const char *event, struct json_object *object); - } on_event; + void (*on_any_event_v12)(const char *event, struct json_object *object); + void (*on_any_event_v3)(struct afb_api_x3 *api, const char *event, struct json_object *object); /* exported data */ union { +#if WITH_LEGACY_BINDING_V1 struct afb_binding_interface_v1 v1; +#endif struct afb_binding_data_v2 *v2; } export; + + /* initial name */ + char name[]; }; -/************************************************************************************************************/ +/*****************************************************************************/ + +static inline struct afb_api_x3 *to_api_x3(struct afb_export *export) +{ + return (struct afb_api_x3*)export; +} + +static inline struct afb_export *from_api_x3(struct afb_api_x3 *api) +{ + return (struct afb_export*)api; +} + +struct afb_export *afb_export_from_api_x3(struct afb_api_x3 *api) +{ + return from_api_x3(api); +} + +struct afb_api_x3 *afb_export_to_api_x3(struct afb_export *export) +{ + return to_api_x3(export); +} + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + SETTINGS + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ -static inline struct afb_dynapi *to_dynapi(struct afb_export *export) +static struct json_object *configuration; + +void afb_export_set_config(struct json_object *config) { - return (struct afb_dynapi*)export; + struct json_object *save = configuration; + configuration = json_object_get(config); + json_object_put(save); } -static inline struct afb_export *from_dynapi(struct afb_dynapi *dynapi) +static struct json_object *make_settings(struct afb_export *export) { - return (struct afb_export*)dynapi; + 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; } -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M D I T F - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ /********************************************** * normal flow **********************************************/ -static void vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void vverbose_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { char *p; - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); if (!fmt || vasprintf(&p, fmt, args) < 0) vverbose(level, file, line, function, fmt, args); else { - verbose(level, file, line, function, "[API %s] %s", export->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 old_vverbose_cb(void *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_eventid *eventid_make_cb(void *closure, const char *name) +static struct afb_event_x2 *event_x2_make_cb(struct afb_api_x3 *closure, const char *name) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); /* check daemon state */ if (export->state == Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->apiname, name); + ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->api.apiname, name); errno = EINVAL; return NULL; } /* create the event */ - return afb_evt_eventid_create2(export->apiname, name); + return afb_evt_event_x2_create2(export->api.apiname, name); } -static struct afb_event event_make_cb(void *closure, const char *name) -{ - struct afb_eventid *eventid = eventid_make_cb(closure, name); - return afb_evt_event_from_evtid(afb_evt_eventid_to_evtid(eventid)); -} - -static int event_broadcast_cb(void *closure, const char *name, struct json_object *object) +static int event_broadcast_cb(struct afb_api_x3 *closure, const char *name, struct json_object *object) { size_t plen, nlen; char *event; - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); /* check daemon state */ if (export->state == Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit", export->apiname, name, json_object_to_json_string(object)); + ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit", + export->api.apiname, name, json_object_to_json_string_ext(object, JSON_C_TO_STRING_NOSLASHESCAPE)); errno = EINVAL; return 0; } /* makes the event name */ - plen = strlen(export->apiname); + plen = strlen(export->api.apiname); nlen = strlen(name); event = alloca(nlen + plen + 2); - memcpy(event, export->apiname, plen); + memcpy(event, export->api.apiname, plen); event[plen] = '/'; memcpy(event + plen + 1, name, nlen + 1); @@ -197,207 +310,294 @@ static int event_broadcast_cb(void *closure, const char *name, struct json_objec return afb_evt_broadcast(event, object); } -static int rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale) +static struct sd_event *get_event_loop(struct afb_api_x3 *closure) { - return afb_common_rootdir_open_locale(filename, flags, locale); + jobs_acquire_event_manager(); + return systemd_get_event_loop(); } -static int queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) +static struct sd_bus *get_user_bus(struct afb_api_x3 *closure) { - return jobs_queue(group, timeout, callback, argument); + jobs_acquire_event_manager(); + return systemd_get_user_bus(); } -static struct afb_req unstore_req_cb(void *closure, struct afb_stored_req *sreq) +static struct sd_bus *get_system_bus(struct afb_api_x3 *closure) { - return afb_xreq_unstore(sreq); + jobs_acquire_event_manager(); + return systemd_get_system_bus(); } -static int require_api_cb(void *closure, const char *name, int initialized) +static int rootdir_open_locale_cb(struct afb_api_x3 *closure, const char *filename, int flags, const char *locale) { - struct afb_export *export = closure; - if (export->state != Api_State_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_require(%s, %d)', must be in Init", export->apiname, name, initialized); - errno = EINVAL; - return -1; - } - return -!(initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->apiset, name, 1); + return afb_common_rootdir_open_locale(filename, flags, locale); } -static int rename_api_cb(void *closure, const char *name) +static int queue_job_cb(struct afb_api_x3 *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) { - struct afb_export *export = closure; - if (export->state != Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_rename(%s)', must be in PreInit", export->apiname, name); + return jobs_queue(group, timeout, callback, argument); +} + +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; } - if (!afb_api_is_valid_name(name, 1)) { - ERROR("[API %s] Can't rename to %s: bad API name", export->apiname, name); + + /* scan the names in a local copy */ + rc = 0; + iter = strdupa(name); + for(;;) { + /* skip any space */ + save = *iter; + while(isspace(save)) + save = *++iter; + if (!save) /* at end? */ + return rc; + + /* search for the end */ + end = iter; + while (save && !isspace(save)) + save = *++end; + *end = 0; + + /* check the required api */ + 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; + + *end = save; + iter = end; + } +} + +static int add_alias_cb(struct afb_api_x3 *closure, const char *apiname, const char *aliasname) +{ + struct afb_export *export = from_api_x3(closure); + if (!afb_api_is_valid_name(aliasname)) { + ERROR("[API %s] Can't add alias to %s: bad API name", export->api.apiname, aliasname); errno = EINVAL; return -1; } - NOTICE("[API %s] renamed to [API %s]", export->apiname, name); - afb_export_rename(export, name); + NOTICE("[API %s] aliasing [API %s] to [API %s]", export->api.apiname, apiname?:"", aliasname); + afb_export_add_alias(export, apiname, aliasname); return 0; } -static int api_new_api_cb( - void *closure, +static struct afb_api_x3 *api_new_api_cb( + struct afb_api_x3 *closure, const char *api, const char *info, int noconcurrency, - int (*preinit)(void*, struct afb_dynapi *), + int (*preinit)(void*, struct afb_api_x3 *), void *preinit_closure) { - struct afb_export *export = closure; - return afb_api_dyn_add(export->apiset, api, info, noconcurrency, preinit, 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, + export, NULL); + return apiv3 ? to_api_x3(afb_api_v3_export(apiv3)) : NULL; } -/********************************************** -* hooked flow -**********************************************/ -static void hooked_vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +#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) { - struct afb_export *export = closure; - va_list ap; - va_copy(ap, args); - vverbose_cb(closure, level, file, line, function, fmt, args); - afb_hook_ditf_vverbose(export, level, file, line, function, fmt, ap); - va_end(ap); + vverbose_cb(closure, level, file, line, NULL, fmt, args); } -static void hooked_old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args) +static struct afb_event_x1 legacy_event_x1_make_cb(struct afb_api_x3 *closure, const char *name) { - hooked_vverbose_cb(closure, level, file, line, NULL, fmt, args); + 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_eventid *hooked_eventid_make_cb(void *closure, const char *name) +static struct afb_req_x1 legacy_unstore_req_cb(struct afb_api_x3 *closure, struct afb_stored_req *sreq) { - struct afb_export *export = closure; - struct afb_eventid *r = eventid_make_cb(closure, name); - afb_hook_ditf_event_make(export, name, r); - return r; + 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); + va_list ap; + va_copy(ap, args); + vverbose_cb(closure, level, file, line, function, fmt, args); + afb_hook_api_vverbose(export, level, file, line, function, fmt, ap); + va_end(ap); } -static struct afb_event hooked_event_make_cb(void *closure, const char *name) +static struct afb_event_x2 *hooked_event_x2_make_cb(struct afb_api_x3 *closure, const char *name) { - struct afb_eventid *eventid = hooked_eventid_make_cb(closure, name); - return (struct afb_event){ .itf = eventid ? eventid->itf : NULL, .closure = eventid }; + struct afb_export *export = from_api_x3(closure); + struct afb_event_x2 *r = event_x2_make_cb(closure, name); + afb_hook_api_event_make(export, name, r); + return r; } -static int hooked_event_broadcast_cb(void *closure, const char *name, struct json_object *object) +static int hooked_event_broadcast_cb(struct afb_api_x3 *closure, const char *name, struct json_object *object) { int r; - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); json_object_get(object); - afb_hook_ditf_event_broadcast_before(export, name, json_object_get(object)); + afb_hook_api_event_broadcast_before(export, name, json_object_get(object)); r = event_broadcast_cb(closure, name, object); - afb_hook_ditf_event_broadcast_after(export, name, object, r); + afb_hook_api_event_broadcast_after(export, name, object, r); json_object_put(object); return r; } -static struct sd_event *hooked_get_event_loop(void *closure) +static struct sd_event *hooked_get_event_loop(struct afb_api_x3 *closure) { - struct afb_export *export = closure; - struct sd_event *r = afb_common_get_event_loop(); - return afb_hook_ditf_get_event_loop(export, r); + struct afb_export *export = from_api_x3(closure); + 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(void *closure) +static struct sd_bus *hooked_get_user_bus(struct afb_api_x3 *closure) { - struct afb_export *export = closure; - struct sd_bus *r = afb_common_get_user_bus(); - return afb_hook_ditf_get_user_bus(export, r); + struct afb_export *export = from_api_x3(closure); + 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(void *closure) +static struct sd_bus *hooked_get_system_bus(struct afb_api_x3 *closure) { - struct afb_export *export = closure; - struct sd_bus *r = afb_common_get_system_bus(); - return afb_hook_ditf_get_system_bus(export, r); + struct afb_export *export = from_api_x3(closure); + struct sd_bus *r; + + jobs_acquire_event_manager(); + r = get_system_bus(closure); + return afb_hook_api_get_system_bus(export, r); } -static int hooked_rootdir_get_fd(void *closure) +static int hooked_rootdir_get_fd(struct afb_api_x3 *closure) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); int r = afb_common_rootdir_get_fd(); - return afb_hook_ditf_rootdir_get_fd(export, r); + return afb_hook_api_rootdir_get_fd(export, r); } -static int hooked_rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale) +static int hooked_rootdir_open_locale_cb(struct afb_api_x3 *closure, const char *filename, int flags, const char *locale) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); int r = rootdir_open_locale_cb(closure, filename, flags, locale); - return afb_hook_ditf_rootdir_open_locale(export, filename, flags, locale, r); + return afb_hook_api_rootdir_open_locale(export, filename, flags, locale, r); } -static int hooked_queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) +static int hooked_queue_job_cb(struct afb_api_x3 *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); int r = queue_job_cb(closure, callback, argument, group, timeout); - return afb_hook_ditf_queue_job(export, callback, argument, group, timeout, r); -} - -static struct afb_req hooked_unstore_req_cb(void *closure, struct afb_stored_req *sreq) -{ - struct afb_export *export = closure; - afb_hook_ditf_unstore_req(export, sreq); - return unstore_req_cb(closure, sreq); + return afb_hook_api_queue_job(export, callback, argument, group, timeout, r); } -static int hooked_require_api_cb(void *closure, const char *name, int initialized) +static int hooked_require_api_cb(struct afb_api_x3 *closure, const char *name, int initialized) { int result; - struct afb_export *export = closure; - afb_hook_ditf_require_api(export, name, initialized); + struct afb_export *export = from_api_x3(closure); + afb_hook_api_require_api(export, name, initialized); result = require_api_cb(closure, name, initialized); - return afb_hook_ditf_require_api_result(export, name, initialized, result); + return afb_hook_api_require_api_result(export, name, initialized, result); } -static int hooked_rename_api_cb(void *closure, const char *name) +static int hooked_add_alias_cb(struct afb_api_x3 *closure, const char *apiname, const char *aliasname) { - struct afb_export *export = closure; - const char *oldname = export->apiname; - int result = rename_api_cb(closure, name); - return afb_hook_ditf_rename_api(export, oldname, name, result); + struct afb_export *export = from_api_x3(closure); + int result = add_alias_cb(closure, apiname, aliasname); + return afb_hook_api_add_alias(export, apiname, aliasname, result); } -static int hooked_api_new_api_cb( - void *closure, +static struct afb_api_x3 *hooked_api_new_api_cb( + struct afb_api_x3 *closure, const char *api, const char *info, int noconcurrency, - int (*preinit)(void*, struct afb_dynapi *), + int (*preinit)(void*, struct afb_api_x3 *), void *preinit_closure) { - /* TODO */ - return api_new_api_cb(closure, api, info, noconcurrency, preinit, preinit_closure); + struct afb_api_x3 *result; + struct afb_export *export = from_api_x3(closure); + afb_hook_api_new_api_before(export, api, info, noconcurrency); + result = api_new_api_cb(closure, api, info, noconcurrency, preinit, preinit_closure); + afb_hook_api_new_api_after(export, -!result, api); + return result; } -/********************************************** -* vectors -**********************************************/ -static const struct afb_daemon_itf daemon_itf = { - .vverbose_v1 = old_vverbose_cb, - .vverbose_v2 = vverbose_cb, - .event_make = event_make_cb, - .event_broadcast = event_broadcast_cb, - .get_event_loop = afb_common_get_event_loop, - .get_user_bus = afb_common_get_user_bus, - .get_system_bus = afb_common_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 = unstore_req_cb, - .require_api = require_api_cb, - .rename_api = rename_api_cb, - .new_api = api_new_api_cb, -}; -static const struct afb_daemon_itf hooked_daemon_itf = { - .vverbose_v1 = hooked_old_vverbose_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, .vverbose_v2 = hooked_vverbose_cb, - .event_make = hooked_event_make_cb, + .event_make = legacy_hooked_event_x1_make_cb, .event_broadcast = hooked_event_broadcast_cb, .get_event_loop = hooked_get_event_loop, .get_user_bus = hooked_get_user_bus, @@ -405,567 +605,553 @@ static const struct afb_daemon_itf hooked_daemon_itf = { .rootdir_get_fd = hooked_rootdir_get_fd, .rootdir_open_locale = hooked_rootdir_open_locale_cb, .queue_job = hooked_queue_job_cb, - .unstore_req = hooked_unstore_req_cb, + .unstore_req = legacy_hooked_unstore_req_cb, .require_api = hooked_require_api_cb, - .rename_api = hooked_rename_api_cb, + .add_alias = hooked_add_alias_cb, .new_api = hooked_api_new_api_cb, }; +#endif -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +#endif + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M S V C - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ /* the common session for services sharing their session */ static struct afb_session *common_session; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M S V C - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ - -/* - * Structure for requests initiated by the service - */ -struct call_req -{ - struct afb_xreq xreq; - - struct afb_export *export; - - /* the args */ - union { - void (*callback)(void*, int, struct json_object*); - void (*callback_dynapi)(void*, int, struct json_object*, struct afb_dynapi*); - }; - void *closure; - - /* sync */ - struct jobloop *jobloop; - struct json_object *result; - int status; -}; - -/* - * destroys the call_req - */ -static void callreq_destroy(struct afb_xreq *xreq) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - - afb_context_disconnect(&callreq->xreq.context); - json_object_put(callreq->xreq.json); - afb_cred_unref(callreq->xreq.cred); - free(callreq); -} - -static void callreq_reply_async(struct afb_xreq *xreq, int status, json_object *obj) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - if (callreq->callback) - callreq->callback(callreq->closure, status, obj); - json_object_put(obj); -} - -static void callreq_reply_async_dynapi(struct afb_xreq *xreq, int status, json_object *obj) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - if (callreq->callback_dynapi) - callreq->callback_dynapi(callreq->closure, status, obj, to_dynapi(callreq->export)); - json_object_put(obj); -} - -static void callreq_sync_leave(struct call_req *callreq) -{ - struct jobloop *jobloop = callreq->jobloop; - - if (jobloop) { - callreq->jobloop = NULL; - jobs_leave(jobloop); - } -} - -static void callreq_reply_sync(struct afb_xreq *xreq, int status, json_object *obj) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - callreq->status = status; - callreq->result = obj; - callreq_sync_leave(callreq); -} - -static void callreq_sync_enter(int signum, void *closure, struct jobloop *jobloop) -{ - struct call_req *callreq = closure; - - if (!signum) { - callreq->jobloop = jobloop; - afb_xreq_process(&callreq->xreq, callreq->export->apiset); - } else { - callreq->result = afb_msg_json_internal_error(); - callreq->status = -1; - callreq_sync_leave(callreq); - } -} + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ -/* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_async_itf = { - .unref = callreq_destroy, - .reply = callreq_reply_async -}; - -/* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_async_dynapi_itf = { - .unref = callreq_destroy, - .reply = callreq_reply_async_dynapi -}; - -/* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_sync_itf = { - .unref = callreq_destroy, - .reply = callreq_reply_sync -}; - -/* - * create an call_req - */ -static struct call_req *callreq_create( - struct afb_export *export, +static void call_x3( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - const struct afb_xreq_query_itf *itf) -{ - struct call_req *callreq; - size_t lenapi, lenverb; - char *copy; - - /* allocates the request */ - lenapi = 1 + strlen(api); - lenverb = 1 + strlen(verb); - callreq = malloc(lenapi + lenverb + sizeof *callreq); - if (callreq != NULL) { - /* initialises the request */ - afb_xreq_init(&callreq->xreq, itf); - afb_context_init(&callreq->xreq.context, export->session, NULL); - callreq->xreq.context.validated = 1; - copy = (char*)&callreq[1]; - memcpy(copy, api, lenapi); - callreq->xreq.request.api = copy; - copy = ©[lenapi]; - memcpy(copy, verb, lenverb); - callreq->xreq.request.verb = copy; - callreq->xreq.listener = export->listener; - callreq->xreq.json = args; - callreq->export = export; - } - return callreq; + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure) +{ + struct afb_export *export = from_api_x3(apix3); + return afb_calls_call(export, api, verb, args, callback, closure); } -/* - * Initiates a call for the service - */ -static void svc_call( - void *closure, +static int call_sync_x3( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*), - void *cbclosure) + struct json_object **object, + char **error, + char **info) { - struct afb_export *export = closure; - struct call_req *callreq; - struct json_object *ierr; - - /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_async_itf); - if (callreq == NULL) { - ERROR("out of memory"); - json_object_put(args); - ierr = afb_msg_json_internal_error(); - if (callback) - callback(cbclosure, -1, ierr); - json_object_put(ierr); - return; - } - - /* initialises the request */ - callreq->jobloop = NULL; - callreq->callback = callback; - callreq->closure = cbclosure; - - /* terminates and frees ressources if needed */ - afb_xreq_process(&callreq->xreq, export->apiset); + struct afb_export *export = from_api_x3(apix3); + return afb_calls_call_sync(export, api, verb, args, object, error, info); } -static void svc_call_dynapi( - struct afb_dynapi *dynapi, +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*, struct afb_dynapi*), - void *cbclosure) -{ - struct afb_export *export = from_dynapi(dynapi); - struct call_req *callreq; - struct json_object *ierr; - - /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_async_dynapi_itf); - if (callreq == NULL) { - ERROR("out of memory"); - json_object_put(args); - ierr = afb_msg_json_internal_error(); - if (callback) - callback(cbclosure, -1, ierr, to_dynapi(export)); - json_object_put(ierr); - return; - } - - /* initialises the request */ - callreq->jobloop = NULL; - callreq->callback_dynapi = callback; - callreq->closure = cbclosure; - - /* terminates and frees ressources if needed */ - afb_xreq_process(&callreq->xreq, export->apiset); + 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_v3(export, api, verb, args, callback, closure); } -static int svc_call_sync( - void *closure, +static int legacy_call_sync( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - struct afb_export *export = closure; - struct call_req *callreq; - struct json_object *resu; - int rc; - - /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_sync_itf); - if (callreq == NULL) { - ERROR("out of memory"); - errno = ENOMEM; - json_object_put(args); - resu = afb_msg_json_internal_error(); - rc = -1; - } else { - /* initialises the request */ - callreq->jobloop = NULL; - callreq->callback = NULL; - callreq->result = NULL; - callreq->status = 0; - afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */ - rc = jobs_enter(NULL, 0, callreq_sync_enter, callreq); - if (rc >= 0) - rc = callreq->status; - resu = (rc >= 0 || callreq->result) ? callreq->result : afb_msg_json_internal_error(); - afb_xreq_unhooked_unref(&callreq->xreq); - } - if (result) - *result = resu; - else - json_object_put(resu); - return rc; + struct afb_export *export = from_api_x3(apix3); + return afb_calls_legacy_call_sync(export, api, verb, args, result); } -struct hooked_call -{ - struct afb_export *export; - union { - void (*callback)(void*, int, struct json_object*); - void (*callback_dynapi)(void*, int, struct json_object*, struct afb_dynapi*); - }; - void *cbclosure; -}; +#if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2 -static void svc_hooked_call_result(void *closure, int status, struct json_object *result) +static void legacy_call_v12( + struct afb_api_x3 *apix3, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure) { - struct hooked_call *hc = closure; - afb_hook_svc_call_result(hc->export, status, result); - hc->callback(hc->cbclosure, status, result); - free(hc); + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_call_v12(export, api, verb, args, callback, closure); } -static void svc_hooked_call_dynapi_result(void *closure, int status, struct json_object *result, struct afb_dynapi *dynapi) +/* 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, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_api_x3*), + void *closure) { - struct hooked_call *hc = closure; - afb_hook_svc_call_result(hc->export, status, result); - hc->callback_dynapi(hc->cbclosure, status, result, dynapi); - free(hc); + struct afb_export *export = from_api_x3(apix3); + afb_calls_hooked_call(export, api, verb, args, callback, closure); } -static void svc_hooked_call( - void *closure, +static int hooked_call_sync_x3( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*), - void *cbclosure) + struct json_object **object, + char **error, + char **info) { - struct afb_export *export = closure; - struct hooked_call *hc; - - if (export->hooksvc & afb_hook_flag_svc_call) - afb_hook_svc_call(export, api, verb, args); - - if (export->hooksvc & afb_hook_flag_svc_call_result) { - hc = malloc(sizeof *hc); - if (!hc) - WARNING("allocation failed"); - else { - hc->export = export; - hc->callback = callback; - hc->cbclosure = cbclosure; - callback = svc_hooked_call_result; - cbclosure = hc; - } - } - svc_call(closure, api, verb, args, callback, cbclosure); + struct afb_export *export = from_api_x3(apix3); + return afb_calls_hooked_call_sync(export, api, verb, args, object, error, info); } -static void svc_hooked_call_dynapi( - struct afb_dynapi *dynapi, +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*, struct afb_dynapi*), - void *cbclosure) + void (*callback)(void*, int, struct json_object*, struct afb_api_x3*), + void *closure) { - struct afb_export *export = from_dynapi(dynapi); - struct hooked_call *hc; - - if (export->hooksvc & afb_hook_flag_svc_call) - afb_hook_svc_call(export, api, verb, args); - - if (export->hooksvc & afb_hook_flag_svc_call_result) { - hc = malloc(sizeof *hc); - if (!hc) - WARNING("allocation failed"); - else { - hc->export = export; - hc->callback_dynapi = callback; - hc->cbclosure = cbclosure; - callback = svc_hooked_call_dynapi_result; - cbclosure = hc; - } - } - svc_call_dynapi(dynapi, api, verb, args, callback, cbclosure); + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_hooked_call_v3(export, api, verb, args, callback, closure); } -static int svc_hooked_call_sync( - void *closure, +static int legacy_hooked_call_sync( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - struct afb_export *export = closure; - struct json_object *resu; - int rc; - - if (export->hooksvc & afb_hook_flag_svc_callsync) - afb_hook_svc_callsync(export, api, verb, args); - - rc = svc_call_sync(closure, api, verb, args, &resu); - - if (export->hooksvc & afb_hook_flag_svc_callsync_result) - afb_hook_svc_callsync_result(export, rc, resu); + struct afb_export *export = from_api_x3(apix3); + return afb_calls_legacy_hooked_call_sync(export, api, verb, args, result); +} - if (result) - *result = resu; - else - json_object_put(resu); +#if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2 - return rc; +static void legacy_hooked_call_v12( + struct afb_api_x3 *apix3, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure) +{ + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_hooked_call_v12(export, api, verb, args, callback, closure); } /* the interface for services */ -static const struct afb_service_itf service_itf = { - .call = svc_call, - .call_sync = svc_call_sync +static const struct afb_service_itf_x1 hooked_service_itf = { + .call = legacy_hooked_call_v12, + .call_sync = legacy_hooked_call_sync }; +#endif -/* the interface for services */ -static const struct afb_service_itf hooked_service_itf = { - .call = svc_hooked_call, - .call_sync = svc_hooked_call_sync -}; +#endif -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M D Y N A P I - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ static int api_set_verbs_v2_cb( - struct afb_dynapi *dynapi, + struct afb_api_x3 *api, const struct afb_verb_v2 *verbs) { - struct afb_export *export = from_dynapi(dynapi); +#if WITH_LEGACY_BINDING_V2 + struct afb_export *export = from_api_x3(api); - if (export->apidyn) { - afb_api_dyn_set_verbs_v2(export->apidyn, verbs); + if (export->unsealed) { + afb_api_v3_set_verbs_v2(export->desc.v3, verbs); return 0; } errno = EPERM; +#else + errno = ECANCELED; +#endif return -1; } +static int api_set_verbs_v3_cb( + struct afb_api_x3 *api, + const struct afb_verb_v3 *verbs) +{ + struct afb_export *export = from_api_x3(api); + + if (!export->unsealed) { + errno = EPERM; + return -1; + } + + afb_api_v3_set_verbs_v3(export->desc.v3, verbs); + return 0; +} + static int api_add_verb_cb( - struct afb_dynapi *dynapi, + struct afb_api_x3 *api, const char *verb, const char *info, - void (*callback)(struct afb_request *request), + void (*callback)(struct afb_req_x2 *req), void *vcbdata, const struct afb_auth *auth, - uint32_t session) + uint32_t session, + int glob) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - if (export->apidyn) - return afb_api_dyn_add_verb(export->apidyn, verb, info, callback, vcbdata, auth, session); + if (!export->unsealed) { + errno = EPERM; + return -1; + } - errno = EPERM; - return -1; + return afb_api_v3_add_verb(export->desc.v3, verb, info, callback, vcbdata, auth, (uint16_t)session, glob); } -static int api_sub_verb_cb( - struct afb_dynapi *dynapi, - const char *verb) +static int api_del_verb_cb( + struct afb_api_x3 *api, + const char *verb, + void **vcbdata) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - if (export->apidyn) - return afb_api_dyn_sub_verb(export->apidyn, verb); + if (!export->unsealed) { + errno = EPERM; + return -1; + } - errno = EPERM; - return -1; + return afb_api_v3_del_verb(export->desc.v3, verb, vcbdata); } static int api_set_on_event_cb( - struct afb_dynapi *dynapi, - void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) + struct afb_api_x3 *api, + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object)) { - struct afb_export *export = from_dynapi(dynapi); - return afb_export_handle_events_vdyn(export, onevent); + struct afb_export *export = from_api_x3(api); + return afb_export_handle_events_v3(export, onevent); } static int api_set_on_init_cb( - struct afb_dynapi *dynapi, - int (*oninit)(struct afb_dynapi *dynapi)) + struct afb_api_x3 *api, + int (*oninit)(struct afb_api_x3 *api)) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - return afb_export_handle_init_vdyn(export, oninit); + return afb_export_handle_init_v3(export, oninit); } static void api_seal_cb( - struct afb_dynapi *dynapi) + struct afb_api_x3 *api) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - export->apidyn = NULL; + export->unsealed = 0; } -static int hooked_api_set_verbs_v2_cb( - struct afb_dynapi *dynapi, - const struct afb_verb_v2 *verbs) +static int 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) { - /* TODO */ - return api_set_verbs_v2_cb(dynapi, verbs); + struct afb_export *export = from_api_x3(api); + + return afb_export_event_handler_add(export, pattern, callback, closure); } -static int hooked_api_add_verb_cb( - struct afb_dynapi *dynapi, - const char *verb, - const char *info, - void (*callback)(struct afb_request *request), - void *vcbdata, - const struct afb_auth *auth, - uint32_t session) +static int event_handler_del_cb( + struct afb_api_x3 *api, + const char *pattern, + void **closure) { - /* TODO */ - return api_add_verb_cb(dynapi, verb, info, callback, vcbdata, auth, session); + struct afb_export *export = from_api_x3(api); + + return afb_export_event_handler_del(export, pattern, closure); } -static int hooked_api_sub_verb_cb( - struct afb_dynapi *dynapi, - const char *verb) +static int class_provide_cb(struct afb_api_x3 *api, const char *name) { - /* TODO */ - return api_sub_verb_cb(dynapi, verb); + struct afb_export *export = from_api_x3(api); + + int rc = 0, rc2; + char *iter, *end, save; + + iter = strdupa(name); + for(;;) { + /* skip any space */ + save = *iter; + while(isspace(save)) + save = *++iter; + if (!save) /* at end? */ + return rc; + + /* search for the end */ + end = iter; + while (save && !isspace(save)) + save = *++end; + *end = 0; + + rc2 = afb_apiset_provide_class(export->declare_set, api->apiname, iter); + if (rc2 < 0) + rc = rc2; + + *end = save; + iter = end; + } } -static int hooked_api_set_on_event_cb( - struct afb_dynapi *dynapi, - void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) +static int class_require_cb(struct afb_api_x3 *api, const char *name) { - /* TODO */ - return api_set_on_event_cb(dynapi, onevent); + struct afb_export *export = from_api_x3(api); + + int rc = 0, rc2; + char *iter, *end, save; + + iter = strdupa(name); + for(;;) { + /* skip any space */ + save = *iter; + while(isspace(save)) + save = *++iter; + if (!save) /* at end? */ + return rc; + + /* search for the end */ + end = iter; + while (save && !isspace(save)) + save = *++end; + *end = 0; + + rc2 = afb_apiset_require_class(export->declare_set, api->apiname, iter); + if (rc2 < 0) + rc = rc2; + + *end = save; + iter = end; + } } -static int hooked_api_set_on_init_cb( - struct afb_dynapi *dynapi, - int (*oninit)(struct afb_dynapi *dynapi)) +static int delete_api_cb(struct afb_api_x3 *api) { - /* TODO */ - return api_set_on_init_cb(dynapi, oninit); + struct afb_export *export = from_api_x3(api); + + if (!export->unsealed) { + errno = EPERM; + return -1; + } + + afb_export_undeclare(export); + afb_export_unref(export); + return 0; } -static void hooked_api_seal_cb( - struct afb_dynapi *dynapi) +static struct json_object *settings_cb(struct afb_api_x3 *api) { - /* TODO */ - api_seal_cb(dynapi); + 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_dynapi_itf dynapi_itf = { +static const struct afb_api_x3_itf api_x3_itf = { .vverbose = (void*)vverbose_cb, - .get_event_loop = afb_common_get_event_loop, - .get_user_bus = afb_common_get_user_bus, - .get_system_bus = afb_common_get_system_bus, + .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, - .rename_api = rename_api_cb, + .add_alias = add_alias_cb, .event_broadcast = event_broadcast_cb, - .eventid_make = eventid_make_cb, + .event_make = event_x2_make_cb, - .call = svc_call_dynapi, - .call_sync = svc_call_sync, + .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_sub_verb = api_sub_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, }; -static const struct afb_dynapi_itf hooked_dynapi_itf = { +#if WITH_AFB_HOOK +static int hooked_api_set_verbs_v2_cb( + struct afb_api_x3 *api, + const struct afb_verb_v2 *verbs) +{ + struct afb_export *export = from_api_x3(api); + int result = api_set_verbs_v2_cb(api, verbs); + return afb_hook_api_api_set_verbs_v2(export, result, verbs); +} + +static int hooked_api_set_verbs_v3_cb( + struct afb_api_x3 *api, + const struct afb_verb_v3 *verbs) +{ + struct afb_export *export = from_api_x3(api); + int result = api_set_verbs_v3_cb(api, verbs); + return afb_hook_api_api_set_verbs_v3(export, result, verbs); +} + +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, @@ -977,88 +1163,229 @@ static const struct afb_dynapi_itf hooked_dynapi_itf = { .queue_job = hooked_queue_job_cb, .require_api = hooked_require_api_cb, - .rename_api = hooked_rename_api_cb, + .add_alias = hooked_add_alias_cb, .event_broadcast = hooked_event_broadcast_cb, - .eventid_make = hooked_eventid_make_cb, + .event_make = hooked_event_x2_make_cb, - .call = svc_hooked_call_dynapi, - .call_sync = svc_hooked_call_sync, + .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_sub_verb = hooked_api_sub_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, -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - F R O M S V C - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + .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 export_on_event_v12(void *closure, const char *event, int eventid, struct json_object *object) -{ - struct afb_export *export = closure; +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 (export->hooksvc & afb_hook_flag_svc_on_event_before) - afb_hook_svc_on_event_before(export, event, eventid, object); - export->on_event.v12(event, object); - if (export->hooksvc & afb_hook_flag_svc_on_event_after) - afb_hook_svc_on_event_after(export, event, eventid, 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_v12_itf = { - .broadcast = export_on_event_v12, - .push = export_on_event_v12 +static const struct afb_evt_itf evt_itf = { + .broadcast = listener_of_broadcasted_events, + .push = listener_of_pushed_events }; -/* - * Propagates the event to the service - */ -static void export_on_event_vdyn(void *closure, const char *event, int eventid, struct json_object *object) +/* ensure an existing listener */ +static int ensure_listener(struct afb_export *export) { - struct afb_export *export = closure; + if (!export->listener) { + export->listener = afb_evt_listener_create(&evt_itf, export); + if (export->listener == NULL) + return -1; + } + return 0; +} - if (export->hooksvc & afb_hook_flag_svc_on_event_before) - afb_hook_svc_on_event_before(export, event, eventid, object); - export->on_event.vdyn(to_dynapi(export), event, object); - if (export->hooksvc & afb_hook_flag_svc_on_event_after) - afb_hook_svc_on_event_after(export, event, eventid, object); - json_object_put(object); +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; } -/* the interface for events */ -static const struct afb_evt_itf evt_vdyn_itf = { - .broadcast = export_on_event_vdyn, - .push = export_on_event_vdyn -}; +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 struct afb_export *create(struct afb_apiset *apiset, const char *apiname, enum afb_api_version version) +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) { @@ -1066,106 +1393,173 @@ static struct afb_export *create(struct afb_apiset *apiset, const char *apiname, if (common_session == NULL) return NULL; } - export = calloc(1, sizeof *export); + lenapi = strlen(apiname); + export = calloc(1, sizeof *export + 1 + lenapi + (path == apiname || !path ? 0 : 1 + strlen(path))); if (!export) errno = ENOMEM; else { - memset(export, 0, sizeof *export); - export->apiname = strdup(apiname); - export->dynapi.apiname = export->apiname; + 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); - export->apiset = afb_apiset_addref(apiset); + export->declare_set = afb_apiset_addref(declare_set); + export->call_set = afb_apiset_addref(call_set); } return export; } +struct afb_export *afb_export_addref(struct afb_export *export) +{ + if (export) + __atomic_add_fetch(&export->refcount, 1, __ATOMIC_RELAXED); + return export; +} + +void afb_export_unref(struct afb_export *export) +{ + if (export && !__atomic_sub_fetch(&export->refcount, 1, __ATOMIC_RELAXED)) + afb_export_destroy(export); +} + void afb_export_destroy(struct afb_export *export) { if (export) { + 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->apiset); - free(export->apiname); + 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); } } -struct afb_export *afb_export_create_v1(struct afb_apiset *apiset, const char *apiname, int (*init)(struct afb_service), void (*onevent)(const char*, struct json_object*)) +struct afb_export *afb_export_create_none_for_path( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *path, + int (*creator)(void*, struct afb_api_x3*), + void *closure) { - struct afb_export *export = create(apiset, apiname, Api_Version_1); + struct afb_export *export = create(declare_set, call_set, path, path, Api_Version_None); + if (export) { + afb_export_logmask_set(export, logmask); + set_interfaces(export); + if (creator && creator(closure, to_api_x3(export)) < 0) { + afb_export_unref(export); + export = NULL; + } + } + return export; +} + +#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*), + const char* path) +{ + struct afb_export *export = create(declare_set, call_set, apiname, path, Api_Version_1); if (export) { export->init.v1 = init; - export->on_event.v12 = onevent; + export->on_any_event_v12 = onevent; export->export.v1.mode = AFB_MODE_LOCAL; - export->export.v1.daemon.closure = export; - afb_export_verbosity_set(export, verbosity); - afb_export_update_hook(export); + export->export.v1.daemon.closure = to_api_x3(export); + afb_export_logmask_set(export, logmask); + set_interfaces(export); } return export; } +#endif -struct afb_export *afb_export_create_v2(struct afb_apiset *apiset, const char *apiname, struct afb_binding_data_v2 *data, int (*init)(), void (*onevent)(const char*, struct json_object*)) +#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*), + const char* path) { - struct afb_export *export = create(apiset, 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_event.v12 = onevent; + export->on_any_event_v12 = onevent; + export->desc.v2 = binding; export->export.v2 = data; - data->daemon.closure = export; - data->service.closure = export; - afb_export_verbosity_set(export, verbosity); - afb_export_update_hook(export); + data->daemon.closure = to_api_x3(export); + data->service.closure = to_api_x3(export); + afb_export_logmask_set(export, logmask); + set_interfaces(export); } return export; } +#endif -struct afb_export *afb_export_create_vdyn(struct afb_apiset *apiset, const char *apiname, struct afb_api_dyn *apidyn) +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_export* creator, + const char* path) { - struct afb_export *export = create(apiset, apiname, Api_Version_Dyn); + struct afb_export *export = create(declare_set, call_set, apiname, path, Api_Version_3); if (export) { - export->apidyn = apidyn; - afb_export_verbosity_set(export, verbosity); - afb_export_update_hook(export); + export->unsealed = 1; + export->desc.v3 = apiv3; + export->creator = afb_export_addref(creator); + afb_export_logmask_set(export, logmask); + set_interfaces(export); } return export; } -void afb_export_rename(struct afb_export *export, const char *apiname) +int afb_export_add_alias(struct afb_export *export, const char *apiname, const char *aliasname) { - free(export->apiname); - export->apiname = strdup(apiname); - export->dynapi.apiname = export->apiname; - afb_export_update_hook(export); + return afb_apiset_add_alias(export->declare_set, apiname ?: export->api.apiname, aliasname); } -const char *afb_export_apiname(const struct afb_export *export) +int afb_export_rename(struct afb_export *export, const char *apiname) { - return export->apiname; -} + char *name; -void afb_export_update_hook(struct afb_export *export) -{ - export->hookditf = afb_hook_flags_ditf(export->apiname); - export->hooksvc = afb_hook_flags_svc(export->apiname); - export->dynapi.itf = export->hookditf|export->hooksvc ? &hooked_dynapi_itf : &dynapi_itf; + if (export->declared) { + errno = EBUSY; + return -1; + } - switch (export->version) { - case Api_Version_1: - export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf; - break; - 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; + /* copy the name locally */ + name = strdup(apiname); + if (!name) { + errno = ENOMEM; + return -1; } + + if (export->api.apiname != export->name) + free((void*)export->api.apiname); + export->api.apiname = name; + + set_interfaces(export); + return 0; } -struct afb_binding_interface_v1 *afb_export_get_interface_v1(struct afb_export *export) +const char *afb_export_apiname(const struct afb_export *export) { - return export->version == Api_Version_1 ? &export->export.v1 : NULL; + return export->api.apiname; } int afb_export_unshare_session(struct afb_export *export) @@ -1182,191 +1576,382 @@ int afb_export_unshare_session(struct afb_export *export) return 0; } -void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset) -{ - struct afb_apiset *prvset = export->apiset; - export->apiset = afb_apiset_addref(apiset); - afb_apiset_unref(prvset); -} - -struct afb_apiset *afb_export_get_apiset(struct afb_export *export) -{ - return export->apiset; -} - +#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) { - case Api_Version_1: case Api_Version_2: break; +#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->apiname); + ERROR("invalid version 12 for API %s", export->api.apiname); errno = EINVAL; return -1; } - /* set the event handler */ - if (!on_event) { - if (export->listener) { - afb_evt_listener_unref(export->listener); - export->listener = NULL; - } - export->on_event.v12 = on_event; - } else { - export->on_event.v12 = on_event; - if (!export->listener) { - export->listener = afb_evt_listener_create(&evt_v12_itf, export); - if (export->listener == NULL) - return -1; - } - } - return 0; + export->on_any_event_v12 = on_event; + return ensure_listener(export); } +#endif -int afb_export_handle_events_vdyn(struct afb_export *export, void (*on_event)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) +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)) { /* check version */ switch (export->version) { - case Api_Version_Dyn: break; + case Api_Version_3: break; default: - ERROR("invalid version Dyn for API %s", export->apiname); + ERROR("invalid version Dyn for API %s", export->api.apiname); errno = EINVAL; return -1; } - /* set the event handler */ - if (!on_event) { - if (export->listener) { - afb_evt_listener_unref(export->listener); - export->listener = NULL; - } - export->on_event.vdyn = on_event; - } else { - export->on_event.vdyn = on_event; - if (!export->listener) { - export->listener = afb_evt_listener_create(&evt_vdyn_itf, export); - if (export->listener == NULL) - return -1; - } - } - return 0; + export->on_any_event_v3 = on_event; + return ensure_listener(export); } -int afb_export_handle_init_vdyn(struct afb_export *export, int (*oninit)(struct afb_dynapi *dynapi)) +int afb_export_handle_init_v3(struct afb_export *export, int (*oninit)(struct afb_api_x3 *api)) { if (export->state != Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_dynapi_on_init', must be in PreInit", export->apiname); + ERROR("[API %s] Bad call to 'afb_api_x3_on_init', must be in PreInit", export->api.apiname); errno = EINVAL; return -1; } - export->init.vdyn = oninit; + export->init.v3 = oninit; return 0; } +#if WITH_LEGACY_BINDING_V1 /* * Starts a new service (v1) */ struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*)) { - return regfun(&export->export.v1); + return export->desc.v1 = regfun(&export->export.v1); } +#endif -int afb_export_preinit_vdyn(struct afb_export *export, int (*preinit)(void*, struct afb_dynapi*), void *closure) +int afb_export_preinit_x3( + struct afb_export *export, + int (*preinit)(void*, struct afb_api_x3*), + void *closure) { - return preinit(closure, to_dynapi(export)); + return preinit(closure, to_api_x3(export)); } -int afb_export_verbosity_get(const struct afb_export *export) +int afb_export_logmask_get(const struct afb_export *export) { - return export->dynapi.verbosity; + return export->api.logmask; } -void afb_export_verbosity_set(struct afb_export *export, int level) +void afb_export_logmask_set(struct afb_export *export, int mask) { - export->dynapi.verbosity = level; + export->api.logmask = mask; switch (export->version) { - case Api_Version_1: export->export.v1.verbosity = level; break; - case Api_Version_2: export->export.v2->verbosity = level; break; +#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 } } -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +void *afb_export_userdata_get(const struct afb_export *export) +{ + return export->api.userdata; +} + +void afb_export_userdata_set(struct afb_export *export, void *data) +{ + export->api.userdata = data; +} + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** N E W - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ + +struct init +{ + int return_code; + struct afb_export *export; +}; -int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset) +static void do_init(int sig, void *closure) { + int rc = -1; + struct init *init = closure; + struct afb_export *export; + + if (sig) + errno = EFAULT; + else { + export = init->export; + switch (export->version) { +#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; + default: + errno = EINVAL; + break; + } + } + init->return_code = rc; +}; + + +int afb_export_start(struct afb_export *export) +{ + struct init init; int rc; /* check state */ - if (export->state != Api_State_Pre_Init) { - /* not an error when onneed */ - if (onneed != 0) - goto done; + switch (export->state) { + case Api_State_Run: + return 0; - /* already started: it is an error */ - ERROR("Service of API %s already started", export->apiname); + case Api_State_Init: + /* starting in progress: it is an error */ + ERROR("Service of API %s required started while starting", export->api.apiname); return -1; - } - /* unshare the session if asked */ - if (!share_session) { - rc = afb_export_unshare_session(export); - if (rc < 0) { - ERROR("Can't unshare the session for %s", export->apiname); - return -1; - } + default: + break; } /* set event handling */ +#if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2 switch (export->version) { +#if WITH_LEGACY_BINDING_V1 case Api_Version_1: +#endif +#if WITH_LEGACY_BINDING_V2 case Api_Version_2: - rc = afb_export_handle_events_v12(export, export->on_event.v12); - break; +#endif + if (export->on_any_event_v12) { + rc = afb_export_handle_events_v12(export, export->on_any_event_v12); + break; + } + /*@fallthrough@*/ default: rc = 0; break; } if (rc < 0) { - ERROR("Can't set event handler for %s", export->apiname); + 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_svc_start_before) - afb_hook_svc_start_before(export); + if (export->hooksvc & afb_hook_flag_api_start) + afb_hook_api_start_before(export); +#endif + export->state = Api_State_Init; + init.export = export; + sig_monitor(0, do_init, &init); + 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 */ + ERROR("Initialisation of service API %s failed (%d): %m", export->api.apiname, rc); + return rc; + } + + return 0; +} + +static void api_call_cb(void *closure, struct afb_xreq *xreq) +{ + struct afb_export *export = closure; + + xreq->request.api = to_api_x3(export); + switch (export->version) { +#if WITH_LEGACY_BINDING_V1 case Api_Version_1: - rc = export->init.v1 ? export->init.v1((struct afb_service){ .itf = &hooked_service_itf, .closure = export }) : 0; + afb_api_so_v1_process_call(export->desc.v1, xreq); break; +#endif +#if WITH_LEGACY_BINDING_V2 case Api_Version_2: - rc = export->init.v2 ? export->init.v2() : 0; + afb_api_so_v2_process_call(export->desc.v2, xreq); break; - case Api_Version_Dyn: - rc = export->init.vdyn ? export->init.vdyn(to_dynapi(export)) : 0; +#endif + case Api_Version_3: + afb_api_v3_process_call(export->desc.v3, xreq); break; default: + afb_xreq_reply(xreq, NULL, afb_error_text_internal_error, NULL); break; } - export->state = Api_State_Run; - if (export->hooksvc & afb_hook_flag_svc_start_after) - afb_hook_svc_start_after(export, rc); - if (rc < 0) { - /* initialisation error */ - ERROR("Initialisation of service API %s failed (%d): %m", export->apiname, rc); - return rc; +} + +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 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; + default: + result = NULL; + break; } + describecb(clocb, result); +} -done: - return 0; +static int api_service_start_cb(void *closure) +{ + struct afb_export *export = closure; + + return afb_export_start(export); +} + +#if WITH_AFB_HOOK +static void api_update_hooks_cb(void *closure) + __attribute__((alias("set_interfaces"))); + +void afb_export_update_hooks(struct afb_export *export) + __attribute__((alias("set_interfaces"))); +#endif + +static int api_get_logmask_cb(void *closure) +{ + struct afb_export *export = closure; + + return afb_export_logmask_get(export); +} + +static void api_set_logmask_cb(void *closure, int level) +{ + struct afb_export *export = closure; + + afb_export_logmask_set(export, level); +} + +static void api_unref_cb(void *closure) +{ + struct afb_export *export = closure; + + afb_export_unref(export); +} + +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, + .unref = api_unref_cb +}; + +int afb_export_declare(struct afb_export *export, + int noconcurrency) +{ + int rc; + struct afb_api_item afb_api; + + if (export->declared) + rc = 0; + else { + /* init the record structure */ + afb_api.closure = afb_export_addref(export); + afb_api.itf = &export_api_itf; + afb_api.group = noconcurrency ? export : NULL; + + /* records the binding */ + rc = afb_apiset_add(export->declare_set, export->api.apiname, afb_api); + if (rc >= 0) + export->declared = 1; + else { + ERROR("can't declare export %s to set %s, ABORTING it!", + export->api.apiname, + afb_apiset_name(export->declare_set)); + afb_export_unref(export); + } + } + + return rc; +} + +void afb_export_undeclare(struct afb_export *export) +{ + if (export->declared) { + export->declared = 0; + afb_apiset_del(export->declare_set, export->api.apiname); + } +} + +int afb_export_subscribe(struct afb_export *export, struct afb_event_x2 *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_listener_unwatch_x2(export->listener, event); +} + +void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq) +{ + afb_xreq_process(xreq, export->call_set); +} + +void afb_export_context_init(struct afb_export *export, struct afb_context *context) +{ + afb_context_init_validated(context, export->session, NULL, NULL); }