#include <ctype.h>
#include <json-c/json.h>
+#if !defined(JSON_C_TO_STRING_NOSLASHESCAPE)
+#define JSON_C_TO_STRING_NOSLASHESCAPE 0
+#endif
#define AFB_BINDING_VERSION 0
#include <afb/afb-binding.h>
#include "afb-calls.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
*/
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 {
} export;
/* initial name */
- char name[1];
+ char name[];
};
/*****************************************************************************/
return to_api_x3(export);
}
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ SETTINGS
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
+
+static struct json_object *configuration;
+
+void afb_export_set_config(struct json_object *config)
+{
+ struct json_object *save = configuration;
+ configuration = json_object_get(config);
+ json_object_put(save);
+}
+
+static struct json_object *make_settings(struct afb_export *export)
+{
+ struct json_object *result;
+ struct json_object *obj;
+ struct afb_export *iter;
+ char *path;
+
+ /* clone the globals */
+ if (json_object_object_get_ex(configuration, "*", &obj))
+ result = wrap_json_clone(obj);
+ else
+ result = json_object_new_object();
+
+ /* add locals */
+ if (json_object_object_get_ex(configuration, export->name, &obj))
+ wrap_json_object_add(result, obj);
+
+ /* add library path */
+ for (iter = export ; iter && !iter->path ; iter = iter->creator);
+ if (iter) {
+ path = realpath(iter->path, NULL);
+ json_object_object_add(result, "binding-path", json_object_new_string(path));
+ free(path);
+ }
+
+ export->settings = result;
+ return result;
+}
+
/******************************************************************************
******************************************************************************
******************************************************************************
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);
}
}
/* 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->api.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;
}
int rc, rc2;
char *iter, *end, save;
+ /* emit a warning about unexpected require in preinit */
+ if (export->state == Api_State_Pre_Init)
+ WARNING("[API %s] requiring apis in pre-init may lead to unexpected result (requires%s: %s)",
+ export->api.apiname, initialized ? " initialized" : "", name);
+
/* scan the names in a local copy */
rc = 0;
iter = strdupa(name);
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;
}
return 0;
}
+static struct json_object *settings_cb(struct afb_api_x3 *api)
+{
+ struct afb_export *export = from_api_x3(api);
+ struct json_object *result = export->settings;
+ if (!result)
+ result = make_settings(export);
+ return result;
+}
+
static int hooked_api_set_verbs_v2_cb(
struct afb_api_x3 *api,
const struct afb_verb_v2 *verbs)
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 api_x3_itf = {
.vverbose = (void*)vverbose_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 = {
.class_require = hooked_class_require_cb,
.delete_api = hooked_delete_api_cb,
+ .settings = hooked_settings_cb,
};
/******************************************************************************
*/
static void listener_of_events(void *closure, const char *event, int 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);
/* hook the event before */
/* 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 (!(export->hooksvc & afb_hook_flag_api_on_event_handler))
+ callback(handler->closure, event, object, to_api_x3(export));
+ 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;
+ } 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);
-
/* hook the event after */
if (export->hooksvc & afb_hook_flag_api_on_event)
afb_hook_api_on_event_after(export, event, eventid, object);
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;
}
/******************************************************************************
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 : 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);
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);
}
#if defined(WITH_LEGACY_BINDING_V1)
-struct afb_export *afb_export_create_v1(
- struct afb_apiset *declare_set,
+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;
}
#endif
-struct afb_export *afb_export_create_v2(
- struct afb_apiset *declare_set,
+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;
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);
}
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;
}