/*
- * Copyright (C) 2016-2019 "IoT.bzh"
+ * Copyright (C) 2015-2020 "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-cred.h"
#include "afb-evt.h"
#include "afb-export.h"
#include "afb-hook.h"
#include "afb-session.h"
#include "afb-xreq.h"
#include "afb-calls.h"
+#include "afb-error-text.h"
#include "systemd.h"
#include "jobs.h"
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
};
/* 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[];
};
/*****************************************************************************/
}
}
-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 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);
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);
+ 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;
*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;
return apiv3 ? to_api_x3(afb_api_v3_export(apiv3)) : NULL;
}
+#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,
.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)
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;
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;
}
+#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,
};
#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 */
.call = legacy_call_v12,
.call_sync = legacy_call_sync
};
+#endif
#if WITH_AFB_HOOK
static void hooked_call_x3(
return afb_calls_hooked_call_sync(export, api, verb, args, object, error, info);
}
-static void legacy_hooked_call_v12(
+static void legacy_hooked_call_x3(
struct afb_api_x3 *apix3,
const char *api,
const char *verb,
struct json_object *args,
- void (*callback)(void*, int, struct json_object*),
+ void (*callback)(void*, int, struct json_object*, struct afb_api_x3*),
void *closure)
{
struct afb_export *export = from_api_x3(apix3);
- afb_calls_legacy_hooked_call_v12(export, api, verb, args, callback, closure);
+ afb_calls_legacy_hooked_call_v3(export, api, verb, args, callback, closure);
}
-static void legacy_hooked_call_x3(
+static int legacy_hooked_call_sync(
struct afb_api_x3 *apix3,
const char *api,
const char *verb,
struct json_object *args,
- void (*callback)(void*, int, struct json_object*, struct afb_api_x3*),
- void *closure)
+ struct json_object **result)
{
struct afb_export *export = from_api_x3(apix3);
- afb_calls_legacy_hooked_call_v3(export, api, verb, args, callback, closure);
+ return afb_calls_legacy_hooked_call_sync(export, api, verb, args, result);
}
-static int legacy_hooked_call_sync(
+#if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2
+
+static void legacy_hooked_call_v12(
struct afb_api_x3 *apix3,
const char *api,
const char *verb,
struct json_object *args,
- struct json_object **result)
+ void (*callback)(void*, int, struct json_object*),
+ void *closure)
{
struct afb_export *export = from_api_x3(apix3);
- return afb_calls_legacy_hooked_call_sync(export, api, verb, args, result);
+ afb_calls_legacy_hooked_call_v12(export, api, verb, args, callback, closure);
}
/* the interface for services */
};
#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;
}
/*
* 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)
{
const struct globset_handler *handler;
void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*);
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 */
export->api.itf = export->hookditf|export->hooksvc ? &hooked_api_x3_itf : &api_x3_itf;
switch (export->version) {
-#if defined(WITH_LEGACY_BINDING_V1)
+#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 defined(WITH_LEGACY_BINDING_V1)
+#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
return NULL;
}
lenapi = strlen(apiname);
- export = calloc(1, sizeof *export + lenapi + (path == apiname || !path ? 0 : strlen(path)));
+ export = calloc(1, sizeof *export + 1 + lenapi + (path == apiname || !path ? 0 : 1 + strlen(path)));
if (!export)
errno = ENOMEM;
else {
return export;
}
-#if defined(WITH_LEGACY_BINDING_V1)
+#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,
}
#endif
+#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,
}
return export;
}
+#endif
struct afb_export *afb_export_create_v3(struct afb_apiset *declare_set,
struct afb_apiset *call_set,
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){
.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 */
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)
int afb_export_subscribe(struct afb_export *export, struct afb_event_x2 *event)
{
- return afb_evt_event_x2_add_watch(export->listener, event);
+ return afb_evt_listener_watch_x2(export->listener, event);
}
int afb_export_unsubscribe(struct afb_export *export, struct afb_event_x2 *event)
{
- return afb_evt_event_x2_remove_watch(export->listener, event);
+ return afb_evt_listener_unwatch_x2(export->listener, event);
}
void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq)
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, NULL, NULL);
}