/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Copyright (C) 2016-2019 "IoT.bzh"
* Author: José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
#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-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
};
/* unsealed */
unsigned unsealed: 1;
+#if WITH_AFB_HOOK
/* hooking flags */
int hookditf;
int hooksvc;
+#endif
/* session for service */
struct afb_session *session;
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;
/* start function */
union {
-#if defined(WITH_LEGACY_BINDING_V1)
+#if WITH_LEGACY_BINDING_V1
int (*v1)(struct afb_service_x1);
#endif
int (*v2)();
/* 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[];
};
/*****************************************************************************/
json_object_put(save);
}
-static struct json_object *get_settings(const char *name)
+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();
- if (json_object_object_get_ex(configuration, name, &obj))
+ /* 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;
}
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);
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;
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);
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);
*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;
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);
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);
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;
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);
}
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;
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,
.add_alias = hooked_add_alias_cb,
.new_api = hooked_api_new_api_cb,
};
+#endif
+
+#endif
/******************************************************************************
******************************************************************************
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,
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
/******************************************************************************
******************************************************************************
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) {
}
errno = EPERM;
+#else
+ errno = ECANCELED;
+#endif
return -1;
}
{
struct afb_export *export = from_api_x3(api);
struct json_object *result = export->settings;
- if (!result) {
- result = get_settings(export->name);
- export->settings = result;
- }
+ 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)
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,
- .settings = settings_cb,
-};
-
static const struct afb_api_x3_itf hooked_api_x3_itf = {
.vverbose = hooked_vverbose_cb,
.delete_api = hooked_delete_api_cb,
.settings = hooked_settings_cb,
};
+#endif
/******************************************************************************
******************************************************************************
/*
* 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 */
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(
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;
}
/******************************************************************************
******************************************************************************
******************************************************************************/
+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) {
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);
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);
- json_object_put(export->settings);
free(export);
}
}
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;
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;
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;
}
free((void*)export->api.apiname);
export->api.apiname = name;
- afb_export_update_hooks(export);
+ set_interfaces(export);
return 0;
}
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) {
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;
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))
{
return 0;
}
-#if defined(WITH_LEGACY_BINDING_V1)
+#if WITH_LEGACY_BINDING_V1
/*
* Starts a new service (v1)
*/
{
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
}
}
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;
}
/* 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;
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;
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 */
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;
result = NULL;
break;
}
- return result;
+ describecb(clocb, result);
}
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)
{
{
.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,
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);
}
}
void afb_export_context_init(struct afb_export *export, struct afb_context *context)
{
- afb_context_init(context, export->session, NULL);
- context->validated = 1;
+ afb_context_init_validated(context, export->session);
}