aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--CMakeLists.txt5
-rw-r--r--README.md166
-rw-r--r--bindings/intrinsics/afb-dbus-binding.c40
-rw-r--r--bindings/samples/AuthLogin.c41
-rw-r--r--bindings/samples/CMakeLists.txt24
-rw-r--r--bindings/samples/DemoContext.c83
-rw-r--r--bindings/samples/DemoPost.c43
-rw-r--r--bindings/samples/HelloWorld.c113
-rw-r--r--bindings/samples/ave.c19
-rw-r--r--bindings/samples/hello3.c486
-rw-r--r--bindings/samples/hi3.c485
-rw-r--r--bindings/samples/tic-tac-toe.c237
-rw-r--r--bindings/tutorial/tuto-1.c10
-rw-r--r--bindings/tutorial/tuto-2.c40
-rw-r--r--bindings/tutorial/tuto-3.cpp28
-rw-r--r--book.json4
-rw-r--r--docs/README.md32
-rw-r--r--docs/REVISIONS.md14
-rw-r--r--docs/SUMMARY.md9
-rw-r--r--docs/afb-binding-references.md283
-rw-r--r--docs/afb-binding-writing.md180
-rw-r--r--docs/afb-daemon-debugging.md2
-rw-r--r--docs/afb-daemon-vocabulary.md6
-rw-r--r--docs/afb-migration-to-binding-v3.md110
-rw-r--r--docs/afb-migration-v1-to-v2.md7
-rw-r--r--docs/afb-overview.md6
-rw-r--r--docs/annexes.md5
-rw-r--r--docs/migration-to-binding-v3.sed68
-rw-r--r--doxyfile.binder2435
-rw-r--r--doxyfile.binding2434
-rw-r--r--include/afb/afb-api-x3-itf.h262
-rw-r--r--include/afb/afb-api-x3.h884
-rw-r--r--include/afb/afb-arg.h33
-rw-r--r--include/afb/afb-auth.h49
-rw-r--r--include/afb/afb-binding-postdefs.h92
-rw-r--r--include/afb/afb-binding-predefs.h372
-rw-r--r--include/afb/afb-binding-v1.h188
-rw-r--r--include/afb/afb-binding-v2.h185
-rw-r--r--include/afb/afb-binding-v3.h262
-rw-r--r--include/afb/afb-binding-vdyn.h95
-rw-r--r--include/afb/afb-binding.h283
-rw-r--r--include/afb/afb-binding.hpp334
-rw-r--r--include/afb/afb-daemon-itf-x1.h91
-rw-r--r--include/afb/afb-daemon-itf.h59
-rw-r--r--include/afb/afb-daemon-v1.h101
-rw-r--r--include/afb/afb-daemon-v2.h76
-rw-r--r--include/afb/afb-dynapi-itf.h166
-rw-r--r--include/afb/afb-dynapi-legacy.h191
-rw-r--r--include/afb/afb-dynapi.h302
-rw-r--r--include/afb/afb-event-x1-itf.h32
-rw-r--r--include/afb/afb-event-x1.h (renamed from include/afb/afb-event.h)55
-rw-r--r--include/afb/afb-event-x2-itf.h (renamed from include/afb/afb-eventid-itf.h)42
-rw-r--r--include/afb/afb-event-x2.h113
-rw-r--r--include/afb/afb-eventid.h83
-rw-r--r--include/afb/afb-req-v1.h20
-rw-r--r--include/afb/afb-req-v2.h10
-rw-r--r--include/afb/afb-req-x1-itf.h (renamed from include/afb/afb-req-itf.h)14
-rw-r--r--include/afb/afb-req-x1.h (renamed from include/afb/afb-req.h)268
-rw-r--r--include/afb/afb-req-x2-itf.h306
-rw-r--r--include/afb/afb-req-x2.h758
-rw-r--r--include/afb/afb-request-itf.h205
-rw-r--r--include/afb/afb-request.h389
-rw-r--r--include/afb/afb-service-itf-x1.h (renamed from include/afb/afb-service-itf.h)23
-rw-r--r--include/afb/afb-service-v1.h10
-rw-r--r--include/afb/afb-service-v2.h6
-rw-r--r--include/afb/afb-session-v1.h59
-rw-r--r--include/afb/afb-session-v2.h38
-rw-r--r--include/afb/afb-session-x1.h61
-rw-r--r--include/afb/afb-session-x2.h38
-rw-r--r--include/afb/afb-verbosity.h43
-rw-r--r--memo-supervisor.txt11
-rw-r--r--memo-v3.txt9
-rw-r--r--mkdocs.yml2
-rw-r--r--src/CMakeLists.txt28
-rw-r--r--src/afb-api-dbus.c129
-rw-r--r--src/afb-api-dbus.h4
-rw-r--r--src/afb-api-dyn.c285
-rw-r--r--src/afb-api-dyn.h63
-rw-r--r--src/afb-api-so-v1.c139
-rw-r--r--src/afb-api-so-v1.h10
-rw-r--r--src/afb-api-so-v2.c125
-rw-r--r--src/afb-api-so-v2.h9
-rw-r--r--src/afb-api-so-v3.c128
-rw-r--r--src/afb-api-so-v3.h23
-rw-r--r--src/afb-api-so-vdyn.c27
-rw-r--r--src/afb-api-so-vdyn.h2
-rw-r--r--src/afb-api-so.c86
-rw-r--r--src/afb-api-so.h12
-rw-r--r--src/afb-api-v3.c358
-rw-r--r--src/afb-api-v3.h81
-rw-r--r--src/afb-api-ws.c23
-rw-r--r--src/afb-api-ws.h8
-rw-r--r--src/afb-api.c4
-rw-r--r--src/afb-api.h13
-rw-r--r--src/afb-apiset.c823
-rw-r--r--src/afb-apiset.h47
-rw-r--r--src/afb-auth.c60
-rw-r--r--src/afb-autoset.c104
-rw-r--r--src/afb-autoset.h23
-rw-r--r--src/afb-calls.c818
-rw-r--r--src/afb-calls.h235
-rw-r--r--src/afb-config.c236
-rw-r--r--src/afb-config.h52
-rw-r--r--src/afb-context.c11
-rw-r--r--src/afb-cred.c110
-rw-r--r--src/afb-cred.h7
-rw-r--r--src/afb-evt.c147
-rw-r--r--src/afb-evt.h30
-rw-r--r--src/afb-export.c1774
-rw-r--r--src/afb-export.h115
-rw-r--r--src/afb-hook.c928
-rw-r--r--src/afb-hook.h375
-rw-r--r--src/afb-hreq.c43
-rw-r--r--src/afb-monitor.c96
-rw-r--r--src/afb-monitor.h4
-rw-r--r--src/afb-msg-json.c21
-rw-r--r--src/afb-msg-json.h4
-rw-r--r--src/afb-proto-ws.c306
-rw-r--r--src/afb-proto-ws.h23
-rw-r--r--src/afb-session.c92
-rw-r--r--src/afb-stub-ws.c138
-rw-r--r--src/afb-stub-ws.h4
-rw-r--r--src/afb-supervision.c39
-rw-r--r--src/afb-trace.c591
-rw-r--r--src/afb-trace.h4
-rw-r--r--src/afb-ws-json1.c16
-rw-r--r--src/afb-xreq.c977
-rw-r--r--src/afb-xreq.h89
-rw-r--r--src/afs-config.c6
-rw-r--r--src/afs-supervision.h2
-rw-r--r--src/afs-supervisor.c133
-rw-r--r--src/afs-supervisor.h5
-rw-r--r--src/devtools/genskel.c108
-rw-r--r--src/devtools/monitor-api.json11
-rw-r--r--src/jobs-fake.c4
-rw-r--r--src/jobs.c2
-rw-r--r--src/main-afb-client-demo.c (renamed from src/afb-client-demo.c)83
-rw-r--r--src/main-afb-daemon.c (renamed from src/main.c)56
-rw-r--r--src/main-afs-supervisor.c (renamed from src/afs-main.c)4
-rw-r--r--src/monitor-api.inc39
-rw-r--r--src/pearson.c39
-rw-r--r--src/pearson.h20
-rw-r--r--src/tests/CMakeLists.txt2
-rw-r--r--src/tests/apiset/CMakeLists.txt23
-rw-r--r--src/tests/apiset/test-apiset.c579
-rw-r--r--src/tests/apiv3/CMakeLists.txt24
-rw-r--r--src/tests/apiv3/test-apiv3.c198
-rw-r--r--src/tests/session/test-session.c2
-rw-r--r--src/verbose.c152
-rw-r--r--src/verbose.h50
-rw-r--r--src/wrap-json.c432
-rw-r--r--src/wrap-json.h19
-rw-r--r--test/monitoring/monitor.js4
-rw-r--r--test/tic-tac-toe.html87
155 files changed, 19209 insertions, 6811 deletions
diff --git a/.gitignore b/.gitignore
index 6ca8cc56..b65071cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,5 @@ node_modules/
_book/
*.kdev4
nbproject/*
+docs/binding
+docs/binder
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cda81908..2213f05d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,7 +23,7 @@ PROJECT(afb-daemon C CXX)
SET(PROJECT_NAME "AFB Daemon")
SET(PROJECT_PRETTY_NAME "Application Framework Binder Daemon")
SET(PROJECT_DESCRIPTION "Secured binder of API for clients of the Application framework")
-SET(PROJECT_VERSION "5.99-FFRC0")
+SET(PROJECT_VERSION "5.99-FFRC1")
set(PROJECT_URL "https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=summary")
SET(LIBAFBWSC_VERSION "1.1")
@@ -37,10 +37,13 @@ INCLUDE(CTest)
###########################################################################
# possible settings
+
set(AGL_DEVEL OFF CACHE BOOL "Activates developping features")
set(INCLUDE_MONITORING OFF CACHE BOOL "Activates installation of monitoring")
set(INCLUDE_SUPERVISOR OFF CACHE BOOL "Activates installation of supervisor")
set(INCLUDE_DBUS_TRANSPARENCY OFF CACHE BOOL "Allows API transparency over DBUS")
+set(INCLUDE_LEGACY_BINDING_V1 OFF CACHE BOOL "Includes the legacy Binding API version 1")
+set(INCLUDE_LEGACY_BINDING_VDYN OFF CACHE BOOL "Includes the legacy Binding API version dynamic")
set(AFS_SUPERVISION_SOCKET "@urn:AGL:afs:supervision:socket" CACHE STRING "Internal socket for supervision")
set(AFS_SUPERVISOR_PORT 1619 CACHE STRING "Port of service for the supervisor")
set(AFS_SUPERVISOR_TOKEN HELLO CACHE STRING "Secret token for the supervisor")
diff --git a/README.md b/README.md
index e548bbb9..e69966e9 100644
--- a/README.md
+++ b/README.md
@@ -1,93 +1,154 @@
-### Application Framework Binder
-This is an undergoing work, publication is only intended for developers to review and provide feedback.
+# AGL Framework Binder
-### License
-Apache 2
+This project provides the binder component of the the microservice architecture
+of Automotive Grade Linux (AGL).
+
+This project is available there https://git.automotivelinux.org/src/app-framework-binder/
+
+It can be cloned with **git clone https://git.automotivelinux.org/src/app-framework-binder**.
+
+
+## License and copying
+
+This software is an open source software funded by LinuxFoundation and Renesas.
+
+This software is delivered under the terms of the open source license Apache 2.
+
+This license is available in the file LICENSE-2.0.txt or on the worl wide web at the
+location https://opensource.org/licenses/Apache-2.0
+
+
+## Building
+
+### Requirements
+
+Building the AGL framework binder has been tested under
+ **Ubuntu**, **Debian** and **Fedora 26** with gcc 6 and 7.
+
+It requires the following libraries:
-### Building
-Building Application Framework Binder has been tested under **Ubuntu 16.04 LTS (Xenial Xerus)** or **Fedora 23**, and requires the following libraries:
* libmagic ("libmagic-dev" under Ubuntu, "file-devel" under Fedora);
- * libmicrohttpd >= 0.9.48 (fetch and build from "http://ftp.gnu.org/gnu/libmicrohttpd");
+ * libmicrohttpd >= 0.9.55 (fetch and build from "http://ftp.gnu.org/gnu/libmicrohttpd");
* json-c ("libjson-c-dev/devel");
* uuid ("uuid-dev/libuuid-devel");
* openssl ("libssl-dev/openssl-devel");
* systemd >= 222 ("libsystemd-dev/systemd-devel");
-Optionally, for plugins :
- * alsa ("libasound2-dev/alsa-devel");
- * pulseaudio ("libpulse-dev/libpulse-devel");
- * rtl-sdr >= 0.5.0 ("librtlsdr-dev", or fetch and build from "git://git.osmocom.org/rtl-sdr" under Fedora);
- * GUPnP ("libglib2.0-dev libgupnp-av-1.0-dev/glib2-devel libgupnp-av-devel");
+The following library can be used for checking permissions:
-Libmicrohttpd :
- * version >= 0.9.54
+ * cynara (https://github.com/Samsung/cynara)
and the following tools:
+
* gcc;
- * make;
* pkg-config;
- * cmake >= 2.8.8.
+ * cmake >= 3.0
To install all dependencies under Ubuntu (excepting libmicrohttpd), please type:
-```
-$ apt-get install libmagic-dev libjson-c-dev uuid-dev libsystemd-dev libssl-dev libasound2-dev libpulse-dev librtlsdr-dev libglib2.0-dev libgupnp-av-1.0-dev gcc make pkg-config cmake
-```
+
+ $ apt-get install libmagic-dev libjson-c-dev uuid-dev libsystemd-dev libssl-dev gcc make pkg-config cmake
+
or under Fedora (excepting libmicrohttpd and rtl-sdr):
-```
-$ dnf install git passwd iproute openssh-server openssh-client openssh-server # Tools needed on top of Docker Minimal Fedora
-$ dnf install file-devel gcc gdb make pkgconfig cmake # install gcc development tool chain + cmake
-$ dnf install file-devel json-c-devel libuuid-devel systemd-devel openssl-devel
-$ dnf install alsa-lib-devel pulseaudio-libs-devel glib2-devel gupnp-av-devel # optional but require to build audio plugin
-```
- To build, move to your HOME directory and type:
-```
-$ LIB_MH_VERSION=0.9.54
-$ export LIBMICRODEST=/opt/libmicrohttpd-${LIB_MH_VERSION}
-$ wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-${LIB_MH_VERSION}.tar.gz
-$ tar -xzf libmicrohttpd-${LIB_MH_VERSION}.tar.gz
-$ cd libmicrohttpd-${LIB_MH_VERSION}
-$ ./configure --prefix=${LIBMICRODEST}
-$ make
-$ sudo make install-strip
-
-$ AFB_DAEMON_DIR=$HOME/app-framework-binder
-$ git clone https://gerrit.automotivelinux.org/gerrit/src/app-framework-binder ${AFB_DAEMON_DIR}
-$ cd ${AFB_DAEMON_DIR}
-$ mkdir -p build; cd build<br />
-$ export PKG_CONFIG_PATH=${LIBMICRODEST}/lib/pkgconfig
-$ cmake ..<br />
-$ make;
-$ sudo make install<br />
-```
+ $ dnf install git passwd iproute openssh-server openssh-client
+ $ dnf install file-devel gcc gdb make pkgconfig cmake
+ $ dnf install json-c-devel libuuid-devel systemd-devel openssl-devel
+
+### Simple compilation
+
+The following commands will install the binder in your subdirectory
+**$HOME/local** (instead of **/usr/local** the default when
+*CMAKE_INSTALL_PREFIX* isn't set).
+
+ $ git clone https://git.automotivelinux.org/src/app-framework-binder
+ $ cd app-framework-binder
+ $ mkdir build
+ $ cd build
+ $ cmake -DCMAKE_INSTALL_PREFIX=$HOME/local ..
+ $ make install
+
+### Advanced compilation
+
+You can tune options when calling cmake. Here are the known options with
+their default values.
+
+ $ git clone https://git.automotivelinux.org/src/app-framework-binder
+ $ cd app-framework-binder
+ $ mkdir build
+ $ cd build
+ $ cmake \
+ -DCMAKE_INSTALL_PREFIX=/usr/local \
+ -DAGL_DEVEL=OFF \
+ -DINCLUDE_MONITORING=OFF \
+ -DINCLUDE_SUPERVISOR=OFF \
+ -DINCLUDE_DBUS_TRANSPARENCY=OFF \
+ -DINCLUDE_LEGACY_BINDING_V1=OFF \
+ -DINCLUDE_LEGACY_BINDING_VDYN=OFF \
+ -DAFS_SUPERVISOR_PORT=1619  \
+ -DAFS_SUPERVISOR_TOKEN="HELLO" \
+ -DAFS_SUPERVISION_SOCKET="@urn:AGL:afs:supervision:socket" \
+ -DUNITDIR_SYSTEM=${CMAKE_INSTALL_LIBDIR}/systemd/system \
+ ..
+ $ make install
+
+The configuration options are:
+
+| Variable | Type | Feature
+|:----------------------------|:-------:|:------------------------------
+| AGL_DEVEL | BOOLEAN | Activates development features
+| INCLUDE_MONITORING | BOOLEAN | Activates installation of monitoring
+| INCLUDE_SUPERVISOR | BOOLEAN | Activates installation of supervisor
+| INCLUDE_DBUS_TRANSPARENCY | BOOLEAN | Allows API transparency over DBUS
+| INCLUDE_LEGACY_BINDING_V1 | BOOLEAN | Includes the legacy Binding API version 1
+| INCLUDE_LEGACY_BINDING_VDYN | BOOLEAN | Includes the legacy Binding API version dynamic
+| AFS_SUPERVISOR_PORT | INTEGER | Port of service for the supervisor
+| AFS_SUPERVISOR_TOKEN | STRING | Secret token for the supervisor
+| AFS_SUPERVISION_SOCKET | STRING | Internal socket path for supervision (internal if starts with @)
+| UNITDIR_SYSTEM | STRING | Path to systemd system unit files for installing supervisor
+
+
+
+
+***** TO BE COMPLETED *****
+
+
+
+
+
+
+
+
+
+
+
+
+## Simple demo
+
-### Archive
-```
-VERSION=2.0
-GIT_TAG=master
-PKG_NAME=app-framework-binder
-git archive --format=tar.gz --prefix=agl-${PKG_NAME}-${VERSION}/ ${GIT_TAG} -o agl-${PKG_NAME}_${VERSION}.orig.tar.gz
-```
### Testing/Debug
+
```
$ ${AFB_DAEMON_DIR}/build/src/afb-daemon --help
$ ${AFB_DAEMON_DIR}/build/src/afb-daemon --port=1234 --token='' --ldpaths=${AFB_DAEMON_DIR}/build --sessiondir=/tmp --rootdir=${AFB_DAEMON_DIR}/test
```
### Starting
+
```
$ afb-daemon --help
$ afb-daemon --verbose --port=<port> --token='' --sessiondir=<working directory> --rootdir=<web directory (index.html)>
```
### Example
+
```
$ afb-daemon --verbose --port=1234 --token='' --sessiondir=/tmp --rootdir=/srv/www/htdocs --alias=icons:/usr/share/icons
```
### Directories & Paths
+
Default behaviour is to locate ROOTDIR in $HOME/.AFB
### REST API
@@ -136,4 +197,3 @@ Only use alias for external support static files. This should not be used for AP
### Ongoing work
Javascript plugins. As of today, only C plugins are supported, but JS plugins are on the TODO list.
-
diff --git a/bindings/intrinsics/afb-dbus-binding.c b/bindings/intrinsics/afb-dbus-binding.c
index a5b7d788..51474f6b 100644
--- a/bindings/intrinsics/afb-dbus-binding.c
+++ b/bindings/intrinsics/afb-dbus-binding.c
@@ -23,15 +23,10 @@
#include <systemd/sd-bus.h>
#include <systemd/sd-bus-protocol.h>
-#define AFB_BINDING_VERSION 1
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
/*
- * the interface to afb-daemon
- */
-const struct afb_binding_interface *afbitf;
-
-/*
* union of possible dbus values
*/
union any {
@@ -497,7 +492,7 @@ error:
/*
* handle the reply
*/
-static int on_rawcall_reply(sd_bus_message *msg, struct afb_req *req, sd_bus_error *ret_error)
+static int on_rawcall_reply(sd_bus_message *msg, afb_req_t *req, sd_bus_error *ret_error)
{
struct json_object *obj = NULL;
int rc;
@@ -532,7 +527,7 @@ static int on_rawcall_reply(sd_bus_message *msg, struct afb_req *req, sd_bus_err
* "arguments": "ARRAY of arguments"
* }
*/
-static void rawcall(struct afb_req req)
+static void rawcall(afb_req_t req)
{
struct json_object *obj;
struct json_object *args;
@@ -569,9 +564,9 @@ static void rawcall(struct afb_req req)
/* get bus */
busname = strval(obj, "bus");
if (busname != NULL && !strcmp(busname, "system"))
- bus = afb_daemon_get_system_bus(afbitf->daemon);
+ bus = afb_api_get_system_bus(req->api);
else
- bus = afb_daemon_get_user_bus(afbitf->daemon);
+ bus = afb_api_get_user_bus(req->api);
/* creates the message */
rc = sd_bus_message_new_method_call(bus, &msg, destination, path, interface, member);
@@ -601,32 +596,19 @@ cleanup:
/*
* array of the verbs exported to afb-daemon
*/
-static const struct afb_verb_desc_v1 binding_verbs[] = {
+static const struct afb_verb_v3 binding_verbs[] = {
/* VERB'S NAME SESSION MANAGEMENT FUNCTION TO CALL SHORT DESCRIPTION */
- { .name= "rawcall", .session= AFB_SESSION_NONE, .callback= rawcall, .info= "raw call to dbus method" },
- { .name= NULL } /* marker for end of the array */
+ { .verb= "rawcall", .session= AFB_SESSION_NONE, .callback= rawcall, .info= "raw call to dbus method" },
+ { .verb= NULL } /* marker for end of the array */
};
/*
* description of the binding for afb-daemon
*/
-static const struct afb_binding binding_description =
+const struct afb_binding_v3 afbBindingV3 =
{
- /* description conforms to VERSION 1 */
- .type= AFB_BINDING_VERSION_1,
- .v1= { /* fills the v1 field of the union when AFB_BINDING_VERSION_1 */
- .prefix= "dbus", /* the API name (or binding name or prefix) */
- .info= "raw dbus binding", /* short description of of the binding */
+ .api = "dbus", /* the API name (or binding name or prefix) */
+ .info = "raw dbus binding", /* short description of of the binding */
.verbs = binding_verbs /* the array describing the verbs of the API */
- }
};
-/*
- * activation function for registering the binding called by afb-daemon
- */
-const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf)
-{
- afbitf = itf; /* records the interface for accessing afb-daemon */
- return &binding_description; /* returns the description of the binding */
-}
-
diff --git a/bindings/samples/AuthLogin.c b/bindings/samples/AuthLogin.c
index a71f7d6e..0f29dd0d 100644
--- a/bindings/samples/AuthLogin.c
+++ b/bindings/samples/AuthLogin.c
@@ -19,7 +19,7 @@
#include <stdio.h>
#include <json-c/json.h>
-#define AFB_BINDING_VERSION 1
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
// Dummy sample of Client Application Context
@@ -37,7 +37,7 @@ static void clientContextFree(void *context) {
}
// Request Creation of new context if it does not exist
-static void clientContextConnect (struct afb_req request)
+static void clientContextConnect (afb_req_t request)
{
json_object *jresp;
@@ -56,7 +56,7 @@ static void clientContextConnect (struct afb_req request)
}
// Before entering here token will be check and renew
-static void clientContextRefresh (struct afb_req request) {
+static void clientContextRefresh (afb_req_t request) {
json_object *jresp;
@@ -68,7 +68,7 @@ static void clientContextRefresh (struct afb_req request) {
// Session token will we verified before entering here
-static void clientContextCheck (struct afb_req request) {
+static void clientContextCheck (afb_req_t request) {
json_object *jresp = json_object_new_object();
json_object_object_add(jresp, "isvalid", json_object_new_boolean (TRUE));
@@ -78,7 +78,7 @@ static void clientContextCheck (struct afb_req request) {
// Close and Free context
-static void clientContextLogout (struct afb_req request) {
+static void clientContextLogout (afb_req_t request) {
json_object *jresp;
/* after this call token will be reset
@@ -95,7 +95,7 @@ static void clientContextLogout (struct afb_req request) {
afb_req_session_set_LOA(request, 0);
}
// Close and Free context
-static void clientGetPing (struct afb_req request) {
+static void clientGetPing (afb_req_t request) {
static int count=0;
json_object *jresp;
@@ -106,25 +106,18 @@ static void clientGetPing (struct afb_req request) {
}
-static const struct afb_verb_desc_v1 verbs[]= {
- {"ping" , AFB_SESSION_NONE , clientGetPing ,"Ping Rest Test Service"},
- {"connect" , AFB_SESSION_LOA_EQ_0 | AFB_SESSION_RENEW, clientContextConnect,"Connect/Login Client"},
- {"refresh" , AFB_SESSION_LOA_GE_1 | AFB_SESSION_RENEW, clientContextRefresh,"Refresh Client Authentication Token"},
- {"check" , AFB_SESSION_LOA_GE_1 , clientContextCheck ,"Check Client Authentication Token"},
- {"logout" , AFB_SESSION_LOA_GE_1 | AFB_SESSION_CLOSE, clientContextLogout ,"Logout Client and Free resources"},
+static const struct afb_verb_v3 verbs[]= {
+ {.verb="ping" , .session=AFB_SESSION_NONE , .callback=clientGetPing ,.info="Ping Rest Test Service"},
+ {.verb="connect" , .session=AFB_SESSION_LOA_0 | AFB_SESSION_RENEW, .callback=clientContextConnect,.info="Connect/Login Client"},
+ {.verb="refresh" , .session=AFB_SESSION_LOA_1 | AFB_SESSION_RENEW, .callback=clientContextRefresh,.info="Refresh Client Authentication Token"},
+ {.verb="check" , .session=AFB_SESSION_LOA_1 , .callback=clientContextCheck ,.info="Check Client Authentication Token"},
+ {.verb="logout" , .session=AFB_SESSION_LOA_1 | AFB_SESSION_CLOSE, .callback=clientContextLogout ,.info="Logout Client and Free resources"},
{NULL}
};
-static const struct afb_binding plugin_desc = {
- .type = AFB_BINDING_VERSION_1,
- .v1 = {
- .info = "Application Framework Binder Authentication sample",
- .prefix = "auth",
- .verbs = verbs
- }
-};
-
-const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
+const struct afb_binding_v3 afbBindingV3 =
{
- return &plugin_desc;
-}
+ .api = "auth", /* the API name (or binding name or prefix) */
+ .info = "Application Framework Binder Authentication sample", /* short description of of the binding */
+ .verbs = verbs /* the array describing the verbs of the API */
+};
diff --git a/bindings/samples/CMakeLists.txt b/bindings/samples/CMakeLists.txt
index f596c333..d4e85e30 100644
--- a/bindings/samples/CMakeLists.txt
+++ b/bindings/samples/CMakeLists.txt
@@ -91,3 +91,27 @@ TARGET_LINK_LIBRARIES(tic-tac-toe ${link_libraries})
INSTALL(TARGETS tic-tac-toe
LIBRARY DESTINATION ${binding_install_dir})
+##################################################
+# hi3
+##################################################
+ADD_LIBRARY(hi3 MODULE hi3.c)
+SET_TARGET_PROPERTIES(hi3 PROPERTIES
+ PREFIX ""
+ LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map"
+)
+TARGET_LINK_LIBRARIES(hi3 ${link_libraries})
+INSTALL(TARGETS hi3
+ LIBRARY DESTINATION ${binding_install_dir})
+
+##################################################
+# hello3
+##################################################
+ADD_LIBRARY(hello3 MODULE hello3.c)
+SET_TARGET_PROPERTIES(hello3 PROPERTIES
+ PREFIX ""
+ LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map"
+)
+TARGET_LINK_LIBRARIES(hello3 ${link_libraries})
+INSTALL(TARGETS hello3
+ LIBRARY DESTINATION ${binding_install_dir})
+
diff --git a/bindings/samples/DemoContext.c b/bindings/samples/DemoContext.c
index bf35ab17..09f1764e 100644
--- a/bindings/samples/DemoContext.c
+++ b/bindings/samples/DemoContext.c
@@ -19,7 +19,7 @@
#include <stdio.h>
#include <json-c/json.h>
-#define AFB_BINDING_VERSION 1
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
typedef struct {
@@ -48,7 +48,7 @@ typedef struct {
// This function is call at session open time. Any client trying to
// call it with an already open session will be denied.
// Ex: http://localhost:1234/api/context/create?token=123456789
-static void myCreate (struct afb_req request)
+static void myCreate (afb_req_t request)
{
MyClientContextT *ctx = malloc (sizeof (MyClientContextT));
@@ -64,7 +64,7 @@ static void myCreate (struct afb_req request)
// session timeout a standard renew api is avaliable at /api/token/renew this API
// can be called automatically with <token-renew> HTML5 widget.
// ex: http://localhost:1234/api/context/action?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx
-static void myAction (struct afb_req request)
+static void myAction (afb_req_t request)
{
MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request);
@@ -81,7 +81,7 @@ static void myAction (struct afb_req request)
// created a context [request->context != NULL] every plugins will be notified
// that they should free context resources.
// ex: http://localhost:1234/api/context/close?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx
-static void myClose (struct afb_req request)
+static void myClose (afb_req_t request)
{
MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request);
@@ -95,75 +95,44 @@ static void myClose (struct afb_req request)
}
// Set the LOA
-static void setLOA(struct afb_req request, unsigned loa)
+static void setLOA(afb_req_t request, unsigned loa)
{
- if (afb_req_session_set_LOA(request, loa))
+ if (afb_req_session_set_LOA(request, loa) >= 0)
afb_req_success_f(request, NULL, "loa set to %u", loa);
else
afb_req_fail_f(request, "failed", "can't set loa to %u", loa);
}
-static void clientSetLOA0(struct afb_req request)
+static void clientSetLOA(afb_req_t request)
{
- setLOA(request, 0);
+ setLOA(request, (unsigned)(intptr_t)request->vcbdata);
}
-static void clientSetLOA1(struct afb_req request)
-{
- setLOA(request, 1);
-}
-
-static void clientSetLOA2(struct afb_req request)
-{
- setLOA(request, 2);
-}
-
-static void clientSetLOA3(struct afb_req request)
-{
- setLOA(request, 3);
-}
-
-static void clientCheckLOA(struct afb_req request)
+static void clientCheckLOA(afb_req_t request)
{
afb_req_success(request, NULL, "LOA checked and okay");
}
// NOTE: this sample does not use session to keep test a basic as possible
// in real application most APIs should be protected with AFB_SESSION_CHECK
-static const struct afb_verb_desc_v1 verbs[]= {
- {"create", AFB_SESSION_CREATE, myCreate , "Create a new session"},
- {"action", AFB_SESSION_CHECK , myAction , "Use Session Context"},
- {"close" , AFB_SESSION_CLOSE , myClose , "Free Context"},
- {"set_loa_0", AFB_SESSION_RENEW, clientSetLOA0 ,"Set level of assurance to 0"},
- {"set_loa_1", AFB_SESSION_RENEW, clientSetLOA1 ,"Set level of assurance to 1"},
- {"set_loa_2", AFB_SESSION_RENEW, clientSetLOA2 ,"Set level of assurance to 2"},
- {"set_loa_3", AFB_SESSION_RENEW, clientSetLOA3 ,"Set level of assurance to 3"},
- {"check_loa_ge_0", AFB_SESSION_LOA_GE_0, clientCheckLOA ,"Check whether level of assurance is greater or equal to 0"},
- {"check_loa_ge_1", AFB_SESSION_LOA_GE_1, clientCheckLOA ,"Check whether level of assurance is greater or equal to 1"},
- {"check_loa_ge_2", AFB_SESSION_LOA_GE_2, clientCheckLOA ,"Check whether level of assurance is greater or equal to 2"},
- {"check_loa_ge_3", AFB_SESSION_LOA_GE_3, clientCheckLOA ,"Check whether level of assurance is greater or equal to 3"},
- {"check_loa_le_0", AFB_SESSION_LOA_LE_0, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 0"},
- {"check_loa_le_1", AFB_SESSION_LOA_LE_1, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 1"},
- {"check_loa_le_2", AFB_SESSION_LOA_LE_2, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 2"},
- {"check_loa_le_3", AFB_SESSION_LOA_LE_3, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 3"},
- {"check_loa_eq_0", AFB_SESSION_LOA_EQ_0, clientCheckLOA ,"Check whether level of assurance is equal to 0"},
- {"check_loa_eq_1", AFB_SESSION_LOA_EQ_1, clientCheckLOA ,"Check whether level of assurance is equal to 1"},
- {"check_loa_eq_2", AFB_SESSION_LOA_EQ_2, clientCheckLOA ,"Check whether level of assurance is equal to 2"},
- {"check_loa_eq_3", AFB_SESSION_LOA_EQ_3, clientCheckLOA ,"Check whether level of assurance is equal to 3"},
+static const struct afb_verb_v3 verbs[]= {
+ {.verb="create", .session=AFB_SESSION_NONE, .callback=myCreate , .info="Create a new session"},
+ {.verb="action", .session=AFB_SESSION_CHECK , .callback=myAction , .info="Use Session Context"},
+ {.verb="close" , .session=AFB_SESSION_CLOSE , .callback=myClose , .info="Free Context"},
+ {.verb="set_loa_0", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)0 ,.info="Set level of assurance to 0"},
+ {.verb="set_loa_1", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)1 ,.info="Set level of assurance to 1"},
+ {.verb="set_loa_2", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)2 ,.info="Set level of assurance to 2"},
+ {.verb="set_loa_3", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)3 ,.info="Set level of assurance to 3"},
+ {.verb="check_loa_ge_0", .session=AFB_SESSION_LOA_0, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)0 ,.info="Check whether level of assurance is greater or equal to 0"},
+ {.verb="check_loa_ge_1", .session=AFB_SESSION_LOA_1, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)1 ,.info="Check whether level of assurance is greater or equal to 1"},
+ {.verb="check_loa_ge_2", .session=AFB_SESSION_LOA_2, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)2 ,.info="Check whether level of assurance is greater or equal to 2"},
+ {.verb="check_loa_ge_3", .session=AFB_SESSION_LOA_3, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)3 ,.info="Check whether level of assurance is greater or equal to 3"},
{NULL}
};
-static const struct afb_binding plugin_desc = {
- .type = AFB_BINDING_VERSION_1,
- .v1 = {
- .info = "Sample of Client Context Usage",
- .prefix = "context",
- .verbs = verbs,
- }
-};
-
-const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
+const struct afb_binding_v3 afbBindingV3 =
{
- return &plugin_desc;
-}
-
+ .api = "context", /* the API name (or binding name or prefix) */
+ .info = "Sample of Client Context Usage", /* short description of of the binding */
+ .verbs = verbs /* the array describing the verbs of the API */
+};
diff --git a/bindings/samples/DemoPost.c b/bindings/samples/DemoPost.c
index d92d502f..3fd6f983 100644
--- a/bindings/samples/DemoPost.c
+++ b/bindings/samples/DemoPost.c
@@ -20,12 +20,12 @@
#include <string.h>
#include <json-c/json.h>
-#define AFB_BINDING_VERSION 1
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
// Sample Generic Ping Debug API
-static void getPingTest(struct afb_req request)
+static void getPingTest(afb_req_t request)
{
static int pingcount = 0;
json_object *query = afb_req_json(request);
@@ -34,7 +34,7 @@ static void getPingTest(struct afb_req request)
}
// With content-type=json data are directly avaliable in request->post->data
-static void GetJsonByPost (struct afb_req request)
+static void GetJsonByPost (afb_req_t request)
{
struct afb_arg arg;
json_object* jresp;
@@ -46,7 +46,7 @@ static void GetJsonByPost (struct afb_req request)
}
// Upload a file and execute a function when upload is done
-static void Uploads (struct afb_req request, const char *destination)
+static void Uploads (afb_req_t request, const char *destination)
{
struct afb_arg a = afb_req_get(request, "file");
if (a.value == NULL || *a.value == 0)
@@ -56,20 +56,20 @@ static void Uploads (struct afb_req request, const char *destination)
}
// Upload a file and execute a function when upload is done
-static void UploadAppli (struct afb_req request)
+static void UploadAppli (afb_req_t request)
{
Uploads(request, "applications");
}
// Simples Upload case just upload a file
-static void UploadMusic (struct afb_req request)
+static void UploadMusic (afb_req_t request)
{
Uploads(request, "musics");
}
// PostForm callback is called multiple times (one or each key within form, or once per file buffer)
// When file has been fully uploaded call is call with item==NULL
-static void UploadImage (struct afb_req request)
+static void UploadImage (afb_req_t request)
{
Uploads(request, "images");
}
@@ -77,25 +77,18 @@ static void UploadImage (struct afb_req request)
// NOTE: this sample does not use session to keep test a basic as possible
// in real application upload-xxx should be protected with AFB_SESSION_CHECK
-static const struct afb_verb_desc_v1 verbs[]= {
- {"ping" , AFB_SESSION_NONE , getPingTest ,"Ping Rest Test Service"},
- {"upload-json" , AFB_SESSION_NONE , GetJsonByPost ,"Demo for Json Buffer on Post"},
- {"upload-image" , AFB_SESSION_NONE , UploadImage ,"Demo for file upload"},
- {"upload-music" , AFB_SESSION_NONE , UploadMusic ,"Demo for file upload"},
- {"upload-appli" , AFB_SESSION_NONE , UploadAppli ,"Demo for file upload"},
- {NULL}
+static const struct afb_verb_v3 verbs[]= {
+ {.verb="ping" , .session=AFB_SESSION_NONE , .callback=getPingTest ,.info="Ping Rest Test Service"},
+ {.verb="upload-json" , .session=AFB_SESSION_NONE , .callback=GetJsonByPost ,.info="Demo for Json Buffer on Post"},
+ {.verb="upload-image" , .session=AFB_SESSION_NONE , .callback=UploadImage ,.info="Demo for file upload"},
+ {.verb="upload-music" , .session=AFB_SESSION_NONE , .callback=UploadMusic ,.info="Demo for file upload"},
+ {.verb="upload-appli" , .session=AFB_SESSION_NONE , .callback=UploadAppli ,.info="Demo for file upload"},
+ {.verb=NULL}
};
-static const struct afb_binding plugin_desc = {
- .type = AFB_BINDING_VERSION_1,
- .v1 = {
- .info = "Sample with Post Upload Files",
- .prefix = "post",
- .verbs = verbs
- }
+const struct afb_binding_v3 afbBindingV3 = {
+ .info = "Sample with Post Upload Files",
+ .api = "post",
+ .verbs = verbs
};
-const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
-{
- return &plugin_desc;
-};
diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c
index fef87d2d..92d7c4d2 100644
--- a/bindings/samples/HelloWorld.c
+++ b/bindings/samples/HelloWorld.c
@@ -21,7 +21,7 @@
#include <json-c/json.h>
-#define AFB_BINDING_VERSION 2
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -29,7 +29,7 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
struct event
{
struct event *next;
- struct afb_event event;
+ afb_event_t event;
char tag[1];
};
@@ -80,7 +80,7 @@ static int event_add(const char *tag, const char *name)
/* make the event */
e->event = afb_daemon_make_event(name);
- if (!e->event.closure) { free(e); return -1; }
+ if (!e->event) { free(e); return -1; }
/* link */
e->next = events;
@@ -88,14 +88,14 @@ static int event_add(const char *tag, const char *name)
return 0;
}
-static int event_subscribe(afb_req request, const char *tag)
+static int event_subscribe(afb_req_t request, const char *tag)
{
struct event *e;
e = event_get(tag);
return e ? afb_req_subscribe(request, e->event) : -1;
}
-static int event_unsubscribe(afb_req request, const char *tag)
+static int event_unsubscribe(afb_req_t request, const char *tag)
{
struct event *e;
e = event_get(tag);
@@ -117,34 +117,34 @@ static int event_broadcast(struct json_object *args, const char *tag)
}
// Sample Generic Ping Debug API
-static void ping(afb_req request, json_object *jresp, const char *tag)
+static void ping(afb_req_t request, json_object *jresp, const char *tag)
{
static int pingcount = 0;
json_object *query = afb_req_json(request);
afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query));
}
-static void pingSample (afb_req request)
+static void pingSample (afb_req_t request)
{
ping(request, json_object_new_string ("Some String"), "pingSample");
}
-static void pingFail (afb_req request)
+static void pingFail (afb_req_t request)
{
afb_req_fail(request, "failed", "Ping Binder Daemon fails");
}
-static void pingNull (afb_req request)
+static void pingNull (afb_req_t request)
{
ping(request, NULL, "pingNull");
}
-static void pingBug (afb_req request)
+static void pingBug (afb_req_t request)
{
- ping((afb_req){NULL,NULL}, NULL, "pingBug");
+ ping(NULL, NULL, "pingBug");
}
-static void pingEvent(afb_req request)
+static void pingEvent(afb_req_t request)
{
json_object *query = afb_req_json(request);
afb_daemon_broadcast_event("event", json_object_get(query));
@@ -153,7 +153,7 @@ static void pingEvent(afb_req request)
// For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/
-static void pingJson (afb_req request) {
+static void pingJson (afb_req_t request) {
json_object *jresp, *embed;
jresp = json_object_new_object();
@@ -169,38 +169,12 @@ static void pingJson (afb_req request) {
ping(request, jresp, "pingJson");
}
-static void subcallcb (void *prequest, int status, json_object *object)
+static void subcallcb (void *closure, json_object *object, const char *error, const char *info, afb_req_t request)
{
- afb_req request = afb_req_unstore(prequest);
- if (status < 0)
- afb_req_fail(request, "failed", json_object_to_json_string(object));
- else
- afb_req_success(request, json_object_get(object), NULL);
- afb_req_unref(request);
-}
-
-static void subcall (afb_req request)
-{
- const char *api = afb_req_value(request, "api");
- const char *verb = afb_req_value(request, "verb");
- const char *args = afb_req_value(request, "args");
- json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
-
- if (object == NULL)
- afb_req_fail(request, "failed", "bad arguments");
- else
- afb_req_subcall(request, api, verb, object, subcallcb, afb_req_store(request));
-}
-
-static void subcallreqcb (void *prequest, int status, json_object *object, afb_req request)
-{
- if (status < 0)
- afb_req_fail(request, "failed", json_object_to_json_string(object));
- else
- afb_req_success(request, json_object_get(object), NULL);
+ afb_req_reply(request, json_object_get(object), error, info);
}
-static void subcallreq (afb_req request)
+static void subcall (afb_req_t request)
{
const char *api = afb_req_value(request, "api");
const char *verb = afb_req_value(request, "verb");
@@ -210,10 +184,10 @@ static void subcallreq (afb_req request)
if (object == NULL)
afb_req_fail(request, "failed", "bad arguments");
else
- afb_req_subcall_req(request, api, verb, object, subcallreqcb, NULL);
+ afb_req_subcall(request, api, verb, object, afb_req_subcall_pass_events, subcallcb, NULL);
}
-static void subcallsync (afb_req request)
+static void subcallsync (afb_req_t request)
{
int rc;
const char *api = afb_req_value(request, "api");
@@ -224,7 +198,7 @@ static void subcallsync (afb_req request)
if (object == NULL)
afb_req_fail(request, "failed", "bad arguments");
else {
- rc = afb_req_subcall_sync(request, api, verb, object, &result);
+ rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result);
if (rc >= 0)
afb_req_success(request, result, NULL);
else {
@@ -234,7 +208,7 @@ static void subcallsync (afb_req request)
}
}
-static void eventadd (afb_req request)
+static void eventadd (afb_req_t request)
{
const char *tag = afb_req_value(request, "tag");
const char *name = afb_req_value(request, "name");
@@ -249,7 +223,7 @@ static void eventadd (afb_req request)
pthread_mutex_unlock(&mutex);
}
-static void eventdel (afb_req request)
+static void eventdel (afb_req_t request)
{
const char *tag = afb_req_value(request, "tag");
@@ -263,7 +237,7 @@ static void eventdel (afb_req request)
pthread_mutex_unlock(&mutex);
}
-static void eventsub (afb_req request)
+static void eventsub (afb_req_t request)
{
const char *tag = afb_req_value(request, "tag");
@@ -277,7 +251,7 @@ static void eventsub (afb_req request)
pthread_mutex_unlock(&mutex);
}
-static void eventunsub (afb_req request)
+static void eventunsub (afb_req_t request)
{
const char *tag = afb_req_value(request, "tag");
@@ -291,7 +265,7 @@ static void eventunsub (afb_req request)
pthread_mutex_unlock(&mutex);
}
-static void eventpush (afb_req request)
+static void eventpush (afb_req_t request)
{
const char *tag = afb_req_value(request, "tag");
const char *data = afb_req_value(request, "data");
@@ -308,9 +282,9 @@ static void eventpush (afb_req request)
json_object_put(object);
}
-static void callcb (void *prequest, int status, json_object *object)
+static void callcb (void *prequest, int status, json_object *object, afb_api_t api)
{
- afb_req request = afb_req_unstore(prequest);
+ afb_req_t request = prequest;
if (status < 0)
afb_req_fail(request, "failed", json_object_to_json_string(object));
else
@@ -318,7 +292,7 @@ static void callcb (void *prequest, int status, json_object *object)
afb_req_unref(request);
}
-static void call (afb_req request)
+static void call (afb_req_t request)
{
const char *api = afb_req_value(request, "api");
const char *verb = afb_req_value(request, "verb");
@@ -328,10 +302,10 @@ static void call (afb_req request)
if (object == NULL)
afb_req_fail(request, "failed", "bad arguments");
else
- afb_service_call(api, verb, object, callcb, afb_req_store(request));
+ afb_service_call(api, verb, object, callcb, afb_req_addref(request));
}
-static void callsync (afb_req request)
+static void callsync (afb_req_t request)
{
int rc;
const char *api = afb_req_value(request, "api");
@@ -352,7 +326,7 @@ static void callsync (afb_req request)
}
}
-static void verbose (afb_req request)
+static void verbose (afb_req_t request)
{
int level = 5;
json_object *query = afb_req_json(request), *l;
@@ -369,7 +343,7 @@ static void verbose (afb_req request)
afb_req_success(request, NULL, NULL);
}
-static void exitnow (afb_req request)
+static void exitnow (afb_req_t request)
{
int code = 0;
json_object *query = afb_req_json(request), *l;
@@ -387,7 +361,7 @@ static void exitnow (afb_req request)
exit(code);
}
-static void broadcast(afb_req request)
+static void broadcast(afb_req_t request)
{
const char *tag = afb_req_value(request, "tag");
const char *name = afb_req_value(request, "name");
@@ -412,7 +386,7 @@ static void broadcast(afb_req request)
json_object_put(object);
}
-static void hasperm (afb_req request)
+static void hasperm (afb_req_t request)
{
const char *perm = afb_req_value(request, "perm");
if (afb_req_has_permission(request, perm))
@@ -421,39 +395,39 @@ static void hasperm (afb_req request)
afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)");
}
-static void appid (afb_req request)
+static void appid (afb_req_t request)
{
char *aid = afb_req_get_application_id(request);
afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?");
free(aid);
}
-static void uid (afb_req request)
+static void uid (afb_req_t request)
{
int uid = afb_req_get_uid(request);
afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid);
}
-static int preinit()
+static int preinit(afb_api_t api)
{
- AFB_NOTICE("hello binding comes to live");
+ AFB_API_NOTICE(api, "hello binding comes to live");
return 0;
}
-static int init()
+static int init(afb_api_t api)
{
- AFB_NOTICE("hello binding starting");
+ AFB_API_NOTICE(api, "hello binding starting");
return 0;
}
-static void onevent(const char *event, struct json_object *object)
+static void onevent(afb_api_t api, const char *event, struct json_object *object)
{
- AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
+ AFB_API_NOTICE(api, "received event %s(%s)", event, json_object_to_json_string(object));
}
// NOTE: this sample does not use session to keep test a basic as possible
// in real application most APIs should be protected with AFB_SESSION_CHECK
-static const afb_verb_v2 verbs[]= {
+static const struct afb_verb_v3 verbs[]= {
{ .verb="ping", .callback=pingSample },
{ .verb="pingfail", .callback=pingFail },
{ .verb="pingnull", .callback=pingNull },
@@ -461,7 +435,6 @@ static const afb_verb_v2 verbs[]= {
{ .verb="pingJson", .callback=pingJson },
{ .verb="pingevent", .callback=pingEvent },
{ .verb="subcall", .callback=subcall },
- { .verb="subcallreq", .callback=subcallreq },
{ .verb="subcallsync", .callback=subcallsync },
{ .verb="eventadd", .callback=eventadd },
{ .verb="eventdel", .callback=eventdel },
@@ -479,7 +452,7 @@ static const afb_verb_v2 verbs[]= {
{ .verb=NULL}
};
-const afb_binding_v2 afbBindingV2 = {
+const struct afb_binding_v3 afbBindingV3 = {
.api = "hello",
.specification = NULL,
.verbs = verbs,
diff --git a/bindings/samples/ave.c b/bindings/samples/ave.c
index 5661e9a5..ce01c6dc 100644
--- a/bindings/samples/ave.c
+++ b/bindings/samples/ave.c
@@ -21,6 +21,7 @@
#include <json-c/json.h>
+#define AFB_BINDING_WANT_DYNAPI
#define AFB_BINDING_VERSION 0
#include <afb/afb-binding.h>
@@ -147,7 +148,7 @@ static void pingBug (afb_request *request)
static void pingEvent(afb_request *request)
{
json_object *query = afb_request_json(request);
- afb_dynapi_broadcast_event(request->dynapi, "event", json_object_get(query));
+ afb_dynapi_broadcast_event(request->api, "event", json_object_get(query));
ping(request, json_object_get(query), "event");
}
@@ -219,7 +220,7 @@ static void eventadd (afb_request *request)
pthread_mutex_lock(&mutex);
if (tag == NULL || name == NULL)
afb_request_fail(request, "failed", "bad arguments");
- else if (0 != event_add(request->dynapi, tag, name))
+ else if (0 != event_add(request->api, tag, name))
afb_request_fail(request, "failed", "creation error");
else
afb_request_success(request, NULL, NULL);
@@ -305,7 +306,7 @@ static void call (afb_request *request)
if (object == NULL)
afb_request_fail(request, "failed", "bad arguments");
else
- afb_dynapi_call(request->dynapi, api, verb, object, callcb, afb_request_addref(request));
+ afb_dynapi_call(request->api, api, verb, object, callcb, afb_request_addref(request));
}
static void callsync (afb_request *request)
@@ -319,7 +320,7 @@ static void callsync (afb_request *request)
if (object == NULL)
afb_request_fail(request, "failed", "bad arguments");
else {
- rc = afb_dynapi_call_sync(request->dynapi, api, verb, object, &result);
+ rc = afb_dynapi_call_sync(request->api, api, verb, object, &result);
if (rc >= 0)
afb_request_success(request, result, NULL);
else {
@@ -379,7 +380,7 @@ static void broadcast(afb_request *request)
afb_request_success(request, NULL, NULL);
pthread_mutex_unlock(&mutex);
} else if (name != NULL) {
- if (0 > afb_dynapi_broadcast_event(request->dynapi, name, object))
+ if (0 > afb_dynapi_broadcast_event(request->api, name, object))
afb_request_fail(request, "failed", "broadcast error");
else
afb_request_success(request, NULL, NULL);
@@ -447,13 +448,13 @@ static const struct {
{ .verb=NULL}
};
-static void pingoo(afb_req req)
+static void pingoo(struct afb_req_x1 req)
{
- json_object *args = afb_req_json(req);
- afb_req_success_f(req, json_object_get(args), "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args));
+ json_object *args = afb_req_x1_json(req);
+ afb_req_x1_reply_f(req, json_object_get(args), NULL, "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args));
}
-static const afb_verb_v2 verbsv2[]= {
+static const struct afb_verb_v2 verbsv2[]= {
{ .verb="pingoo", .callback=pingoo },
{ .verb="ping", .callback=pingoo },
{ .verb=NULL}
diff --git a/bindings/samples/hello3.c b/bindings/samples/hello3.c
new file mode 100644
index 00000000..ae70d1e5
--- /dev/null
+++ b/bindings/samples/hello3.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2015-2018 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <json-c/json.h>
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+struct event
+{
+ struct event *next;
+ afb_event_t event;
+ char tag[1];
+};
+
+static struct event *events = 0;
+
+/* searchs the event of tag */
+static struct event *event_get(const char *tag)
+{
+ struct event *e = events;
+ while(e && strcmp(e->tag, tag))
+ e = e->next;
+ return e;
+}
+
+/* deletes the event of tag */
+static int event_del(const char *tag)
+{
+ struct event *e, **p;
+
+ /* check exists */
+ e = event_get(tag);
+ if (!e) return -1;
+
+ /* unlink */
+ p = &events;
+ while(*p != e) p = &(*p)->next;
+ *p = e->next;
+
+ /* destroys */
+ afb_event_unref(e->event);
+ free(e);
+ return 0;
+}
+
+/* creates the event of tag */
+static int event_add(const char *tag, const char *name)
+{
+ struct event *e;
+
+ /* check valid tag */
+ e = event_get(tag);
+ if (e) return -1;
+
+ /* creation */
+ e = malloc(strlen(tag) + sizeof *e);
+ if (!e) return -1;
+ strcpy(e->tag, tag);
+
+ /* make the event */
+ e->event = afb_daemon_make_event(name);
+ if (!e->event) { free(e); return -1; }
+
+ /* link */
+ e->next = events;
+ events = e;
+ return 0;
+}
+
+static int event_subscribe(afb_req_t request, const char *tag)
+{
+ struct event *e;
+ e = event_get(tag);
+ return e ? afb_req_subscribe(request, e->event) : -1;
+}
+
+static int event_unsubscribe(afb_req_t request, const char *tag)
+{
+ struct event *e;
+ e = event_get(tag);
+ return e ? afb_req_unsubscribe(request, e->event) : -1;
+}
+
+static int event_push(struct json_object *args, const char *tag)
+{
+ struct event *e;
+ e = event_get(tag);
+ return e ? afb_event_push(e->event, json_object_get(args)) : -1;
+}
+
+static int event_broadcast(struct json_object *args, const char *tag)
+{
+ struct event *e;
+ e = event_get(tag);
+ return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1;
+}
+
+// Sample Generic Ping Debug API
+static void ping(afb_req_t request, json_object *jresp, const char *tag)
+{
+ static int pingcount = 0;
+ json_object *query = afb_req_json(request);
+ afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query));
+}
+
+static void pingSample (afb_req_t request)
+{
+ ping(request, json_object_new_string ("Some String"), "pingSample");
+}
+
+static void pingFail (afb_req_t request)
+{
+ afb_req_fail(request, "failed", "Ping Binder Daemon fails");
+}
+
+static void pingNull (afb_req_t request)
+{
+ ping(request, NULL, "pingNull");
+}
+
+static void pingBug (afb_req_t request)
+{
+ ping(NULL, NULL, "pingBug");
+}
+
+static void pingEvent(afb_req_t request)
+{
+ json_object *query = afb_req_json(request);
+ afb_daemon_broadcast_event("event", json_object_get(query));
+ ping(request, json_object_get(query), "event");
+}
+
+
+// For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/
+static void pingJson (afb_req_t request) {
+ json_object *jresp, *embed;
+
+ jresp = json_object_new_object();
+ json_object_object_add(jresp, "myString", json_object_new_string ("Some String"));
+ json_object_object_add(jresp, "myInt", json_object_new_int (1234));
+
+ embed = json_object_new_object();
+ json_object_object_add(embed, "subObjString", json_object_new_string ("Some String"));
+ json_object_object_add(embed, "subObjInt", json_object_new_int (5678));
+
+ json_object_object_add(jresp,"eobj", embed);
+
+ ping(request, jresp, "pingJson");
+}
+
+static void subcallcb (void *prequest, int status, json_object *object, afb_req_t request)
+{
+ if (status < 0)
+ afb_req_fail(request, "failed", json_object_to_json_string(object));
+ else
+ afb_req_success(request, json_object_get(object), NULL);
+ afb_req_unref(request);
+}
+
+static void subcall (afb_req_t request)
+{
+ const char *api = afb_req_value(request, "api");
+ const char *verb = afb_req_value(request, "verb");
+ const char *args = afb_req_value(request, "args");
+ json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
+
+ if (object == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else
+ afb_req_subcall_legacy(request, api, verb, object, subcallcb, NULL);
+}
+
+static void subcallreqcb (void *prequest, int status, json_object *object, afb_req_t request)
+{
+ if (status < 0)
+ afb_req_fail(request, "failed", json_object_to_json_string(object));
+ else
+ afb_req_success(request, json_object_get(object), NULL);
+}
+
+static void subcallreq (afb_req_t request)
+{
+ const char *api = afb_req_value(request, "api");
+ const char *verb = afb_req_value(request, "verb");
+ const char *args = afb_req_value(request, "args");
+ json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
+
+ if (object == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else
+ afb_req_subcall_legacy(request, api, verb, object, subcallreqcb, NULL);
+}
+
+static void subcallsync (afb_req_t request)
+{
+ int rc;
+ const char *api = afb_req_value(request, "api");
+ const char *verb = afb_req_value(request, "verb");
+ const char *args = afb_req_value(request, "args");
+ json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL;
+
+ if (object == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else {
+ rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result);
+ if (rc >= 0)
+ afb_req_success(request, result, NULL);
+ else {
+ afb_req_fail(request, "failed", json_object_to_json_string(result));
+ json_object_put(result);
+ }
+ }
+}
+
+static void eventadd (afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+ const char *name = afb_req_value(request, "name");
+
+ pthread_mutex_lock(&mutex);
+ if (tag == NULL || name == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else if (0 != event_add(tag, name))
+ afb_req_fail(request, "failed", "creation error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void eventdel (afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+
+ pthread_mutex_lock(&mutex);
+ if (tag == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else if (0 != event_del(tag))
+ afb_req_fail(request, "failed", "deletion error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void eventsub (afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+
+ pthread_mutex_lock(&mutex);
+ if (tag == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else if (0 != event_subscribe(request, tag))
+ afb_req_fail(request, "failed", "subscription error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void eventunsub (afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+
+ pthread_mutex_lock(&mutex);
+ if (tag == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else if (0 != event_unsubscribe(request, tag))
+ afb_req_fail(request, "failed", "unsubscription error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void eventpush (afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+ const char *data = afb_req_value(request, "data");
+ json_object *object = data ? json_tokener_parse(data) : NULL;
+
+ pthread_mutex_lock(&mutex);
+ if (tag == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else if (0 > event_push(object, tag))
+ afb_req_fail(request, "failed", "push error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+ json_object_put(object);
+}
+
+static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api)
+{
+ afb_req_t request = afb_req_unstore(prequest);
+ afb_req_reply(request, json_object_get(object), error, info);
+ afb_req_unref(request);
+}
+
+static void call (afb_req_t request)
+{
+ const char *api = afb_req_value(request, "api");
+ const char *verb = afb_req_value(request, "verb");
+ const char *args = afb_req_value(request, "args");
+ json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
+
+ if (object == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else
+ afb_api_call(request->api, api, verb, object, callcb, afb_req_store(request));
+}
+
+static void callsync (afb_req_t request)
+{
+ int rc;
+ const char *api = afb_req_value(request, "api");
+ const char *verb = afb_req_value(request, "verb");
+ const char *args = afb_req_value(request, "args");
+ json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL;
+
+ if (object == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else {
+ rc = afb_service_call_sync(api, verb, object, &result);
+ if (rc >= 0)
+ afb_req_success(request, result, NULL);
+ else {
+ afb_req_fail(request, "failed", json_object_to_json_string(result));
+ json_object_put(result);
+ }
+ }
+}
+
+static void verbose (afb_req_t request)
+{
+ int level = 5;
+ json_object *query = afb_req_json(request), *l;
+
+ if (json_object_is_type(query,json_type_int))
+ level = json_object_get_int(query);
+ else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int))
+ level = json_object_get_int(l);
+
+ if (!json_object_object_get_ex(query,"message",&l))
+ l = query;
+
+ AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l));
+ afb_req_success(request, NULL, NULL);
+}
+
+static void exitnow (afb_req_t request)
+{
+ int code = 0;
+ json_object *query = afb_req_json(request), *l;
+
+ if (json_object_is_type(query,json_type_int))
+ code = json_object_get_int(query);
+ else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int))
+ code = json_object_get_int(l);
+
+ if (!json_object_object_get_ex(query,"reason",&l))
+ l = NULL;
+
+ AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown");
+ afb_req_success(request, NULL, NULL);
+ exit(code);
+}
+
+static void broadcast(afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+ const char *name = afb_req_value(request, "name");
+ const char *data = afb_req_value(request, "data");
+ json_object *object = data ? json_tokener_parse(data) : NULL;
+
+ if (tag != NULL) {
+ pthread_mutex_lock(&mutex);
+ if (0 > event_broadcast(object, tag))
+ afb_req_fail(request, "failed", "broadcast error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+ } else if (name != NULL) {
+ if (0 > afb_daemon_broadcast_event(name, object))
+ afb_req_fail(request, "failed", "broadcast error");
+ else
+ afb_req_success(request, NULL, NULL);
+ } else {
+ afb_req_fail(request, "failed", "bad arguments");
+ }
+ json_object_put(object);
+}
+
+static void hasperm (afb_req_t request)
+{
+ const char *perm = afb_req_value(request, "perm");
+ if (afb_req_has_permission(request, perm))
+ afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)");
+ else
+ afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)");
+}
+
+static void appid (afb_req_t request)
+{
+ char *aid = afb_req_get_application_id(request);
+ afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?");
+ free(aid);
+}
+
+static void uid (afb_req_t request)
+{
+ int uid = afb_req_get_uid(request);
+ afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid);
+}
+
+static int preinit()
+{
+ AFB_NOTICE("hello binding comes to live");
+ return 0;
+}
+
+static int init()
+{
+ AFB_NOTICE("hello binding starting");
+ return 0;
+}
+
+static void onevent(afb_api_t api, const char *event, struct json_object *object)
+{
+ AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
+}
+
+// NOTE: this sample does not use session to keep test a basic as possible
+// in real application most APIs should be protected with AFB_SESSION_CHECK
+static const struct afb_verb_v3 verbs[]= {
+ { .verb="ping", .callback=pingSample },
+ { .verb="pingfail", .callback=pingFail },
+ { .verb="pingnull", .callback=pingNull },
+ { .verb="pingbug", .callback=pingBug },
+ { .verb="pingJson", .callback=pingJson },
+ { .verb="pingevent", .callback=pingEvent },
+ { .verb="subcall", .callback=subcall },
+ { .verb="subcallreq", .callback=subcallreq },
+ { .verb="subcallsync", .callback=subcallsync },
+ { .verb="eventadd", .callback=eventadd },
+ { .verb="eventdel", .callback=eventdel },
+ { .verb="eventsub", .callback=eventsub },
+ { .verb="eventunsub", .callback=eventunsub },
+ { .verb="eventpush", .callback=eventpush },
+ { .verb="call", .callback=call },
+ { .verb="callsync", .callback=callsync },
+ { .verb="verbose", .callback=verbose },
+ { .verb="broadcast", .callback=broadcast },
+ { .verb="hasperm", .callback=hasperm },
+ { .verb="appid", .callback=appid },
+ { .verb="uid", .callback=uid },
+ { .verb="exit", .callback=exitnow },
+ { .verb=NULL}
+};
+
+const struct afb_binding_v3 afbBindingV3 = {
+ .api = "hello3",
+ .specification = NULL,
+ .verbs = verbs,
+ .preinit = preinit,
+ .init = init,
+ .onevent = onevent
+};
+
diff --git a/bindings/samples/hi3.c b/bindings/samples/hi3.c
new file mode 100644
index 00000000..5202c46a
--- /dev/null
+++ b/bindings/samples/hi3.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2015-2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <json-c/json.h>
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+struct event
+{
+ struct event *next;
+ afb_event_t event;
+ char tag[1];
+};
+
+static struct event *events = 0;
+
+/* searchs the event of tag */
+static struct event *event_get(const char *tag)
+{
+ struct event *e = events;
+ while(e && strcmp(e->tag, tag))
+ e = e->next;
+ return e;
+}
+
+/* deletes the event of tag */
+static int event_del(const char *tag)
+{
+ struct event *e, **p;
+
+ /* check exists */
+ e = event_get(tag);
+ if (!e) return -1;
+
+ /* unlink */
+ p = &events;
+ while(*p != e) p = &(*p)->next;
+ *p = e->next;
+
+ /* destroys */
+ afb_event_unref(e->event);
+ free(e);
+ return 0;
+}
+
+/* creates the event of tag */
+static int event_add(afb_api_t api, const char *tag, const char *name)
+{
+ struct event *e;
+
+ /* check valid tag */
+ e = event_get(tag);
+ if (e) return -1;
+
+ /* creation */
+ e = malloc(strlen(tag) + sizeof *e);
+ if (!e) return -1;
+ strcpy(e->tag, tag);
+
+ /* make the event */
+ e->event = afb_api_make_event(api, name);
+ if (!e->event) { free(e); return -1; }
+
+ /* link */
+ e->next = events;
+ events = e;
+ return 0;
+}
+
+static int event_subscribe(afb_req_t request, const char *tag)
+{
+ struct event *e;
+ e = event_get(tag);
+ return e ? afb_req_subscribe(request, e->event) : -1;
+}
+
+static int event_unsubscribe(afb_req_t request, const char *tag)
+{
+ struct event *e;
+ e = event_get(tag);
+ return e ? afb_req_unsubscribe(request, e->event) : -1;
+}
+
+static int event_push(struct json_object *args, const char *tag)
+{
+ struct event *e;
+ e = event_get(tag);
+ return e ? afb_event_push(e->event, json_object_get(args)) : -1;
+}
+
+static int event_broadcast(struct json_object *args, const char *tag)
+{
+ struct event *e;
+ e = event_get(tag);
+ return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1;
+}
+
+// Sample Generic Ping Debug API
+static void ping(afb_req_t request, json_object *jresp, const char *tag)
+{
+ static int pingcount = 0;
+ json_object *query = afb_req_json(request);
+ afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query));
+}
+
+static void pingSample (afb_req_t request)
+{
+ ping(request, json_object_new_string ("Some String"), "pingSample");
+}
+
+static void pingFail (afb_req_t request)
+{
+ afb_req_fail(request, "failed", "Ping Binder Daemon fails");
+}
+
+static void pingNull (afb_req_t request)
+{
+ ping(request, NULL, "pingNull");
+}
+
+static void pingBug (afb_req_t request)
+{
+ ping(NULL, NULL, "pingBug");
+}
+
+static void pingEvent(afb_req_t request)
+{
+ json_object *query = afb_req_json(request);
+ afb_api_broadcast_event(request->api, "event", json_object_get(query));
+ ping(request, json_object_get(query), "event");
+}
+
+
+// For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/
+static void pingJson (afb_req_t request) {
+ json_object *jresp, *embed;
+
+ jresp = json_object_new_object();
+ json_object_object_add(jresp, "myString", json_object_new_string ("Some String"));
+ json_object_object_add(jresp, "myInt", json_object_new_int (1234));
+
+ embed = json_object_new_object();
+ json_object_object_add(embed, "subObjString", json_object_new_string ("Some String"));
+ json_object_object_add(embed, "subObjInt", json_object_new_int (5678));
+
+ json_object_object_add(jresp,"eobj", embed);
+
+ ping(request, jresp, "pingJson");
+}
+
+static void subcallcb (void *closure, json_object *object, const char *error, const char *info, afb_req_t request)
+{
+ afb_req_reply(request, json_object_get(object), error, info);
+}
+
+static void subcall (afb_req_t request)
+{
+ const char *api = afb_req_value(request, "api");
+ const char *verb = afb_req_value(request, "verb");
+ const char *args = afb_req_value(request, "args");
+ json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
+
+ if (object == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else
+ afb_req_subcall(request, api, verb, object, afb_req_subcall_pass_events, subcallcb, NULL);
+}
+
+static void subcallsync (afb_req_t request)
+{
+ int rc;
+ const char *api = afb_req_value(request, "api");
+ const char *verb = afb_req_value(request, "verb");
+ const char *args = afb_req_value(request, "args");
+ json_object *oargs = api && verb && args ? json_tokener_parse(args) : NULL;
+ json_object *object;
+ char *error, *info;
+
+ if (oargs == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else {
+ rc = afb_req_subcall_sync(request, api, verb, oargs, afb_req_subcall_pass_events, &object, &error, &info);
+ afb_req_reply_f(request, object, error, "rc=%d, info=%s", rc, info?:"NULL");
+ free(error);
+ free(info);
+ }
+}
+
+static void eventadd (afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+ const char *name = afb_req_value(request, "name");
+
+ pthread_mutex_lock(&mutex);
+ if (tag == NULL || name == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else if (0 != event_add(request->api, tag, name))
+ afb_req_fail(request, "failed", "creation error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void eventdel (afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+
+ pthread_mutex_lock(&mutex);
+ if (tag == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else if (0 != event_del(tag))
+ afb_req_fail(request, "failed", "deletion error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void eventsub (afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+
+ pthread_mutex_lock(&mutex);
+ if (tag == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else if (0 != event_subscribe(request, tag))
+ afb_req_fail(request, "failed", "subscription error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void eventunsub (afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+
+ pthread_mutex_lock(&mutex);
+ if (tag == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else if (0 != event_unsubscribe(request, tag))
+ afb_req_fail(request, "failed", "unsubscription error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void eventpush (afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+ const char *data = afb_req_value(request, "data");
+ json_object *object = data ? json_tokener_parse(data) : NULL;
+
+ pthread_mutex_lock(&mutex);
+ if (tag == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else if (0 > event_push(object, tag))
+ afb_req_fail(request, "failed", "push error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+ json_object_put(object);
+}
+
+static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api)
+{
+ afb_req_t request = prequest;
+ afb_req_reply(request, json_object_get(object), error, info);
+ afb_req_unref(request);
+}
+
+static void call (afb_req_t request)
+{
+ const char *api = afb_req_value(request, "api");
+ const char *verb = afb_req_value(request, "verb");
+ const char *args = afb_req_value(request, "args");
+ json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
+
+ if (object == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else
+ afb_api_call(request->api, api, verb, object, callcb, afb_req_addref(request));
+}
+
+static void callsync (afb_req_t request)
+{
+ int rc;
+ const char *api = afb_req_value(request, "api");
+ const char *verb = afb_req_value(request, "verb");
+ const char *args = afb_req_value(request, "args");
+ json_object *oargs = api && verb && args ? json_tokener_parse(args) : NULL;
+ json_object *object;
+ char *error, *info;
+
+ if (oargs == NULL)
+ afb_req_fail(request, "failed", "bad arguments");
+ else {
+ rc = afb_api_call_sync(request->api, api, verb, oargs, &object, &error, &info);
+ afb_req_reply_f(request, object, error, "rc=%d, info=%s", rc, info);
+ free(error);
+ free(info);
+ }
+}
+
+static void verbose (afb_req_t request)
+{
+ int level = 5;
+ json_object *query = afb_req_json(request), *l;
+
+ if (json_object_is_type(query,json_type_int))
+ level = json_object_get_int(query);
+ else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int))
+ level = json_object_get_int(l);
+
+ if (!json_object_object_get_ex(query,"message",&l))
+ l = query;
+
+ AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l));
+ afb_req_success(request, NULL, NULL);
+}
+
+static void exitnow (afb_req_t request)
+{
+ int code = 0;
+ json_object *query = afb_req_json(request), *l;
+
+ if (json_object_is_type(query,json_type_int))
+ code = json_object_get_int(query);
+ else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int))
+ code = json_object_get_int(l);
+
+ if (!json_object_object_get_ex(query,"reason",&l))
+ l = NULL;
+
+ AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown");
+ afb_req_success(request, NULL, NULL);
+ exit(code);
+}
+
+static void broadcast(afb_req_t request)
+{
+ const char *tag = afb_req_value(request, "tag");
+ const char *name = afb_req_value(request, "name");
+ const char *data = afb_req_value(request, "data");
+ json_object *object = data ? json_tokener_parse(data) : NULL;
+
+ if (tag != NULL) {
+ pthread_mutex_lock(&mutex);
+ if (0 > event_broadcast(object, tag))
+ afb_req_fail(request, "failed", "broadcast error");
+ else
+ afb_req_success(request, NULL, NULL);
+ pthread_mutex_unlock(&mutex);
+ } else if (name != NULL) {
+ if (0 > afb_api_broadcast_event(request->api, name, object))
+ afb_req_fail(request, "failed", "broadcast error");
+ else
+ afb_req_success(request, NULL, NULL);
+ } else {
+ afb_req_fail(request, "failed", "bad arguments");
+ }
+ json_object_put(object);
+}
+
+static void hasperm (afb_req_t request)
+{
+ const char *perm = afb_req_value(request, "perm");
+ if (afb_req_has_permission(request, perm))
+ afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)");
+ else
+ afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)");
+}
+
+static void appid (afb_req_t request)
+{
+ char *aid = afb_req_get_application_id(request);
+ afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?");
+ free(aid);
+}
+
+static int init(afb_api_t api)
+{
+ AFB_API_NOTICE(api, "dynamic binding AVE(%s) starting", (const char*)api->userdata);
+ return 0;
+}
+
+static void onevent(afb_api_t api, const char *event, struct json_object *object)
+{
+ AFB_API_NOTICE(api, "received event %s(%s) by AVE(%s)",
+ event, json_object_to_json_string(object),
+ (const char*)afb_api_get_userdata(api));
+}
+
+// NOTE: this sample does not use session to keep test a basic as possible
+// in real application most APIs should be protected with AFB_SESSION_CHECK
+static const struct {
+ const char *verb;
+ void (*callback)(afb_req_t); } verbs[] =
+{
+ { .verb="ping", .callback=pingSample },
+ { .verb="pingfail", .callback=pingFail },
+ { .verb="pingnull", .callback=pingNull },
+ { .verb="pingbug", .callback=pingBug },
+ { .verb="pingJson", .callback=pingJson },
+ { .verb="pingevent", .callback=pingEvent },
+ { .verb="subcall", .callback=subcall },
+ { .verb="subcallsync", .callback=subcallsync },
+ { .verb="eventadd", .callback=eventadd },
+ { .verb="eventdel", .callback=eventdel },
+ { .verb="eventsub", .callback=eventsub },
+ { .verb="eventunsub", .callback=eventunsub },
+ { .verb="eventpush", .callback=eventpush },
+ { .verb="call", .callback=call },
+ { .verb="callsync", .callback=callsync },
+ { .verb="verbose", .callback=verbose },
+ { .verb="broadcast", .callback=broadcast },
+ { .verb="hasperm", .callback=hasperm },
+ { .verb="appid", .callback=appid },
+ { .verb="exit", .callback=exitnow },
+ { .verb=NULL}
+};
+
+static void pingoo(struct afb_req_x1 req)
+{
+ json_object *args = afb_req_x1_json(req);
+ afb_req_x1_reply_f(req, json_object_get(args), NULL, "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args));
+}
+
+static const struct afb_verb_v2 verbsv2[]= {
+ { .verb="pingoo", .callback=pingoo },
+ { .verb="ping", .callback=pingoo },
+ { .verb=NULL}
+};
+
+static const char *apis[] = { "ave3", "hi3", "salut3", NULL };
+
+static int build_api(void *closure, afb_api_t api)
+{
+ int i, rc;
+
+ afb_api_set_userdata(api, closure);
+ AFB_API_NOTICE(api, "dynamic binding AVE(%s) comes to live", (const char*)afb_api_get_userdata(api));
+ afb_api_on_init(api, init);
+ afb_api_on_event(api, onevent);
+
+ rc = afb_api_set_verbs_v2(api, verbsv2);
+ for (i = rc = 0; verbs[i].verb && rc >= 0 ; i++) {
+ rc = afb_api_add_verb(api, verbs[i].verb, NULL, verbs[i].callback, (void*)(intptr_t)i, NULL, 0, 0);
+ }
+ afb_api_seal(api);
+ return rc;
+}
+
+int afbBindingV3entry(afb_api_t api)
+{
+ int i;
+ afb_api_t napi;
+
+ for (i = 0; apis[i] ; i++) {
+ napi = afb_api_new_api(api, apis[i], NULL, 0, build_api, (void*)apis[i]);
+ if (!napi)
+ AFB_API_ERROR(api, "can't create API %s", apis[i]);
+ }
+ return 0;
+}
+
diff --git a/bindings/samples/tic-tac-toe.c b/bindings/samples/tic-tac-toe.c
index 6b7022b8..2ee251cb 100644
--- a/bindings/samples/tic-tac-toe.c
+++ b/bindings/samples/tic-tac-toe.c
@@ -20,17 +20,14 @@
#include <string.h>
#include <json-c/json.h>
-#define AFB_BINDING_VERSION 2
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
-/*
- * definition of waiters
- */
-struct waiter
-{
- struct waiter *next;
- struct afb_req req;
-};
+static const char SPACE = ' ';
+static const char CROSS = 'X';
+static const char ROUND = 'O';
+static const char NHERE = '+';
+static const int DEFLVL = 8;
/*
* definition of a board
@@ -44,7 +41,7 @@ struct board
int id;
int level;
char board[9];
- struct waiter *waiters;
+ afb_event_t event;
};
/*
@@ -67,19 +64,21 @@ static struct board *search_board(int id)
/*
* Creates a new board and returns it.
*/
-static struct board *get_new_board()
+static struct board *get_new_board(afb_req_t req)
{
/* allocation */
struct board *board = calloc(1, sizeof *board);
/* initialisation */
- memset(board->board, ' ', sizeof board->board);
+ memset(board->board, SPACE, sizeof board->board);
board->use_count = 1;
- board->level = 1;
+ board->level = DEFLVL;
board->moves = 0;
do {
board->id = (rand() >> 2) % 1000;
} while(board->id == 0 || search_board(board->id) != NULL);
+ board->event = afb_daemon_make_event("board");
+ afb_req_subscribe(req, board->event);
/* link */
board->next = all_boards;
@@ -87,6 +86,12 @@ static struct board *get_new_board()
return board;
}
+static void *get_new_board_cb(void *closure)
+{
+ afb_req_t req = closure;
+ return get_new_board(req);
+}
+
/*
* Release a board
*/
@@ -95,6 +100,7 @@ static void release_board(struct board *board)
/* decrease the reference count ... */
if (--board->use_count == 0) {
/* ... no more use */
+ afb_event_unref(board->event);
/* unlink from the list of boards */
struct board **prv = &all_boards;
while (*prv != NULL && *prv != board)
@@ -106,6 +112,24 @@ static void release_board(struct board *board)
}
}
+static void release_board_cb(void *closure)
+{
+ struct board *board = closure;
+ return release_board(board);
+}
+
+/*
+ * Checks who wins
+ * Returns zero if there is no winner
+ * Returns the char of the winner if a player won
+ */
+static char wins(const char b[9], int first, int incr)
+{
+ char c = b[first];
+
+ return c != SPACE && b[first + incr] == c && b[first + incr + incr] == c ? c : 0;
+}
+
/*
* Checks who wins
* Returns zero if there is no winner
@@ -113,31 +137,39 @@ static void release_board(struct board *board)
*/
static char winner(const char b[9])
{
- int i;
char c;
- /* check diagonals */
- c = b[4];
- if (c != ' ') {
- if (b[0] == c && b[8] == c)
- return c;
- if (b[2] == c && b[6] == c)
- return c;
- }
+ c = wins(b, 0, 1);
+ if (c)
+ return c;
- /* check lines */
- for (i = 0 ; i <= 6 ; i += 3) {
- c = b[i];
- if (c != ' ' && b[i+1] == c && b[i+2] == c)
- return c;
- }
+ c = wins(b, 3, 1);
+ if (c)
+ return c;
- /* check columns */
- for (i = 0 ; i <= 2 ; i++) {
- c = b[i];
- if (c != ' ' && b[i+3] == c && b[i+6] == c)
- return c;
- }
+ c = wins(b, 6, 1);
+ if (c)
+ return c;
+
+ c = wins(b, 0, 3);
+ if (c)
+ return c;
+
+ c = wins(b, 1, 3);
+ if (c)
+ return c;
+
+ c = wins(b, 2, 3);
+ if (c)
+ return c;
+
+ c = wins(b, 0, 4);
+ if (c)
+ return c;
+
+ c = wins(b, 2, 2);
+ if (c)
+ return c;
return 0;
}
@@ -145,7 +177,7 @@ static char winner(const char b[9])
/* get the color (X or 0) of the move of index 'move' */
static char color(int move)
{
- return (move & 1) == 0 ? 'X' : '0';
+ return (move & 1) == 0 ? CROSS : ROUND;
}
/* adds the move to the board */
@@ -160,7 +192,7 @@ static void add_move(struct board *board, int index)
static int get_random_move(char b[9])
{
int index = rand() % 9;
- while (b[index] != ' ')
+ while (b[index] != SPACE)
index = (index + 1) % 9;
return index;
}
@@ -174,40 +206,41 @@ static int get_random_move(char b[9])
*/
static int score_position(char b[9], char c, int depth)
{
- int i, t, r;
+ int i, s, nc, wc, lc;
/* check if winner */
if (winner(b) == c)
return 1;
/* when depth of analysis is reached return unknown case */
- if (--depth == 0)
+ if (--depth <= 0)
return 0;
/* switch to the opponent */
- c = (char)('O' + 'X' - c);
+ c = (char)(ROUND + CROSS - c);
/* inspect opponent moves */
- r = 1;
+ nc = wc = lc = 0;
for (i = 0 ; i < 9 ; i++) {
- if (b[i] == ' ') {
+ if (b[i] == SPACE) {
b[i] = c;
- t = score_position(b, c, depth);
- b[i] = ' ';
- if (t > 0)
- return -1; /* opponent will win */
-
- if (t == 0)
- r = 0; /* something not clear */
+ s = score_position(b, c, depth);
+ b[i] = SPACE;
+ if (s > 0)
+ lc++; /* opponent's victory, inc loose count */
+ else if (s < 0)
+ wc++; /* current's victory, inc win count */
+ else
+ nc++; /* none wins, increment null count */
}
}
- return r;
+ return lc ? -lc : wc;
}
/* get one move: return the computed index of the move */
static int get_move(struct board *board)
{
- int index, depth, t, f;
+ int index, depth, f, s, smax, imax;
char c;
char b[9];
@@ -222,22 +255,24 @@ static int get_move(struct board *board)
/* depth and more */
memcpy(b, board->board, 9);
+ f = smax = 0;
c = color(board->moves);
- f = 0;
for (index = 0 ; index < 9 ; index++) {
- if (board->board[index] == ' ') {
+ if (board->board[index] == SPACE) {
board->board[index] = c;
- t = score_position(board->board, c, depth);
- board->board[index] = ' ';
- if (t > 0)
- return index;
- if (t < 0)
- b[index] = '+';
- else
+ s = score_position(board->board, c, depth);
+ board->board[index] = SPACE;
+ if (s < 0)
+ b[index] = NHERE;
+ else if (s <= smax)
f = 1;
+ else {
+ smax = s;
+ imax = index;
+ }
}
}
- return get_random_move(f ? b : board->board);
+ return smax ? imax : get_random_move(f ? b : board->board);
}
/*
@@ -279,37 +314,21 @@ static struct json_object *describe(struct board *board)
*/
static void changed(struct board *board, const char *reason)
{
- struct waiter *waiter, *next;
- struct json_object *description;
-
- /* get the description */
- description = describe(board);
-
- waiter = board->waiters;
- board->waiters = NULL;
- while (waiter != NULL) {
- next = waiter->next;
- afb_req_success(waiter->req, json_object_get(description), reason);
- afb_req_unref(waiter->req);
- free(waiter);
- waiter = next;
- }
-
- afb_daemon_broadcast_event(reason, description);
+ afb_event_push(board->event, json_object_new_string(reason));
}
/*
* retrieves the board of the request
*/
-static inline struct board *board_of_req(struct afb_req req)
+static inline struct board *board_of_req(afb_req_t req)
{
- return afb_req_context(req, (void*)get_new_board, (void*)release_board);
+ return afb_req_context(req, 0, get_new_board_cb, release_board_cb, req);
}
/*
* start a new game
*/
-static void new(struct afb_req req)
+static void new(afb_req_t req)
{
struct board *board;
@@ -318,7 +337,7 @@ static void new(struct afb_req req)
AFB_INFO("method 'new' called for boardid %d", board->id);
/* reset the game */
- memset(board->board, ' ', sizeof board->board);
+ memset(board->board, SPACE, sizeof board->board);
board->moves = 0;
/* replies */
@@ -331,7 +350,7 @@ static void new(struct afb_req req)
/*
* get the board
*/
-static void board(struct afb_req req)
+static void board(afb_req_t req)
{
struct board *board;
struct json_object *description;
@@ -350,7 +369,7 @@ static void board(struct afb_req req)
/*
* move a piece
*/
-static void move(struct afb_req req)
+static void move(afb_req_t req)
{
struct board *board;
int i;
@@ -379,7 +398,7 @@ static void move(struct afb_req req)
}
/* checks validity of the move */
- if (board->board[i] != ' ') {
+ if (board->board[i] != SPACE) {
AFB_WARNING("can't move to %s: room occupied", index);
afb_req_fail(req, "error", "occupied");
return;
@@ -399,7 +418,7 @@ static void move(struct afb_req req)
/*
* set the level
*/
-static void level(struct afb_req req)
+static void level(afb_req_t req)
{
struct board *board;
int l;
@@ -434,7 +453,7 @@ static void level(struct afb_req req)
/*
* Join a board
*/
-static void join(struct afb_req req)
+static void join(afb_req_t req)
{
struct board *board, *new_board;
const char *id;
@@ -450,8 +469,8 @@ static void join(struct afb_req req)
/* none is a special id for joining a new session */
if (strcmp(id, "none") == 0) {
- new_board = get_new_board();
- goto success;
+ new_board = get_new_board(req);
+ goto setctx;
}
/* searchs the board to join */
@@ -466,13 +485,16 @@ static void join(struct afb_req req)
* function 'release_board'. So the use_count MUST not
* be incremented.
*/
- if (new_board != board)
- new_board->use_count++;
+ if (new_board == board)
+ goto success;
-success:
+ new_board->use_count++;
+setctx:
/* set the new board (and leaves the previous one) */
- afb_req_context_set(req, new_board, (void*)release_board);
+ afb_req_context(req, 1, NULL, release_board_cb, new_board);
+ afb_req_unsubscribe(req, board->event);
+success:
/* replies */
afb_req_success(req, NULL, NULL);
return;
@@ -486,7 +508,7 @@ bad_request:
/*
* Undo the last move
*/
-static void undo(struct afb_req req)
+static void undo(afb_req_t req)
{
struct board *board;
int i;
@@ -504,7 +526,7 @@ static void undo(struct afb_req req)
/* undo the last move */
i = board->history[--board->moves];
- board->board[i] = ' ';
+ board->board[i] = SPACE;
/* replies */
afb_req_success(req, NULL, NULL);
@@ -516,7 +538,7 @@ static void undo(struct afb_req req)
/*
* computer plays
*/
-static void play(struct afb_req req)
+static void play(afb_req_t req)
{
struct board *board;
int index;
@@ -543,27 +565,10 @@ static void play(struct afb_req req)
changed(board, "play");
}
-static void wait(struct afb_req req)
-{
- struct board *board;
- struct waiter *waiter;
-
- /* retrieves the context for the session */
- board = board_of_req(req);
- AFB_INFO("method 'wait' called for boardid %d", board->id);
-
- /* creates the waiter and enqueues it */
- waiter = calloc(1, sizeof *waiter);
- waiter->req = req;
- waiter->next = board->waiters;
- afb_req_addref(req);
- board->waiters = waiter;
-}
-
/*
* array of the verbs exported to afb-daemon
*/
-static const struct afb_verb_v2 verbs[] = {
+static const afb_verb_t verbs[] = {
{ .verb="new", .callback=new },
{ .verb="play", .callback=play },
{ .verb="move", .callback=move },
@@ -571,17 +576,17 @@ static const struct afb_verb_v2 verbs[] = {
{ .verb="level", .callback=level },
{ .verb="join", .callback=join },
{ .verb="undo", .callback=undo },
- { .verb="wait", .callback=wait },
{ .verb=NULL }
};
/*
* description of the binding for afb-daemon
*/
-const afb_binding_v2 afbBindingV2 = {
+const afb_binding_t afbBindingV3 = {
.api = "tictactoe",
.specification = NULL,
- .verbs = verbs
+ .verbs = verbs,
+ .noconcurrency = 1
};
diff --git a/bindings/tutorial/tuto-1.c b/bindings/tutorial/tuto-1.c
index 433a4ebb..1f58be6c 100644
--- a/bindings/tutorial/tuto-1.c
+++ b/bindings/tutorial/tuto-1.c
@@ -1,18 +1,18 @@
-#define AFB_BINDING_VERSION 2
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
-void hello(afb_req req)
+void hello(afb_req_t req)
{
AFB_REQ_DEBUG(req, "hello world");
- afb_req_success(req, NULL, "hello world");
+ afb_req_reply(req, NULL, NULL, "hello world");
}
-const afb_verb_v2 verbs[] = {
+const afb_verb_t verbs[] = {
{ .verb="hello", .callback=hello },
{ .verb=NULL }
};
-const afb_binding_v2 afbBindingV2 = {
+const afb_binding_t afbBindingExport = {
.api = "tuto-1",
.verbs = verbs
};
diff --git a/bindings/tutorial/tuto-2.c b/bindings/tutorial/tuto-2.c
index dc2d55ab..10797081 100644
--- a/bindings/tutorial/tuto-2.c
+++ b/bindings/tutorial/tuto-2.c
@@ -1,12 +1,12 @@
#include <string.h>
#include <json-c/json.h>
-#define AFB_BINDING_VERSION 2
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
-afb_event event_login, event_logout;
+afb_event_t event_login, event_logout;
-void login(afb_req req)
+void login(afb_req_t req)
{
json_object *args, *user, *passwd;
char *usr;
@@ -15,24 +15,24 @@ void login(afb_req req)
if (!json_object_object_get_ex(args, "user", &user)
|| !json_object_object_get_ex(args, "password", &passwd)) {
AFB_REQ_ERROR(req, "login, bad request: %s", json_object_get_string(args));
- afb_req_fail(req, "bad-request", NULL);
+ afb_req_reply(req, NULL, "bad-request", NULL);
} else if (afb_req_context_get(req)) {
AFB_REQ_ERROR(req, "login, bad state, logout first");
- afb_req_fail(req, "bad-state", NULL);
+ afb_req_reply(req, NULL, "bad-state", NULL);
} else if (strcmp(json_object_get_string(passwd), "please")) {
AFB_REQ_ERROR(req, "login, unauthorized: %s", json_object_get_string(args));
- afb_req_fail(req, "unauthorized", NULL);
+ afb_req_reply(req, NULL, "unauthorized", NULL);
} else {
usr = strdup(json_object_get_string(user));
AFB_REQ_NOTICE(req, "login user: %s", usr);
afb_req_session_set_LOA(req, 1);
afb_req_context_set(req, usr, free);
- afb_req_success(req, NULL, NULL);
+ afb_req_reply(req, NULL, NULL, NULL);
afb_event_push(event_login, json_object_new_string(usr));
}
}
-void action(afb_req req)
+void action(afb_req_t req)
{
json_object *args, *val;
char *usr;
@@ -51,10 +51,10 @@ void action(afb_req req)
afb_req_unsubscribe(req, event_logout);
}
}
- afb_req_success(req, json_object_get(args), NULL);
+ afb_req_reply(req, json_object_get(args), NULL, NULL);
}
-void logout(afb_req req)
+void logout(afb_req_t req)
{
char *usr;
@@ -63,34 +63,34 @@ void logout(afb_req req)
afb_event_push(event_logout, json_object_new_string(usr));
afb_req_session_set_LOA(req, 0);
afb_req_context_clear(req);
- afb_req_success(req, NULL, NULL);
+ afb_req_reply(req, NULL, NULL, NULL);
}
-int preinit()
+int preinit(afb_api_t api)
{
- AFB_NOTICE("preinit");
+ AFB_API_NOTICE(api, "preinit");
return 0;
}
-int init()
+int init(afb_api_t api)
{
- AFB_NOTICE("init");
- event_login = afb_daemon_make_event("login");
- event_logout = afb_daemon_make_event("logout");
+ AFB_API_NOTICE(api, "init");
+ event_login = afb_api_make_event(api, "login");
+ event_logout = afb_api_make_event(api, "logout");
if (afb_event_is_valid(event_login) && afb_event_is_valid(event_logout))
return 0;
- AFB_ERROR("Can't create events");
+ AFB_API_ERROR(api, "Can't create events");
return -1;
}
-const afb_verb_v2 verbs[] = {
+const afb_verb_t verbs[] = {
{ .verb="login", .callback=login },
{ .verb="action", .callback=action, .session=AFB_SESSION_LOA_1 },
{ .verb="logout", .callback=logout, .session=AFB_SESSION_LOA_1 },
{ .verb=NULL }
};
-const afb_binding_v2 afbBindingV2 = {
+const afb_binding_t afbBindingExport = {
.api = "tuto-2",
.specification = NULL,
.verbs = verbs,
diff --git a/bindings/tutorial/tuto-3.cpp b/bindings/tutorial/tuto-3.cpp
index 7400b986..66f8e83a 100644
--- a/bindings/tutorial/tuto-3.cpp
+++ b/bindings/tutorial/tuto-3.cpp
@@ -1,11 +1,12 @@
#include <string.h>
#include <json-c/json.h>
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding>
afb::event event_login, event_logout;
-void login(afb_req r)
+void login(afb_req_t r)
{
json_object *args, *user, *passwd;
char *usr;
@@ -26,20 +27,21 @@ void login(afb_req r)
usr = strdup(json_object_get_string(user));
AFB_REQ_NOTICE(req, "login user: %s", usr);
req.session_set_LOA(1);
- req.context_set(usr, free);
+// req.context(1, nullptr, free, usr);
req.success();
event_login.push(json_object_new_string(usr));
}
}
-void action(afb_req r)
+void action(afb_req_t r)
{
json_object *args, *val;
char *usr;
afb::req req(r);
args = req.json();
- usr = (char*)req.context_get();
+// usr = (char*)req.context_get();
+usr = nullptr;
AFB_REQ_NOTICE(req, "action for user %s: %s", usr, json_object_get_string(args));
if (json_object_object_get_ex(args, "subscribe", &val)) {
if (json_object_get_boolean(val)) {
@@ -55,20 +57,25 @@ void action(afb_req r)
req.success(json_object_get(args));
}
-void logout(afb_req r)
+void logout(afb_req_t r)
{
char *usr;
afb::req req(r);
- usr = (char*)req.context_get();
+// usr = (char*)req.context_get();
+usr = nullptr;
AFB_REQ_NOTICE(req, "login user %s out", usr);
event_logout.push(json_object_new_string(usr));
req.session_set_LOA(0);
- req.context_clear();
+// req.context_clear();
req.success();
}
-int init()
+int init(
+#if AFB_BINDING_VERSION >= 3
+ afb_api_t api
+#endif
+)
{
AFB_NOTICE("init");
event_login = afb_daemon_make_event("login");
@@ -79,12 +86,13 @@ int init()
return -1;
}
-const afb_verb_v2 verbs[] = {
+const afb_verb_t verbs[] = {
afb::verb("login", login, "log in the system"),
afb::verb("action", action, "perform an action", AFB_SESSION_LOA_1),
afb::verb("logout", logout, "log out the system", AFB_SESSION_LOA_1),
afb::verbend()
};
-const afb_binding_v2 afbBindingV2 = afb::binding("tuto-3", verbs, "third tutorial: C++", init);
+const afb_binding_t afbBindingExport = afb::binding("tuto-3", verbs, "third tutorial: C++", init);
+
diff --git a/book.json b/book.json
index 41e4cddd..e7127c49 100644
--- a/book.json
+++ b/book.json
@@ -6,7 +6,7 @@
"author": "IoT.Bzh Team",
"website": "http://iot.bzh",
"published": "February 2018",
- "version": "5.99-FFRC0",
+ "version": "5.99-FFRC1",
"gitbook": "3.2.2",
"root": "docs",
@@ -89,6 +89,6 @@
"decode": true
}
]
- }
+ }
}
}
diff --git a/docs/README.md b/docs/README.md
index 94dc16aa..503b8545 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,13 +1,19 @@
-Document revisions
-==================
-
-| Date | Version | Designation  | Author |
-|--------------|------------|----------------------------------------------|-------------------------------------------------------|
-| 23 May 2016 | 0.9 | Initial release | J. Bollo [ IoT.bzh ] <br/> M. Bachmann [ IoT.bzh ] |
-| 30 May 2016 | 1.0 | Master document edition, final review | S. Desneux [ IoT.bzh ] <br/> F. Ar Foll [ IoT.bzh ] |
-| 21 Sept 2016 | 2.0 | Updated with new sections (events,widgets) | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] |
-| 12 Dec 2016 | 2.1 | Updated for CC Release | S. Desneux [ IoT.bzh ] |
-| 14 Dec 2016 | 3.0 | Minor fixes, alignment with CC version | S. Desneux [ IoT.bzh ] |
-| 20 Mar 2017 | 3.1 | Systemd integration | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] |
-| 21 Jun 2017 | 4.0 | Update for AGL DD | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] |
-| 21 Sep 2017 | 4.99-EERC1 | Update for AGL EE-RC1 | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] |
+
+# AGL Framework Binder
+
+This project provides the binder component of the the microservice architecture
+of Automotive Grade Linux (AGL).
+
+This project is available there https://git.automotivelinux.org/src/app-framework-binder/
+
+It can be cloned with **git clone https://git.automotivelinux.org/src/app-framework-binder**.
+
+## License and copying
+
+This software is an open source software funded by LinuxFoundation and Renesas.
+
+This software is delivered under the terms of the open source license Apache 2.
+
+This license is available in the file LICENSE-2.0.txt or on the worl wide web at the
+location https://opensource.org/licenses/Apache-2.0
+
diff --git a/docs/REVISIONS.md b/docs/REVISIONS.md
new file mode 100644
index 00000000..00787b02
--- /dev/null
+++ b/docs/REVISIONS.md
@@ -0,0 +1,14 @@
+Document revisions
+==================
+
+| Date | Version | Designation  | Author |
+|--------------|:----------:|----------------------------------------------|-------------------------------------------------------|
+| 23 May 2016 | 0.9 | Initial release | J. Bollo [ IoT.bzh ] <br/> M. Bachmann [ IoT.bzh ] |
+| 30 May 2016 | 1.0 | Master document edition, final review | S. Desneux [ IoT.bzh ] <br/> F. Ar Foll [ IoT.bzh ] |
+| 21 Sept 2016 | 2.0 | Updated with new sections (events,widgets) | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] |
+| 12 Dec 2016 | 2.1 | Updated for CC Release | S. Desneux [ IoT.bzh ] |
+| 14 Dec 2016 | 3.0 | Minor fixes, alignment with CC version | S. Desneux [ IoT.bzh ] |
+| 20 Mar 2017 | 3.1 | Systemd integration | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] |
+| 21 Jun 2017 | 4.0 | Update for AGL DD | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] |
+| 21 Sep 2017 | 4.99-EERC1 | Update for AGL EE-RC1 | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] |
+| 14 Jun 2018 | 5.99-FFRC1 | Update for AGL FF-RC1 | J. Bollo [ IoT.bzh ] |
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index 44b06f8d..580660ea 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -1,14 +1,15 @@
# Summary
-* [Document revisions](README.md)
* [Binder Overview](afb-introduction.md)
+* [Binder daemon vocabulary](afb-daemon-vocabulary.md)
* [How to write a binding ?](afb-binding-writing.md)
* [Binding references](afb-binding-references.md)
-* [Migration from v1 to v2](afb-migration-v1-to-v2.md)
* [Binder events guide](afb-events-guide.md)
* [Binder Application writing guide](afb-application-writing.md)
-* [Binder daemon vocabulary](afb-daemon-vocabulary.md)
* [Annexes](annexes.md)
+ * [Migration to binding v3](afb-migration-to-binding-v3.md)
* [Installing the binder on a desktop](afb-desktop-package.md)
* [Options of afb-daemon](afb-daemon-options.md)
- * [Debugging afb-daemon](afb-daemon-debugging.md)
+ * [Debugging binder and bindings](afb-daemon-debugging.md)
+ * [(LEGACY) guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md)
+* [Document revisions](REVISIONS.md)
diff --git a/docs/afb-binding-references.md b/docs/afb-binding-references.md
index 0e30ffe7..4ff0f042 100644
--- a/docs/afb-binding-references.md
+++ b/docs/afb-binding-references.md
@@ -2,47 +2,98 @@
## Structure for declaring binding
-### struct afb_binding_v2
+### afb_binding_t
-The main structure, of type **afb_binding_v2**, for describing the binding
-must be exported under the name **afbBindingV2**.
+The main structure, of type **afb_binding_t**, for describing the binding
+must be exported under the name **afbBindingExport**.
This structure is defined as below.
```C
-/*
- * Description of the bindings of type version 2
+typedef struct afb_binding_v3 afb_binding_t;
+```
+
+Where:
+
+```C
+/**
+ * Description of the bindings of type version 3
*/
-struct afb_binding_v2
+struct afb_binding_v3
{
- const char *api; /* api name for the binding */
- const char *specification; /* textual openAPIv3 specification of the binding */
- const char *info; /* some info about the api, can be NULL */
- const struct afb_verb_v2 *verbs; /* array of descriptions of verbs terminated by a NULL name */
- int (*preinit)(); /* callback at load of the binding */
- int (*init)(); /* callback for starting the service */
- void (*onevent)(const char *event, struct json_object *object); /* callback for handling events */
- unsigned noconcurrency: 1; /* avoids concurrent requests to verbs */
+ /** api name for the binding, can't be NULL */
+ const char *api;
+
+ /** textual specification of the binding, can be NULL */
+ const char *specification;
+
+ /** some info about the api, can be NULL */
+ const char *info;
+
+ /** array of descriptions of verbs terminated by a NULL name, can be NULL */
+ const struct afb_verb_v3 *verbs;
+
+ /** callback at load of the binding */
+ int (*preinit)(struct afb_api_x3 *api);
+
+ /** callback for starting the service */
+ int (*init)(struct afb_api_x3 *api);
+
+ /** callback for handling events */
+ void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object);
+
+ /** userdata for afb_api_x3 */
+ void *userdata;
+
+ /** space separated list of provided class(es) */
+ const char *provide_class;
+
+ /** space separated list of required class(es) */
+ const char *require_class;
+
+ /** space separated list of required API(es) */
+ const char *require_api;
+
+ /** avoids concurrent requests to verbs */
+ unsigned noconcurrency: 1;
};
```
-### struct afb_verb_v2
+### struct afb_verb_t
-Each verb is described with a structure of type **afb_verb_v2**
+Each verb is described with a structure of type **afb_verb_t**
defined below:
```C
-/*
- * Description of one verb of the API provided by the binding
- * This enumeration is valid for bindings of type version 2
+typedef struct afb_verb_v3 afb_verb_t;
+```
+
+```C
+/**
+ * Description of one verb as provided for binding API version 3
*/
-struct afb_verb_v2
+struct afb_verb_v3
{
- const char *verb; /* name of the verb */
- void (*callback)(struct afb_req req); /* callback function implementing the verb */
- const struct afb_auth *auth; /* required authorization */
- const char *info; /* some info about the verb, can be NULL */
- uint32_t session; /* authorization and session requirements of the verb */
+ /** name of the verb, NULL only at end of the array */
+ const char *verb;
+
+ /** callback function implementing the verb */
+ void (*callback)(afb_req_t_x2 *req);
+
+ /** required authorization, can be NULL */
+ const struct afb_auth *auth;
+
+ /** some info about the verb, can be NULL */
+ const char *info;
+
+ /**< data for the verb callback */
+ void *vcbdata;
+
+ /** authorization and session requirements of the verb */
+ uint16_t session;
+
+ /** is the verb glob name */
+ uint16_t glob: 1;
};
```
@@ -55,55 +106,91 @@ The **session** flags is one of the constant defined below:
- AFB_SESSION_LOA_3 : Requires the LOA to be 3 or more
- AFB_SESSION_CHECK : Requires the token to be set and valid
- AFB_SESSION_REFRESH : Implies a token refresh
-- AFB_SESSION_CLOSE : Implies cloing the session
+- AFB_SESSION_CLOSE : Implies closing the session after request processed
-The LOA (Level Of Assurance) is set, by binding, using the function **afb_req_session_set_LOA**.
+The LOA (Level Of Assurance) is set, by binding api, using the function **afb_req_session_set_LOA**.
-### struct afb_auth and enum afb_auth_type
+The session can be closed, by binding api, using the function **afb_req_session_close**.
-The structure **afb_auth** is used within verb description to
+### afb_auth_t and afb_auth_type_t
+
+The structure **afb_auth_t** is used within verb description to
set security requirements.
The interpretation of the structure depends on the value of the field **type**.
```C
+typedef struct afb_auth afb_auth_t;
+
+/**
+ * Definition of an authorization entry
+ */
struct afb_auth
{
- const enum afb_auth_type type;
- union {
- const char *text;
- const unsigned loa;
- const struct afb_auth *first;
- };
- const struct afb_auth *next;
+ /** type of entry @see afb_auth_type */
+ enum afb_auth_type type;
+
+ union {
+ /** text when @ref type == @ref afb_auth_Permission */
+ const char *text;
+
+ /** level of assurancy when @ref type == @ref afb_auth_LOA */
+ unsigned loa;
+
+ /** first child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And, @ref afb_auth_Not } */
+ const struct afb_auth *first;
+ };
+
+ /** second child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And } */
+ const struct afb_auth *next;
};
+
```
The possible values for **type** is defined here:
```C
-/*
- * Enum for Session/Token/Assurance middleware.
+typedef enum afb_auth_type afb_auth_type_t;
+
+/**
+ * Enumeration for authority (Session/Token/Assurance) definitions.
+ *
+ * @see afb_auth
*/
enum afb_auth_type
{
- afb_auth_No = 0, /** never authorized, no data */
- afb_auth_Token, /** authorized if token valid, no data */
- afb_auth_LOA, /** authorized if LOA greater than data 'loa' */
- afb_auth_Permission, /** authorized if permission 'text' is granted */
- afb_auth_Or, /** authorized if 'first' or 'next' is authorized */
- afb_auth_And, /** authorized if 'first' and 'next' are authorized */
- afb_auth_Not, /** authorized if 'first' is not authorized */
- afb_auth_Yes /** always authorized, no data */
+ /** never authorized, no data */
+ afb_auth_No = 0,
+
+ /** authorized if token valid, no data */
+ afb_auth_Token,
+
+ /** authorized if LOA greater than data 'loa' */
+ afb_auth_LOA,
+
+ /** authorized if permission 'text' is granted */
+ afb_auth_Permission,
+
+ /** authorized if 'first' or 'next' is authorized */
+ afb_auth_Or,
+
+ /** authorized if 'first' and 'next' are authorized */
+ afb_auth_And,
+
+ /** authorized if 'first' is not authorized */
+ afb_auth_Not,
+
+ /** always authorized, no data */
+ afb_auth_Yes
};
```
Example:
```C
-static const struct afb_auth _afb_auths_v2_monitor[] = {
- { .type = afb_auth_Permission, .text = "urn:AGL:permission:monitor:public:set" },
- { .type = afb_auth_Permission, .text = "urn:AGL:permission:monitor:public:get" },
- { .type = afb_auth_Or, .first = &_afb_auths_v2_monitor[1], .next = &_afb_auths_v2_monitor[0] }
+static const afb_auth_t myauth[] = {
+ { .type = afb_auth_Permission, .text = "urn:AGL:permission:me:public:set" },
+ { .type = afb_auth_Permission, .text = "urn:AGL:permission:me:public:get" },
+ { .type = afb_auth_Or, .first = &myauth[1], .next = &myauth[0] }
};
```
@@ -115,17 +202,18 @@ to **sd_bus** features.
```C
/*
- * Retrieves the common systemd's event loop of AFB
+ * Retrieves the common systemd's event loop of AFB
+ *
*/
struct sd_event *afb_daemon_get_event_loop();
/*
- * Retrieves the common systemd's user/session d-bus of AFB
+ * Retrieves the common systemd's user/session d-bus of AFB if active
*/
struct sd_bus *afb_daemon_get_user_bus();
/*
- * Retrieves the common systemd's system d-bus of AFB
+ * Retrieves the common systemd's system d-bus of AFB if active or NULL
*/
struct sd_bus *afb_daemon_get_system_bus();
```
@@ -155,7 +243,7 @@ int afb_daemon_broadcast_event(const char *name, struct json_object *object);
*
* See afb_event_is_valid to check if there is an error.
*/
-struct afb_event afb_daemon_make_event(const char *name);
+afb_event_t afb_daemon_make_event(const char *name);
```
The following function is used by logging macros and should normally
@@ -319,7 +407,7 @@ It must be used when creating events.
*
* Returns 0 if not valid or 1 if valid.
*/
-int afb_event_is_valid(struct afb_event event);
+int afb_event_is_valid(afb_event_t event);
```
The two following functions are used to broadcast or push
@@ -336,7 +424,7 @@ event with its data.
*
* Returns the count of clients that received the event.
*/
-int afb_event_broadcast(struct afb_event event, struct json_object *object);
+int afb_event_broadcast(afb_event_t event, struct json_object *object);
/*
* Pushes the 'event' with the data 'object' to its observers.
@@ -348,18 +436,29 @@ int afb_event_broadcast(struct afb_event event, struct json_object *object);
*
* Returns the count of clients that received the event.
*/
-int afb_event_push(struct afb_event event, struct json_object *object);
+int afb_event_push(afb_event_t event, struct json_object *object);
+```
+
+The following function remove one reference to the event.
+
+```C
+/*
+ * Decrease the reference count of the event.
+ * After calling this function, the event
+ * MUST NOT BE USED ANYMORE.
+ */
+void afb_event_unref(afb_event_t event);
```
-The following function destiys the event.
+The following function add one reference to the event.
```C
/*
- * Drops the data associated to the 'event'
+ * Decrease the reference count of the event.
* After calling this function, the event
* MUST NOT BE USED ANYMORE.
*/
-void afb_event_drop(struct afb_event event);
+void afb_event_unref(afb_event_t event);
```
This function allows to retrieve the exact name of the event.
@@ -368,7 +467,7 @@ This function allows to retrieve the exact name of the event.
/*
* Gets the name associated to the 'event'.
*/
-const char *afb_event_name(struct afb_event event);
+const char *afb_event_name(afb_event_t event);
```
## Functions of class afb_req
@@ -381,7 +480,7 @@ This function checks the validity of the **req**.
*
* Returns 0 if not valid or 1 if valid.
*/
-int afb_req_is_valid(struct afb_req req);
+int afb_req_is_valid(afb_req_t req);
```
The following functions retrieves parameters of the request.
@@ -399,7 +498,7 @@ The following functions retrieves parameters of the request.
* an HTTP POST of Content-Type "application/json". In that case, the
* argument of name "" receives the value of the body of the HTTP request.
*/
-struct afb_arg afb_req_get(struct afb_req req, const char *name);
+afb_arg_t afb_req_get(afb_req_t req, const char *name);
/*
* Gets from the request 'req' the string value of the argument of 'name'.
@@ -408,7 +507,7 @@ struct afb_arg afb_req_get(struct afb_req req, const char *name);
*
* Shortcut for: afb_req_get(req, name).value
*/
-const char *afb_req_value(struct afb_req req, const char *name);
+const char *afb_req_value(afb_req_t req, const char *name);
/*
* Gets from the request 'req' the path for file attached to the argument of 'name'.
@@ -417,13 +516,13 @@ const char *afb_req_value(struct afb_req req, const char *name);
*
* Shortcut for: afb_req_get(req, name).path
*/
-const char *afb_req_path(struct afb_req req, const char *name);
+const char *afb_req_path(afb_req_t req, const char *name);
/*
* Gets from the request 'req' the json object hashing the arguments.
* The returned object must not be released using 'json_object_put'.
*/
-struct json_object *afb_req_json(struct afb_req req);
+struct json_object *afb_req_json(afb_req_t req);
```
The following functions emit the reply to the request.
@@ -439,7 +538,7 @@ The following functions emit the reply to the request.
* Thus, in the case where 'obj' should remain available after
* the function returns, the function 'json_object_get' shall be used.
*/
-void afb_req_success(struct afb_req req, struct json_object *obj, const char *info);
+void afb_req_success(afb_req_t req, struct json_object *obj, const char *info);
/*
* Same as 'afb_req_success' but the 'info' is a formatting
@@ -449,7 +548,7 @@ void afb_req_success(struct afb_req req, struct json_object *obj, const char *in
* Thus, in the case where 'obj' should remain available after
* the function returns, the function 'json_object_get' shall be used.
*/
-void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...);
+void afb_req_success_f(afb_req_t req, struct json_object *obj, const char *info, ...);
/*
* Same as 'afb_req_success_f' but the arguments to the format 'info'
@@ -459,30 +558,30 @@ void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *
* Thus, in the case where 'obj' should remain available after
* the function returns, the function 'json_object_get' shall be used.
*/
-void afb_req_success_v(struct afb_req req, struct json_object *obj, const char *info, va_list args);
+void afb_req_success_v(afb_req_t req, struct json_object *obj, const char *info, va_list args);
/*
* Sends a reply of kind failure to the request 'req'.
* The status of the reply is set to 'status' and an
- * informationnal comment 'info' (can also be NULL) can be added.
+ * informational comment 'info' (can also be NULL) can be added.
*
* Note that calling afb_req_fail("success", info) is equivalent
* to call afb_req_success(NULL, info). Thus even if possible it
* is strongly recommended to NEVER use "success" for status.
*/
-void afb_req_fail(struct afb_req req, const char *status, const char *info);
+void afb_req_fail(afb_req_t req, const char *status, const char *info);
/*
* Same as 'afb_req_fail' but the 'info' is a formatting
* string followed by arguments.
*/
-void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...);
+void afb_req_fail_f(afb_req_t req, const char *status, const char *info, ...);
/*
* Same as 'afb_req_fail_f' but the arguments to the format 'info'
* are given as a variable argument list instance.
*/
-void afb_req_fail_v(struct afb_req req, const char *status, const char *info, va_list args);
+void afb_req_fail_v(afb_req_t req, const char *status, const char *info, va_list args);
```
The following functions handle the session data.
@@ -492,14 +591,14 @@ The following functions handle the session data.
* Gets the pointer stored by the binding for the session of 'req'.
* When the binding has not yet recorded a pointer, NULL is returned.
*/
-void *afb_req_context_get(struct afb_req req);
+void *afb_req_context_get(afb_req_t req);
/*
* Stores for the binding the pointer 'context' to the session of 'req'.
* The function 'free_context' will be called when the session is closed
* or if binding stores an other pointer.
*/
-void afb_req_context_set(struct afb_req req, void *context, void (*free_context)(void*));
+void afb_req_context_set(afb_req_t req, void *context, void (*free_context)(void*));
/*
* Gets the pointer stored by the binding for the session of 'req'.
@@ -508,7 +607,7 @@ void afb_req_context_set(struct afb_req req, void *context, void (*free_context)
* the function 'create_context' and stores it with the freeing function
* 'free_context'.
*/
-void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*));
+void *afb_req_context(afb_req_t req, void *(*create_context)(), void (*free_context)(void*));
/*
* Frees the pointer stored by the binding for the session of 'req'
@@ -516,13 +615,13 @@ void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free
*
* Shortcut for: afb_req_context_set(req, NULL, NULL)
*/
-void afb_req_context_clear(struct afb_req req);
+void afb_req_context_clear(afb_req_t req);
/*
* Closes the session associated with 'req'
* and delete all associated contexts.
*/
-void afb_req_session_close(struct afb_req req);
+void afb_req_session_close(afb_req_t req);
/*
* Sets the level of assurance of the session of 'req'
@@ -530,7 +629,7 @@ void afb_req_session_close(struct afb_req req);
* security policies.
* Returns 1 on success or 0 if failed.
*/
-int afb_req_session_set_LOA(struct afb_req req, unsigned level);
+int afb_req_session_set_LOA(afb_req_t req, unsigned level);
```
The 4 following functions must be used for asynchronous handling requests.
@@ -541,14 +640,14 @@ The 4 following functions must be used for asynchronous handling requests.
* This function MUST be called by asynchronous implementations
* of verbs if no reply was sent before returning.
*/
-void afb_req_addref(struct afb_req req);
+void afb_req_addref(afb_req_t req);
/*
* Substracts one to the count of references of 'req'.
* This function MUST be called by asynchronous implementations
* of verbs after sending the asynchronous reply.
*/
-void afb_req_unref(struct afb_req req);
+void afb_req_unref(afb_req_t req);
/*
* Stores 'req' on heap for asynchronous use.
@@ -556,7 +655,7 @@ void afb_req_unref(struct afb_req req);
* The count of reference to 'req' is incremented on success
* (see afb_req_addref).
*/
-struct afb_stored_req *afb_req_store(struct afb_req req);
+struct afb_stored_req *afb_req_store(afb_req_t req);
/*
* Retrieves the afb_req stored at 'sreq'.
@@ -565,7 +664,7 @@ struct afb_stored_req *afb_req_store(struct afb_req req);
* function 'afb_req_unref' should be called on the result
* after that the asynchronous reply if sent.
*/
-struct afb_req afb_req_unstore(struct afb_stored_req *sreq);
+afb_req_t afb_req_unstore(struct afb_stored_req *sreq);
```
The two following functions are used to associate client with events
@@ -577,14 +676,14 @@ The two following functions are used to associate client with events
* to the 'event'.
* Returns 0 in case of successful subscription or -1 in case of error.
*/
-int afb_req_subscribe(struct afb_req req, struct afb_event event);
+int afb_req_subscribe(afb_req_t req, afb_event_t event);
/*
* Revokes the subscription established to the 'event' for the client
* link identified by 'req'.
* Returns 0 in case of successful subscription or -1 in case of error.
*/
-int afb_req_unsubscribe(struct afb_req req, struct afb_event event);
+int afb_req_unsubscribe(afb_req_t req, afb_event_t event);
```
The following functions must be used to make request in the name of the
@@ -609,7 +708,7 @@ client (with its permissions).
* - 'afb_req_subcall_sync' the synchronous version
*/
void afb_req_subcall(
- struct afb_req req,
+ afb_req_t req,
const char *api,
const char *verb,
struct json_object *args,
@@ -634,7 +733,7 @@ void afb_req_subcall(
* - 'afb_req_subcall' that doesn't keep request alive automatically.
* - 'afb_req_subcall_sync' the synchronous version
*/
-static inline void afb_req_subcall_req(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req req), void *closure)
+static inline void afb_req_subcall_req(afb_req_t req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, afb_req_t req), void *closure)
{
req.itf->subcall_req(req.closure, api, verb, args, callback, closure);
}
@@ -656,7 +755,7 @@ static inline void afb_req_subcall_req(struct afb_req req, const char *api, cons
* - 'afb_req_subcall' that doesn't keep request alive automatically.
*/
int afb_req_subcall_sync(
- struct afb_req req,
+ afb_req_t req,
const char *api,
const char *verb,
struct json_object *args,
@@ -691,7 +790,7 @@ Instead, you should use the macros:
* INFO 6 Informational
* DEBUG 7 Debug-level messages
*/
-void afb_req_verbose(struct afb_req req, int level, const char *file, int line, const char * func, const char *fmt, ...);
+void afb_req_verbose(afb_req_t req, int level, const char *file, int line, const char * func, const char *fmt, ...);
```
The functions below allow a binding involved in the platform security
@@ -705,7 +804,7 @@ application identity.
*
* Returns 1 if the permission is granted or 0 otherwise.
*/
-int afb_req_has_permission(struct afb_req req, const char *permission);
+int afb_req_has_permission(afb_req_t req, const char *permission);
/*
* Get the application identifier of the client application for the
@@ -716,7 +815,7 @@ int afb_req_has_permission(struct afb_req req, const char *permission);
*
* The returned value if not NULL must be freed by the caller
*/
-char *afb_req_get_application_id(struct afb_req req);
+char *afb_req_get_application_id(afb_req_t req);
/*
* Get the user identifier (UID) of the client application for the
@@ -724,7 +823,7 @@ char *afb_req_get_application_id(struct afb_req req);
*
* Returns -1 when the application can not be identified.
*/
-int afb_req_get_uid(struct afb_req req);
+int afb_req_get_uid(afb_req_t req);
```
## Logging macros
diff --git a/docs/afb-binding-writing.md b/docs/afb-binding-writing.md
index aad422c4..69090e3d 100644
--- a/docs/afb-binding-writing.md
+++ b/docs/afb-binding-writing.md
@@ -51,14 +51,21 @@ The binder makes no distinctions between upper case and lower case
latin letters.
So **API/VERB** matches **Api/Verb** or **api/verb**.
-Actually it exists 2 ways of writing ***bindings***.
+## Versions of the bindings
+
+Since introduction of the binder, the way how bindings are written
+evolved a little. While changing, attention was made to ensure binary
+compatibility between the different versions.
+
+Actually it exists 3 ways of writing ***bindings***.
You can either write:
-- a binding version 1 (not recommended);
-- a binding version 2 (RECOMMENDED).
+- a binding version 1 (not more supported);
+- a binding version 2 (not recommended);
+- a binding version 3 (RECOMMENDED).
A ***binder*** loads and runs any of these version in any combination.
-This document explain how to write bindings version 2.
+This document explain how to write bindings version 3.
<!-- pagebreak -->
@@ -67,21 +74,21 @@ This document explain how to write bindings version 2.
This is the code of the binding **tuto-1.c**:
```C
- 1 #define AFB_BINDING_VERSION 2
+ 1 #define AFB_BINDING_VERSION 3
2 #include <afb/afb-binding.h>
3
- 4 void hello(afb_req req)
+ 4 void hello(afb_req_t req)
5 {
6 AFB_REQ_DEBUG(req, "hello world");
- 7 afb_req_success(req, NULL, "hello world");
+ 7 afb_req_reply(req, NULL, NULL, "hello world");
8 }
9
- 10 const afb_verb_v2 verbs[] = {
+ 10 const afb_verb_t verbs[] = {
11 { .verb="hello", .callback=hello },
12 { .verb=NULL }
13 };
14
- 15 const afb_binding_v2 afbBindingV2 = {
+ 15 const afb_binding_t afbBindingExport = {
16 .api = "tuto-1",
17 .verbs = verbs
18 };
@@ -93,12 +100,18 @@ Compiling:
gcc -fPIC -shared tuto-1.c -o tuto-1.so $(pkg-config --cflags-only-I afb-daemon)
```
+> Note: the variable environment variable PKG_CONFIG_PATH might be necessary
+> tuned to get **pkg-config** working properly
+
Running:
```bash
afb-daemon --binding tuto-1.so --port 3333 --token ''
```
+At this point, afb-daemon has started, it loaded the binding tuto-1.so and now
+listen at localhost on the port 3333.
+
Testing using **curl**:
```bash
@@ -133,18 +146,15 @@ This shows basic things:
The lines 1 and 2 show how to get the include file **afb-binding.h**.
```C
- 1 #define AFB_BINDING_VERSION 2
+ 1 #define AFB_BINDING_VERSION 3
2 #include <afb/afb-binding.h>
```
-You must define the version of ***binding*** that you are using.
-This is done line 1 where we define that this is the version 2.
+You must define the version of ***binding*** that you are using.
+This is done line 1 where we define that this is the version 3 (earlier
+versions 1 and 2 are deprecated).
-If you don't define it, a warning message is prompted by the compiler
-and the version is switched to version 1.
-This behaviour is temporarily and enables to continue to use previously written
-***binding*** without change but it will change in some future when
-***bindings*** V1 will become obsoletes.
+If you don't define it, an error is reported and the compilation aborts.
To include **afb-binding.h** successfully, the include search path
should be set correctly if needed (not needed only if installed in
@@ -156,81 +166,54 @@ Setting the include path is easy using **pkg-config**:
pkg-config --cflags-only-I afb-daemon
```
-Note for **C++** developers:
-
-- The ***binder*** currently expose only **C** language **API**.
- The file **afb/afb-binding.h** isn't **C++** ready.
-
-You should use the construct **extern "C"** as below:
+> Note for **C++** developers:
+>
+> The ***binder*** currently expose a draft version of **C++** api.
+> To get it include the file <**afb/afb-binding**> (without **.h**).
-```C
- #define AFB_BINDING_VERSION 2
- extern "C" {
- #include <afb/afb-binding.h>
- }
-```
-
-Future version of the ***binder*** will include a **C++**
-interface.
-Until it is available, please, use the above construct.
### Declaring the API of the binding
Lines 10 to 18 show the declaration of the ***binding***.
-The ***binder*** knows that this is a ***binding*** version 2 because
-it finds the exported symbol **afbBindingV2** that is expected to be
-a structure of type **afb_binding_v2**.
+The ***binder*** knows that this is a ***binding*** because
+it finds the exported symbol **afbBindingExport** that is expected to be
+a structure of type **afb_binding_t**.
```C
- 10 const afb_verb_v2 verbs[] = {
+ 10 const afb_verb_t verbs[] = {
11 { .verb="hello", .callback=hello },
12 { .verb=NULL }
13 };
14
- 15 const afb_binding_v2 afbBindingV2 = {
+ 15 const afb_binding_t afbBindingExport = {
16 .api = "tuto-1",
17 .verbs = verbs
18 };
```
-The structure **afbBindingV2** actually tells that:
+The structure **afbBindingExport** actually tells that:
- the exported **API** name is **tuto-1** (line 16)
- the array of verbs is the above defined one
-The exported list of verb is specified by an array of structures,
-each describing a verb, ended with a verb NULL (line 12).
+The exported list of verb is specified by an array of structures of
+type **afb_verb_t**, each describing a verb, ended with a verb NULL (line 12).
The only defined verb here (line 11) is named **hello** (field **.verb**)
and the function that handle the related request is **hello**
(field **.callback**).
-Note that you can explicitly mark the fact that these are
-struct by typing the **struct** as below:
-
-```C
- 10 const struct afb_verb_v2 verbs[] = {
- 11 { .verb="hello", .callback=hello },
- 12 { .verb=NULL }
- 13 };
- 14
- 15 const struct afb_binding_v2 afbBindingV2 = {
- 16 .api = "tuto-1",
- 17 .verbs = verbs
- 18 };
-```
-
### Handling binder's requests
As shown above this is by default the common include directory where
the AGL stuff is installed.
```C
- 4 void hello(afb_req req)
+ 4 void hello(afb_req_t req)
5 {
6 AFB_REQ_DEBUG(req, "hello world");
- 7 afb_req_success(req, NULL, "hello world");
+ 7 afb_req_reply(req, NULL, NULL, "hello world");
8 }
```
@@ -241,18 +224,15 @@ with the argument **req** that handles the client request.
The callback has to treat synchronously or asynchronously the request and
should at the end emit a reply for the request.
-Here, the callback for **tuto-1/hello** replies a successful answer
-(line 7) to the request **req**.
-The second parameter (here NULL) is a json object that is sent to the client with the reply.
-The third parameter is also sent with the reply and is a string
-called info that can be used as some meta data.
+At the line 7, the callback for **tuto-1/hello** replies to the request **req**.
+Parameters of the reply are:
-Here again, you can explicitly mark the fact that
-**afb_req** is a structure by declaring **hello** as below:
+ 1. The first parameter is the replied request
+ 2. The second parameter is a json object (here NULL)
+ 3. The third parameter is the error string indication (here NULL: no error)
+ 4. The fourth parameter is an informative string (that can be NULL) that can be used to provide meta data.
-```C
- 4 void hello(struct afb_req req)
-```
+The 3 last parameters are sent back to the client as the reply content.
<!-- pagebreak -->
@@ -268,43 +248,43 @@ This is the code of the binding **tuto-2.c**:
```C
1 #include <string.h>
2 #include <json-c/json.h>
- 3
- 4 #define AFB_BINDING_VERSION 2
+ 3
+ 4 #define AFB_BINDING_VERSION 3
5 #include <afb/afb-binding.h>
- 6
- 7 afb_event event_login, event_logout;
- 8
- 9 void login(afb_req req)
+ 6
+ 7 afb_event_t event_login, event_logout;
+ 8
+ 9 void login(afb_req_t req)
10 {
11 json_object *args, *user, *passwd;
12 char *usr;
- 13
+ 13
14 args = afb_req_json(req);
15 if (!json_object_object_get_ex(args, "user", &user)
16 || !json_object_object_get_ex(args, "password", &passwd)) {
17 AFB_REQ_ERROR(req, "login, bad request: %s", json_object_get_string(args));
- 18 afb_req_fail(req, "bad-request", NULL);
+ 18 afb_req_reply(req, NULL, "bad-request", NULL);
19 } else if (afb_req_context_get(req)) {
20 AFB_REQ_ERROR(req, "login, bad state, logout first");
- 21 afb_req_fail(req, "bad-state", NULL);
+ 21 afb_req_reply(req, NULL, "bad-state", NULL);
22 } else if (strcmp(json_object_get_string(passwd), "please")) {
23 AFB_REQ_ERROR(req, "login, unauthorized: %s", json_object_get_string(args));
- 24 afb_req_fail(req, "unauthorized", NULL);
+ 24 afb_req_reply(req, NULL, "unauthorized", NULL);
25 } else {
26 usr = strdup(json_object_get_string(user));
27 AFB_REQ_NOTICE(req, "login user: %s", usr);
28 afb_req_session_set_LOA(req, 1);
29 afb_req_context_set(req, usr, free);
- 30 afb_req_success(req, NULL, NULL);
+ 30 afb_req_reply(req, NULL, NULL, NULL);
31 afb_event_push(event_login, json_object_new_string(usr));
32 }
33 }
- 34
- 35 void action(afb_req req)
+ 34
+ 35 void action(afb_req_t req)
36 {
37 json_object *args, *val;
38 char *usr;
- 39
+ 39
40 args = afb_req_json(req);
41 usr = afb_req_context_get(req);
42 AFB_REQ_NOTICE(req, "action for user %s: %s", usr, json_object_get_string(args));
@@ -319,46 +299,46 @@ This is the code of the binding **tuto-2.c**:
51 afb_req_unsubscribe(req, event_logout);
52 }
53 }
- 54 afb_req_success(req, json_object_get(args), NULL);
+ 54 afb_req_reply(req, json_object_get(args), NULL, NULL);
55 }
- 56
- 57 void logout(afb_req req)
+ 56
+ 57 void logout(afb_req_t req)
58 {
59 char *usr;
- 60
+ 60
61 usr = afb_req_context_get(req);
62 AFB_REQ_NOTICE(req, "login user %s out", usr);
63 afb_event_push(event_logout, json_object_new_string(usr));
64 afb_req_session_set_LOA(req, 0);
65 afb_req_context_clear(req);
- 66 afb_req_success(req, NULL, NULL);
+ 66 afb_req_reply(req, NULL, NULL, NULL);
67 }
- 68
- 69 int preinit()
+ 68
+ 69 int preinit(afb_api_t api)
70 {
- 71 AFB_NOTICE("preinit");
+ 71 AFB_API_NOTICE(api, "preinit");
72 return 0;
73 }
- 74
- 75 int init()
+ 74
+ 75 int init(afb_api_t api)
76 {
- 77 AFB_NOTICE("init");
- 78 event_login = afb_daemon_make_event("login");
- 79 event_logout = afb_daemon_make_event("logout");
+ 77 AFB_API_NOTICE(api, "init");
+ 78 event_login = afb_api_make_event(api, "login");
+ 79 event_logout = afb_api_make_event(api, "logout");
80 if (afb_event_is_valid(event_login) && afb_event_is_valid(event_logout))
81 return 0;
- 82 AFB_ERROR("Can't create events");
+ 82 AFB_API_ERROR(api, "Can't create events");
83 return -1;
84 }
- 85
- 86 const afb_verb_v2 verbs[] = {
+ 85
+ 86 const afb_verb_t verbs[] = {
87 { .verb="login", .callback=login },
88 { .verb="action", .callback=action, .session=AFB_SESSION_LOA_1 },
89 { .verb="logout", .callback=logout, .session=AFB_SESSION_LOA_1 },
90 { .verb=NULL }
91 };
- 92
- 93 const afb_binding_v2 afbBindingV2 = {
+ 92
+ 93 const afb_binding_t afbBindingExport = {
94 .api = "tuto-2",
95 .specification = NULL,
96 .verbs = verbs,
diff --git a/docs/afb-daemon-debugging.md b/docs/afb-daemon-debugging.md
index dd5fd64b..4cf62bea 100644
--- a/docs/afb-daemon-debugging.md
+++ b/docs/afb-daemon-debugging.md
@@ -1,4 +1,4 @@
-# Debugging afb-daemon and its bindings
+# Debugging binder and bindings
When compiled with the symbol AGL_DEVEL defined, the ***binder***
understand the 2 configuration variables:
diff --git a/docs/afb-daemon-vocabulary.md b/docs/afb-daemon-vocabulary.md
index 6c51f124..efe53d20 100644
--- a/docs/afb-daemon-vocabulary.md
+++ b/docs/afb-daemon-vocabulary.md
@@ -24,10 +24,6 @@ assurance that the services can expect from the session.
The exact definition of the meaning of these levels and how to use it remains to
be achieved.
-## Plugin
-
-Old name for binding, see binding.
-
## Request
A request is an invocation by a client to a binding method using a message
@@ -51,7 +47,7 @@ It can serve many client.
Each one attached to one session.
The framework establishes connection between the services and the clients.
-Using DBus currently but other protocols are considered.
+Using sockets currently but other protocols are considered.
## Session
diff --git a/docs/afb-migration-to-binding-v3.md b/docs/afb-migration-to-binding-v3.md
new file mode 100644
index 00000000..8f1e678c
--- /dev/null
+++ b/docs/afb-migration-to-binding-v3.md
@@ -0,0 +1,110 @@
+Migration to binding V3
+=======================
+
+The ***binding*** interface evolved from version 1 to version 2
+for the following reasons:
+
+- integration of the security requirements within the bindings
+- simplification of the API (after developer feedbacks)
+- removal of obscure features, cleanup
+
+The ***binder*** can run ***bindings*** v1, v2 and/or v3 in any combination.
+Thus moving from v1 or v2 to v3 is not enforced at this time. But ...
+
+In the face to face meeting of Karlsruhe it was decided to remove support
+of bindings v1 and to deprecate the use of bindings v2.
+
+So at the end, **IT IS HIGHLY NEEDED TO SWITCH TO VERSION 3**
+
+This guide covers the migration of bindings from version 2 to version 3.
+
+The migration from version 1 is not treated here because bindings version 1
+are very old and probably does not exist anymore. If needed you can refer
+to the old [guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md).
+
+
+Differences between version 2 and version 3
+-------------------------------------------
+
+### in v3 all is api
+
+The version 3 introduce the concept of "API" that gather what was called before
+the daemon and the service. This is the new concept that predates the 2 others.
+
+The concept of API is intended to allow the definition of multiple APIs
+by a same "binding" (a dynamically loaded library).
+
+Because there is potentially several "API", the functions that were without
+context in bindings version 2 need now to tell what API is consumer.
+
+To be compatible with version 2, the bindings v3 still have a default hidden
+context: the default API named **afbBindingV3root**.
+
+To summarize, the functions of class **daemon** and **service** use the default
+hidden API.
+
+It is encouraged to avoid use of functions of class **daemon** and **service**.
+You should replace these implicit calls to explicit **api** calls that
+reference **afbBindingV3root**.
+
+Same thing for the logging macros: **AFB_ERROR**, **AFB_WARNING**,
+**AFB_NOTICE**, **AFB_INFO**, **AFB_DEBUG** that becomes respectively
+**AFB_API_ERROR**, **AFB_API_WARNING**, **AFB_API_NOTICE**, **AFB_API_INFO**,
+**AFB_API_DEBUG**.
+
+Example of 2 equivalent writes:
+
+```C
+ AFB_NOTICE("send stress event");
+ afb_daemon_broadcast_event(stressed_event, NULL);
+```
+
+or
+
+```C
+ AFB_API_NOTICE(afbBindingV3root, "send stress event");
+ afb_api_broadcast_event(afbBindingV3root, stressed_event, NULL);
+```
+
+### the reply mechanism predates success and fail
+
+### subcall has more power
+
+Task list for the migration
+---------------------------
+
+This task list is:
+
+1. Use the automatic migration procedure described below
+2. Adapt the init and preinit functions
+3. Consider to change to use the new reply
+4. Consider to change to use the new (sub)call
+
+The remaining chapters explain these task with more details.
+
+Automatic migration!
+--------------------
+
+A tiny **sed** script is intended to perform a first pass on the code that
+you want to upgrade. It can be down using **curl** and applied using **sed**
+as below.
+
+```bash
+BASE=https://git.automotivelinux.org/src/app-framework-binder/tree
+SED=migration-to-binding-v3.sed
+curl -o $SED $BASE/docs/$SED
+sed -i -f $SED file1 file2 file3...
+```
+
+This automatic action does most of the boring job nut not all the job.
+The remaining of this guide explains the missing part.
+
+Adapt the init and preinit functions
+------------------------------------
+
+Consider to change to use the new reply
+---------------------------------------
+
+Consider to change to use the new (sub)call
+-------------------------------------------
+
diff --git a/docs/afb-migration-v1-to-v2.md b/docs/afb-migration-v1-to-v2.md
index f3182918..9a43454e 100644
--- a/docs/afb-migration-v1-to-v2.md
+++ b/docs/afb-migration-v1-to-v2.md
@@ -1,6 +1,11 @@
-Migration from binding V1 to binding V2
+[LEGACY] Migration from binding V1 to binding V2
=======================================
+> LEGACY!!! IT IS NOT EXPECTED THAT YOU STILL NEED THIS GUIDE.
+>
+> THIS GUIDE WILL BE REMOVED IN A NEAR FUTURE
+
+
The ***binding*** interface evolved from version 1 to version 2
for the following reasons:
diff --git a/docs/afb-overview.md b/docs/afb-overview.md
index 0cff24cc..2682d8d1 100644
--- a/docs/afb-overview.md
+++ b/docs/afb-overview.md
@@ -6,14 +6,14 @@ the services that it needs.
It provides a fast way to securely offer APIs to applications
written in any language and running almost anywhere.
-- The ***binder*** is developed for AGL.
+- The ***binder*** is developed for AGL (Automotive Grade Linux) but it is not bound to AGL.
- The ***binder*** is the usual name.
- The binary is named **afb-daemon**.
- The name **afb-daemon** stands for ***Application Framework Binder Daemon***.
The word *daemon*, here, denote the fact that the ***binder*** makes witchcraft to
-connect applications to their expected services.
-(note: that usually the term of daemon denotes background process but not here).
+connect applications to their expected services. (note: that usually the term of
+daemon denotes background process but not here).
Each ***binder*** **afb-daemon** is in charge to bind one instance of
an application or service to the rest of the system, applications and services.
diff --git a/docs/annexes.md b/docs/annexes.md
index 2304bfb0..10952e0f 100644
--- a/docs/annexes.md
+++ b/docs/annexes.md
@@ -1,4 +1,7 @@
# Annexes
+* [Migration to binding v3](afb-migration-to-binding-v3.md)
+* [Options of afb-daemon](afb-daemon-options.md)
* [Installing the binder on a desktop](afb-desktop-package.md)
-* [Options of afb-daemon](afb-daemon-options.md) \ No newline at end of file
+* [Debugging afb-daemon](afb-daemon-debugging.md)
+* [(LEGACY) guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md).
diff --git a/docs/migration-to-binding-v3.sed b/docs/migration-to-binding-v3.sed
new file mode 100644
index 00000000..a6682051
--- /dev/null
+++ b/docs/migration-to-binding-v3.sed
@@ -0,0 +1,68 @@
+#######################################################################################
+# Script sed for migrating from AFB_BINDING_VERSION 2 to AFB_BINDING_VERSION 3
+# See http://docs.automotivelinux.org/docs/apis_services/en/dev/reference/af-binder/afb-migration-to-ibinding-v3.html
+#######################################################################################
+# update the version
+# ------------------
+s:\(\<AFB_BINDING_VERSION[[:blank:]]\{1,\}\)2\>:\13:
+
+# update common types
+# -------------------
+s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_req\>:afb_req_t:g
+s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_event\>:afb_event_t:g
+s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_verb_v2\>:afb_verb_t:g
+s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_binding_v2\>:afb_binding_t:g
+
+# update common names
+# -------------------
+s:\<afbBindingV2\>:afbBindingExport:g
+
+# very special
+# ------------
+s:( *afb_req_t *) *{ *NULL *, *NULL *}:NULL:g
+
+# special dynapi
+# --------------
+s:\(\<AFB_BINDING_VERSION[[:blank:]]\{1,\}\)0\>:\13:
+/^[[:blank:]]*# *define *\<AFB_BINDING_WANT_DYNAPI\>/d
+s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_dynapi\>\([[:blank:]]*\)\*:afb_api_t\2:g
+s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_request\>\([[:blank:]]*\)\*:afb_req_t\2:g
+s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_eventid\>\([[:blank:]]*\)\*:afb_event_t\2:g
+s:\<afb_request_:afb_req_:g
+s:\<afb_dynapi_:afb_api_:g
+s:\<afb_eventid_:afb_event_:g
+s:\<AFB_DYNAPI_:AFB_API_:g
+s:\<AFB_REQUEST_:AFB_REQ_:g
+s:\<afbBindingVdyn\>:afbBindingV3entry:g
+s:\<dynapi\>:api:g
+s:\<eventid\>:event:g
+s:\<afb_api_make_eventid\>:afb_api_make_event:g
+s:\<afb_api_new_api\>:-!&:g
+s:\<afb_api_sub_verb\>:afb_api_del_verb:g
+
+# udate legacy calls
+# ------------------
+s:\<afb_req_subcall\(_req\)\>:afb_req_subcall_legacy:g
+s:\<afb_req_subcall_sync\>:afb_req_subcall_sync_legacy:g
+s:\<afb_api_call\>:afb_api_call_legacy:g
+s:\<afb_api_call_sync\>:afb_api_call_sync_legacy:g
+s:\<afb_req_store\>:afb_req_addref:g
+s:\<afb_req_unstore\> *( *\(.*\) *):\1:g
+s:\<afb_daemon_\([a-z_0-9]* *(\):afb_api_\1afbBindingV3root,:g
+s:\<afb_daemon_\([a-z_0-9]* *(\):afb_api_\1afbBindingV3root,:g
+s:\<afb_service_call_\([a-z_0-9]*\)\( *(\):afb_api_\1_legacy\2afbBindingV3root,:g
+s:\<afb_service_\([a-z_0-9]* *(\):afb_api_\1afbBindingV3root,:g
+s:\<AFB_\(\(ERROR\|WARNING\|NOTICE\|INFO\|DEBUG\)\> *(\):AFB_API_\1afbBindingV3root,:g
+
+# special app-controller
+# ----------------------
+s:\<_\(AFB_SYSLOG_LEVEL_[A-Z]*\)_\>:\1:g
+
+# UNSAFES (uncomment it if optimistic)
+# --------------
+#s:\<afb_req_fail\(_[fv]\)\{0,1\}\>\( *([^,]*\):afb_req_reply\1\2, NULL:g
+#s:\<afb_req_success\(_[fv]\)\{0,1\}\>\( *([^,]*,[^,]*\):afb_req_reply\1\2, NULL:g
+#
+#s:\<afb_api_add_verb\>[^)]*:&, 0:g ;# dynapi
+#s:\<afb_api_del_verb\>[^)]*:&, NULL:g ;# dynapi
+#######################################################################################
diff --git a/doxyfile.binder b/doxyfile.binder
new file mode 100644
index 00000000..4aef9a15
--- /dev/null
+++ b/doxyfile.binder
@@ -0,0 +1,2435 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "AGL micro-service binder"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ./docs/binder
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = NO
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ./include \
+ ./src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS = *.c \
+ *.cxx \
+ *.cpp \
+ *.h \
+ *.hxx \
+ *.hpp \
+ *.md
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH = bindings/tutorial
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = NO
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 30
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 150
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 150
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: https://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH = ../app-framework-binder/include
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = __attribute__(x)= \
+ AFB_BINDING_VERSION=3
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/doxyfile.binding b/doxyfile.binding
new file mode 100644
index 00000000..78841591
--- /dev/null
+++ b/doxyfile.binding
@@ -0,0 +1,2434 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "AGL micro-service API for bindings"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ./docs/binding
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = NO
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ./include
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS = *.c \
+ *.cxx \
+ *.cpp \
+ *.h \
+ *.hxx \
+ *.hpp \
+ *.md
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH = bindings/tutorial
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = NO
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 130
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 100
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: https://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH = ../app-framework-binder/include
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = __attribute__(x)= \
+ AFB_BINDING_VERSION=3
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/include/afb/afb-api-x3-itf.h b/include/afb/afb-api-x3-itf.h
new file mode 100644
index 00000000..38b29196
--- /dev/null
+++ b/include/afb/afb-api-x3-itf.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/* declared here */
+struct afb_api_x3;
+struct afb_api_x3_itf;
+
+/* referenced here */
+struct sd_event;
+struct sd_bus;
+struct afb_req_x2;
+struct afb_event_x2;
+struct afb_auth;
+struct afb_verb_v2;
+struct afb_verb_v3;
+
+/**
+ * Structure for the APIv3
+ */
+struct afb_api_x3
+{
+ /**
+ * Interface functions
+ *
+ * Don't use it directly, prefer helper functions.
+ */
+ const struct afb_api_x3_itf *itf;
+
+ /**
+ * The name of the api
+ *
+ * @see afb_api_x3_name
+ */
+ const char *apiname;
+
+ /**
+ * User defined data
+ *
+ * @see afb_api_x3_set_userdata
+ * @see afb_api_x3_get_userdata
+ */
+ void *userdata;
+
+ /**
+ * Current verbosity mask
+ *
+ * The bits tells what verbosity is required for the api.
+ * It is related to the syslog levels.
+ *
+ * EMERGENCY 0 System is unusable
+ * ALERT 1 Action must be taken immediately
+ * CRITICAL 2 Critical conditions
+ * ERROR 3 Error conditions
+ * WARNING 4 Warning conditions
+ * NOTICE 5 Normal but significant condition
+ * INFO 6 Informational
+ * DEBUG 7 Debug-level messages
+ */
+ int logmask;
+};
+
+/**
+ * Definition of the function's interface for the APIv3
+ */
+struct afb_api_x3_itf
+{
+ /* CAUTION: respect the order, add at the end */
+
+ /** sending log messages */
+ void (*vverbose)(
+ struct afb_api_x3 *api,
+ int level,
+ const char *file,
+ int line,
+ const char * func,
+ const char *fmt,
+ va_list args);
+
+ /** gets the common systemd's event loop */
+ struct sd_event *(*get_event_loop)(
+ struct afb_api_x3 *api);
+
+ /** gets the common systemd's user d-bus */
+ struct sd_bus *(*get_user_bus)(
+ struct afb_api_x3 *api);
+
+ /** gets the common systemd's system d-bus */
+ struct sd_bus *(*get_system_bus)(
+ struct afb_api_x3 *api);
+
+ /** get the file descriptor for the root directory */
+ int (*rootdir_get_fd)(
+ struct afb_api_x3 *api);
+
+ /** get a file using locale setting */
+ int (*rootdir_open_locale)(
+ struct afb_api_x3 *api,
+ const char *filename,
+ int flags,
+ const char *locale);
+
+ /** queue a job */
+ int (*queue_job)(
+ struct afb_api_x3 *api,
+ void (*callback)(int signum, void *arg),
+ void *argument,
+ void *group,
+ int timeout);
+
+ /** requires an api initialized or not */
+ int (*require_api)(
+ struct afb_api_x3 *api,
+ const char *name,
+ int initialized);
+
+ /** add an alias */
+ int (*add_alias)(
+ struct afb_api_x3 *api,
+ const char *name,
+ const char *as_name);
+
+ /** broadcasts event 'name' with 'object' */
+ int (*event_broadcast)(
+ struct afb_api_x3 *api,
+ const char *name,
+ struct json_object *object);
+
+ /** creates an event of 'name' */
+ struct afb_event_x2 *(*event_make)(
+ struct afb_api_x3 *api,
+ const char *name);
+
+ /** legacy asynchronous invocation */
+ void (*legacy_call)(
+ struct afb_api_x3 *api,
+ const char *apiname,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *),
+ void *closure);
+
+ /** legacy synchronous invocation */
+ int (*legacy_call_sync)(
+ struct afb_api_x3 *api,
+ const char *apiname,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result);
+
+ /** creation of a new api*/
+ struct afb_api_x3 *(*api_new_api)(
+ struct afb_api_x3 *api,
+ const char *apiname,
+ const char *info,
+ int noconcurrency,
+ int (*preinit)(void*, struct afb_api_x3 *),
+ void *closure);
+
+ /** set verbs of the api using v2 description */
+ int (*api_set_verbs_v2)(
+ struct afb_api_x3 *api,
+ const struct afb_verb_v2 *verbs);
+
+ /** add one verb to the api */
+ int (*api_add_verb)(
+ 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);
+
+ /** delete one verb of the api */
+ int (*api_del_verb)(
+ struct afb_api_x3 *api,
+ const char *verb,
+ void **vcbdata);
+
+ /** set the api's callback for processing events */
+ int (*api_set_on_event)(
+ struct afb_api_x3 *api,
+ void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object));
+
+ /** set the api's callback for initialisation */
+ int (*api_set_on_init)(
+ struct afb_api_x3 *api,
+ int (*oninit)(struct afb_api_x3 *api));
+
+ /** seal the api */
+ void (*api_seal)(
+ struct afb_api_x3 *api);
+
+ /** set verbs of the api using v3 description */
+ int (*api_set_verbs_v3)(
+ struct afb_api_x3 *api,
+ const struct afb_verb_v3 *verbs);
+
+ /** add an event handler for the api */
+ int (*event_handler_add)(
+ struct afb_api_x3 *api,
+ const char *pattern,
+ void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*),
+ void *closure);
+
+ /** delete an event handler of the api */
+ int (*event_handler_del)(
+ struct afb_api_x3 *api,
+ const char *pattern,
+ void **closure);
+
+ /** asynchronous call for the api */
+ void (*call)(
+ struct afb_api_x3 *api,
+ const char *apiname,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_api_x3 *),
+ void *closure);
+
+ /** synchronous call for the api */
+ int (*call_sync)(
+ struct afb_api_x3 *api,
+ const char *apiname,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result,
+ char **error,
+ char **info);
+
+ /** indicate provided classes of the api */
+ int (*class_provide)(
+ struct afb_api_x3 *api,
+ const char *name);
+
+ /** indicate required classes of the api */
+ int (*class_require)(
+ struct afb_api_x3 *api,
+ const char *name);
+
+ /** delete the api */
+ int (*delete_api)(
+ struct afb_api_x3 *api);
+};
+
diff --git a/include/afb/afb-api-x3.h b/include/afb/afb-api-x3.h
new file mode 100644
index 00000000..81323ef5
--- /dev/null
+++ b/include/afb/afb-api-x3.h
@@ -0,0 +1,884 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "afb-verbosity.h"
+#include "afb-api-x3-itf.h"
+
+/**
+ * Get the name of the 'api'.
+ *
+ * @param api the api whose name is to be returned
+ *
+ * @return the name of the api.
+ *
+ * The returned value must not be changed nor freed.
+ */
+static inline
+const char *afb_api_x3_name(struct afb_api_x3 *api)
+{
+ return api->apiname;
+}
+
+/**
+ * Get the "userdata" pointer of the 'api'
+ *
+ * @param api the api whose user's data is to be returned
+ *
+ * @return the user's data pointer of the api.
+ *
+ * @see afb_api_x3_set_userdata
+ */
+static inline
+void *afb_api_x3_get_userdata(struct afb_api_x3 *api)
+{
+ return api->userdata;
+}
+
+/**
+ * Set the "userdata" pointer of the 'api' to 'value'
+ *
+ * @param api the api whose user's data is to be set
+ * @param value the data to set
+ *
+ * @see afb_api_x3_get_userdata
+ */
+static inline
+void afb_api_x3_set_userdata(struct afb_api_x3 *api, void *value)
+{
+ api->userdata = value;
+}
+
+/**
+ * Is the log message of 'level (as defined for syslog) required for the api?
+ *
+ * @param api the api to check
+ * @param level the level to check as defined for syslog:
+ *
+ * EMERGENCY 0 System is unusable
+ * ALERT 1 Action must be taken immediately
+ * CRITICAL 2 Critical conditions
+ * ERROR 3 Error conditions
+ * WARNING 4 Warning conditions
+ * NOTICE 5 Normal but significant condition
+ * INFO 6 Informational
+ * DEBUG 7 Debug-level messages
+ *
+ * @return 0 if not required or a value not null if required
+ *
+ * @see syslog
+ */
+static inline
+int afb_api_x3_wants_log_level(struct afb_api_x3 *api, int level)
+{
+ return AFB_SYSLOG_MASK_WANT(api->logmask, level);
+}
+
+/**
+ * Send to the journal with the log 'level' a message described
+ * by 'fmt' applied to the va-list 'args'.
+ *
+ * 'file', 'line' and 'func' are indicators of position of the code in source files
+ * (see macros __FILE__, __LINE__ and __func__).
+ *
+ * 'level' is defined by syslog standard:
+ *
+ * EMERGENCY 0 System is unusable
+ * ALERT 1 Action must be taken immediately
+ * CRITICAL 2 Critical conditions
+ * ERROR 3 Error conditions
+ * WARNING 4 Warning conditions
+ * NOTICE 5 Normal but significant condition
+ * INFO 6 Informational
+ * DEBUG 7 Debug-level messages
+ *
+ * @param api the api that collects the logging message
+ * @param level the level of the message
+ * @param file the source file that logs the messages or NULL
+ * @param line the line in the source file that logs the message
+ * @param func the name of the function in the source file that logs
+ * @param fmt the format of the message as in printf
+ * @param args the arguments to the format string of the message as a va_list
+ *
+ * @see syslog
+ * @see printf
+ */
+static inline
+void afb_api_x3_vverbose(struct afb_api_x3 *api, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
+{
+ api->itf->vverbose(api, level, file, line, func, fmt, args);
+}
+
+/**
+ * Send to the journal with the log 'level' a message described
+ * by 'fmt' and following parameters.
+ *
+ * 'file', 'line' and 'func' are indicators of position of the code in source files
+ * (see macros __FILE__, __LINE__ and __func__).
+ *
+ * 'level' is defined by syslog standard:
+ * EMERGENCY 0 System is unusable
+ * ALERT 1 Action must be taken immediately
+ * CRITICAL 2 Critical conditions
+ * ERROR 3 Error conditions
+ * WARNING 4 Warning conditions
+ * NOTICE 5 Normal but significant condition
+ * INFO 6 Informational
+ * DEBUG 7 Debug-level messages
+ *
+ * @param api the api that collects the logging message
+ * @param level the level of the message
+ * @param file the source file that logs the messages or NULL
+ * @param line the line in the source file that logs the message
+ * @param func the name of the function in the source file that logs
+ * @param fmt the format of the message as in printf
+ * @param ... the arguments to the format string of the message
+ *
+ * @see syslog
+ * @see printf
+ */
+__attribute__((format(printf, 6, 7)))
+static inline
+void afb_api_x3_verbose(
+ struct afb_api_x3 *api,
+ int level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *fmt,
+ ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ api->itf->vverbose(api, level, file, line, func, fmt, args);
+ va_end(args);
+}
+
+/**
+ * Retrieves the common systemd's event loop of AFB
+ *
+ * @param api the api that uses the event loop
+ *
+ * @return the systemd event loop if active, NULL otherwise
+ *
+ * @see afb_api_x3_get_user_bus
+ * @see afb_api_x3_get_system_bus
+ */
+static inline
+struct sd_event *afb_api_x3_get_event_loop(struct afb_api_x3 *api)
+{
+ return api->itf->get_event_loop(api);
+}
+
+/**
+ * Retrieves the common systemd's user/session d-bus of AFB
+ *
+ * @param api the api that uses the user dbus
+ *
+ * @return the systemd user connection to dbus if active, NULL otherwise
+ *
+ * @see afb_api_x3_get_event_loop
+ * @see afb_api_x3_get_system_bus
+ */
+static inline
+struct sd_bus *afb_api_x3_get_user_bus(struct afb_api_x3 *api)
+{
+ return api->itf->get_user_bus(api);
+}
+
+/**
+ * Retrieves the common systemd's system d-bus of AFB
+ *
+ * @param api the api that uses the system dbus
+ *
+ * @return the systemd system connection to dbus if active, NULL otherwise
+ *
+ * @see afb_api_x3_get_event_loop
+ * @see afb_api_x3_get_user_bus
+ */
+
+static inline
+struct sd_bus *afb_api_x3_get_system_bus(struct afb_api_x3 *api)
+{
+ return api->itf->get_system_bus(api);
+}
+
+/**
+ * Get the root directory file descriptor. This file descriptor can
+ * be used with functions 'openat', 'fstatat', ...
+ *
+ * CAUTION, manipulate this this descriptor with care, in particular, don't close
+ * it.
+ *
+ * This can be used to get the path of the root directory using:
+ *
+ * ```C
+ * char buffer[MAX_PATH];
+ * int dirfd = afb_api_x3_rootdir_get_fd(api);
+ * snprintf(buffer, sizeof buffer, "/proc/self/fd/%d", dirfd);
+ * readlink(buffer, buffer, sizeof buffer);
+ * ```
+ *
+ * But note that within AGL this is the value given by the environment variable
+ * AFM_APP_INSTALL_DIR.
+ *
+ * @param api the api that uses the directory file descriptor
+ *
+ * @return the file descriptor of the root directory.
+ *
+ * @see afb_api_x3_rootdir_open_locale
+ */
+static inline
+int afb_api_x3_rootdir_get_fd(struct afb_api_x3 *api)
+{
+ return api->itf->rootdir_get_fd(api);
+}
+
+/**
+ * Opens 'filename' within the root directory with 'flags' (see function openat)
+ * using the 'locale' definition (example: "jp,en-US") that can be NULL.
+ *
+ * The filename must be relative to the root of the bindings.
+ *
+ * The opening mode must be for read or write but not for O_CREAT.
+ *
+ * The definition of locales and of how files are searched can be checked
+ * here: https://www.w3.org/TR/widgets/#folder-based-localization
+ * and https://tools.ietf.org/html/rfc7231#section-5.3.5
+ *
+ * @param api the api that queries the file
+ * @param filename the relative path to the file to open
+ * @param flags the flags for opening as for C function 'open'
+ * @param locale string indicating how to search content, can be NULL
+ *
+ * @return the file descriptor or -1 in case of error and errno is set with the
+ * error indication.
+ *
+ * @see open
+ * @see afb_api_x3_rootdir_get_fd
+ */
+static inline
+int afb_api_x3_rootdir_open_locale(struct afb_api_x3 *api, const char *filename, int flags, const char *locale)
+{
+ return api->itf->rootdir_open_locale(api, filename, flags, locale);
+}
+
+/**
+ * Queue the job defined by 'callback' and 'argument' for being executed asynchronously
+ * in this thread (later) or in an other thread.
+ *
+ * If 'group' is not NULL, the jobs queued with a same value (as the pointer value 'group')
+ * are executed in sequence in the order of there submission.
+ *
+ * If 'timeout' is not 0, it represent the maximum execution time for the job in seconds.
+ * At first, the job is called with 0 as signum and the given argument.
+ *
+ * The job is executed with the monitoring of its time and some signals like SIGSEGV and
+ * SIGFPE. When a such signal is catched, the job is terminated and reexecuted but with
+ * signum being the signal number (SIGALRM when timeout expired).
+ *
+ * When executed, the callback function receives 2 arguments:
+ *
+ * - int signum: the signal catched if any or zero at the beginning
+ * - void *arg: the parameter 'argument'
+ *
+ * A typical implmentation of the job callback is:
+ *
+ * ```C
+ * void my_job_cb(int signum, void *arg)
+ * {
+ * struct myarg_t *myarg = arg;
+ * if (signum)
+ * AFB_API_ERROR(myarg->api, "job interupted with signal %s", strsignal(signum));
+ * else
+ * really_do_my_job(myarg);
+ * }
+ * ```
+ *
+ * @param api the api that queue the job
+ * @param callback the job as a callback function
+ * @param argument the argument to pass to the queued job
+ * @param group the group of the job, NULL if no group
+ * @param timeout the timeout of execution of the job
+ *
+ * @return 0 in case of success or -1 in case of error with errno set appropriately.
+ */
+static inline
+int afb_api_x3_queue_job(struct afb_api_x3 *api, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
+{
+ return api->itf->queue_job(api, callback, argument, group, timeout);
+}
+
+/**
+ * Tells that it requires the API of "name" to exist
+ * and if 'initialized' is not null to be initialized.
+ * Calling this function is only allowed within init.
+ *
+ * A single request allows to require multiple apis.
+ *
+ * @param api the api that requires the other api by its name
+ * @param name a space separated list of the names of the required api
+ * @param initialized if zero, the api is just required to exist. If not zero,
+ * the api is required to exist and to be initialized.
+ *
+ * @return 0 in case of success or -1 in case of error with errno set appropriately.
+ */
+static inline
+int afb_api_x3_require_api(struct afb_api_x3 *api, const char *name, int initialized)
+{
+ return api->itf->require_api(api, name, initialized);
+}
+
+/**
+ * Create an aliased name 'as_name' for the api 'name'.
+ * Calling this function is only allowed within preinit.
+ *
+ * @param api the api that requires the aliasing
+ * @param name the api to alias
+ * @param as_name the aliased name of the aliased api
+ *
+ * @return 0 in case of success or -1 in case of error with errno set appropriately.
+ */
+static inline
+int afb_api_x3_add_alias(struct afb_api_x3 *api, const char *name, const char *as_name)
+{
+ return api->itf->add_alias(api, name, as_name);
+}
+
+/**
+ * Broadcasts widely the event of 'name' with the data 'object'.
+ * 'object' can be NULL.
+ *
+ * For convenience, the function calls 'json_object_put' for 'object'.
+ * Thus, in the case where 'object' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * Calling this function is only forbidden during preinit.
+ *
+ * The event sent as the name API/name where API is the name of the
+ * api.
+ *
+ * @param api the api that broadcast the event
+ * @param name the event name suffix
+ * @param object the object that comes with the event
+ *
+ * @return the count of clients that received the event.
+ */
+static inline
+int afb_api_x3_broadcast_event(struct afb_api_x3 *api, const char *name, struct json_object *object)
+{
+ return api->itf->event_broadcast(api, name, object);
+}
+
+/**
+ * Creates an event of 'name' and returns it.
+ *
+ * Calling this function is only forbidden during preinit.
+ *
+ * See afb_event_is_valid to check if there is an error.
+ *
+ * The event created as the name API/name where API is the name of the
+ * api.
+ *
+ * @param api the api that creates the event
+ * @param name the event name suffix
+ *
+ * @return the created event. Use the function afb_event_is_valid to check
+ * whether the event is valid (created) or not (error as reported by errno).
+ *
+ * @see afb_event_is_valid
+ */
+static inline
+struct afb_event_x2 *afb_api_x3_make_event_x2(struct afb_api_x3 *api, const char *name)
+{
+ return api->itf->event_make(api, name);
+}
+
+/**
+ * @deprecated try to use @ref afb_api_x3_call instead
+ *
+ * * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
+ * The result of the call is delivered to the 'callback' function with the 'callback_closure'.
+ *
+ * For convenience, the function calls 'json_object_put' for 'args'.
+ * Thus, in the case where 'args' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * The 'callback' receives 3 arguments:
+ * 1. 'closure' the user defined closure pointer 'closure',
+ * 2. 'status' a status being 0 on success or negative when an error occurred,
+ * 2. 'result' the resulting data as a JSON object.
+ *
+ * @param api The api
+ * @param apiname The api name of the method to call
+ * @param verb The verb name of the method to call
+ * @param args The arguments to pass to the method
+ * @param callback The to call on completion
+ * @param closure The closure to pass to the callback
+ *
+ * @see also 'afb_api_call'
+ * @see also 'afb_api_call_sync'
+ * @see also 'afb_api_call_sync_legacy'
+ * @see also 'afb_req_subcall'
+ * @see also 'afb_req_subcall_sync'
+ */
+static inline
+void afb_api_x3_call_legacy(
+ struct afb_api_x3 *api,
+ const char *apiname,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void *closure, int status, struct json_object *result, struct afb_api_x3 *api),
+ void *closure)
+{
+ api->itf->legacy_call(api, apiname, verb, args, callback, closure);
+}
+
+/**
+ * @deprecated try to use @ref afb_api_x3_call_sync instead
+ *
+ * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
+ * 'result' will receive the response.
+ *
+ * For convenience, the function calls 'json_object_put' for 'args'.
+ * Thus, in the case where 'args' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * @param api The api
+ * @param apiname The api name of the method to call
+ * @param verb The verb name of the method to call
+ * @param args The arguments to pass to the method
+ * @param result Where to store the result - should call json_object_put on it -
+ *
+ * @returns 0 in case of success or a negative value in case of error.
+ *
+ * @see also 'afb_api_call'
+ * @see also 'afb_api_call_sync'
+ * @see also 'afb_api_call_legacy'
+ * @see also 'afb_req_subcall'
+ * @see also 'afb_req_subcall_sync'
+ */
+static inline
+int afb_api_x3_call_sync_legacy(
+ struct afb_api_x3 *api,
+ const char *apiname,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result)
+{
+ return api->itf->legacy_call_sync(api, apiname, verb, args, result);
+}
+
+/**
+ * Creates a new api of name 'apiname' briefly described by 'info' (that can
+ * be NULL).
+ *
+ * When the pre-initialization function is given, it is a function that
+ * receives 2 parameters:
+ *
+ * - the closure as given in the call
+ * - the created api that can be initialised
+ *
+ * This pre-initialization function must return a negative value to abort
+ * the creation of the api. Otherwise, it returns a non-negative value to
+ * continue.
+ *
+ * @param api the api that creates the other one
+ * @param apiname the name of the new api
+ * @param info the brief description of the new api (can be NULL)
+ * @param noconcurrency zero or not zero whether the new api is reentrant or not
+ * @param preinit the pre-initialization function if any (can be NULL)
+ * @param closure the closure for the pre-initialization \ref preinit
+ *
+ * @return 0 in case of success or -1 on failure with errno set
+ *
+ * @see afb_api_x3_delete_api
+ */
+static inline
+struct afb_api_x3 *afb_api_x3_new_api(
+ struct afb_api_x3 *api,
+ const char *apiname,
+ const char *info,
+ int noconcurrency,
+ int (*preinit)(void*, struct afb_api_x3 *),
+ void *closure)
+{
+ return api->itf->api_new_api(api, apiname, info, noconcurrency, preinit, closure);
+}
+
+/**
+ * @deprecated use @ref afb_api_x3_set_verbs_v3 instead
+ *
+ * Set the verbs of the 'api' using description of verbs of the api v2
+ *
+ * @param api the api that will get the verbs
+ * @param verbs the array of verbs to add terminated with an item with name=NULL
+ *
+ * @return 0 in case of success or -1 on failure with errno set
+ *
+ * @see afb_verb_v2
+ * @see afb_api_x3_add_verb
+ * @see afb_api_x3_set_verbs_v3
+ */
+static inline
+int afb_api_x3_set_verbs_v2(
+ struct afb_api_x3 *api,
+ const struct afb_verb_v2 *verbs)
+{
+ return api->itf->api_set_verbs_v2(api, verbs);
+}
+
+/**
+ * Add one verb to the dynamic set of the api
+ *
+ * @param api the api to change
+ * @param verb name of the verb
+ * @param info brief description of the verb, can be NULL
+ * @param callback callback function implementing the verb
+ * @param vcbdata data for the verb callback, available through req
+ * @param auth required authorization, can be NULL
+ * @param session authorization and session requirements of the verb
+ * @param glob is the verb glob name
+ *
+ * @return 0 in case of success or -1 on failure with errno set
+ *
+ * @see afb_verb_v3
+ * @see afb_api_x3_del_verb
+ * @see afb_api_x3_set_verbs_v3
+ * @see fnmatch for matching names using glob
+ */
+static inline
+int afb_api_x3_add_verb(
+ 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)
+{
+ return api->itf->api_add_verb(api, verb, info, callback, vcbdata, auth, session, glob);
+}
+
+/**
+ * Delete one verb from the dynamic set of the api
+ *
+ * @param api the api to change
+ * @param verb name of the verb to delete
+ * @param vcbdata if not NULL will receive the vcbdata of the deleted verb
+ *
+ * @return 0 in case of success or -1 on failure with errno set
+ *
+ * @see afb_api_x3_add_verb
+ */
+static inline
+int afb_api_x3_del_verb(
+ struct afb_api_x3 *api,
+ const char *verb,
+ void **vcbdata)
+{
+ return api->itf->api_del_verb(api, verb, vcbdata);
+}
+
+/**
+ * Set the callback 'onevent' to process events in the name of the 'api'.
+ *
+ * This setting can be done statically using the global variable
+ * @ref afbBindingV3.
+ *
+ * This function replace any previously global event callback set.
+ *
+ * When an event is received, the callback 'onevent' is called with 3 parameters
+ *
+ * - the api that recorded the event handler
+ * - the full name of the event
+ * - the companion JSON object of the event
+ *
+ * @param api the api that wants to process events
+ * @param onevent the callback function that will process events (can be NULL
+ * to remove event callback)
+ *
+ * @return 0 in case of success or -1 on failure with errno set
+ *
+ * @see afbBindingV3
+ * @see afb_binding_v3
+ * @see afb_api_x3_event_handler_add
+ * @see afb_api_x3_event_handler_del
+ */
+static inline
+int afb_api_x3_on_event(
+ struct afb_api_x3 *api,
+ void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object))
+{
+ return api->itf->api_set_on_event(api, onevent);
+}
+
+/**
+ * Set the callback 'oninit' to process initialization of the 'api'.
+ *
+ * This setting can be done statically using the global variable
+ * @ref afbBindingV3
+ *
+ * This function replace any previously initialization callback set.
+ *
+ * This function is only valid during the pre-initialization stage.
+ *
+ * The callback initialization function will receive one argument: the api
+ * to initialize.
+ *
+ * @param api the api that wants to process events
+ * @param oninit the callback function that initialize the api
+ *
+ * @return 0 in case of success or -1 on failure with errno set
+ *
+ * @see afbBindingV3
+ * @see afb_binding_v3
+ */
+static inline
+int afb_api_x3_on_init(
+ struct afb_api_x3 *api,
+ int (*oninit)(struct afb_api_x3 *api))
+{
+ return api->itf->api_set_on_init(api, oninit);
+}
+
+/**
+ * Seal the api. After a call to this function the api can not be modified
+ * anymore.
+ *
+ * @param api the api to be sealed
+ */
+static inline
+void afb_api_x3_seal(
+ struct afb_api_x3 *api)
+{
+ api->itf->api_seal(api);
+}
+
+/**
+ * Set the verbs of the 'api' using description of verbs of the api v2
+ *
+ * @param api the api that will get the verbs
+ * @param verbs the array of verbs to add terminated with an item with name=NULL
+ *
+ * @return 0 in case of success or -1 on failure with errno set
+ *
+ * @see afb_verb_v3
+ * @see afb_api_x3_add_verb
+ * @see afb_api_x3_del_verb
+ */
+static inline
+int afb_api_x3_set_verbs_v3(
+ struct afb_api_x3 *api,
+ const struct afb_verb_v3 *verbs)
+{
+ return api->itf->api_set_verbs_v3(api, verbs);
+}
+
+/**
+ * Add a specific event handler for the api
+ *
+ * The handler callback is called when an event matching the given pattern
+ * is received (it is received if broadcasted or after subscription through
+ * a call or a subcall).
+ *
+ * The handler callback receive 4 arguments:
+ *
+ * - the closure given here
+ * - the event full name
+ * - the companion JSON object of the event
+ * - the api that subscribed the event
+ *
+ * @param api the api that creates the handler
+ * @param pattern the global pattern of the event to handle
+ * @param callback the handler callback function
+ * @param closure the closure of the handler
+ *
+ * @return 0 in case of success or -1 on failure with errno set
+ *
+ * @see afb_api_x3_on_event
+ * @see afb_api_x3_event_handler_del
+ */
+static inline
+int afb_api_x3_event_handler_add(
+ struct afb_api_x3 *api,
+ const char *pattern,
+ void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*),
+ void *closure)
+{
+ return api->itf->event_handler_add(api, pattern, callback, closure);
+}
+
+/**
+ * Delete a specific event handler for the api
+ *
+ * @param api the api that the handler belongs to
+ * @param pattern the global pattern of the handler to remove
+ * @param closure if not NULL it will receive the closure set to the handler
+ *
+ * @return 0 in case of success or -1 on failure with errno set
+ *
+ * @see afb_api_x3_on_event
+ * @see afb_api_x3_event_handler_add
+ */
+static inline
+int afb_api_x3_event_handler_del(
+ struct afb_api_x3 *api,
+ const char *pattern,
+ void **closure)
+{
+ return api->itf->event_handler_del(api, pattern, closure);
+}
+
+/**
+ * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
+ * The result of the call is delivered to the 'callback' function with the 'callback_closure'.
+ *
+ * For convenience, the function calls 'json_object_put' for 'args'.
+ * Thus, in the case where 'args' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * The 'callback' receives 5 arguments:
+ * 1. 'closure' the user defined closure pointer 'closure',
+ * 2. 'object' a JSON object returned (can be NULL)
+ * 3. 'error' a string not NULL in case of error but NULL on success
+ * 4. 'info' a string handling some info (can be NULL)
+ * 5. 'api' the api
+ *
+ * @param api The api that makes the call
+ * @param apiname The api name of the method to call
+ * @param verb The verb name of the method to call
+ * @param args The arguments to pass to the method
+ * @param callback The to call on completion
+ * @param closure The closure to pass to the callback
+ *
+ *
+ * @see afb_req_subcall
+ * @see afb_req_subcall_sync
+ * @see afb_api_x3_call_sync
+ */
+static inline
+void afb_api_x3_call(
+ struct afb_api_x3 *api,
+ const char *apiname,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_api_x3 *api),
+ void *closure)
+{
+ api->itf->call(api, apiname, verb, args, callback, closure);
+}
+
+/**
+ * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
+ * 'result' will receive the response.
+ *
+ * For convenience, the function calls 'json_object_put' for 'args'.
+ * Thus, in the case where 'args' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * @param api The api that makes the call
+ * @param apiname The api name of the method to call
+ * @param verb The verb name of the method to call
+ * @param args The arguments to pass to the method
+ * @param object Where to store the returned object - should call json_object_put on it - can be NULL
+ * @param error Where to store the copied returned error - should call free on it - can be NULL
+ * @param info Where to store the copied returned info - should call free on it - can be NULL
+ *
+ * @returns 0 in case of success or a negative value in case of error.
+ *
+ * @see afb_req_subcall
+ * @see afb_req_subcall_sync
+ * @see afb_api_x3_call
+ */
+static inline
+int afb_api_x3_call_sync(
+ struct afb_api_x3 *api,
+ const char *apiname,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **object,
+ char **error,
+ char **info)
+{
+ return api->itf->call_sync(api, apiname, verb, args, object, error, info);
+}
+
+/**
+ * Tells that the api provides a class of features. Classes are intended to
+ * allow ordering of initializations: apis that provides a given class are
+ * initialized before apis requiring it.
+ *
+ * This function is only valid during the pre-initialization stage.
+ *
+ * @param api the api that provides the classes
+ * @param name a space separated list of the names of the provided classes
+ *
+ * @returns 0 in case of success or a negative value in case of error.
+ *
+ * @see afb_api_x3_require_class
+ */
+static inline
+int afb_api_x3_provide_class(
+ struct afb_api_x3 *api,
+ const char *name)
+{
+ return api->itf->class_provide(api, name);
+}
+
+/**
+ * Tells that the api requires a set of class features. Classes are intended to
+ * allow ordering of initializations: apis that provides a given class are
+ * initialized before apis requiring it.
+ *
+ * This function is only valid during the pre-initialization stage.
+ *
+ * @param api the api that requires the classes
+ * @param name a space separated list of the names of the requireded classes
+ *
+ * @returns 0 in case of success or a negative value in case of error.
+ *
+ * @see afb_api_x3_provide_class
+ */
+static inline
+int afb_api_x3_require_class(
+ struct afb_api_x3 *api,
+ const char *name)
+{
+ return api->itf->class_require(api, name);
+}
+
+/**
+ * Delete the given api.
+ *
+ * It is of the responsibility of the caller to don't used the deleted api
+ * anymore after this function returned.
+ *
+ * @param api the api to delete
+ *
+ * @returns 0 in case of success or a negative value in case of error.
+ *
+ * @see afb_api_x3_new_api
+ */
+static inline
+int afb_api_x3_delete_api(
+ struct afb_api_x3 *api)
+{
+ return api->itf->delete_api(api);
+}
diff --git a/include/afb/afb-arg.h b/include/afb/afb-arg.h
new file mode 100644
index 00000000..de3fb9b5
--- /dev/null
+++ b/include/afb/afb-arg.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/**
+ * Describes an argument (or parameter) of a request.
+ *
+ * @see afb_req_get
+ */
+struct afb_arg
+{
+ const char *name; /**< name of the argument or NULL if invalid */
+ const char *value; /**< string representation of the value of the argument */
+ /**< original filename of the argument if path != NULL */
+ const char *path; /**< if not NULL, path of the received file for the argument */
+ /**< when the request is finalized this file is removed */
+};
+
diff --git a/include/afb/afb-auth.h b/include/afb/afb-auth.h
index da4f8be8..3ce78666 100644
--- a/include/afb/afb-auth.h
+++ b/include/afb/afb-auth.h
@@ -17,29 +17,58 @@
#pragma once
-/*
- * Enum for Session/Token/Assurance middleware.
+/**
+ * Enumeration for authority (Session/Token/Assurance) definitions.
+ *
+ * @see afb_auth
*/
enum afb_auth_type
{
- afb_auth_No = 0, /** never authorized, no data */
- afb_auth_Token, /** authorized if token valid, no data */
- afb_auth_LOA, /** authorized if LOA greater than data 'loa' */
- afb_auth_Permission, /** authorized if permission 'text' is granted */
- afb_auth_Or, /** authorized if 'first' or 'next' is authorized */
- afb_auth_And, /** authorized if 'first' and 'next' are authorized */
- afb_auth_Not, /** authorized if 'first' is not authorized */
- afb_auth_Yes /** always authorized, no data */
+ /** never authorized, no data */
+ afb_auth_No = 0,
+
+ /** authorized if token valid, no data */
+ afb_auth_Token,
+
+ /** authorized if LOA greater than data 'loa' */
+ afb_auth_LOA,
+
+ /** authorized if permission 'text' is granted */
+ afb_auth_Permission,
+
+ /** authorized if 'first' or 'next' is authorized */
+ afb_auth_Or,
+
+ /** authorized if 'first' and 'next' are authorized */
+ afb_auth_And,
+
+ /** authorized if 'first' is not authorized */
+ afb_auth_Not,
+
+ /** always authorized, no data */
+ afb_auth_Yes
};
+/**
+ * Definition of an authorization entry
+ */
struct afb_auth
{
+ /** type of entry @see afb_auth_type */
enum afb_auth_type type;
+
union {
+ /** text when @ref type == @ref afb_auth_Permission */
const char *text;
+
+ /** level of assurancy when @ref type == @ref afb_auth_LOA */
unsigned loa;
+
+ /** first child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And, @ref afb_auth_Not } */
const struct afb_auth *first;
};
+
+ /** second child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And } */
const struct afb_auth *next;
};
diff --git a/include/afb/afb-binding-postdefs.h b/include/afb/afb-binding-postdefs.h
new file mode 100644
index 00000000..93cd46ef
--- /dev/null
+++ b/include/afb/afb-binding-postdefs.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+typedef enum afb_auth_type afb_auth_type_t;
+typedef struct afb_auth afb_auth_t;
+typedef struct afb_arg afb_arg_t;
+
+#if AFB_BINDING_VERSION == 1
+
+typedef struct afb_verb_desc_v1 afb_verb_t;
+typedef struct afb_binding_v1 afb_binding_t;
+typedef struct afb_binding_interface_v1 afb_binding_interface_v1;
+
+typedef struct afb_daemon_x1 afb_daemon_t;
+typedef struct afb_service_x1 afb_service_t;
+
+typedef struct afb_event_x1 afb_event_t;
+typedef struct afb_req_x1 afb_req_t;
+
+typedef struct afb_stored_req afb_stored_req_t;
+
+#ifndef __cplusplus
+typedef struct afb_event_x1 afb_event;
+typedef struct afb_req_x1 afb_req;
+typedef struct afb_stored_req afb_stored_req;
+#endif
+
+#endif
+
+#if AFB_BINDING_VERSION == 2
+
+typedef struct afb_verb_v2 afb_verb_t;
+typedef struct afb_binding_v2 afb_binding_t;
+
+typedef struct afb_daemon afb_daemon_t;
+typedef struct afb_event afb_event_t;
+typedef struct afb_req afb_req_t;
+typedef struct afb_stored_req afb_stored_req_t;
+typedef struct afb_service afb_service_t;
+
+#define afbBindingExport afbBindingV2
+
+#ifndef __cplusplus
+typedef struct afb_verb_v2 afb_verb_v2;
+typedef struct afb_binding_v2 afb_binding_v2;
+typedef struct afb_event_x1 afb_event;
+typedef struct afb_req_x1 afb_req;
+typedef struct afb_stored_req afb_stored_req;
+#endif
+
+#endif
+
+#if AFB_BINDING_VERSION == 3
+
+typedef struct afb_verb_v3 afb_verb_t;
+typedef struct afb_binding_v3 afb_binding_t;
+
+typedef struct afb_event_x2 *afb_event_t;
+typedef struct afb_req_x2 *afb_req_t;
+typedef struct afb_api_x3 *afb_api_t;
+
+#define afbBindingExport afbBindingV3
+
+/* compatibility with previous versions */
+
+typedef struct afb_api_x3 *afb_daemon_t;
+typedef struct afb_api_x3 *afb_service_t;
+
+#endif
+
+
+#if defined(AFB_BINDING_WANT_DYNAPI)
+typedef struct afb_dynapi *afb_dynapi_t;
+typedef struct afb_request *afb_request_t;
+typedef struct afb_eventid *afb_eventid_t;
+#endif \ No newline at end of file
diff --git a/include/afb/afb-binding-predefs.h b/include/afb/afb-binding-predefs.h
new file mode 100644
index 00000000..f1765edb
--- /dev/null
+++ b/include/afb/afb-binding-predefs.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/******************************************************************************/
+
+#if AFB_BINDING_VERSION == 1 || AFB_BINDING_VERSION == 2
+
+#define afb_req afb_req_x1
+#define afb_req_is_valid afb_req_x1_is_valid
+#define afb_req_get afb_req_x1_get
+#define afb_req_value afb_req_x1_value
+#define afb_req_path afb_req_x1_path
+#define afb_req_json afb_req_x1_json
+#define afb_req_reply afb_req_x1_reply
+#define afb_req_reply_f afb_req_x1_reply_f
+#define afb_req_reply_v afb_req_x1_reply_v
+#define afb_req_success(r,o,i) afb_req_x1_reply(r,o,0,i)
+#define afb_req_success_f(r,o,...) afb_req_x1_reply_f(r,o,0,__VA_ARGS__)
+#define afb_req_success_v(r,o,f,v) afb_req_x1_reply_v(r,o,0,f,v)
+#define afb_req_fail(r,e,i) afb_req_x1_reply(r,0,e,i)
+#define afb_req_fail_f(r,e,...) afb_req_x1_reply_f(r,0,e,__VA_ARGS__)
+#define afb_req_fail_v(r,e,f,v) afb_req_x1_reply_v(r,0,e,f,v)
+#define afb_req_context_get afb_req_x1_context_get
+#define afb_req_context_set afb_req_x1_context_set
+#define afb_req_context afb_req_x1_context
+#define afb_req_context_make afb_req_x1_context_make
+#define afb_req_context_clear afb_req_x1_context_clear
+#define afb_req_addref afb_req_x1_addref
+#define afb_req_unref afb_req_x1_unref
+#define afb_req_session_close afb_req_x1_session_close
+#define afb_req_session_set_LOA afb_req_x1_session_set_LOA
+#define afb_req_subscribe afb_req_x1_subscribe
+#define afb_req_unsubscribe afb_req_x1_unsubscribe
+#define afb_req_subcall afb_req_x1_subcall
+#define afb_req_subcall_req afb_req_x1_subcall_req
+#define afb_req_subcall_sync afb_req_x1_subcall_sync
+#define afb_req_verbose afb_req_x1_verbose
+#define afb_req_has_permission afb_req_x1_has_permission
+#define afb_req_get_application_id afb_req_x1_get_application_id
+#define afb_req_get_uid afb_req_x1_get_uid
+#define afb_req_get_client_info afb_req_x1_get_client_info
+
+#define afb_event afb_event_x1
+#define afb_event_to_event_x2 afb_event_x1_to_event_x2
+#define afb_event_is_valid afb_event_x1_is_valid
+#define afb_event_broadcast afb_event_x1_broadcast
+#define afb_event_push afb_event_x1_push
+#define afb_event_drop afb_event_x1_unref
+#define afb_event_name afb_event_x1_name
+#define afb_event_unref afb_event_x1_unref
+#define afb_event_addref afb_event_x1_addref
+
+#define afb_service afb_service_x1
+#define afb_daemon afb_daemon_x1
+
+#define _AFB_SYSLOG_LEVEL_EMERGENCY_ AFB_SYSLOG_LEVEL_EMERGENCY
+#define _AFB_SYSLOG_LEVEL_ALERT_ AFB_SYSLOG_LEVEL_ALERT
+#define _AFB_SYSLOG_LEVEL_CRITICAL_ AFB_SYSLOG_LEVEL_CRITICAL
+#define _AFB_SYSLOG_LEVEL_ERROR_ AFB_SYSLOG_LEVEL_ERROR
+#define _AFB_SYSLOG_LEVEL_WARNING_ AFB_SYSLOG_LEVEL_WARNING
+#define _AFB_SYSLOG_LEVEL_NOTICE_ AFB_SYSLOG_LEVEL_NOTICE
+#define _AFB_SYSLOG_LEVEL_INFO_ AFB_SYSLOG_LEVEL_INFO
+#define _AFB_SYSLOG_LEVEL_DEBUG_ AFB_SYSLOG_LEVEL_DEBUG
+
+#endif
+
+/******************************************************************************/
+#if AFB_BINDING_VERSION == 1
+
+#define afb_req_store afb_req_x1_store_v1
+#define afb_req_unstore afb_req_x1_unstore_v1
+
+#define afb_binding afb_binding_v1
+#define afb_binding_interface afb_binding_interface_v1
+
+#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v1
+#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v1
+#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v1
+#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v1
+#define afb_daemon_make_event afb_daemon_make_event_v1
+#define afb_daemon_verbose afb_daemon_verbose_v1
+#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v1
+#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v1
+#define afb_daemon_queue_job afb_daemon_queue_job_v1
+#define afb_daemon_require_api afb_daemon_require_api_v1
+#define afb_daemon_rename_api afb_daemon_add_alias_v1
+
+#define afb_service_call afb_service_call_v1
+#define afb_service_call_sync afb_service_call_sync_v1
+
+# define AFB_ERROR AFB_ERROR_V1
+# define AFB_WARNING AFB_WARNING_V1
+# define AFB_NOTICE AFB_NOTICE_V1
+# define AFB_INFO AFB_INFO_V1
+# define AFB_DEBUG AFB_DEBUG_V1
+
+# define AFB_REQ_ERROR AFB_REQ_ERROR_V1
+# define AFB_REQ_WARNING AFB_REQ_WARNING_V1
+# define AFB_REQ_NOTICE AFB_REQ_NOTICE_V1
+# define AFB_REQ_INFO AFB_REQ_INFO_V1
+# define AFB_REQ_DEBUG AFB_REQ_DEBUG_V1
+
+#define AFB_REQ_VERBOSE AFB_REQ_VERBOSE_V1
+
+# define AFB_SESSION_NONE AFB_SESSION_NONE_X1
+# define AFB_SESSION_CREATE AFB_SESSION_CREATE_X1
+# define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_X1
+# define AFB_SESSION_RENEW AFB_SESSION_RENEW_X1
+# define AFB_SESSION_CHECK AFB_SESSION_CHECK_X1
+
+# define AFB_SESSION_LOA_GE AFB_SESSION_LOA_GE_X1
+# define AFB_SESSION_LOA_LE AFB_SESSION_LOA_LE_X1
+# define AFB_SESSION_LOA_EQ AFB_SESSION_LOA_EQ_X1
+
+# define AFB_SESSION_LOA_SHIFT AFB_SESSION_LOA_SHIFT_X1
+# define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_X1
+
+# define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_X1
+# define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_X1
+# define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_X1
+# define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_X1
+# define AFB_SESSION_LOA_4 AFB_SESSION_LOA_4_X1
+
+# define AFB_SESSION_LOA_LE_0 AFB_SESSION_LOA_LE_0_X1
+# define AFB_SESSION_LOA_LE_1 AFB_SESSION_LOA_LE_1_X1
+# define AFB_SESSION_LOA_LE_2 AFB_SESSION_LOA_LE_2_X1
+# define AFB_SESSION_LOA_LE_3 AFB_SESSION_LOA_LE_3_X1
+
+# define AFB_SESSION_LOA_EQ_0 AFB_SESSION_LOA_EQ_0_X1
+# define AFB_SESSION_LOA_EQ_1 AFB_SESSION_LOA_EQ_1_X1
+# define AFB_SESSION_LOA_EQ_2 AFB_SESSION_LOA_EQ_2_X1
+# define AFB_SESSION_LOA_EQ_3 AFB_SESSION_LOA_EQ_3_X1
+
+# define AFB_SESSION_LOA_GE_0 AFB_SESSION_LOA_GE_0_X1
+# define AFB_SESSION_LOA_GE_1 AFB_SESSION_LOA_GE_1_X1
+# define AFB_SESSION_LOA_GE_2 AFB_SESSION_LOA_GE_2_X1
+# define AFB_SESSION_LOA_GE_3 AFB_SESSION_LOA_GE_3_X1
+
+#endif
+
+/******************************************************************************/
+#if AFB_BINDING_VERSION == 2
+
+#define afb_req_store afb_req_x1_store_v2
+#define afb_req_unstore afb_daemon_unstore_req_v2
+
+#define afb_binding afb_binding_v2
+
+#define afb_get_verbosity afb_get_verbosity_v2
+#define afb_get_daemon afb_get_daemon_v2
+#define afb_get_service afb_get_service_v2
+
+#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v2
+#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v2
+#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v2
+#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v2
+#define afb_daemon_make_event afb_daemon_make_event_v2
+#define afb_daemon_verbose afb_daemon_verbose_v2
+#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v2
+#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v2
+#define afb_daemon_queue_job afb_daemon_queue_job_v2
+#define afb_daemon_unstore_req afb_daemon_unstore_req_v2
+#define afb_daemon_require_api afb_daemon_require_api_v2
+#define afb_daemon_rename_api(x) afb_daemon_add_alias_v2(0,x)
+#define afb_daemon_add_alias afb_daemon_add_alias_v2
+
+#define afb_service_call afb_service_call_v2
+#define afb_service_call_sync afb_service_call_sync_v2
+
+#define AFB_ERROR AFB_ERROR_V2
+#define AFB_WARNING AFB_WARNING_V2
+#define AFB_NOTICE AFB_NOTICE_V2
+#define AFB_INFO AFB_INFO_V2
+#define AFB_DEBUG AFB_DEBUG_V2
+
+#define AFB_REQ_ERROR AFB_REQ_ERROR_V2
+#define AFB_REQ_WARNING AFB_REQ_WARNING_V2
+#define AFB_REQ_NOTICE AFB_REQ_NOTICE_V2
+#define AFB_REQ_INFO AFB_REQ_INFO_V2
+#define AFB_REQ_DEBUG AFB_REQ_DEBUG_V2
+
+#define AFB_REQ_VERBOSE AFB_REQ_VERBOSE_V2
+
+#endif
+
+/******************************************************************************/
+#if AFB_BINDING_VERSION == 2 || AFB_BINDING_VERSION == 3
+
+#define AFB_SESSION_NONE AFB_SESSION_NONE_X2
+#define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_X2
+#define AFB_SESSION_RENEW AFB_SESSION_REFRESH_X2
+#define AFB_SESSION_REFRESH AFB_SESSION_REFRESH_X2
+#define AFB_SESSION_CHECK AFB_SESSION_CHECK_X2
+
+#define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_X2
+
+#define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_X2
+#define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_X2
+#define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_X2
+#define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_X2
+
+#endif
+
+/******************************************************************************/
+#if AFB_BINDING_VERSION == 2
+
+#define AFB_SESSION_NONE_V2 AFB_SESSION_NONE_X2
+#define AFB_SESSION_CLOSE_V2 AFB_SESSION_CLOSE_X2
+#define AFB_SESSION_RENEW_V2 AFB_SESSION_REFRESH_X2
+#define AFB_SESSION_REFRESH_V2 AFB_SESSION_REFRESH_X2
+#define AFB_SESSION_CHECK_V2 AFB_SESSION_CHECK_X2
+
+#define AFB_SESSION_LOA_MASK_V2 AFB_SESSION_LOA_MASK_X2
+
+#define AFB_SESSION_LOA_0_V2 AFB_SESSION_LOA_0_X2
+#define AFB_SESSION_LOA_1_V2 AFB_SESSION_LOA_1_X2
+#define AFB_SESSION_LOA_2_V2 AFB_SESSION_LOA_2_X2
+#define AFB_SESSION_LOA_3_V2 AFB_SESSION_LOA_3_X2
+
+#endif
+
+/******************************************************************************/
+#if AFB_BINDING_VERSION == 3
+
+#define afb_req_x2 afb_req
+
+#define afb_req_x2_is_valid afb_req_is_valid
+#define afb_req_x2_get_api afb_req_get_api
+#define afb_req_x2_get_vcbdata afb_req_get_vcbdata
+#define afb_req_x2_get_called_api afb_req_get_called_api
+#define afb_req_x2_get_called_verb afb_req_get_called_verb
+#define afb_req_x2_wants_log_level afb_req_wants_log_level
+
+#define afb_req_x2_get afb_req_get
+#define afb_req_x2_value afb_req_value
+#define afb_req_x2_path afb_req_path
+#define afb_req_x2_json afb_req_json
+#define afb_req_x2_reply afb_req_reply
+#define afb_req_x2_reply_f afb_req_reply_f
+#define afb_req_x2_reply_v afb_req_reply_v
+#define afb_req_success(r,o,i) afb_req_reply(r,o,0,i)
+#define afb_req_success_f(r,o,...) afb_req_reply_f(r,o,0,__VA_ARGS__)
+#define afb_req_success_v(r,o,f,v) afb_req_reply_v(r,o,0,f,v)
+#define afb_req_fail(r,e,i) afb_req_reply(r,0,e,i)
+#define afb_req_fail_f(r,e,...) afb_req_reply_f(r,0,e,__VA_ARGS__)
+#define afb_req_fail_v(r,e,f,v) afb_req_reply_v(r,0,e,f,v)
+#define afb_req_x2_context_get afb_req_context_get
+#define afb_req_x2_context_set afb_req_context_set
+#define afb_req_x2_context afb_req_context
+#define afb_req_x2_context_make afb_req_context_make
+#define afb_req_x2_context_clear afb_req_context_clear
+#define afb_req_x2_addref afb_req_addref
+#define afb_req_x2_unref afb_req_unref
+#define afb_req_x2_session_close afb_req_session_close
+#define afb_req_x2_session_set_LOA afb_req_session_set_LOA
+#define afb_req_x2_subscribe afb_req_subscribe
+#define afb_req_x2_unsubscribe afb_req_unsubscribe
+#define afb_req_x2_subcall afb_req_subcall
+#define afb_req_x2_subcall_legacy afb_req_subcall_legacy
+#define afb_req_x2_subcall_req afb_req_subcall_req
+#define afb_req_x2_subcall_sync_legacy afb_req_subcall_sync_legacy
+#define afb_req_x2_subcall_sync afb_req_subcall_sync
+#define afb_req_x2_verbose afb_req_verbose
+#define afb_req_x2_has_permission afb_req_has_permission
+#define afb_req_x2_get_application_id afb_req_get_application_id
+#define afb_req_x2_get_uid afb_req_get_uid
+#define afb_req_x2_get_client_info afb_req_get_client_info
+
+#define afb_req_x2_subcall_catch_events afb_req_subcall_catch_events
+#define afb_req_x2_subcall_pass_events afb_req_subcall_pass_events
+#define afb_req_x2_subcall_on_behalf afb_req_subcall_on_behalf
+
+#define afb_event_x2 afb_event
+#define afb_event_x2_is_valid afb_event_is_valid
+#define afb_event_x2_broadcast afb_event_broadcast
+#define afb_event_x2_push afb_event_push
+#define afb_event_x2_name afb_event_name
+#define afb_event_x2_unref afb_event_unref
+#define afb_event_x2_addref afb_event_addref
+
+#define afb_api_x3 afb_api
+
+#define afb_api_x3_name afb_api_name
+#define afb_api_x3_get_userdata afb_api_get_userdata
+#define afb_api_x3_set_userdata afb_api_set_userdata
+#define afb_api_x3_wants_log_level afb_api_wants_log_level
+
+#define afb_api_x3_verbose afb_api_verbose
+#define afb_api_x3_get_event_loop afb_api_get_event_loop
+#define afb_api_x3_get_user_bus afb_api_get_user_bus
+#define afb_api_x3_get_system_bus afb_api_get_system_bus
+#define afb_api_x3_rootdir_get_fd afb_api_rootdir_get_fd
+#define afb_api_x3_rootdir_open_locale afb_api_rootdir_open_locale
+#define afb_api_x3_queue_job afb_api_queue_job
+#define afb_api_x3_require_api afb_api_require_api
+#define afb_api_x3_broadcast_event afb_api_broadcast_event
+#define afb_api_x3_make_event_x2 afb_api_make_event
+#define afb_api_x3_call afb_api_call
+#define afb_api_x3_call_sync afb_api_call_sync
+#define afb_api_x3_call_legacy afb_api_call_legacy
+#define afb_api_x3_call_sync_legacy afb_api_call_sync_legacy
+#define afb_api_x3_new_api afb_api_new_api
+#define afb_api_x3_set_verbs_v2 afb_api_set_verbs_v2
+#define afb_api_x3_add_verb afb_api_add_verb
+#define afb_api_x3_del_verb afb_api_del_verb
+#define afb_api_x3_on_event afb_api_on_event
+#define afb_api_x3_on_init afb_api_on_init
+#define afb_api_x3_seal afb_api_seal
+#define afb_api_x3_add_alias afb_api_add_alias
+
+#define AFB_API_ERROR AFB_API_ERROR_V3
+#define AFB_API_WARNING AFB_API_WARNING_V3
+#define AFB_API_NOTICE AFB_API_NOTICE_V3
+#define AFB_API_INFO AFB_API_INFO_V3
+#define AFB_API_DEBUG AFB_API_DEBUG_V3
+
+#define AFB_REQ_ERROR AFB_REQ_ERROR_V3
+#define AFB_REQ_WARNING AFB_REQ_WARNING_V3
+#define AFB_REQ_NOTICE AFB_REQ_NOTICE_V3
+#define AFB_REQ_INFO AFB_REQ_INFO_V3
+#define AFB_REQ_DEBUG AFB_REQ_DEBUG_V3
+
+#define AFB_REQ_VERBOSE AFB_REQ_VERBOSE_V3
+
+#define afb_stored_req afb_req_x2
+#define afb_req_store(x) afb_req_x2_addref(x)
+#define afb_req_unstore(x) (x)
+
+#define afb_get_verbosity afb_get_verbosity_v3
+#define afb_get_logmask afb_get_logmask_v3
+#define afb_get_daemon afb_get_root_api_v3
+#define afb_get_service afb_get_root_api_v3
+
+#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v3
+#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v3
+#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v3
+#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v3
+#define afb_daemon_make_event afb_daemon_make_event_v3
+#define afb_daemon_verbose afb_daemon_verbose_v3
+#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v3
+#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v3
+#define afb_daemon_queue_job afb_daemon_queue_job_v3
+#define afb_daemon_require_api afb_daemon_require_api_v3
+#define afb_daemon_add_alias afb_daemon_add_alias_v3
+
+# define afb_service_call afb_service_call_v3
+# define afb_service_call_sync afb_service_call_sync_v3
+
+# define AFB_ERROR AFB_ERROR_V3
+# define AFB_WARNING AFB_WARNING_V3
+# define AFB_NOTICE AFB_NOTICE_V3
+# define AFB_INFO AFB_INFO_V3
+# define AFB_DEBUG AFB_DEBUG_V3
+
+#endif
+
diff --git a/include/afb/afb-binding-v1.h b/include/afb/afb-binding-v1.h
index 9fb0ab89..3d5010d0 100644
--- a/include/afb/afb-binding-v1.h
+++ b/include/afb/afb-binding-v1.h
@@ -17,22 +17,27 @@
#pragma once
-struct json_object;
+/******************************************************************************/
-#include "afb-req.h"
-#include "afb-event.h"
-#include "afb-service-itf.h"
-#include "afb-daemon-itf.h"
+#include "afb-verbosity.h"
+#include "afb-req-x1.h"
+#include "afb-event-x1.h"
+#include "afb-service-itf-x1.h"
+#include "afb-daemon-itf-x1.h"
#include "afb-req-v1.h"
-#include "afb-session-v1.h"
+#include "afb-session-x1.h"
#include "afb-service-v1.h"
#include "afb-daemon-v1.h"
struct afb_binding_v1;
struct afb_binding_interface_v1;
-/*
+/******************************************************************************/
+
+/**
+ * @deprecated use bindings version 3
+ *
* Function for registering the binding
*
* A binding V1 MUST have an exported function of name
@@ -57,7 +62,9 @@ struct afb_binding_interface_v1;
*/
extern const struct afb_binding_v1 *afbBindingV1Register (const struct afb_binding_interface_v1 *interface);
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* When a binding have an exported implementation of the
* function 'afbBindingV1ServiceInit', defined below,
* the framework calls it for initialising the service after
@@ -69,9 +76,11 @@ extern const struct afb_binding_v1 *afbBindingV1Register (const struct afb_bindi
* The function should return 0 in case of success or, else, should return
* a negative value.
*/
-extern int afbBindingV1ServiceInit(struct afb_service service);
+extern int afbBindingV1ServiceInit(struct afb_service_x1 service);
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* When a binding have an implementation of the function 'afbBindingV1ServiceEvent',
* defined below, the framework calls that function for any broadcasted event or for
* events that the service subscribed to in its name.
@@ -82,30 +91,36 @@ extern int afbBindingV1ServiceInit(struct afb_service service);
extern void afbBindingV1ServiceEvent(const char *event, struct json_object *object);
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Description of one verb of the API provided by the binding
* This enumeration is valid for bindings of type version 1
*/
struct afb_verb_desc_v1
{
- const char *name; /* name of the verb */
- enum afb_session_flags_v1 session; /* authorisation and session requirements of the verb */
- void (*callback)(struct afb_req req); /* callback function implementing the verb */
- const char *info; /* textual description of the verb */
+ const char *name; /**< name of the verb */
+ enum afb_session_flags_x1 session; /**< authorisation and session requirements of the verb */
+ void (*callback)(struct afb_req_x1 req);/**< callback function implementing the verb */
+ const char *info; /**< textual description of the verb */
};
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Description of the bindings of type version 1
*/
struct afb_binding_desc_v1
{
- const char *info; /* textual information about the binding */
- const char *prefix; /* required prefix name for the binding */
- const struct afb_verb_desc_v1 *verbs; /* array of descriptions of verbs terminated by a NULL name */
+ const char *info; /**< textual information about the binding */
+ const char *prefix; /**< required prefix name for the binding */
+ const struct afb_verb_desc_v1 *verbs; /**< array of descriptions of verbs terminated by a NULL name */
};
-/*
- * Definition of the type+versions of the binding.
+/**
+ * @deprecated use bindings version 3
+ *
+ * Definition of the type+versions of the binding version 1.
* The definition uses hashes.
*/
enum afb_binding_type_v1
@@ -113,94 +128,107 @@ enum afb_binding_type_v1
AFB_BINDING_VERSION_1 = 123456789
};
-/*
- * Description of a binding
+/**
+ * @deprecated use bindings version 3
+ *
+ * Description of a binding version 1
*/
struct afb_binding_v1
{
- enum afb_binding_type_v1 type; /* type of the binding */
+ enum afb_binding_type_v1 type; /**< type of the binding */
union {
- struct afb_binding_desc_v1 v1; /* description of the binding of type 1 */
+ struct afb_binding_desc_v1 v1; /**< description of the binding of type 1 */
};
};
-/*
- * config mode
+/**
+ * @deprecated use bindings version 3
+ *
+ * config mode for bindings version 1
*/
enum afb_mode_v1
{
- AFB_MODE_LOCAL = 0, /* run locally */
- AFB_MODE_REMOTE, /* run remotely */
- AFB_MODE_GLOBAL /* run either remotely or locally (DONT USE! reserved for future) */
+ AFB_MODE_LOCAL = 0, /**< run locally */
+ AFB_MODE_REMOTE, /**< run remotely */
+ AFB_MODE_GLOBAL /**< run either remotely or locally (DONT USE! reserved for future) */
};
-/*
- * Interface between the daemon and the binding.
+/**
+ * @deprecated use bindings version 3
+ *
+ * Interface between the daemon and the binding version 1.
*/
struct afb_binding_interface_v1
{
- struct afb_daemon daemon; /* access to the daemon facilies */
- int verbosity; /* level of verbosity */
- enum afb_mode_v1 mode; /* run mode (local or remote) */
+ struct afb_daemon_x1 daemon; /**< access to the daemon facilies */
+ int verbosity; /**< level of verbosity */
+ enum afb_mode_v1 mode; /**< run mode (local or remote) */
};
+/******************************************************************************/
/*
* Macros for logging messages
*/
#if defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DATA)
-# define _AFB_LOGGING_V1_(itf,vlevel,llevel,...) \
- do{ \
- if(itf->verbosity>=vlevel) {\
- if (llevel <= AFB_VERBOSITY_LEVEL_ERROR) \
- afb_daemon_verbose2_v1(itf->daemon,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
- else \
- afb_daemon_verbose2_v1(itf->daemon,llevel,__FILE__,__LINE__,NULL,NULL); \
- } \
- }while(0)
-# define _AFB_REQ_LOGGING_V1_(itf,vlevel,llevel,req,...) \
- do{ \
- if(itf->verbosity>=vlevel) \
- afb_req_verbose(req,llevel,__FILE__,__LINE__,NULL,NULL); \
- }while(0)
+# define AFB_VERBOSE_V1(itf,level,...) \
+ do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \
+ afb_daemon_verbose2_v1(itf->daemon,level,__FILE__,__LINE__,NULL,__VA_ARGS__); \
+ else afb_daemon_verbose2_v1(itf->daemon,level,__FILE__,__LINE__,NULL); } while(0)
+
+# define AFB_REQ_VERBOSE_V1(req,level,...) \
+ do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \
+ afb_req_x1_verbose(req,level,__FILE__,__LINE__,NULL,__VA_ARGS__); \
+ else afb_req_x1_verbose(req,level,__FILE__,__LINE__,NULL); } while(0)
#elif defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS)
-# define _AFB_LOGGING_V1_(itf,vlevel,llevel,...) \
- do{ \
- if(itf->verbosity>=vlevel) \
- afb_daemon_verbose2_v1(itf->daemon,llevel,NULL,0,NULL,__VA_ARGS__); \
- }while(0)
-# define _AFB_REQ_LOGGING_V1_(itf,vlevel,llevel,req,...) \
- do{ \
- if(itf->verbosity>=vlevel) \
- afb_req_verbose(req,llevel,NULL,0,NULL,__VA_ARGS__); \
- }while(0)
+# define AFB_VERBOSE_V1(itf,level,...) \
+ afb_daemon_verbose2_v1(itf->daemon,level,NULL,0,NULL,__VA_ARGS__)
+
+# define AFB_REQ_VERBOSE_V1(req,level,...) \
+ afb_req_x1_verbose(req,level,NULL,0,NULL,__VA_ARGS__)
#else
-# define _AFB_LOGGING_V1_(itf,vlevel,llevel,...) \
- do{ \
- if(itf->verbosity>=vlevel) \
- afb_daemon_verbose2_v1(itf->daemon,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
- }while(0)
-# define _AFB_REQ_LOGGING_V1_(itf,vlevel,llevel,req,...) \
- do{ \
- if(itf->verbosity>=vlevel) \
- afb_req_verbose(req,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
- }while(0)
+# define AFB_VERBOSE_V1(itf,level,...) \
+ afb_daemon_verbose2_v1(itf->daemon,level,__FILE__,__LINE__,__func__,__VA_ARGS__)
+
+# define AFB_REQ_VERBOSE_V1(req,level,...) \
+ afb_req_x1_verbose(req,level,__FILE__,__LINE__,__func__,__VA_ARGS__)
#endif
-# include "afb-verbosity.h"
-# define AFB_ERROR_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__)
-# define AFB_WARNING_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__)
-# define AFB_NOTICE_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__)
-# define AFB_INFO_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__)
-# define AFB_DEBUG_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__)
-# define AFB_REQ_ERROR_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__)
-# define AFB_REQ_WARNING_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__)
-# define AFB_REQ_NOTICE_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__)
-# define AFB_REQ_INFO_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__)
-# define AFB_REQ_DEBUG_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__)
+#define _AFB_LOGGING_V1_(itf,vlevel,llevel,...) \
+ do{ if(itf->verbosity>=vlevel) AFB_VERBOSE_V1(itf,llevel,__VA_ARGS__); }while(0)
+#define _AFB_REQ_LOGGING_V1_(itf,vlevel,llevel,req,...) \
+ do{ if(itf->verbosity>=vlevel) AFB_REQ_VERBOSE_V1(itf,llevel,__VA_ARGS__); }while(0)
+
+# define AFB_ERROR_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_ERROR,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__)
+# define AFB_WARNING_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_WARNING,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__)
+# define AFB_NOTICE_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_NOTICE,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__)
+# define AFB_INFO_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_INFO,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__)
+# define AFB_DEBUG_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_DEBUG,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__)
+
+# define AFB_REQ_ERROR_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_ERROR,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__)
+# define AFB_REQ_WARNING_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_WARNING,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__)
+# define AFB_REQ_NOTICE_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_NOTICE,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__)
+# define AFB_REQ_INFO_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_INFO,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__)
+# define AFB_REQ_DEBUG_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_DEBUG,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__)
+
+/******************************************************************************/
+
+#if AFB_BINDING_VERSION == 1 && defined(AFB_BINDING_PRAGMA_KEEP_VERBOSE_UNPREFIX)
+# define ERROR AFB_ERROR
+# define WARNING AFB_WARNING
+# define NOTICE AFB_NOTICE
+# define INFO AFB_INFO
+# define DEBUG AFB_DEBUG
+
+# define REQ_ERROR AFB_REQ_ERROR
+# define REQ_WARNING AFB_REQ_WARNING
+# define REQ_NOTICE AFB_REQ_NOTICE
+# define REQ_INFO AFB_REQ_INFO
+# define REQ_DEBUG AFB_REQ_DEBUG
+#endif
diff --git a/include/afb/afb-binding-v2.h b/include/afb/afb-binding-v2.h
index 3aa61b23..1535f429 100644
--- a/include/afb/afb-binding-v2.h
+++ b/include/afb/afb-binding-v2.h
@@ -17,137 +17,156 @@
#pragma once
-#include <stdint.h>
+/******************************************************************************/
+#include "afb-verbosity.h"
#include "afb-auth.h"
-#include "afb-event.h"
-#include "afb-req.h"
-#include "afb-service-itf.h"
-#include "afb-daemon-itf.h"
+#include "afb-event-x1.h"
+#include "afb-req-x1.h"
+#include "afb-service-itf-x1.h"
+#include "afb-daemon-itf-x1.h"
#include "afb-req-v2.h"
-#include "afb-session-v2.h"
+#include "afb-session-x2.h"
-struct json_object;
+/******************************************************************************/
-/*
- * Description of one verb of the API provided by the binding
- * This enumeration is valid for bindings of type version 2
+/**
+ * @deprecated use bindings version 3
+ *
+ * Description of one verb as provided for binding API version 2
*/
struct afb_verb_v2
{
- const char *verb; /* name of the verb, NULL only at end of the array */
- void (*callback)(struct afb_req req); /* callback function implementing the verb */
- const struct afb_auth *auth; /* required authorisation, can be NULL */
- const char *info; /* some info about the verb, can be NULL */
- uint32_t session; /* authorisation and session requirements of the verb */
+ const char *verb; /**< name of the verb, NULL only at end of the array */
+ void (*callback)(struct afb_req_x1 req);/**< callback function implementing the verb */
+ const struct afb_auth *auth; /**< required authorisation, can be NULL */
+ const char *info; /**< some info about the verb, can be NULL */
+ uint32_t session; /**< authorisation and session requirements of the verb */
};
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Description of the bindings of type version 2
*/
struct afb_binding_v2
{
- const char *api; /* api name for the binding */
- const char *specification; /* textual specification of the binding, can be NULL */
- const char *info; /* some info about the api, can be NULL */
- const struct afb_verb_v2 *verbs; /* array of descriptions of verbs terminated by a NULL name */
- int (*preinit)(); /* callback at load of the binding */
- int (*init)(); /* callback for starting the service */
- void (*onevent)(const char *event, struct json_object *object); /* callback for handling events */
- unsigned noconcurrency: 1; /* avoids concurrent requests to verbs */
+ const char *api; /**< api name for the binding */
+ const char *specification; /**< textual specification of the binding, can be NULL */
+ const char *info; /**< some info about the api, can be NULL */
+ const struct afb_verb_v2 *verbs; /**< array of descriptions of verbs terminated by a NULL name */
+ int (*preinit)(); /**< callback at load of the binding */
+ int (*init)(); /**< callback for starting the service */
+ void (*onevent)(const char *event, struct json_object *object); /**< callback for handling events */
+ unsigned noconcurrency: 1; /**< avoids concurrent requests to verbs */
};
+/**
+ * @deprecated use bindings version 3
+ *
+ * structure for the global data of the binding
+ */
struct afb_binding_data_v2
{
- int verbosity; /* level of verbosity */
- struct afb_daemon daemon; /* access to daemon APIs */
- struct afb_service service; /* access to service APIs */
+ int verbosity; /**< level of verbosity */
+ struct afb_daemon_x1 daemon; /**< access to daemon APIs */
+ struct afb_service_x1 service; /**< access to service APIs */
};
-/*
+/**
+ * @page validity-v2 Validity of a binding v2
+ *
* A binding V2 MUST have two exported symbols of name:
*
- * - afbBindingV2
- * - afbBindingV2data
+ * - @ref afbBindingV2
+ * - @ref afbBindingV2data
+ */
+
+/**
+ * @deprecated use bindings version 3
*
+ * The global mandatory description of the binding
*/
#if !defined(AFB_BINDING_MAIN_NAME_V2)
extern const struct afb_binding_v2 afbBindingV2;
#endif
-#if !defined(AFB_BINDING_DATA_NAME_V2)
-#define AFB_BINDING_DATA_NAME_V2 afbBindingV2data
-#endif
-
+/**
+ * @deprecated use bindings version 3
+ *
+ * The global auto declared internal data of the binding
+ */
#if AFB_BINDING_VERSION != 2
extern
#endif
-struct afb_binding_data_v2 AFB_BINDING_DATA_NAME_V2 __attribute__ ((weak));
+struct afb_binding_data_v2 afbBindingV2data __attribute__ ((weak));
-#define afb_get_verbosity_v2() (AFB_BINDING_DATA_NAME_V2.verbosity)
-#define afb_get_daemon_v2() (AFB_BINDING_DATA_NAME_V2.daemon)
-#define afb_get_service_v2() (AFB_BINDING_DATA_NAME_V2.service)
+#define afb_get_verbosity_v2() (afbBindingV2data.verbosity)
+#define afb_get_daemon_v2() (afbBindingV2data.daemon)
+#define afb_get_service_v2() (afbBindingV2data.service)
+/******************************************************************************/
/*
* Macros for logging messages
*/
#if defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DATA)
-# define _AFB_LOGGING_V2_(vlevel,llevel,...) \
- do{ \
- if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) {\
- if (llevel <= AFB_VERBOSITY_LEVEL_ERROR) \
- afb_daemon_verbose_v2(llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
- else \
- afb_daemon_verbose_v2(llevel,__FILE__,__LINE__,NULL,NULL); \
- } \
- }while(0)
-# define _AFB_REQ_LOGGING_V2_(vlevel,llevel,req,...) \
- do{ \
- if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) \
- afb_req_verbose(req,llevel,__FILE__,__LINE__,NULL,NULL); \
- }while(0)
+#define AFB_VERBOSE_V2(level,...) \
+ do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \
+ afb_daemon_verbose_v2(level,__FILE__,__LINE__,NULL,__VA_ARGS__); \
+ else afb_daemon_verbose_v2(level,__FILE__,__LINE__,NULL); } while(0)
+
+#define AFB_REQ_VERBOSE_V2(req,level,...) \
+ do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \
+ afb_req_x1_verbose(req,level,__FILE__,__LINE__,NULL,__VA_ARGS__); \
+ else afb_req_x1_verbose(req,level,__FILE__,__LINE__,NULL); } while(0)
#elif defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS)
-# define _AFB_LOGGING_V2_(vlevel,llevel,...) \
- do{ \
- if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) \
- afb_daemon_verbose_v2(llevel,NULL,0,NULL,__VA_ARGS__); \
- }while(0)
-# define _AFB_REQ_LOGGING_V2_(vlevel,llevel,req,...) \
- do{ \
- if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) \
- afb_req_verbose(req,llevel,NULL,0,NULL,__VA_ARGS__); \
- }while(0)
+#define AFB_VERBOSE_V2(level,...) \
+ afb_daemon_verbose_v2(level,NULL,0,NULL,__VA_ARGS__)
+
+#define AFB_REQ_VERBOSE_V2(req,level,...) \
+ afb_req_x1_verbose(req,level,NULL,0,NULL,__VA_ARGS__)
#else
-# define _AFB_LOGGING_V2_(vlevel,llevel,...) \
- do{ \
- if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) \
- afb_daemon_verbose_v2(llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
- }while(0)
-# define _AFB_REQ_LOGGING_V2_(vlevel,llevel,req,...) \
- do{ \
- if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) \
- afb_req_verbose(req,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
- }while(0)
+#define AFB_VERBOSE_V2(level,...) \
+ afb_daemon_verbose_v2(level,__FILE__,__LINE__,__func__,__VA_ARGS__)
+
+#define AFB_REQ_VERBOSE_V2(req,level,...) \
+ afb_req_x1_verbose(req,level,__FILE__,__LINE__,__func__,__VA_ARGS__)
#endif
-#include "afb-verbosity.h"
-#define AFB_ERROR_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__)
-#define AFB_WARNING_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__)
-#define AFB_NOTICE_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__)
-#define AFB_INFO_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__)
-#define AFB_DEBUG_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__)
-#define AFB_REQ_ERROR_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__)
-#define AFB_REQ_WARNING_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__)
-#define AFB_REQ_NOTICE_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__)
-#define AFB_REQ_INFO_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__)
-#define AFB_REQ_DEBUG_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__)
+#define _AFB_LOGGING_V2_(vlevel,llevel,...) \
+ do{ if(afb_get_verbosity_v2()>=vlevel) AFB_VERBOSE_V2(llevel,__VA_ARGS__); } while(0)
+#define _AFB_REQ_LOGGING_V2_(vlevel,llevel,req,...) \
+ do{ if(afb_get_verbosity_v2()>=vlevel) AFB_REQ_VERBOSE_V2(req,llevel,__VA_ARGS__); } while(0)
+
+#define AFB_ERROR_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_ERROR,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__)
+#define AFB_WARNING_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_WARNING,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__)
+#define AFB_NOTICE_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_NOTICE,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__)
+#define AFB_INFO_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_INFO,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__)
+#define AFB_DEBUG_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_DEBUG,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__)
+#define AFB_REQ_ERROR_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_ERROR,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__)
+#define AFB_REQ_WARNING_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_WARNING,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__)
+#define AFB_REQ_NOTICE_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_NOTICE,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__)
+#define AFB_REQ_INFO_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_INFO,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__)
+#define AFB_REQ_DEBUG_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_DEBUG,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__)
+
+/******************************************************************************/
+
+#if 0 && AFB_BINDING_VERSION >= 2
+
+# define afb_verbose_error() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_ERROR)
+# define afb_verbose_warning() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_WARNING)
+# define afb_verbose_notice() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_NOTICE)
+# define afb_verbose_info() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_INFO)
+# define afb_verbose_debug() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_DEBUG)
+
+#endif
#include "afb-daemon-v2.h"
#include "afb-service-v2.h"
diff --git a/include/afb/afb-binding-v3.h b/include/afb/afb-binding-v3.h
new file mode 100644
index 00000000..ece3f1c4
--- /dev/null
+++ b/include/afb/afb-binding-v3.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**< @file afb/afb-binding-v3.h */
+
+#pragma once
+
+/******************************************************************************/
+
+#include "afb-auth.h"
+#include "afb-event-x2.h"
+#include "afb-req-x2.h"
+#include "afb-session-x2.h"
+#include "afb-api-x3.h"
+
+/******************************************************************************/
+
+/**
+ * @page validity-v3 Validity of a binding v3
+ *
+ * A binding V3 MUST have at least two exported symbols of name:
+ *
+ * - @ref afbBindingV3root
+ * - @ref afbBindingV3 and/or @ref afbBindingV3entry
+ *
+ * @ref afbBindingV3root is automatically created when **AFB_BINDING_VERSION == 3**
+ * without programmer action, as a hidden variable linked as *weak*.
+ *
+ * The symbols @ref afbBindingV3 and **afbBindingV3entry** are under control
+ * of the programmer.
+ *
+ * The symbol @ref afbBindingV3 if defined is used, as in binding v2, to describe
+ * an API that will be declared during pre-initialization of bindings.
+ *
+ * The symbol @ref afbBindingV3entry if defined will be called during
+ * pre-initialization.
+ *
+ * If @ref afbBindingV3entry and @ref afbBindingV3 are both defined, it is an
+ * error to fill the field @ref preinit of @ref afbBindingV3.
+ *
+ * @see afb_binding_v3
+ * @see afbBindingV3root
+ * @see afbBindingV3entry
+ * @see afbBindingV3
+ */
+
+/**
+ * Description of one verb as provided for binding API version 3
+ */
+struct afb_verb_v3
+{
+ /** name of the verb, NULL only at end of the array */
+ const char *verb;
+
+ /** callback function implementing the verb */
+ void (*callback)(struct afb_req_x2 *req);
+
+ /** required authorization, can be NULL */
+ const struct afb_auth *auth;
+
+ /** some info about the verb, can be NULL */
+ const char *info;
+
+ /**< data for the verb callback */
+ void *vcbdata;
+
+ /** authorization and session requirements of the verb */
+ uint16_t session;
+
+ /** is the verb glob name */
+ uint16_t glob: 1;
+};
+
+/**
+ * Description of the bindings of type version 3
+ */
+struct afb_binding_v3
+{
+ /** api name for the binding, can't be NULL */
+ const char *api;
+
+ /** textual specification of the binding, can be NULL */
+ const char *specification;
+
+ /** some info about the api, can be NULL */
+ const char *info;
+
+ /** array of descriptions of verbs terminated by a NULL name, can be NULL */
+ const struct afb_verb_v3 *verbs;
+
+ /** callback at load of the binding */
+ int (*preinit)(struct afb_api_x3 *api);
+
+ /** callback for starting the service */
+ int (*init)(struct afb_api_x3 *api);
+
+ /** callback for handling events */
+ void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object);
+
+ /** userdata for afb_api_x3 */
+ void *userdata;
+
+ /** space separated list of provided class(es) */
+ const char *provide_class;
+
+ /** space separated list of required class(es) */
+ const char *require_class;
+
+ /** space separated list of required API(es) */
+ const char *require_api;
+
+ /** avoids concurrent requests to verbs */
+ unsigned noconcurrency: 1;
+};
+
+/**
+ * Default root binding's api that can be used when no explicit context is
+ * available.
+ *
+ * When @ref afbBindingV3 is defined, this variable records the corresponding
+ * api handler. Otherwise, it points to an fake handles that allows logging
+ * and api creation.
+ *
+ * @see afbBindingV3entry
+ * @see afbBindingV3
+ * @see @ref validity-v3
+ */
+#if AFB_BINDING_VERSION != 3
+extern
+#endif
+struct afb_api_x3 *afbBindingV3root __attribute__((weak));
+
+/**
+ * Pre-initialization function.
+ *
+ * If this function is defined and exported in the produced binding
+ * (shared object), it will be called during pre-initialization with the
+ * rootapi defined by \ref afbBindingV3root
+ *
+ * @param rootapi the root api (equals to afbBindingV3root)
+ *
+ * @return the function must return a negative integer on error to abort the
+ * initialization of the binding. Any positive or zero returned value is a
+ * interpreted as a success.
+
+ * @see afbBindingV3root
+ * @see afbBindingV3
+ * @see @ref validity-v3
+ */
+extern int afbBindingV3entry(struct afb_api_x3 *rootapi);
+
+/**
+ * Static definition of the root api of the binding.
+ *
+ * This symbol if defined describes the API of the binding.
+ *
+ * If it is not defined then the function @ref afbBindingV3entry must be defined
+ *
+ * @see afbBindingV3root
+ * @see afbBindingV3entry
+ * @see @ref validity-v3
+ */
+extern const struct afb_binding_v3 afbBindingV3;
+
+#include "afb-auth.h"
+#include "afb-session-x2.h"
+#include "afb-verbosity.h"
+
+#include "afb-event-x2.h"
+#include "afb-req-x2.h"
+#include "afb-api-x3.h"
+
+/*
+ * Macros for logging messages
+ */
+
+#if defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DATA)
+
+# define AFB_API_VERBOSE_V3(api,level,...) \
+ do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \
+ afb_api_v3_verbose(api,level,__FILE__,__LINE__,NULL,__VA_ARGS__); \
+ else afb_api_v3_verbose(api,level,__FILE__,__LINE__,NULL); } while(0)
+
+# define AFB_REQ_VERBOSE_V3(req,level,...) \
+ do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \
+ afb_req_x2_verbose(req,level,__FILE__,__LINE__,NULL,__VA_ARGS__); \
+ else afb_req_x2_verbose(req,level,__FILE__,__LINE__,NULL); } while(0)
+
+#elif defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS)
+
+# define AFB_API_VERBOSE_V3(api,level,...) \
+ afb_api_v3_verbose(api,level,NULL,0,NULL,__VA_ARGS__)
+
+# define AFB_REQ_VERBOSE_V3(req,level,...) \
+ afb_req_x2_verbose(req,level,NULL,0,NULL,__VA_ARGS__)
+
+#else
+
+# define AFB_API_VERBOSE_V3(api,level,...) \
+ afb_api_x3_verbose(api,level,__FILE__,__LINE__,__func__,__VA_ARGS__)
+
+# define AFB_REQ_VERBOSE_V3(req,level,...) \
+ afb_req_x2_verbose(req,level,__FILE__,__LINE__,__func__,__VA_ARGS__)
+
+#endif
+
+#define _AFB_API_LOGGING_V3_(api,llevel,...) \
+ do{ if(AFB_SYSLOG_MASK_WANT((api)->logmask,(llevel))) AFB_API_VERBOSE_V3((api),(llevel),__VA_ARGS__); }while(0)
+#define _AFB_REQ_LOGGING_V3_(req,llevel,...) \
+ do{ if(AFB_SYSLOG_MASK_WANT((req)->api->logmask,(llevel))) AFB_REQ_VERBOSE_V3((req),(llevel),__VA_ARGS__); }while(0)
+
+#define AFB_API_ERROR_V3(api,...) _AFB_API_LOGGING_V3_(api,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__)
+#define AFB_API_WARNING_V3(api,...) _AFB_API_LOGGING_V3_(api,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__)
+#define AFB_API_NOTICE_V3(api,...) _AFB_API_LOGGING_V3_(api,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__)
+#define AFB_API_INFO_V3(api,...) _AFB_API_LOGGING_V3_(api,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__)
+#define AFB_API_DEBUG_V3(api,...) _AFB_API_LOGGING_V3_(api,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__)
+
+#define AFB_REQ_ERROR_V3(req,...) _AFB_REQ_LOGGING_V3_(req,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__)
+#define AFB_REQ_WARNING_V3(req,...) _AFB_REQ_LOGGING_V3_(req,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__)
+#define AFB_REQ_NOTICE_V3(req,...) _AFB_REQ_LOGGING_V3_(req,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__)
+#define AFB_REQ_INFO_V3(req,...) _AFB_REQ_LOGGING_V3_(req,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__)
+#define AFB_REQ_DEBUG_V3(req,...) _AFB_REQ_LOGGING_V3_(req,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__)
+
+#define AFB_ERROR_V3(...) AFB_API_ERROR_V3(afbBindingV3root,__VA_ARGS__)
+#define AFB_WARNING_V3(...) AFB_API_WARNING_V3(afbBindingV3root,__VA_ARGS__)
+#define AFB_NOTICE_V3(...) AFB_API_NOTICE_V3(afbBindingV3root,__VA_ARGS__)
+#define AFB_INFO_V3(...) AFB_API_INFO_V3(afbBindingV3root,__VA_ARGS__)
+#define AFB_DEBUG_V3(...) AFB_API_DEBUG_V3(afbBindingV3root,__VA_ARGS__)
+
+#define afb_get_root_api_v3() (afbBindingV3root)
+#define afb_get_logmask_v3() (afbBindingV3root->logmask)
+#define afb_get_verbosity_v3() AFB_SYSLOG_LEVEL_TO_VERBOSITY(_afb_verbomask_to_upper_level_(afbBindingV3root->logmask))
+
+#define afb_daemon_get_event_loop_v3(...) afb_api_get_event_loop(afbBindingV3root,__VA_ARGS__)
+#define afb_daemon_get_user_bus_v3(...) afb_api_get_user_bus(afbBindingV3root,__VA_ARGS__)
+#define afb_daemon_get_system_bus_v3(...) afb_api_get_system_bus(afbBindingV3root,__VA_ARGS__)
+#define afb_daemon_broadcast_event_v3(...) afb_api_broadcast_event(afbBindingV3root,__VA_ARGS__)
+#define afb_daemon_make_event_v3(...) afb_api_make_event(afbBindingV3root,__VA_ARGS__)
+#define afb_daemon_verbose_v3(...) afb_api_verbose(afbBindingV3root,__VA_ARGS__)
+#define afb_daemon_rootdir_get_fd_v3() afb_api_rootdir_get_fd(afbBindingV3root)
+#define afb_daemon_rootdir_open_locale_v3(...) afb_api_rootdir_open_locale(afbBindingV3root,__VA_ARGS__)
+#define afb_daemon_queue_job_v3(...) afb_api_queue_job(afbBindingV3root,__VA_ARGS__)
+#define afb_daemon_require_api_v3(...) afb_api_require_api(afbBindingV3root,__VA_ARGS__)
+#define afb_daemon_add_alias_v3(...) afb_api_add_alias(afbBindingV3root,__VA_ARGS__)
+
+#define afb_service_call_v3(...) afb_api_call_legacy(afbBindingV3root,__VA_ARGS__)
+#define afb_service_call_sync_v3(...) afb_api_call_sync_legacy(afbBindingV3root,__VA_ARGS__)
+
diff --git a/include/afb/afb-binding-vdyn.h b/include/afb/afb-binding-vdyn.h
deleted file mode 100644
index 357a85f6..00000000
--- a/include/afb/afb-binding-vdyn.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author: José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "afb-auth.h"
-#include "afb-session-v2.h"
-#include "afb-verbosity.h"
-
-#include "afb-eventid.h"
-#include "afb-request.h"
-#include "afb-dynapi.h"
-
-/*
- * The function afbBindingVdyn if exported allows to create
- * pure dynamic bindings. When the binding is loaded, it receives
- * a virtual dynapi that can be used to create apis. The
- * given API can not be used except for creating dynamic apis.
- */
-extern int afbBindingVdyn(struct afb_dynapi *dynapi);
-
-/*
- * Macros for logging messages
- */
-#if defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DATA)
-
-# define _AFB_DYNAPI_LOGGING_(vlevel,llevel,dynapi,...) \
- do{ \
- if(dynapi->verbosity>=vlevel) {\
- if (llevel <= AFB_VERBOSITY_LEVEL_ERROR) \
- afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
- else \
- afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,NULL,NULL); \
- } \
- }while(0)
-# define _AFB_REQUEST_LOGGING_(vlevel,llevel,request,...) \
- do{ \
- if(request->dynapi->verbosity>=vlevel) \
- afb_request_verbose(request,llevel,__FILE__,__LINE__,NULL,NULL); \
- }while(0)
-
-#elif defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS)
-
-# define _AFB_DYNAPI_LOGGING_(vlevel,llevel,dynapi,...) \
- do{ \
- if(dynapi->verbosity>=vlevel) \
- afb_dynapi_verbose(dynapi,llevel,NULL,0,NULL,__VA_ARGS__); \
- }while(0)
-# define _AFB_REQUEST_LOGGING_(vlevel,llevel,request,...) \
- do{ \
- if(request->dynapi->verbosity>=vlevel) \
- afb_request_verbose(request,llevel,NULL,0,NULL,__VA_ARGS__); \
- }while(0)
-
-#else
-
-# define _AFB_DYNAPI_LOGGING_(vlevel,llevel,dynapi,...) \
- do{ \
- if(dynapi->verbosity>=vlevel) \
- afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
- }while(0)
-# define _AFB_REQUEST_LOGGING_(vlevel,llevel,request,...) \
- do{ \
- if(request->dynapi->verbosity>=vlevel) \
- afb_request_verbose(request,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
- }while(0)
-
-#endif
-
-#define AFB_DYNAPI_ERROR(...) _AFB_DYNAPI_LOGGING_(AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__)
-#define AFB_DYNAPI_WARNING(...) _AFB_DYNAPI_LOGGING_(AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__)
-#define AFB_DYNAPI_NOTICE(...) _AFB_DYNAPI_LOGGING_(AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__)
-#define AFB_DYNAPI_INFO(...) _AFB_DYNAPI_LOGGING_(AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__)
-#define AFB_DYNAPI_DEBUG(...) _AFB_DYNAPI_LOGGING_(AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__)
-#define AFB_REQUEST_ERROR(...) _AFB_REQUEST_LOGGING_(AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__)
-#define AFB_REQUEST_WARNING(...) _AFB_REQUEST_LOGGING_(AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__)
-#define AFB_REQUEST_NOTICE(...) _AFB_REQUEST_LOGGING_(AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__)
-#define AFB_REQUEST_INFO(...) _AFB_REQUEST_LOGGING_(AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__)
-#define AFB_REQUEST_DEBUG(...) _AFB_REQUEST_LOGGING_(AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__)
-
-
diff --git a/include/afb/afb-binding.h b/include/afb/afb-binding.h
index 37305991..085dc388 100644
--- a/include/afb/afb-binding.h
+++ b/include/afb/afb-binding.h
@@ -17,246 +17,105 @@
#pragma once
+/**
+ * @mainpage
+ *
+ * @section brief Brief introduction
+ *
+ * This is part of the AGL framework micro-service binder and is provided as the
+ * API for writing bindings.
+ *
+ * The normal usage is to include only one file as below:
+ *
+ * ```C
+ * #define AFB_BINDING_VERSION 3
+ * #include <afb/afb-binding.h>
+ * ```
+ *
+ * @example tuto-1.c
+ * @example tuto-2.c
+ */
+/**
+ * @file afb/afb-binding.h
+ */
+
#include <stdarg.h>
+#include <stdint.h>
+struct json_object;
-/*****************************************************************************
- * This files is the main file to include for writing bindings dedicated to
+/**
+ * @def AFB_BINDING_INTERFACE_VERSION
+
+ * * Version of the binding interface.
*
- * AFB-DAEMON
+ * This is intended to be test for tuning condition code.
+ * It is of the form MAJOR * 1000 + REVISION.
*
- * Functions of bindings of afb-daemon are accessible by authorized clients
- * through the apis module of afb-daemon.
+ * @see AFB_BINDING_UPPER_VERSION that should match MAJOR
*/
+#define AFB_BINDING_INTERFACE_VERSION 3000
+/**
+ * @def AFB_BINDING_LOWER_VERSION
+ *
+ * Lowest binding API version supported.
+ *
+ * @see AFB_BINDING_VERSION
+ * @see AFB_BINDING_UPPER_VERSION
+ */
#define AFB_BINDING_LOWER_VERSION 1
-#define AFB_BINDING_UPPER_VERSION 2
+
+/**
+ * @def AFB_BINDING_UPPER_VERSION
+ *
+ * Upper binding API version supported.
+ *
+ * @see AFB_BINDING_VERSION
+ * @see AFB_BINDING_LOWER_VERSION
+ */
+#define AFB_BINDING_UPPER_VERSION 3
+
+/**
+ * @def AFB_BINDING_VERSION
+ *
+ * This macro must be defined before including <afb/afb-binding.h> to set
+ * the required binding API.
+ */
#ifndef AFB_BINDING_VERSION
-#define AFB_BINDING_VERSION 1
-#pragma GCC warning "\
+#error "\
\n\
\n\
AFB_BINDING_VERSION should be defined before including <afb/afb-binding.h>\n\
AFB_BINDING_VERSION defines the version of binding that you use.\n\
- Currently, known versions are 1 or 2.\n\
- Setting now AFB_BINDING_VERSION to 1 (version 1 by default)\n\
- NOTE THAT VERSION 2 IS NOW RECOMMENDED!\n\
+ Currently the version to use is 3 (older versions: 1 is obsolete, 2 is legacy).\n\
Consider to add one of the following define before including <afb/afb-binding.h>:\n\
\n\
- #define AFB_BINDING_VERSION 1\n\
- #define AFB_BINDING_VERSION 2\n\
+ #define AFB_BINDING_VERSION 3\n\
\n\
- Note that in some case it will enforce you to include <stdio.h>\n\
"
-#include <stdio.h> /* old version side effect */
#else
# if AFB_BINDING_VERSION == 1
-# pragma GCC warning "Using binding version 1, consider to switch to version 2"
+# pragma GCC warning "Using binding version 1, consider to switch to version 3"
+# endif
+# if AFB_BINDING_VERSION == 2
+# pragma GCC warning "Using binding version 2, consider to switch to version 3"
# endif
#endif
#if AFB_BINDING_VERSION != 0
# if AFB_BINDING_VERSION < AFB_BINDING_LOWER_VERSION || AFB_BINDING_VERSION > AFB_BINDING_UPPER_VERSION
-# error "Unsupported binding version AFB_BINDING_VERSION " #AFB_BINDING_VERSION
+# error "Unsupported binding version AFB_BINDING_VERSION"
# endif
#endif
-/*
- * Some function of the library are exported to afb-daemon.
- */
-
+/***************************************************************************************************/
+#include "afb-binding-predefs.h"
#include "afb-binding-v1.h"
#include "afb-binding-v2.h"
-#include "afb-binding-vdyn.h"
-
-typedef struct afb_verb_desc_v1 afb_verb_desc_v1;
-typedef struct afb_binding_desc_v1 afb_binding_desc_v1;
-typedef struct afb_binding_v1 afb_binding_v1;
-typedef struct afb_binding_interface_v1 afb_binding_interface_v1;
-
-typedef struct afb_verb_v2 afb_verb_v2;
-typedef struct afb_binding_v2 afb_binding_v2;
-
-typedef enum afb_auth_type afb_auth_type;
-typedef struct afb_auth afb_auth;
-typedef struct afb_daemon afb_daemon;
-typedef struct afb_event afb_event;
-typedef struct afb_arg afb_arg;
-typedef struct afb_req afb_req;
-typedef struct afb_stored_req afb_stored_req;
-typedef struct afb_service afb_service;
-
-typedef struct afb_dynapi afb_dynapi;
-typedef struct afb_request afb_request;
-typedef struct afb_eventid afb_eventid;
-
-#if 0
-/* these typedef's shouldn't be needed */
-typedef enum afb_binding_type_v1 afb_binding_type_v1;
-typedef enum afb_mode_v1 afb_mode_v1;
-typedef enum afb_session_flags_v1 afb_session_flags_v1;
-typedef enum afb_session_flags_v2 afb_session_flags_v2;
-typedef struct afb_binding_data_v2 afb_binding_data_v2;
-typedef struct afb_daemon_itf afb_daemon_itf;
-typedef struct afb_event_itf afb_event_itf;
-typedef struct afb_req_itf afb_req_itf;
-typedef struct afb_service_itf afb_service_itf;
-#endif
-
-/***************************************************************************************************/
-
-#if AFB_BINDING_VERSION == 1
-
-# define afb_binding afb_binding_v1
-# define afb_binding_interface afb_binding_interface_v1
-
-# define AFB_SESSION_NONE AFB_SESSION_NONE_V1
-# define AFB_SESSION_CREATE AFB_SESSION_CREATE_V1
-# define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_V1
-# define AFB_SESSION_RENEW AFB_SESSION_RENEW_V1
-# define AFB_SESSION_CHECK AFB_SESSION_CHECK_V1
-
-# define AFB_SESSION_LOA_GE AFB_SESSION_LOA_GE_V1
-# define AFB_SESSION_LOA_LE AFB_SESSION_LOA_LE_V1
-# define AFB_SESSION_LOA_EQ AFB_SESSION_LOA_EQ_V1
-
-# define AFB_SESSION_LOA_SHIFT AFB_SESSION_LOA_SHIFT_V1
-# define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_V1
-
-# define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_V1
-# define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_V1
-# define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_V1
-# define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_V1
-# define AFB_SESSION_LOA_4 AFB_SESSION_LOA_4_V1
-
-# define AFB_SESSION_LOA_LE_0 AFB_SESSION_LOA_LE_0_V1
-# define AFB_SESSION_LOA_LE_1 AFB_SESSION_LOA_LE_1_V1
-# define AFB_SESSION_LOA_LE_2 AFB_SESSION_LOA_LE_2_V1
-# define AFB_SESSION_LOA_LE_3 AFB_SESSION_LOA_LE_3_V1
-
-# define AFB_SESSION_LOA_EQ_0 AFB_SESSION_LOA_EQ_0_V1
-# define AFB_SESSION_LOA_EQ_1 AFB_SESSION_LOA_EQ_1_V1
-# define AFB_SESSION_LOA_EQ_2 AFB_SESSION_LOA_EQ_2_V1
-# define AFB_SESSION_LOA_EQ_3 AFB_SESSION_LOA_EQ_3_V1
-
-# define AFB_SESSION_LOA_GE_0 AFB_SESSION_LOA_GE_0_V1
-# define AFB_SESSION_LOA_GE_1 AFB_SESSION_LOA_GE_1_V1
-# define AFB_SESSION_LOA_GE_2 AFB_SESSION_LOA_GE_2_V1
-# define AFB_SESSION_LOA_GE_3 AFB_SESSION_LOA_GE_3_V1
-
-# define AFB_ERROR AFB_ERROR_V1
-# define AFB_WARNING AFB_WARNING_V1
-# define AFB_NOTICE AFB_NOTICE_V1
-# define AFB_INFO AFB_INFO_V1
-# define AFB_DEBUG AFB_DEBUG_V1
-
-# define AFB_REQ_ERROR AFB_REQ_ERROR_V1
-# define AFB_REQ_WARNING AFB_REQ_WARNING_V1
-# define AFB_REQ_NOTICE AFB_REQ_NOTICE_V1
-# define AFB_REQ_INFO AFB_REQ_INFO_V1
-# define AFB_REQ_DEBUG AFB_REQ_DEBUG_V1
-
-#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v1
-#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v1
-#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v1
-#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v1
-#define afb_daemon_make_event afb_daemon_make_event_v1
-#define afb_daemon_verbose afb_daemon_verbose_v1
-#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v1
-#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v1
-#define afb_daemon_queue_job afb_daemon_queue_job_v1
-#define afb_daemon_require_api afb_daemon_require_api_v1
-#define afb_daemon_rename_api afb_daemon_rename_api_v1
-
-#define afb_service_call afb_service_call_v1
-#define afb_service_call_sync afb_service_call_sync_v1
-
-#define afb_req_store afb_req_store_v1
-#define afb_req_unstore afb_req_unstore_v1
-
-#endif
-
-/***************************************************************************************************/
-
-#if AFB_BINDING_VERSION == 2
-
-# define afb_binding afb_binding_v2
-# define afb_get_verbosity afb_get_verbosity_v2
-# define afb_get_daemon afb_get_daemon_v2
-# define afb_get_service afb_get_service_v2
-
-
-# define AFB_SESSION_NONE AFB_SESSION_NONE_V2
-# define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_V2
-# define AFB_SESSION_RENEW AFB_SESSION_REFRESH_V2
-# define AFB_SESSION_REFRESH AFB_SESSION_REFRESH_V2
-# define AFB_SESSION_CHECK AFB_SESSION_CHECK_V2
-
-# define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_V2
-
-# define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_V2
-# define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_V2
-# define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_V2
-# define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_V2
-
-# define AFB_ERROR AFB_ERROR_V2
-# define AFB_WARNING AFB_WARNING_V2
-# define AFB_NOTICE AFB_NOTICE_V2
-# define AFB_INFO AFB_INFO_V2
-# define AFB_DEBUG AFB_DEBUG_V2
-
-# define AFB_REQ_ERROR AFB_REQ_ERROR_V2
-# define AFB_REQ_WARNING AFB_REQ_WARNING_V2
-# define AFB_REQ_NOTICE AFB_REQ_NOTICE_V2
-# define AFB_REQ_INFO AFB_REQ_INFO_V2
-# define AFB_REQ_DEBUG AFB_REQ_DEBUG_V2
-
-#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v2
-#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v2
-#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v2
-#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v2
-#define afb_daemon_make_event afb_daemon_make_event_v2
-#define afb_daemon_verbose afb_daemon_verbose_v2
-#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v2
-#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v2
-#define afb_daemon_queue_job afb_daemon_queue_job_v2
-#define afb_daemon_unstore_req afb_daemon_unstore_req_v2
-#define afb_daemon_require_api afb_daemon_require_api_v2
-#define afb_daemon_rename_api afb_daemon_rename_api_v2
-
-#define afb_service_call afb_service_call_v2
-#define afb_service_call_sync afb_service_call_sync_v2
-
-#define afb_req_store afb_req_store_v2
-#define afb_req_unstore afb_daemon_unstore_req_v2
-
-#endif
-
-/***************************************************************************************************/
-
-#if AFB_BINDING_VERSION >= 2
-
-# define afb_verbose_error() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_ERROR)
-# define afb_verbose_warning() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_WARNING)
-# define afb_verbose_notice() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_NOTICE)
-# define afb_verbose_info() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_INFO)
-# define afb_verbose_debug() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_DEBUG)
-
-#endif
-
-/***************************************************************************************************/
-
-#if defined(AFB_BINDING_PRAGMA_KEEP_VERBOSE_UNPREFIX)
-# define ERROR AFB_ERROR
-# define WARNING AFB_WARNING
-# define NOTICE AFB_NOTICE
-# define INFO AFB_INFO
-# define DEBUG AFB_DEBUG
-
-# define REQ_ERROR AFB_REQ_ERROR
-# define REQ_WARNING AFB_REQ_WARNING
-# define REQ_NOTICE AFB_REQ_NOTICE
-# define REQ_INFO AFB_REQ_INFO
-# define REQ_DEBUG AFB_REQ_DEBUG
+#include "afb-binding-v3.h"
+#if defined(AFB_BINDING_WANT_DYNAPI)
+# include "afb-dynapi-legacy.h"
#endif
+#include "afb-binding-postdefs.h"
diff --git a/include/afb/afb-binding.hpp b/include/afb/afb-binding.hpp
index ee151339..27715f39 100644
--- a/include/afb/afb-binding.hpp
+++ b/include/afb/afb-binding.hpp
@@ -17,18 +17,19 @@
#pragma once
+#include <cstddef>
#include <cstdlib>
#include <cstdarg>
#include <functional>
/* ensure version */
#ifndef AFB_BINDING_VERSION
-# define AFB_BINDING_VERSION 2
+# define AFB_BINDING_VERSION 3
#endif
/* check the version */
#if AFB_BINDING_VERSION < 2
-# error "AFB_BINDING_VERSION must be at least 2"
+# error "AFB_BINDING_VERSION must be at least 2 but 3 is prefered"
#endif
/* get C definitions of bindings */
@@ -44,16 +45,11 @@ namespace afb {
class arg;
class event;
class req;
-class stored_req;
/*************************************************************************/
/* declaration of functions */
/*************************************************************************/
-struct sd_event *get_event_loop();
-struct sd_bus *get_system_bus();
-struct sd_bus *get_user_bus();
-
int broadcast_event(const char *name, json_object *object = nullptr);
event make_event(const char *name);
@@ -70,7 +66,7 @@ int queue_job(void (*callback)(int signum, void *arg), void *argument, void *gro
int require_api(const char *apiname, bool initialized = true);
-int rename_api(const char *apiname);
+int add_alias(const char *apiname, const char *aliasname);
int verbosity();
@@ -80,9 +76,17 @@ bool wants_notices();
bool wants_infos();
bool wants_debugs();
+#if AFB_BINDING_VERSION >= 3
+void call(const char *api, const char *verb, struct json_object *args, void (*callback)(void*closure, int iserror, struct json_object *result, afb_api_t api), void *closure);
+
+template <class T> void call(const char *api, const char *verb, struct json_object *args, void (*callback)(T*closure, int iserror, struct json_object *result, afb_api_t api), T *closure);
+
+bool callsync(const char *api, const char *verb, struct json_object *args, struct json_object *&result);
+#else
void call(const char *api, const char *verb, struct json_object *args, void (*callback)(void*closure, int iserror, struct json_object *result), void *closure);
template <class T> void call(const char *api, const char *verb, struct json_object *args, void (*callback)(T*closure, int iserror, struct json_object *result), T *closure);
+#endif
bool callsync(const char *api, const char *verb, struct json_object *args, struct json_object *&result);
@@ -93,14 +97,15 @@ bool callsync(const char *api, const char *verb, struct json_object *args, struc
/* events */
class event
{
- struct afb_event event_;
+ afb_event_t event_;
public:
- event() { event_.itf = nullptr; event_.closure = nullptr; }
- event(const struct afb_event &e);
+ event() { invalidate(); }
+ event(afb_event_t e);
event(const event &other);
event &operator=(const event &other);
- operator const struct afb_event&() const;
+ operator afb_event_t() const;
+ afb_event_t operator->() const;
operator bool() const;
bool is_valid() const;
@@ -139,30 +144,16 @@ public:
/* req(uest) */
class req
{
- struct afb_req req_;
-public:
- class stored
- {
- struct afb_stored_req *sreq_;
-
- friend class req;
- stored() = delete;
- stored(struct afb_stored_req *sr);
- public:
- stored(const stored &other);
- stored &operator =(const stored &other);
- req unstore() const;
- };
-
- class stored;
+ afb_req_t req_;
public:
req() = delete;
- req(const struct afb_req &r);
+ req(afb_req_t r);
req(const req &other);
req &operator=(const req &other);
- operator const struct afb_req&() const;
+ operator afb_req_t() const;
+ afb_req_t operator->() const;
operator bool() const;
bool is_valid() const;
@@ -175,22 +166,20 @@ public:
json_object *json() const;
+ void reply(json_object *obj = nullptr, const char *error = nullptr, const char *info = nullptr) const;
+ void replyf(json_object *obj, const char *error, const char *info, ...) const;
+ void replyv(json_object *obj, const char *error, const char *info, va_list args) const;
+
void success(json_object *obj = nullptr, const char *info = nullptr) const;
void successf(json_object *obj, const char *info, ...) const;
+ void successv(json_object *obj, const char *info, va_list args) const;
- void fail(const char *status = "failed", const char *info = nullptr) const;
- void failf(const char *status, const char *info, ...) const;
-
- void *context_get() const;
-
- void context_set(void *context, void (*free_context)(void*)) const;
-
- void *context(void *(*create_context)(), void (*free_context)(void*)) const;
+ void fail(const char *error = "failed", const char *info = nullptr) const;
+ void failf(const char *error, const char *info, ...) const;
+ void failv(const char *error, const char *info, va_list args) const;
template < class T > T *context() const;
- void context_clear() const;
-
void addref() const;
void unref() const;
@@ -199,19 +188,22 @@ public:
bool session_set_LOA(unsigned level) const;
- stored store() const;
-
bool subscribe(const event &event) const;
bool unsubscribe(const event &event) const;
- void subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result), void *closure) const;
+ void subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result, afb_req_t req), void *closure) const;
+ template <class T> void subcall(const char *api, const char *verb, json_object *args, void (*callback)(T *closure, int iserror, json_object *result, afb_req_t req), T *closure) const;
- void subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result, afb_req req), void *closure) const;
+ bool subcallsync(const char *api, const char *verb, json_object *args, struct json_object *&result) const;
- template <class T> void subcall(const char *api, const char *verb, json_object *args, void (*callback)(T *closure, int iserror, json_object *result), T *closure) const;
+#if AFB_BINDING_VERSION >= 3
+ void subcall(const char *api, const char *verb, json_object *args, int flags, void (*callback)(void *closure, json_object *object, const char *error, const char *info, afb_req_t req), void *closure) const;
- bool subcallsync(const char *api, const char *verb, json_object *args, struct json_object *&result) const;
+ template <class T> void subcall(const char *api, const char *verb, json_object *args, int flags, void (*callback)(T *closure, json_object *object, const char *error, const char *info, afb_req_t req), T *closure) const;
+
+ bool subcallsync(const char *api, const char *verb, json_object *args, int flags, struct json_object *&object, char *&error, char *&info) const;
+#endif
void verbose(int level, const char *file, int line, const char * func, const char *fmt, va_list args) const;
@@ -222,6 +214,8 @@ public:
char *get_application_id() const;
int get_uid() const;
+
+ json_object *get_client_info() const;
};
/*************************************************************************/
@@ -250,18 +244,23 @@ public:
/*************************************************************************/
/* events */
-inline event::event(const struct afb_event &e) : event_(e) { }
+inline event::event(afb_event_t e) : event_(e) { }
inline event::event(const event &other) : event_(other.event_) { }
inline event &event::operator=(const event &other) { event_ = other.event_; return *this; }
-inline event::operator const struct afb_event&() const { return event_; }
+inline event::operator afb_event_t() const { return event_; }
+inline afb_event_t event::operator->() const { return event_; }
inline event::operator bool() const { return is_valid(); }
-inline bool event::is_valid() const { return afb_event_is_valid(event_); }
+inline bool event::is_valid() const { return afb_event_is_valid(event_); }
-inline void event::invalidate() { event_.itf = NULL; event_.closure = NULL; }
+#if AFB_BINDING_VERSION >= 3
+inline void event::invalidate() { event_ = nullptr; }
+#else
+inline void event::invalidate() { event_ = { nullptr, nullptr }; }
+#endif
-inline int event::broadcast(json_object *object) const { return afb_event_broadcast(event_, object); }
+inline int event::broadcast(json_object *object) const { return afb_event_broadcast(event_, object); }
inline int event::push(json_object *object) const { return afb_event_push(event_, object); }
inline void event::unref() { afb_event_unref(event_); invalidate(); }
@@ -285,23 +284,16 @@ inline const char *arg::path() const { return arg_.path; }
/* req(uests)s */
-inline req::stored::stored(struct afb_stored_req *sr) : sreq_(sr) {}
-
-inline req::stored::stored(const req::stored &other) : sreq_(other.sreq_) {}
-
-inline req::stored &req::stored::operator =(const req::stored &other) { sreq_ = other.sreq_; return *this; }
-
-inline req req::stored::unstore() const { return req(afb_daemon_unstore_req_v2(sreq_)); }
-
-inline req::req(const struct afb_req &r) : req_(r) {}
+inline req::req(afb_req_t r) : req_(r) {}
inline req::req(const req &other) : req_(other.req_) {}
inline req &req::operator=(const req &other) { req_ = other.req_; return *this; }
-inline req::operator const struct afb_req&() const { return req_; }
+inline req::operator afb_req_t() const { return req_; }
+inline afb_req_t req::operator->() const { return req_; }
-inline req::operator bool() const { return !!afb_req_is_valid(req_); }
-inline bool req::is_valid() const { return !!afb_req_is_valid(req_); }
+inline req::operator bool() const { return is_valid(); }
+inline bool req::is_valid() const { return afb_req_is_valid(req_); }
inline arg req::get(const char *name) const { return arg(afb_req_get(req_, name)); }
@@ -311,160 +303,210 @@ inline const char *req::path(const char *name) const { return afb_req_path(req_,
inline json_object *req::json() const { return afb_req_json(req_); }
-inline void req::success(json_object *obj, const char *info) const { afb_req_success(req_, obj, info); }
-inline void req::successf(json_object *obj, const char *info, ...) const
+inline void req::reply(json_object *obj, const char *error, const char *info) const { afb_req_reply(req_, obj, error, info); }
+inline void req::replyv(json_object *obj, const char *error, const char *info, va_list args) const { afb_req_reply_v(req_, obj, error, info, args); }
+inline void req::replyf(json_object *obj, const char *error, const char *info, ...) const
{
va_list args;
va_start(args, info);
- afb_req_success_v(req_, obj, info, args);
+ replyv(obj, error, info, args);
va_end(args);
}
-inline void req::fail(const char *status, const char *info) const { afb_req_fail(req_, status, info); }
-inline void req::failf(const char *status, const char *info, ...) const
+inline void req::success(json_object *obj, const char *info) const { reply(obj, nullptr, info); }
+inline void req::successv(json_object *obj, const char *info, va_list args) const { replyv(obj, nullptr, info, args); }
+inline void req::successf(json_object *obj, const char *info, ...) const
{
va_list args;
va_start(args, info);
- afb_req_fail_v(req_, status, info, args);
+ successv(obj, info, args);
va_end(args);
}
-inline void *req::context_get() const { return afb_req_context_get(req_); }
-
-inline void req::context_set(void *context, void (*free_context)(void*)) const { afb_req_context_set(req_, context, free_context); }
-
-inline void *req::context(void *(*create_context)(), void (*free_context)(void*)) const { return afb_req_context(req_, create_context, free_context); }
+inline void req::fail(const char *error, const char *info) const { reply(nullptr, error, info); }
+inline void req::failv(const char *error, const char *info, va_list args) const { replyv(nullptr, error, info, args); }
+inline void req::failf(const char *error, const char *info, ...) const
+{
+ va_list args;
+ va_start(args, info);
+ failv(error, info, args);
+ va_end(args);
+}
template < class T >
inline T *req::context() const
{
+#if AFB_BINDING_VERSION >= 3
+ T* (*creater)(void*) = [](){return new T();};
+ void (*freer)(T*) = [](T*t){delete t;};
+ return reinterpret_cast<T*>(afb_req_context(req_, 0,
+ reinterpret_cast<void *(*)(void*)>(creater),
+ reinterpret_cast<void (*)(void*)>(freer), nullptr));
+#else
T* (*creater)() = [](){return new T();};
void (*freer)(T*) = [](T*t){delete t;};
return reinterpret_cast<T*>(afb_req_context(req_,
reinterpret_cast<void *(*)()>(creater),
reinterpret_cast<void (*)(void*)>(freer)));
+#endif
}
-inline void req::context_clear() const { afb_req_context_clear(req_); }
-
inline void req::addref() const { afb_req_addref(req_); }
inline void req::unref() const { afb_req_unref(req_); }
inline void req::session_close() const { afb_req_session_close(req_); }
-inline bool req::session_set_LOA(unsigned level) const { return !!afb_req_session_set_LOA(req_, level); }
-
-inline req::stored req::store() const { return stored(afb_req_store_v2(req_)); }
+inline bool req::session_set_LOA(unsigned level) const { return !afb_req_session_set_LOA(req_, level); }
inline bool req::subscribe(const event &event) const { return !afb_req_subscribe(req_, event); }
inline bool req::unsubscribe(const event &event) const { return !afb_req_unsubscribe(req_, event); }
-inline void req::subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result), void *closure) const
+
+
+
+
+#if AFB_BINDING_VERSION >= 3
+
+inline void req::subcall(const char *api, const char *verb, json_object *args, int flags, void (*callback)(void *closure, json_object *result, const char *error, const char *info, afb_req_t req), void *closure) const
{
- afb_req_subcall(req_, api, verb, args, callback, closure);
+ afb_req_subcall(req_, api, verb, args, flags, callback, closure);
}
-inline void req::subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result, struct afb_req req), void *closure) const
+template <class T>
+inline void req::subcall(const char *api, const char *verb, json_object *args, int flags, void (*callback)(T *closure, json_object *result, const char *error, const char *info, afb_req_t req), T *closure) const
{
+ subcall(api, verb, args, flags, reinterpret_cast<void(*)(void*,json_object*,const char*,const char*,afb_req_t)>(callback), reinterpret_cast<void*>(closure));
+}
+
+inline bool req::subcallsync(const char *api, const char *verb, json_object *args, int flags, struct json_object *&object, char *&error, char *&info) const
+{
+ return !afb_req_subcall_sync(req_, api, verb, args, flags, &object, &error, &info);
+}
+
+#endif
+
+inline void req::subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result, afb_req_t req), void *closure) const
+{
+#if AFB_BINDING_VERSION >= 3
+ afb_req_subcall_legacy(req_, api, verb, args, callback, closure);
+#else
afb_req_subcall_req(req_, api, verb, args, callback, closure);
+#endif
}
template <class T>
-inline void req::subcall(const char *api, const char *verb, json_object *args, void (*callback)(T *closure, int iserror, json_object *result), T *closure) const
+inline void req::subcall(const char *api, const char *verb, json_object *args, void (*callback)(T *closure, int iserror, json_object *result, afb_req_t req), T *closure) const
{
- afb_req_subcall(req_, api, verb, args, reinterpret_cast<void(*)(void*,int,json_object*)>(callback), reinterpret_cast<void*>(closure));
+ subcall(api, verb, args, reinterpret_cast<void(*)(void*,int,json_object*,afb_req_t)>(callback), reinterpret_cast<void*>(closure));
}
inline bool req::subcallsync(const char *api, const char *verb, json_object *args, struct json_object *&result) const
{
- return !!afb_req_subcall_sync(req_, api, verb, args, &result);
+#if AFB_BINDING_VERSION >= 3
+ return !afb_req_subcall_sync_legacy(req_, api, verb, args, &result);
+#else
+ return !afb_req_subcall_sync(req_, api, verb, args, &result);
+#endif
}
inline void req::verbose(int level, const char *file, int line, const char * func, const char *fmt, va_list args) const
{
- req_.itf->vverbose(req_.closure, level, file, line, func, fmt, args);
+ afb_req_verbose(req_, level, file, line, func, fmt, args);
}
inline void req::verbose(int level, const char *file, int line, const char * func, const char *fmt, ...) const
{
va_list args;
va_start(args, fmt);
- req_.itf->vverbose(req_.closure, level, file, line, func, fmt, args);
+ afb_req_verbose(req_, level, file, line, func, fmt, args);
va_end(args);
}
inline bool req::has_permission(const char *permission) const
{
- return bool(req_.itf->has_permission(req_.closure, permission));
+ return bool(afb_req_has_permission(req_, permission));
}
inline char *req::get_application_id() const
{
- return req_.itf->get_application_id(req_.closure);
+ return afb_req_get_application_id(req_);
}
inline int req::get_uid() const
{
- return req_.itf->get_uid(req_.closure);
+ return afb_req_get_uid(req_);
}
-/* commons */
-inline struct sd_event *get_event_loop()
- { return afb_daemon_get_event_loop_v2(); }
-
-inline struct sd_bus *get_system_bus()
- { return afb_daemon_get_system_bus_v2(); }
-
-inline struct sd_bus *get_user_bus()
- { return afb_daemon_get_user_bus_v2(); }
+inline json_object *req::get_client_info() const
+{
+ return afb_req_get_client_info(req_);
+}
+/* commons */
inline int broadcast_event(const char *name, json_object *object)
- { return afb_daemon_broadcast_event_v2(name, object); }
+ { return afb_daemon_broadcast_event(name, object); }
inline event make_event(const char *name)
- { return afb_daemon_make_event_v2(name); }
+ { return afb_daemon_make_event(name); }
inline void verbose(int level, const char *file, int line, const char * func, const char *fmt, va_list args)
- { afb_daemon_verbose_v2(level, file, line, func, fmt, args); }
+ { afb_daemon_verbose(level, file, line, func, fmt, args); }
inline void verbose(int level, const char *file, int line, const char * func, const char *fmt, ...)
{ va_list args; va_start(args, fmt); verbose(level, file, line, func, fmt, args); va_end(args); }
inline int rootdir_get_fd()
- { return afb_daemon_rootdir_get_fd_v2(); }
+ { return afb_daemon_rootdir_get_fd(); }
inline int rootdir_open_locale_fd(const char *filename, int flags, const char *locale)
- { return afb_daemon_rootdir_open_locale_v2(filename, flags, locale); }
+ { return afb_daemon_rootdir_open_locale(filename, flags, locale); }
inline int queue_job(void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
- { return afb_daemon_queue_job_v2(callback, argument, group, timeout); }
+ { return afb_daemon_queue_job(callback, argument, group, timeout); }
inline int require_api(const char *apiname, bool initialized)
- { return afb_daemon_require_api_v2(apiname, int(initialized)); }
+ { return afb_daemon_require_api(apiname, int(initialized)); }
-inline int rename_api(const char *apiname)
- { return afb_daemon_rename_api_v2(apiname); }
+inline int add_alias(const char *apiname, const char *aliasname)
+ { return afb_daemon_add_alias(apiname, aliasname); }
-inline int verbosity()
- { return afb_get_verbosity(); }
+#if AFB_BINDING_VERSION >= 3
+inline int logmask()
+ { return afb_get_logmask(); }
+#else
+inline int logmask()
+ { return (1 << (1 + afb_get_verbosity() + AFB_SYSLOG_LEVEL_ERROR)) - 1; }
+#endif
inline bool wants_errors()
- { return afb_verbose_error(); }
+ { return AFB_SYSLOG_MASK_WANT_ERROR(logmask()); }
inline bool wants_warnings()
- { return afb_verbose_warning(); }
+ { return AFB_SYSLOG_MASK_WANT_WARNING(logmask()); }
inline bool wants_notices()
- { return afb_verbose_notice(); }
+ { return AFB_SYSLOG_MASK_WANT_NOTICE(logmask()); }
inline bool wants_infos()
- { return afb_verbose_info(); }
+ { return AFB_SYSLOG_MASK_WANT_INFO(logmask()); }
inline bool wants_debugs()
- { return afb_verbose_debug(); }
+ { return AFB_SYSLOG_MASK_WANT_DEBUG(logmask()); }
+#if AFB_BINDING_VERSION >= 3
+inline void call(const char *api, const char *verb, struct json_object *args, void (*callback)(void*closure, int iserror, struct json_object *result, afb_api_t api), void *closure)
+{
+ afb_service_call(api, verb, args, callback, closure);
+}
+
+template <class T>
+inline void call(const char *api, const char *verb, struct json_object *args, void (*callback)(T*closure, int iserror, struct json_object *result, afb_api_t api), T *closure)
+{
+ afb_service_call(api, verb, args, reinterpret_cast<void(*)(void*,int,json_object*,afb_api_t)>(callback), reinterpret_cast<void*>(closure));
+}
+#else
inline void call(const char *api, const char *verb, struct json_object *args, void (*callback)(void*closure, int iserror, struct json_object *result), void *closure)
{
afb_service_call(api, verb, args, callback, closure);
@@ -475,6 +517,7 @@ inline void call(const char *api, const char *verb, struct json_object *args, vo
{
afb_service_call(api, verb, args, reinterpret_cast<void(*)(void*,int,json_object*)>(callback), reinterpret_cast<void*>(closure));
}
+#endif
inline bool callsync(const char *api, const char *verb, struct json_object *args, struct json_object *&result)
{
@@ -563,31 +606,67 @@ constexpr afb_auth auth_and(const afb_auth &first, const afb_auth &next)
return auth_and(&first, &next);
}
-constexpr afb_verb_v2 verb(const char *name, void (*callback)(afb_req), const char *info = nullptr, unsigned session = 0, const afb_auth *auth = nullptr)
+constexpr afb_verb_t verb(
+ const char *name,
+ void (*callback)(afb_req_t),
+ const char *info = nullptr,
+ uint16_t session = 0,
+ const afb_auth *auth = nullptr
+#if AFB_BINDING_VERSION >= 3
+ ,
+ bool glob = false,
+ void *vcbdata = nullptr
+#endif
+)
{
- afb_verb_v2 r = { 0, 0, 0, 0, 0 };
+#if AFB_BINDING_VERSION >= 3
+ afb_verb_t r = { 0, 0, 0, 0, 0, 0, 0 };
+#else
+ afb_verb_t r = { 0, 0, 0, 0, 0 };
+#endif
r.verb = name;
r.callback = callback;
r.info = info;
r.session = session;
r.auth = auth;
+#if AFB_BINDING_VERSION >= 3
+ r.glob = (unsigned)glob;
+ r.vcbdata = vcbdata;
+#endif
return r;
}
-constexpr afb_verb_v2 verbend()
+constexpr afb_verb_t verbend()
{
- afb_verb_v2 r = { 0, 0, 0, 0, 0 };
- r.verb = nullptr;
- r.callback = nullptr;
- r.info = nullptr;
- r.session = 0;
- r.auth = nullptr;
+ afb_verb_t r = verb(nullptr, nullptr);
return r;
}
-constexpr afb_binding_v2 binding(const char *name, const struct afb_verb_v2 *verbs, const char *info = nullptr, int (*init)() = nullptr, const char *specification = nullptr, void (*onevent)(const char*, struct json_object*) = nullptr, bool noconcurrency = false, int (*preinit)() = nullptr)
+constexpr afb_binding_t binding(
+ const char *name,
+ const afb_verb_t *verbs,
+ const char *info = nullptr,
+#if AFB_BINDING_VERSION >= 3
+ int (*init)(afb_api_t) = nullptr,
+ const char *specification = nullptr,
+ void (*onevent)(afb_api_t, const char*, struct json_object*) = nullptr,
+ bool noconcurrency = false,
+ int (*preinit)(afb_api_t) = nullptr,
+ void *userdata = nullptr
+#else
+ int (*init)() = nullptr,
+ const char *specification = nullptr,
+ void (*onevent)(const char*, struct json_object*) = nullptr,
+ bool noconcurrency = false,
+ int (*preinit)() = nullptr
+#endif
+)
{
- afb_binding_v2 r = { 0, 0, 0, 0, 0, 0, 0, 0 };
+#if AFB_BINDING_VERSION >= 3
+ afb_binding_t r = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+#else
+ afb_binding_t r = { 0, 0, 0, 0, 0, 0, 0, 0 };
+#endif
r.api = name;
r.specification = specification;
r.info = info;
@@ -596,6 +675,9 @@ constexpr afb_binding_v2 binding(const char *name, const struct afb_verb_v2 *ver
r.init = init;
r.onevent = onevent;
r.noconcurrency = noconcurrency ? 1 : 0;
+#if AFB_BINDING_VERSION >= 3
+ r.userdata = userdata;
+#endif
return r;
};
diff --git a/include/afb/afb-daemon-itf-x1.h b/include/afb/afb-daemon-itf-x1.h
new file mode 100644
index 00000000..3ca12eba
--- /dev/null
+++ b/include/afb/afb-daemon-itf-x1.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdarg.h>
+
+/* declaration of features of libsystemd */
+struct sd_event;
+struct sd_bus;
+struct afb_stored_req;
+struct afb_req_x1;
+struct afb_event_x1;
+struct afb_api_x3;
+
+/**
+ * @deprecated use bindings version 3
+ *
+ * Definition of the facilities provided by the daemon.
+ */
+struct afb_daemon_itf_x1
+{
+ /** broadcasts evant 'name' with 'object' */
+ int (*event_broadcast)(struct afb_api_x3 *closure, const char *name, struct json_object *object);
+
+ /** gets the common systemd's event loop */
+ struct sd_event *(*get_event_loop)(struct afb_api_x3 *closure);
+
+ /** gets the common systemd's user d-bus */
+ struct sd_bus *(*get_user_bus)(struct afb_api_x3 *closure);
+
+ /** gets the common systemd's system d-bus */
+ struct sd_bus *(*get_system_bus)(struct afb_api_x3 *closure);
+
+ /** logging messages */
+ void (*vverbose_v1)(struct afb_api_x3*closure, int level, const char *file, int line, const char *fmt, va_list args);
+
+ /** creates an event of 'name' */
+ struct afb_event_x1 (*event_make)(struct afb_api_x3 *closure, const char *name);
+
+ /** get the file descriptor of the install directory */
+ int (*rootdir_get_fd)(struct afb_api_x3 *closure);
+
+ /** opens a file of the install directory */
+ int (*rootdir_open_locale)(struct afb_api_x3 *closure, const char *filename, int flags, const char *locale);
+
+ /** queue a job */
+ int (*queue_job)(struct afb_api_x3 *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout);
+
+ /** logging messages */
+ void (*vverbose_v2)(struct afb_api_x3*closure, int level, const char *file, int line, const char * func, const char *fmt, va_list args);
+
+ /** retrieve a stored request */
+ struct afb_req_x1 (*unstore_req)(struct afb_api_x3*closure, struct afb_stored_req *sreq);
+
+ /** require an api */
+ int (*require_api)(struct afb_api_x3*closure, const char *name, int initialized);
+
+ /** aliases an api */
+ int (*add_alias)(struct afb_api_x3*closure, const char *name, const char *as_name);
+
+ /** creates a new api */
+ struct afb_api_x3 *(*new_api)(struct afb_api_x3 *closure, const char *api, const char *info, int noconcurrency, int (*preinit)(void*, struct afb_api_x3 *), void *preinit_closure);
+};
+
+/**
+ * @deprecated use bindings version 3
+ *
+ * Structure for accessing daemon.
+ * See also: afb_daemon_get_event_sender, afb_daemon_get_event_loop, afb_daemon_get_user_bus, afb_daemon_get_system_bus
+ */
+struct afb_daemon_x1
+{
+ const struct afb_daemon_itf_x1 *itf; /**< the interfacing functions */
+ struct afb_api_x3 *closure; /**< the closure when calling these functions */
+};
+
diff --git a/include/afb/afb-daemon-itf.h b/include/afb/afb-daemon-itf.h
deleted file mode 100644
index b8fa1931..00000000
--- a/include/afb/afb-daemon-itf.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author: José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdarg.h>
-
-/* declaration of features of libsystemd */
-struct sd_event;
-struct sd_bus;
-struct afb_stored_req;
-struct afb_req;
-struct afb_dynapi;
-
-/*
- * Definition of the facilities provided by the daemon.
- */
-struct afb_daemon_itf
-{
- int (*event_broadcast)(void *closure, const char *name, struct json_object *object); /* broadcasts evant 'name' with 'object' */
- struct sd_event *(*get_event_loop)(void *closure); /* gets the common systemd's event loop */
- struct sd_bus *(*get_user_bus)(void *closure); /* gets the common systemd's user d-bus */
- struct sd_bus *(*get_system_bus)(void *closure); /* gets the common systemd's system d-bus */
- void (*vverbose_v1)(void*closure, int level, const char *file, int line, const char *fmt, va_list args);
- struct afb_event (*event_make)(void *closure, const char *name); /* creates an event of 'name' */
- int (*rootdir_get_fd)(void *closure);
- int (*rootdir_open_locale)(void *closure, const char *filename, int flags, const char *locale);
- int (*queue_job)(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout);
- void (*vverbose_v2)(void*closure, int level, const char *file, int line, const char * func, const char *fmt, va_list args);
- struct afb_req (*unstore_req)(void*closure, struct afb_stored_req *sreq);
- int (*require_api)(void*closure, const char *name, int initialized);
- int (*rename_api)(void*closure, const char *name);
- int (*new_api)(void *closure, const char *api, const char *info, int noconcurrency, int (*preinit)(void*, struct afb_dynapi *), void *preinit_closure);
-};
-
-/*
- * Structure for accessing daemon.
- * See also: afb_daemon_get_event_sender, afb_daemon_get_event_loop, afb_daemon_get_user_bus, afb_daemon_get_system_bus
- */
-struct afb_daemon
-{
- const struct afb_daemon_itf *itf; /* the interfacing functions */
- void *closure; /* the closure when calling these functions */
-};
-
diff --git a/include/afb/afb-daemon-v1.h b/include/afb/afb-daemon-v1.h
index 5a78b15d..d84517d1 100644
--- a/include/afb/afb-daemon-v1.h
+++ b/include/afb/afb-daemon-v1.h
@@ -17,36 +17,44 @@
#pragma once
-#include "afb-daemon-itf.h"
+#include "afb-daemon-itf-x1.h"
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Retrieves the common systemd's event loop of AFB
* 'daemon' MUST be the daemon given in interface when activating the binding.
*/
-static inline struct sd_event *afb_daemon_get_event_loop_v1(struct afb_daemon daemon)
+static inline struct sd_event *afb_daemon_get_event_loop_v1(struct afb_daemon_x1 daemon)
{
return daemon.itf->get_event_loop(daemon.closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Retrieves the common systemd's user/session d-bus of AFB
* 'daemon' MUST be the daemon given in interface when activating the binding.
*/
-static inline struct sd_bus *afb_daemon_get_user_bus_v1(struct afb_daemon daemon)
+static inline struct sd_bus *afb_daemon_get_user_bus_v1(struct afb_daemon_x1 daemon)
{
return daemon.itf->get_user_bus(daemon.closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Retrieves the common systemd's system d-bus of AFB
* 'daemon' MUST be the daemon given in interface when activating the binding.
*/
-static inline struct sd_bus *afb_daemon_get_system_bus_v1(struct afb_daemon daemon)
+static inline struct sd_bus *afb_daemon_get_system_bus_v1(struct afb_daemon_x1 daemon)
{
return daemon.itf->get_system_bus(daemon.closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Broadcasts widely the event of 'name' with the data 'object'.
* 'object' can be NULL.
* 'daemon' MUST be the daemon given in interface when activating the binding.
@@ -59,12 +67,14 @@ static inline struct sd_bus *afb_daemon_get_system_bus_v1(struct afb_daemon daem
*
* Returns the count of clients that received the event.
*/
-static inline int afb_daemon_broadcast_event_v1(struct afb_daemon daemon, const char *name, struct json_object *object)
+static inline int afb_daemon_broadcast_event_v1(struct afb_daemon_x1 daemon, const char *name, struct json_object *object)
{
return daemon.itf->event_broadcast(daemon.closure, name, object);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Creates an event of 'name' and returns it.
* 'daemon' MUST be the daemon given in interface when activating the binding.
*
@@ -72,12 +82,14 @@ static inline int afb_daemon_broadcast_event_v1(struct afb_daemon daemon, const
*
* See afb_event_is_valid to check if there is an error.
*/
-static inline struct afb_event afb_daemon_make_event_v1(struct afb_daemon daemon, const char *name)
+static inline struct afb_event_x1 afb_daemon_make_event_v1(struct afb_daemon_x1 daemon, const char *name)
{
return daemon.itf->event_make(daemon.closure, name);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Send a message described by 'fmt' and following parameters
* to the journal for the verbosity 'level'.
*
@@ -96,8 +108,8 @@ static inline struct afb_event afb_daemon_make_event_v1(struct afb_daemon daemon
* INFO 6 Informational
* DEBUG 7 Debug-level messages
*/
-static inline void afb_daemon_verbose_v1(struct afb_daemon daemon, int level, const char *file, int line, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
-static inline void afb_daemon_verbose_v1(struct afb_daemon daemon, int level, const char *file, int line, const char *fmt, ...)
+static inline void afb_daemon_verbose_v1(struct afb_daemon_x1 daemon, int level, const char *file, int line, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
+static inline void afb_daemon_verbose_v1(struct afb_daemon_x1 daemon, int level, const char *file, int line, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
@@ -105,7 +117,9 @@ static inline void afb_daemon_verbose_v1(struct afb_daemon daemon, int level, co
va_end(args);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Send a message described by 'fmt' and following parameters
* to the journal for the verbosity 'level'.
*
@@ -124,8 +138,8 @@ static inline void afb_daemon_verbose_v1(struct afb_daemon daemon, int level, co
* INFO 6 Informational
* DEBUG 7 Debug-level messages
*/
-static inline void afb_daemon_verbose2_v1(struct afb_daemon daemon, int level, const char *file, int line, const char *func, const char *fmt, ...) __attribute__((format(printf, 6, 7)));
-static inline void afb_daemon_verbose2_v1(struct afb_daemon daemon, int level, const char *file, int line, const char *func, const char *fmt, ...)
+static inline void afb_daemon_verbose2_v1(struct afb_daemon_x1 daemon, int level, const char *file, int line, const char *func, const char *fmt, ...) __attribute__((format(printf, 6, 7)));
+static inline void afb_daemon_verbose2_v1(struct afb_daemon_x1 daemon, int level, const char *file, int line, const char *func, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
@@ -133,26 +147,34 @@ static inline void afb_daemon_verbose2_v1(struct afb_daemon daemon, int level, c
va_end(args);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Get the root directory file descriptor. This file descriptor can
* be used with functions 'openat', 'fstatat', ...
+ *
+ * Returns the file descriptor or -1 in case of error.
*/
-static inline int afb_daemon_rootdir_get_fd_v1(struct afb_daemon daemon)
+static inline int afb_daemon_rootdir_get_fd_v1(struct afb_daemon_x1 daemon)
{
return daemon.itf->rootdir_get_fd(daemon.closure);
}
-/*
- * Opens 'filename' within the root directory with 'flags' (see function openat)
+/**
+ * @deprecated use bindings version 3
+ *
* using the 'locale' definition (example: "jp,en-US") that can be NULL.
+ *
* Returns the file descriptor or -1 in case of error.
*/
-static inline int afb_daemon_rootdir_open_locale_v1(struct afb_daemon daemon, const char *filename, int flags, const char *locale)
+static inline int afb_daemon_rootdir_open_locale_v1(struct afb_daemon_x1 daemon, const char *filename, int flags, const char *locale)
{
return daemon.itf->rootdir_open_locale(daemon.closure, filename, flags, locale);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Queue the job defined by 'callback' and 'argument' for being executed asynchronously
* in this thread (later) or in an other thread.
* If 'group' is not NUL, the jobs queued with a same value (as the pointer value 'group')
@@ -165,39 +187,52 @@ static inline int afb_daemon_rootdir_open_locale_v1(struct afb_daemon daemon, co
*
* Returns 0 in case of success or -1 in case of error.
*/
-static inline int afb_daemon_queue_job_v1(struct afb_daemon daemon, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
+static inline int afb_daemon_queue_job_v1(struct afb_daemon_x1 daemon, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
{
return daemon.itf->queue_job(daemon.closure, callback, argument, group, timeout);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Tells that it requires the API of "name" to exist
* and if 'initialized' is not null to be initialized.
* Calling this function is only allowed within init.
+ *
* Returns 0 in case of success or -1 in case of error.
*/
-static inline int afb_daemon_require_api_v1(struct afb_daemon daemon, const char *name, int initialized)
+static inline int afb_daemon_require_api_v1(struct afb_daemon_x1 daemon, const char *name, int initialized)
{
return daemon.itf->require_api(daemon.closure, name, initialized);
}
-/*
- * Set the name of the API to 'name'.
+/**
+ * @deprecated use bindings version 3
+ *
+ * Create an aliased name 'as_name' for the api 'name'.
* Calling this function is only allowed within preinit.
+ *
* Returns 0 in case of success or -1 in case of error.
*/
-static inline int afb_daemon_rename_api_v1(struct afb_daemon daemon, const char *name)
+static inline int afb_daemon_add_alias_v1(struct afb_daemon_x1 daemon, const char *name, const char *as_name)
{
- return daemon.itf->rename_api(daemon.closure, name);
+ return daemon.itf->add_alias(daemon.closure, name, as_name);
}
+/**
+ * @deprecated use bindings version 3
+ *
+ * Creates a new api of name 'api' with brief 'info'.
+ *
+ * Returns 0 in case of success or -1 in case of error.
+ */
static inline int afb_daemon_new_api_v1(
- struct afb_daemon daemon,
+ struct afb_daemon_x1 daemon,
const char *api,
const char *info,
int noconcurrency,
- int (*preinit)(void*, struct afb_dynapi *),
+ int (*preinit)(void*, struct afb_api_x3 *),
void *closure)
{
- return daemon.itf->new_api(daemon.closure, api, info, noconcurrency, preinit, closure);
+ return -!daemon.itf->new_api(daemon.closure, api, info, noconcurrency, preinit, closure);
}
diff --git a/include/afb/afb-daemon-v2.h b/include/afb/afb-daemon-v2.h
index 4b8399c4..f3c2c904 100644
--- a/include/afb/afb-daemon-v2.h
+++ b/include/afb/afb-daemon-v2.h
@@ -17,9 +17,11 @@
#pragma once
-#include "afb-daemon-itf.h"
+#include "afb-daemon-itf-x1.h"
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Retrieves the common systemd's event loop of AFB
*/
static inline struct sd_event *afb_daemon_get_event_loop_v2()
@@ -27,7 +29,9 @@ static inline struct sd_event *afb_daemon_get_event_loop_v2()
return afb_get_daemon_v2().itf->get_event_loop(afb_get_daemon_v2().closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Retrieves the common systemd's user/session d-bus of AFB
*/
static inline struct sd_bus *afb_daemon_get_user_bus_v2()
@@ -35,7 +39,9 @@ static inline struct sd_bus *afb_daemon_get_user_bus_v2()
return afb_get_daemon_v2().itf->get_user_bus(afb_get_daemon_v2().closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Retrieves the common systemd's system d-bus of AFB
*/
static inline struct sd_bus *afb_daemon_get_system_bus_v2()
@@ -43,7 +49,9 @@ static inline struct sd_bus *afb_daemon_get_system_bus_v2()
return afb_get_daemon_v2().itf->get_system_bus(afb_get_daemon_v2().closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Broadcasts widely the event of 'name' with the data 'object'.
* 'object' can be NULL.
*
@@ -60,19 +68,23 @@ static inline int afb_daemon_broadcast_event_v2(const char *name, struct json_ob
return afb_get_daemon_v2().itf->event_broadcast(afb_get_daemon_v2().closure, name, object);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Creates an event of 'name' and returns it.
*
* Calling this function is only forbidden during preinit.
*
* See afb_event_is_valid to check if there is an error.
*/
-static inline struct afb_event afb_daemon_make_event_v2(const char *name)
+static inline struct afb_event_x1 afb_daemon_make_event_v2(const char *name)
{
return afb_get_daemon_v2().itf->event_make(afb_get_daemon_v2().closure, name);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Send a message described by 'fmt' and following parameters
* to the journal for the verbosity 'level'.
*
@@ -98,18 +110,25 @@ static inline void afb_daemon_verbose_v2(int level, const char *file, int line,
va_end(args);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Get the root directory file descriptor. This file descriptor can
* be used with functions 'openat', 'fstatat', ...
+ *
+ * Returns the file descriptor or -1 in case of error.
*/
static inline int afb_daemon_rootdir_get_fd_v2()
{
return afb_get_daemon_v2().itf->rootdir_get_fd(afb_get_daemon_v2().closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Opens 'filename' within the root directory with 'flags' (see function openat)
* using the 'locale' definition (example: "jp,en-US") that can be NULL.
+ *
* Returns the file descriptor or -1 in case of error.
*/
static inline int afb_daemon_rootdir_open_locale_v2(const char *filename, int flags, const char *locale)
@@ -117,7 +136,9 @@ static inline int afb_daemon_rootdir_open_locale_v2(const char *filename, int fl
return afb_get_daemon_v2().itf->rootdir_open_locale(afb_get_daemon_v2().closure, filename, flags, locale);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Queue the job defined by 'callback' and 'argument' for being executed asynchronously
* in this thread (later) or in an other thread.
* If 'group' is not NUL, the jobs queued with a same value (as the pointer value 'group')
@@ -135,22 +156,27 @@ static inline int afb_daemon_queue_job_v2(void (*callback)(int signum, void *arg
return afb_get_daemon_v2().itf->queue_job(afb_get_daemon_v2().closure, callback, argument, group, timeout);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Retrieves the afb_req stored at 'sreq'.
* Returns the stored request.
* The count of reference is UNCHANGED, thus, the
* function 'afb_req_unref' should be called on the result
* after that the asynchronous reply if sent.
*/
-static inline struct afb_req afb_daemon_unstore_req_v2(struct afb_stored_req *sreq)
+static inline struct afb_req_x1 afb_daemon_unstore_req_v2(struct afb_stored_req *sreq)
{
return afb_get_daemon_v2().itf->unstore_req(afb_get_daemon_v2().closure, sreq);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Tells that it requires the API of "name" to exist
* and if 'initialized' is not null to be initialized.
* Calling this function is only allowed within init.
+ *
* Returns 0 in case of success or -1 in case of error.
*/
static inline int afb_daemon_require_api_v2(const char *name, int initialized)
@@ -158,23 +184,33 @@ static inline int afb_daemon_require_api_v2(const char *name, int initialized)
return afb_get_daemon_v2().itf->require_api(afb_get_daemon_v2().closure, name, initialized);
}
-/*
- * Set the name of the API to 'name'.
+/**
+ * @deprecated use bindings version 3
+ *
+ * Create an aliased name 'as_name' for the api 'name'.
* Calling this function is only allowed within preinit.
+ *
* Returns 0 in case of success or -1 in case of error.
*/
-static inline int afb_daemon_rename_api_v2(const char *name)
+static inline int afb_daemon_add_alias_v2(const char *name, const char *as_name)
{
- return afb_get_daemon_v2().itf->rename_api(afb_get_daemon_v2().closure, name);
+ return afb_get_daemon_v2().itf->add_alias(afb_get_daemon_v2().closure, name, as_name);
}
+/**
+ * @deprecated use bindings version 3
+ *
+ * Creates a new api of name 'api' with brief 'info'.
+ *
+ * Returns 0 in case of success or -1 in case of error.
+ */
static inline int afb_daemon_new_api_v2(
const char *api,
const char *info,
int noconcurrency,
- int (*preinit)(void*, struct afb_dynapi *),
+ int (*preinit)(void*, struct afb_api_x3 *),
void *closure)
{
- return afb_get_daemon_v2().itf->new_api(afb_get_daemon_v2().closure, api, info, noconcurrency, preinit, closure);
+ return -!(afb_get_daemon_v2().itf->new_api(afb_get_daemon_v2().closure, api, info, noconcurrency, preinit, closure));
}
diff --git a/include/afb/afb-dynapi-itf.h b/include/afb/afb-dynapi-itf.h
deleted file mode 100644
index 979088d6..00000000
--- a/include/afb/afb-dynapi-itf.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author: José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-/* declared here */
-struct afb_dynapi;
-struct afb_dynapi_itf;
-
-/* referenced here */
-#include <stdarg.h>
-struct sd_event;
-struct sd_bus;
-struct afb_request;
-struct afb_eventid;
-struct afb_auth;
-struct afb_verb_v2;
-
-/*
- * structure for the dynapi
- */
-struct afb_dynapi
-{
- /* interface for the dynapi */
- const struct afb_dynapi_itf *itf;
-
- /* user defined data */
- void *userdata;
-
- /* current verbosity level */
- int verbosity;
-
- /* the name of the api */
- const char *apiname;
-};
-
-/*
- * Definition of the interface for the API
- */
-struct afb_dynapi_itf
-{
- /* CAUTION: respect the order, add at the end */
-
- void (*vverbose)(
- void *dynapi,
- int level,
- const char *file,
- int line,
- const char * func,
- const char *fmt,
- va_list args);
-
- /* gets the common systemd's event loop */
- struct sd_event *(*get_event_loop)(
- void *dynapi);
-
- /* gets the common systemd's user d-bus */
- struct sd_bus *(*get_user_bus)(
- void *dynapi);
-
- /* gets the common systemd's system d-bus */
- struct sd_bus *(*get_system_bus)(
- void *dynapi);
-
- int (*rootdir_get_fd)(
- void *dynapi);
-
- int (*rootdir_open_locale)(
- void *dynapi,
- const char *filename,
- int flags,
- const char *locale);
-
- int (*queue_job)(
- void *dynapi,
- void (*callback)(int signum, void *arg),
- void *argument,
- void *group,
- int timeout);
-
- int (*require_api)(
- void *dynapi,
- const char *name,
- int initialized);
-
- int (*rename_api)(
- void *dynapi,
- const char *name);
-
- /* broadcasts event 'name' with 'object' */
- int (*event_broadcast)(
- void *dynapi,
- const char *name,
- struct json_object *object);
-
- /* creates an event of 'name' */
- struct afb_eventid *(*eventid_make)(
- void *dynapi,
- const char *name);
-
- void (*call)(
- struct afb_dynapi *dynapi,
- const char *api,
- const char *verb,
- struct json_object *args,
- void (*callback)(void*, int, struct json_object*, struct afb_dynapi *),
- void *callback_closure);
-
- int (*call_sync)(
- void *dynapi,
- const char *api,
- const char *verb,
- struct json_object *args,
- struct json_object **result);
-
- int (*api_new_api)(
- void *dynapi,
- const char *api,
- const char *info,
- int noconcurrency,
- int (*preinit)(void*, struct afb_dynapi *),
- void *closure);
-
- int (*api_set_verbs_v2)(
- struct afb_dynapi *dynapi,
- const struct afb_verb_v2 *verbs);
-
- int (*api_add_verb)(
- 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);
-
- int (*api_sub_verb)(
- struct afb_dynapi *dynapi,
- const char *verb);
-
- int (*api_set_on_event)(
- struct afb_dynapi *dynapi,
- void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object));
-
- int (*api_set_on_init)(
- struct afb_dynapi *dynapi,
- int (*oninit)(struct afb_dynapi *dynapi));
-
- void (*api_seal)(
- struct afb_dynapi *dynapi);
-};
-
diff --git a/include/afb/afb-dynapi-legacy.h b/include/afb/afb-dynapi-legacy.h
new file mode 100644
index 00000000..ffa0d92a
--- /dev/null
+++ b/include/afb/afb-dynapi-legacy.h
@@ -0,0 +1,191 @@
+
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/***************************************************************************************************/
+
+#define afb_dynapi afb_api_x3
+#define afb_dynapi_itf afb_api_x3_itf
+
+#define afb_request afb_req_x2
+#define afb_request_get_dynapi afb_req_x2_get_api
+#define afb_request_get_vcbdata afb_req_x2_get_vcbdata
+#define afb_request_get_api afb_req_x2_get_called_api
+#define afb_request_get_verb afb_req_x2_get_called_verb
+#define afb_request_wants_log_level afb_req_x2_wants_log_level
+
+#define afb_request_get afb_req_x2_get
+#define afb_request_value afb_req_x2_value
+#define afb_request_path afb_req_x2_path
+#define afb_request_json afb_req_x2_json
+#define afb_request_reply afb_req_x2_reply
+#define afb_request_reply_f afb_req_x2_reply_f
+#define afb_request_reply_v afb_req_x2_reply_v
+#define afb_request_success(r,o,i) afb_req_x2_reply(r,o,0,i)
+#define afb_request_success_f(r,o,...) afb_req_x2_reply_f(r,o,0,__VA_ARGS__)
+#define afb_request_success_v(r,o,f,v) afb_req_x2_reply_v(r,o,0,f,v)
+#define afb_request_fail(r,e,i) afb_req_x2_reply(r,0,e,i)
+#define afb_request_fail_f(r,e,f,...) afb_req_x2_reply_f(r,0,e,f,__VA_ARGS__)
+#define afb_request_fail_v(r,e,f,v) afb_req_x2_reply_v(r,0,e,f,v)
+#define afb_request_context_get afb_req_x2_context_get
+#define afb_request_context_set afb_req_x2_context_set
+#define afb_request_context afb_req_x2_context
+#define afb_request_context_clear afb_req_x2_context_clear
+#define afb_request_addref afb_req_x2_addref
+#define afb_request_unref afb_req_x2_unref
+#define afb_request_session_close afb_req_x2_session_close
+#define afb_request_session_set_LOA afb_req_x2_session_set_LOA
+#define afb_request_subscribe afb_req_x2_subscribe
+#define afb_request_unsubscribe afb_req_x2_unsubscribe
+#define afb_request_subcall afb_req_x2_subcall_legacy
+#define afb_request_subcall_sync afb_req_x2_subcall_sync_legacy
+#define afb_request_verbose afb_req_x2_verbose
+#define afb_request_has_permission afb_req_x2_has_permission
+#define afb_request_get_application_id afb_req_x2_get_application_id
+#define afb_request_get_uid afb_req_x2_get_uid
+#define afb_request_get_client_info afb_req_x2_get_client_info
+
+#define afb_dynapi_name afb_api_x3_name
+#define afb_dynapi_get_userdata afb_api_x3_get_userdata
+#define afb_dynapi_set_userdata afb_api_x3_set_userdata
+#define afb_dynapi_wants_log_level afb_api_x3_wants_log_level
+
+#define afb_dynapi_verbose afb_api_x3_verbose
+#define afb_dynapi_vverbose afb_api_x3_vverbose
+#define afb_dynapi_get_event_loop afb_api_x3_get_event_loop
+#define afb_dynapi_get_user_bus afb_api_x3_get_user_bus
+#define afb_dynapi_get_system_bus afb_api_x3_get_system_bus
+#define afb_dynapi_rootdir_get_fd afb_api_x3_rootdir_get_fd
+#define afb_dynapi_rootdir_open_locale afb_api_x3_rootdir_open_locale
+#define afb_dynapi_queue_job afb_api_x3_queue_job
+#define afb_dynapi_require_api afb_api_x3_require_api
+#define afb_dynapi_rename_api afb_api_x3_add_alias
+#define afb_dynapi_broadcast_event afb_api_x3_broadcast_event
+#define afb_dynapi_make_eventid afb_api_x3_make_event_x2
+#define afb_dynapi_call afb_api_x3_call_legacy
+#define afb_dynapi_call_sync afb_api_x3_call_sync_legacy
+#define afb_dynapi_new_api(...) (-!afb_api_x3_new_api(__VA_ARGS__))
+#define afb_dynapi_set_verbs_v2 afb_api_x3_set_verbs_v2
+#define afb_dynapi_add_verb(a,b,c,d,e,f,g) afb_api_x3_add_verb(a,b,c,d,e,f,g,0)
+#define afb_dynapi_sub_verb(a,b) afb_api_x3_del_verb(a,b,NULL)
+#define afb_dynapi_on_event afb_api_x3_on_event
+#define afb_dynapi_on_init afb_api_x3_on_init
+#define afb_dynapi_seal afb_api_x3_seal
+
+#define afb_eventid_broadcast afb_event_x2_broadcast
+#define afb_eventid_push afb_event_x2_push
+#define afb_eventid_name afb_event_x2_name
+#define afb_eventid_unref afb_event_x2_unref
+#define afb_eventid_addref afb_event_x2_addref
+
+#define afb_eventid afb_event_x2
+#define afb_eventid_is_valid afb_event_x2_is_valid
+#define afb_eventid_broadcast afb_event_x2_broadcast
+#define afb_eventid_push afb_event_x2_push
+#define afb_eventid_drop afb_event_x2_unref
+#define afb_eventid_name afb_event_x2_name
+#define afb_eventid_unref afb_event_x2_unref
+#define afb_eventid_addref afb_event_x2_addref
+
+/*
+ * The function afbBindingVdyn if exported allows to create
+ * pure dynamic bindings. When the binding is loaded, it receives
+ * a virtual dynapi that can be used to create apis. The
+ * given API can not be used except for creating dynamic apis.
+ */
+extern int afbBindingVdyn(struct afb_dynapi *dynapi);
+
+/*
+ * Macros for logging messages
+ */
+/* macro for setting file, line and function automatically */
+# if !defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS)
+#define AFB_REQUEST_VERBOSE(req,level,...) afb_req_x2_verbose(req,level,__FILE__,__LINE__,__func__,__VA_ARGS__)
+#else
+#define AFB_REQUEST_VERBOSE(req,level,...) afb_req_x2_verbose(req,level,NULL,0,NULL,__VA_ARGS__)
+#endif
+
+#if defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DATA)
+
+# define _AFB_DYNAPI_LOGGING_(llevel,dynapi,...) \
+ do{ \
+ if(_AFB_SYSLOG_MASK_WANT_(dynapi->logmask,llevel)) {\
+ if (llevel <= AFB_VERBOSITY_LEVEL_ERROR) \
+ afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
+ else \
+ afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,NULL,NULL); \
+ } \
+ }while(0)
+# define _AFB_REQUEST_LOGGING_(llevel,request,...) \
+ do{ \
+ if(request->_AFB_SYSLOG_MASK_WANT_(dynapi->logmask,llevel)) \
+ afb_request_verbose(request,llevel,__FILE__,__LINE__,NULL,NULL); \
+ }while(0)
+
+#elif defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS)
+
+# define _AFB_DYNAPI_LOGGING_(llevel,dynapi,...) \
+ do{ \
+ if(_AFB_SYSLOG_MASK_WANT_(dynapi->logmask,llevel)) \
+ afb_dynapi_verbose(dynapi,llevel,NULL,0,NULL,__VA_ARGS__); \
+ }while(0)
+# define _AFB_REQUEST_LOGGING_(llevel,request,...) \
+ do{ \
+ if(request->_AFB_SYSLOG_MASK_WANT_(dynapi->logmask,llevel)) \
+ afb_request_verbose(request,llevel,NULL,0,NULL,__VA_ARGS__); \
+ }while(0)
+
+#else
+
+# define _AFB_DYNAPI_LOGGING_(llevel,dynapi,...) \
+ do{ \
+ if(AFB_SYSLOG_MASK_WANT(dynapi->logmask,llevel)) \
+ afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
+ }while(0)
+# define _AFB_REQUEST_LOGGING_(llevel,request,...) \
+ do{ \
+ if(AFB_SYSLOG_MASK_WANT(request->api->logmask,llevel)) \
+ afb_request_verbose(request,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \
+ }while(0)
+
+#endif
+
+#define AFB_DYNAPI_ERROR(...) _AFB_DYNAPI_LOGGING_(AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__)
+#define AFB_DYNAPI_WARNING(...) _AFB_DYNAPI_LOGGING_(AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__)
+#define AFB_DYNAPI_NOTICE(...) _AFB_DYNAPI_LOGGING_(AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__)
+#define AFB_DYNAPI_INFO(...) _AFB_DYNAPI_LOGGING_(AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__)
+#define AFB_DYNAPI_DEBUG(...) _AFB_DYNAPI_LOGGING_(AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__)
+#define AFB_REQUEST_ERROR(...) _AFB_REQUEST_LOGGING_(AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__)
+#define AFB_REQUEST_WARNING(...) _AFB_REQUEST_LOGGING_(AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__)
+#define AFB_REQUEST_NOTICE(...) _AFB_REQUEST_LOGGING_(AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__)
+#define AFB_REQUEST_INFO(...) _AFB_REQUEST_LOGGING_(AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__)
+#define AFB_REQUEST_DEBUG(...) _AFB_REQUEST_LOGGING_(AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__)
+
+typedef struct afb_eventid afb_eventid;
+typedef struct afb_dynapi afb_dynapi;
+typedef struct afb_request afb_request;
+
+#define _AFB_SYSLOG_LEVEL_EMERGENCY_ AFB_SYSLOG_LEVEL_EMERGENCY
+#define _AFB_SYSLOG_LEVEL_ALERT_ AFB_SYSLOG_LEVEL_ALERT
+#define _AFB_SYSLOG_LEVEL_CRITICAL_ AFB_SYSLOG_LEVEL_CRITICAL
+#define _AFB_SYSLOG_LEVEL_ERROR_ AFB_SYSLOG_LEVEL_ERROR
+#define _AFB_SYSLOG_LEVEL_WARNING_ AFB_SYSLOG_LEVEL_WARNING
+#define _AFB_SYSLOG_LEVEL_NOTICE_ AFB_SYSLOG_LEVEL_NOTICE
+#define _AFB_SYSLOG_LEVEL_INFO_ AFB_SYSLOG_LEVEL_INFO
+#define _AFB_SYSLOG_LEVEL_DEBUG_ AFB_SYSLOG_LEVEL_DEBUG
diff --git a/include/afb/afb-dynapi.h b/include/afb/afb-dynapi.h
deleted file mode 100644
index 2a26915c..00000000
--- a/include/afb/afb-dynapi.h
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author: José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "afb-dynapi-itf.h"
-
-static inline const char *afb_dynapi_name(struct afb_dynapi *dynapi)
-{
- return dynapi->apiname;
-}
-
-static inline void *afb_dynapi_get_userdata(struct afb_dynapi *dynapi)
-{
- return dynapi->userdata;
-}
-
-static inline void afb_dynapi_set_userdata(struct afb_dynapi *dynapi, void *userdata)
-{
- dynapi->userdata = userdata;
-}
-
-/*
- * Send a message described by 'fmt' and following parameters
- * to the journal for the verbosity 'level'.
- *
- * 'file', 'line' and 'func' are indicators of position of the code in source files
- * (see macros __FILE__, __LINE__ and __func__).
- *
- *
- * 'level' is defined by syslog standard:
- * EMERGENCY 0 System is unusable
- * ALERT 1 Action must be taken immediately
- * CRITICAL 2 Critical conditions
- * ERROR 3 Error conditions
- * WARNING 4 Warning conditions
- * NOTICE 5 Normal but significant condition
- * INFO 6 Informational
- * DEBUG 7 Debug-level messages
- */
-static inline void afb_dynapi_verbose(struct afb_dynapi *dynapi, int level, const char *file, int line, const char *func, const char *fmt, ...) __attribute__((format(printf, 6, 7)));
-static inline void afb_dynapi_verbose(struct afb_dynapi *dynapi, int level, const char *file, int line, const char *func, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- dynapi->itf->vverbose(dynapi, level, file, line, func, fmt, args);
- va_end(args);
-}
-static inline void afb_dynapi_vverbose(struct afb_dynapi *dynapi, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
-{
- dynapi->itf->vverbose(dynapi, level, file, line, func, fmt, args);
-}
-
-/*
- * Retrieves the common systemd's event loop of AFB
- */
-static inline struct sd_event *afb_dynapi_get_event_loop(struct afb_dynapi *dynapi)
-{
- return dynapi->itf->get_event_loop(dynapi);
-}
-
-/*
- * Retrieves the common systemd's user/session d-bus of AFB
- */
-static inline struct sd_bus *afb_dynapi_get_user_bus(struct afb_dynapi *dynapi)
-{
- return dynapi->itf->get_user_bus(dynapi);
-}
-
-/*
- * Retrieves the common systemd's system d-bus of AFB
- */
-static inline struct sd_bus *afb_dynapi_get_system_bus(struct afb_dynapi *dynapi)
-{
- return dynapi->itf->get_system_bus(dynapi);
-}
-
-/*
- * Get the root directory file descriptor. This file descriptor can
- * be used with functions 'openat', 'fstatat', ...
- */
-static inline int afb_dynapi_rootdir_get_fd(struct afb_dynapi *dynapi)
-{
- return dynapi->itf->rootdir_get_fd(dynapi);
-}
-
-/*
- * Opens 'filename' within the root directory with 'flags' (see function openat)
- * using the 'locale' definition (example: "jp,en-US") that can be NULL.
- * Returns the file descriptor or -1 in case of error.
- */
-static inline int afb_dynapi_rootdir_open_locale(struct afb_dynapi *dynapi, const char *filename, int flags, const char *locale)
-{
- return dynapi->itf->rootdir_open_locale(dynapi, filename, flags, locale);
-}
-
-/*
- * Queue the job defined by 'callback' and 'argument' for being executed asynchronously
- * in this thread (later) or in an other thread.
- * If 'group' is not NUL, the jobs queued with a same value (as the pointer value 'group')
- * are executed in sequence in the order of there submission.
- * If 'timeout' is not 0, it represent the maximum execution time for the job in seconds.
- * At first, the job is called with 0 as signum and the given argument.
- * The job is executed with the monitoring of its time and some signals like SIGSEGV and
- * SIGFPE. When a such signal is catched, the job is terminated and reexecuted but with
- * signum being the signal number (SIGALRM when timeout expired).
- *
- * Returns 0 in case of success or -1 in case of error.
- */
-static inline int afb_dynapi_queue_job(struct afb_dynapi *dynapi, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
-{
- return dynapi->itf->queue_job(dynapi, callback, argument, group, timeout);
-}
-
-/*
- * Tells that it requires the API of "name" to exist
- * and if 'initialized' is not null to be initialized.
- * Calling this function is only allowed within init.
- * Returns 0 in case of success or -1 in case of error.
- */
-static inline int afb_dynapi_require_api(struct afb_dynapi *dynapi, const char *name, int initialized)
-{
- return dynapi->itf->require_api(dynapi, name, initialized);
-}
-
-/*
- * Set the name of the API to 'name'.
- * Calling this function is only allowed within preinit.
- * Returns 0 in case of success or -1 in case of error.
- */
-static inline int afb_dynapi_rename_api(struct afb_dynapi *dynapi, const char *name)
-{
- return dynapi->itf->rename_api(dynapi, name);
-}
-
-/*
- * Broadcasts widely the event of 'name' with the data 'object'.
- * 'object' can be NULL.
- *
- * For convenience, the function calls 'json_object_put' for 'object'.
- * Thus, in the case where 'object' should remain available after
- * the function returns, the function 'json_object_get' shall be used.
- *
- * Calling this function is only forbidden during preinit.
- *
- * Returns the count of clients that received the event.
- */
-static inline int afb_dynapi_broadcast_event(struct afb_dynapi *dynapi, const char *name, struct json_object *object)
-{
- return dynapi->itf->event_broadcast(dynapi, name, object);
-}
-
-/*
- * Creates an event of 'name' and returns it.
- *
- * Calling this function is only forbidden during preinit.
- *
- * See afb_event_is_valid to check if there is an error.
- */
-static inline struct afb_eventid *afb_dynapi_make_eventid(struct afb_dynapi *dynapi, const char *name)
-{
- return dynapi->itf->eventid_make(dynapi, name);
-}
-
-/**
- * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
- * The result of the call is delivered to the 'callback' function with the 'callback_closure'.
- *
- * For convenience, the function calls 'json_object_put' for 'args'.
- * Thus, in the case where 'args' should remain available after
- * the function returns, the function 'json_object_get' shall be used.
- *
- * The 'callback' receives 3 arguments:
- * 1. 'closure' the user defined closure pointer 'callback_closure',
- * 2. 'status' a status being 0 on success or negative when an error occured,
- * 2. 'result' the resulting data as a JSON object.
- *
- * @param dynapi The dynapi
- * @param api The api name of the method to call
- * @param verb The verb name of the method to call
- * @param args The arguments to pass to the method
- * @param callback The to call on completion
- * @param callback_closure The closure to pass to the callback
- *
- * @see also 'afb_req_subcall'
- */
-static inline void afb_dynapi_call(
- struct afb_dynapi *dynapi,
- const char *api,
- const char *verb,
- struct json_object *args,
- void (*callback)(void *closure, int status, struct json_object *result, struct afb_dynapi *dynapi),
- void *callback_closure)
-{
- dynapi->itf->call(dynapi, api, verb, args, callback, callback_closure);
-}
-
-/**
- * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
- * 'result' will receive the response.
- *
- * For convenience, the function calls 'json_object_put' for 'args'.
- * Thus, in the case where 'args' should remain available after
- * the function returns, the function 'json_object_get' shall be used.
- *
- * @param dynapi The dynapi
- * @param api The api name of the method to call
- * @param verb The verb name of the method to call
- * @param args The arguments to pass to the method
- * @param result Where to store the result - should call json_object_put on it -
- *
- * @returns 0 in case of success or a negative value in case of error.
- *
- * @see also 'afb_req_subcall'
- */
-static inline int afb_dynapi_call_sync(
- struct afb_dynapi *dynapi,
- const char *api,
- const char *verb,
- struct json_object *args,
- struct json_object **result)
-{
- return dynapi->itf->call_sync(dynapi, api, verb, args, result);
-}
-
-
-static inline int afb_dynapi_new_api(
- struct afb_dynapi *dynapi,
- const char *api,
- const char *info,
- int noconcurrency,
- int (*preinit)(void*, struct afb_dynapi *),
- void *closure)
-{
- return dynapi->itf->api_new_api(dynapi, api, info, noconcurrency, preinit, closure);
-}
-
-static inline int afb_dynapi_set_verbs_v2(
- struct afb_dynapi *dynapi,
- const struct afb_verb_v2 *verbs)
-{
- return dynapi->itf->api_set_verbs_v2(dynapi, verbs);
-}
-
-static inline int afb_dynapi_add_verb(
- 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)
-{
- return dynapi->itf->api_add_verb(dynapi, verb, info, callback, vcbdata, auth, session);
-}
-
-
-static inline int afb_dynapi_sub_verb(
- struct afb_dynapi *dynapi,
- const char *verb)
-{
- return dynapi->itf->api_sub_verb(dynapi, verb);
-}
-
-
-static inline int afb_dynapi_on_event(
- struct afb_dynapi *dynapi,
- void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object))
-{
- return dynapi->itf->api_set_on_event(dynapi, onevent);
-}
-
-
-static inline int afb_dynapi_on_init(
- struct afb_dynapi *dynapi,
- int (*oninit)(struct afb_dynapi *dynapi))
-{
- return dynapi->itf->api_set_on_init(dynapi, oninit);
-}
-
-
-static inline void afb_dynapi_seal(
- struct afb_dynapi *dynapi)
-{
- dynapi->itf->api_seal(dynapi);
-}
-
-
diff --git a/include/afb/afb-event-x1-itf.h b/include/afb/afb-event-x1-itf.h
new file mode 100644
index 00000000..afd033b8
--- /dev/null
+++ b/include/afb/afb-event-x1-itf.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "afb-event-x2-itf.h"
+
+/**
+ * @deprecated use bindings version 3
+ *
+ * Describes the request of afb-daemon for bindings
+ */
+struct afb_event_x1
+{
+ const struct afb_event_x2_itf *itf; /**< the interface to use */
+ struct afb_event_x2 *closure; /**< the closure argument for functions of 'itf' */
+};
+
diff --git a/include/afb/afb-event.h b/include/afb/afb-event-x1.h
index 0876d8cf..1fc7696f 100644
--- a/include/afb/afb-event.h
+++ b/include/afb/afb-event-x1.h
@@ -17,36 +17,33 @@
#pragma once
-#include "afb-eventid-itf.h"
+#include "afb-event-x1-itf.h"
-/*
- * Describes the request of afb-daemon for bindings
- */
-struct afb_event
-{
- const struct afb_eventid_itf *itf; /* the interface to use */
- struct afb_eventid *closure; /* the closure argument for functions of 'itf' */
-};
-
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Converts the 'event' to an afb_eventid.
*/
-static inline struct afb_eventid *afb_event_to_eventid(struct afb_event event)
+static inline struct afb_event_x2 *afb_event_x1_to_event_x2(struct afb_event_x1 event)
{
return event.closure;
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Checks wether the 'event' is valid or not.
*
* Returns 0 if not valid or 1 if valid.
*/
-static inline int afb_event_is_valid(struct afb_event event)
+static inline int afb_event_x1_is_valid(struct afb_event_x1 event)
{
return !!event.itf;
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Broadcasts widely the 'event' with the data 'object'.
* 'object' can be NULL.
*
@@ -56,12 +53,14 @@ static inline int afb_event_is_valid(struct afb_event event)
*
* Returns the count of clients that received the event.
*/
-static inline int afb_event_broadcast(struct afb_event event, struct json_object *object)
+static inline int afb_event_x1_broadcast(struct afb_event_x1 event, struct json_object *object)
{
return event.itf->broadcast(event.closure, object);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Pushes the 'event' with the data 'object' to its observers.
* 'object' can be NULL.
*
@@ -71,35 +70,41 @@ static inline int afb_event_broadcast(struct afb_event event, struct json_object
*
* Returns the count of clients that received the event.
*/
-static inline int afb_event_push(struct afb_event event, struct json_object *object)
+static inline int afb_event_x1_push(struct afb_event_x1 event, struct json_object *object)
{
return event.itf->push(event.closure, object);
}
/* OBSOLETE */
-#define afb_event_drop afb_event_unref
+#define afb_event_x1_drop afb_event_x1_unref
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Gets the name associated to the 'event'.
*/
-static inline const char *afb_event_name(struct afb_event event)
+static inline const char *afb_event_x1_name(struct afb_event_x1 event)
{
return event.itf->name(event.closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Decreases the count of reference to 'event' and
* destroys the event when the reference count falls to zero.
*/
-static inline void afb_event_unref(struct afb_event event)
+static inline void afb_event_x1_unref(struct afb_event_x1 event)
{
event.itf->unref(event.closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Increases the count of reference to 'event'
*/
-static inline void afb_event_addref(struct afb_event event)
+static inline void afb_event_x1_addref(struct afb_event_x1 event)
{
event.itf->addref(event.closure);
}
diff --git a/include/afb/afb-eventid-itf.h b/include/afb/afb-event-x2-itf.h
index 0af36581..ecc42c79 100644
--- a/include/afb/afb-eventid-itf.h
+++ b/include/afb/afb-event-x2-itf.h
@@ -17,31 +17,41 @@
#pragma once
-struct json_object;
-struct afb_eventid;
-struct afb_eventid_itf;
+struct afb_event_x2;
+struct afb_event_x2_itf;
-/*
- * Interface for handling eventid.
- * It records the functions to be called for the eventid.
+/**
+ * Interface for handling event_x2.
+ *
+ * It records the functions to be called for the event_x2.
+ *
* Don't use this structure directly.
*/
-struct afb_eventid_itf
+struct afb_event_x2_itf
{
/* CAUTION: respect the order, add at the end */
- int (*broadcast)(struct afb_eventid *eventid, struct json_object *obj);
- int (*push)(struct afb_eventid *eventid, struct json_object *obj);
- void (*unref)(struct afb_eventid *eventid); /* aka drop */
- const char *(*name)(struct afb_eventid *eventid);
- struct afb_eventid *(*addref)(struct afb_eventid *eventid);
+ /** broadcast the event */
+ int (*broadcast)(struct afb_event_x2 *event, struct json_object *obj);
+
+ /** push the event to its subscribers */
+ int (*push)(struct afb_event_x2 *event, struct json_object *obj);
+
+ /** unreference the event */
+ void (*unref)(struct afb_event_x2 *event); /* aka drop */
+
+ /** get the event name */
+ const char *(*name)(struct afb_event_x2 *event);
+
+ /** rereference the event */
+ struct afb_event_x2 *(*addref)(struct afb_event_x2 *event);
};
-/*
- * Describes the eventid
+/**
+ * Describes the event_x2
*/
-struct afb_eventid
+struct afb_event_x2
{
- const struct afb_eventid_itf *itf; /* the interface to use */
+ const struct afb_event_x2_itf *itf; /**< the interface functions to use */
};
diff --git a/include/afb/afb-event-x2.h b/include/afb/afb-event-x2.h
new file mode 100644
index 00000000..f0a27877
--- /dev/null
+++ b/include/afb/afb-event-x2.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "afb-event-x2-itf.h"
+
+/**
+ * Checks whether the 'event' is valid or not.
+ *
+ * @param event the event to check
+ *
+ * @return 0 if not valid or 1 if valid.
+ */
+static inline int afb_event_x2_is_valid(struct afb_event_x2 *event)
+{
+ return !!event;
+}
+
+/**
+ * Broadcasts widely an event of 'event' with the data 'object'.
+ * 'object' can be NULL.
+ *
+ * For convenience, the function calls 'json_object_put' for 'object'.
+ * Thus, in the case where 'object' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * @param event the event to broadcast
+ * @param object the companion object to associate to the broadcasted event (can be NULL)
+ *
+ * @return the count of clients that received the event.
+ */
+static inline int afb_event_x2_broadcast(
+ struct afb_event_x2 *event,
+ struct json_object *object)
+{
+ return event->itf->broadcast(event, object);
+}
+
+/**
+ * Pushes an event of 'event' with the data 'object' to its observers.
+ * 'object' can be NULL.
+ *
+ * For convenience, the function calls 'json_object_put' for 'object'.
+ * Thus, in the case where 'object' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * @param event the event to push
+ * @param object the companion object to associate to the pushed event (can be NULL)
+ *
+ * @return the count of clients that received the event.
+ */
+static inline int afb_event_x2_push(
+ struct afb_event_x2 *event,
+ struct json_object *object)
+{
+ return event->itf->push(event, object);
+}
+
+/**
+ * Gets the name associated to 'event'.
+ *
+ * @param event the event whose name is requested
+ *
+ * @return the name of the event
+ *
+ * The returned name can be used until call to 'afb_event_x2_unref'.
+ * It shouldn't be freed.
+ */
+static inline const char *afb_event_x2_name(struct afb_event_x2 *event)
+{
+ return event->itf->name(event);
+}
+
+/**
+ * Decrease the count of references to 'event'.
+ * Call this function when the evenid is no more used.
+ * It destroys the event_x2 when the reference count falls to zero.
+ *
+ * @param event the event
+ */
+static inline void afb_event_x2_unref(struct afb_event_x2 *event)
+{
+ event->itf->unref(event);
+}
+
+/**
+ * Increases the count of references to 'event'
+ *
+ * @param event the event
+ *
+ * @return the event
+ */
+static inline struct afb_event_x2 *afb_event_x2_addref(
+ struct afb_event_x2 *event)
+{
+ return event->itf->addref(event);
+}
+
diff --git a/include/afb/afb-eventid.h b/include/afb/afb-eventid.h
deleted file mode 100644
index 69d82a75..00000000
--- a/include/afb/afb-eventid.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author: José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "afb-eventid-itf.h"
-
-/*
- * Broadcasts widely an event of 'eventid' with the data 'object'.
- * 'object' can be NULL.
- *
- * For convenience, the function calls 'json_object_put' for 'object'.
- * Thus, in the case where 'object' should remain available after
- * the function returns, the function 'json_object_get' shall be used.
- *
- * Returns the count of clients that received the event.
- */
-static inline int afb_eventid_broadcast(
- struct afb_eventid *eventid,
- struct json_object *object)
-{
- return eventid->itf->broadcast(eventid, object);
-}
-
-/*
- * Pushes an event of 'eventid' with the data 'object' to its observers.
- * 'object' can be NULL.
- *
- * For convenience, the function calls 'json_object_put' for 'object'.
- * Thus, in the case where 'object' should remain available after
- * the function returns, the function 'json_object_get' shall be used.
- *
- * Returns the count of clients that received the event.
- */
-static inline int afb_eventid_push(
- struct afb_eventid *eventid,
- struct json_object *object)
-{
- return eventid->itf->push(eventid, object);
-}
-
-/*
- * Gets the name associated to 'eventid'.
- * The returned name can be used until call to 'afb_eventid_unref'.
- */
-static inline const char *afb_eventid_name(struct afb_eventid *eventid)
-{
- return eventid->itf->name(eventid);
-}
-
-/*
- * Decrease the count of references to 'eventid'.
- * Call this function when the evenid is no more used.
- * It destroys the eventid when the reference count falls to zero.
- */
-static inline void afb_eventid_unref(struct afb_eventid *eventid)
-{
- eventid->itf->unref(eventid);
-}
-
-/*
- * Increases the count of references to 'eventid'
- */
-static inline struct afb_eventid *afb_eventid_addref(
- struct afb_eventid *eventid)
-{
- return eventid->itf->addref(eventid);
-}
-
diff --git a/include/afb/afb-req-v1.h b/include/afb/afb-req-v1.h
index f1bcd47d..40fb3b85 100644
--- a/include/afb/afb-req-v1.h
+++ b/include/afb/afb-req-v1.h
@@ -18,34 +18,38 @@
#pragma once
#include <stdlib.h>
-#include "afb-req.h"
+#include "afb-req-x1.h"
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Stores 'req' on heap for asynchrnous use.
* Returns a pointer to the stored 'req' or NULL on memory depletion.
* The count of reference to 'req' is incremented on success
* (see afb_req_addref).
*/
-static inline struct afb_req *afb_req_store_v1(struct afb_req req)
+static inline struct afb_req_x1 *afb_req_x1_store_v1(struct afb_req_x1 req)
{
- struct afb_req *result = (struct afb_req*)malloc(sizeof *result);
+ struct afb_req_x1 *result = (struct afb_req_x1*)malloc(sizeof *result);
if (result) {
*result = req;
- afb_req_addref(req);
+ afb_req_x1_addref(req);
}
return result;
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Retrieves the afb_req stored at 'req' and frees the memory.
* Returns the stored request.
* The count of reference is UNCHANGED, thus, normally, the
* function 'afb_req_unref' should be called on the result
* after that the asynchronous reply if sent.
*/
-static inline struct afb_req afb_req_unstore_v1(struct afb_req *req)
+static inline struct afb_req_x1 afb_req_unstore_x1_v1(struct afb_req_x1 *req)
{
- struct afb_req result = *req;
+ struct afb_req_x1 result = *req;
free(req);
return result;
}
diff --git a/include/afb/afb-req-v2.h b/include/afb/afb-req-v2.h
index 34cbbdaa..f7901908 100644
--- a/include/afb/afb-req-v2.h
+++ b/include/afb/afb-req-v2.h
@@ -17,16 +17,18 @@
#pragma once
-#include "afb-req.h"
+#include "afb-req-x1.h"
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Stores 'req' on heap for asynchrnous use.
* Returns a handler to the stored 'req' or NULL on memory depletion.
* The count of reference to 'req' is incremented on success
* (see afb_req_addref).
*/
-static inline struct afb_stored_req *afb_req_store_v2(struct afb_req req)
+static inline struct afb_stored_req *afb_req_x1_store_v2(struct afb_req_x1 req)
{
- return req.itf->store(req.closure);
+ return req.itf->legacy_store_req(req.closure);
}
diff --git a/include/afb/afb-req-itf.h b/include/afb/afb-req-x1-itf.h
index 2dd42d2e..dce936d1 100644
--- a/include/afb/afb-req-itf.h
+++ b/include/afb/afb-req-x1-itf.h
@@ -17,14 +17,16 @@
#pragma once
-#include "afb-request-itf.h"
+#include "afb-req-x2-itf.h"
-/*
- * Describes the request by bindings from afb-daemon
+/**
+ * @deprecated use bindings version 3
+ *
+ * Describes the request to bindings version 1 and 2
*/
-struct afb_req
+struct afb_req_x1
{
- const struct afb_request_itf *itf; /* the interface to use */
- struct afb_request *closure; /* the closure argument for functions of 'itf' */
+ const struct afb_req_x2_itf *itf; /**< the interface to use */
+ struct afb_req_x2 *closure; /**< the closure argument for functions of 'itf' */
};
diff --git a/include/afb/afb-req.h b/include/afb/afb-req-x1.h
index 77153ef1..cea17d0c 100644
--- a/include/afb/afb-req.h
+++ b/include/afb/afb-req-x1.h
@@ -17,28 +17,34 @@
#pragma once
-#include "afb-req-itf.h"
-#include "afb-event.h"
+#include "afb-req-x1-itf.h"
+#include "afb-event-x1.h"
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Converts the 'req' to an afb_request.
*/
-static inline struct afb_request *afb_req_to_request(struct afb_req req)
+static inline struct afb_req_x2 *afb_req_x1_to_req_x2(struct afb_req_x1 req)
{
return req.closure;
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Checks whether the request 'req' is valid or not.
*
* Returns 0 if not valid or 1 if valid.
*/
-static inline int afb_req_is_valid(struct afb_req req)
+static inline int afb_req_x1_is_valid(struct afb_req_x1 req)
{
return !!req.itf;
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Gets from the request 'req' the argument of 'name'.
* Returns a PLAIN structure of type 'struct afb_arg'.
* When the argument of 'name' is not found, all fields of result are set to NULL.
@@ -50,157 +56,141 @@ static inline int afb_req_is_valid(struct afb_req req)
* an HTTP POST of Content-Type "application/json". In that case, the
* argument of name "" receives the value of the body of the HTTP request.
*/
-static inline struct afb_arg afb_req_get(struct afb_req req, const char *name)
+static inline struct afb_arg afb_req_x1_get(struct afb_req_x1 req, const char *name)
{
return req.itf->get(req.closure, name);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Gets from the request 'req' the string value of the argument of 'name'.
* Returns NULL if when there is no argument of 'name'.
* Returns the value of the argument of 'name' otherwise.
*
* Shortcut for: afb_req_get(req, name).value
*/
-static inline const char *afb_req_value(struct afb_req req, const char *name)
+static inline const char *afb_req_x1_value(struct afb_req_x1 req, const char *name)
{
- return afb_req_get(req, name).value;
+ return afb_req_x1_get(req, name).value;
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Gets from the request 'req' the path for file attached to the argument of 'name'.
* Returns NULL if when there is no argument of 'name' or when there is no file.
* Returns the path of the argument of 'name' otherwise.
*
* Shortcut for: afb_req_get(req, name).path
*/
-static inline const char *afb_req_path(struct afb_req req, const char *name)
+static inline const char *afb_req_x1_path(struct afb_req_x1 req, const char *name)
{
- return afb_req_get(req, name).path;
+ return afb_req_x1_get(req, name).path;
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Gets from the request 'req' the json object hashing the arguments.
* The returned object must not be released using 'json_object_put'.
*/
-static inline struct json_object *afb_req_json(struct afb_req req)
+static inline struct json_object *afb_req_x1_json(struct afb_req_x1 req)
{
return req.itf->json(req.closure);
}
-/*
- * Sends a reply of kind success to the request 'req'.
- * The status of the reply is automatically set to "success".
+/**
+ * @deprecated use bindings version 3
+ *
+ * Sends a reply to the request 'req'.
+ * The status of the reply is set to 'error' (that must be NULL on success).
* Its send the object 'obj' (can be NULL) with an
- * informationnal comment 'info (can also be NULL).
+ * informational comment 'info (can also be NULL).
*
* For convenience, the function calls 'json_object_put' for 'obj'.
* Thus, in the case where 'obj' should remain available after
* the function returns, the function 'json_object_get' shall be used.
*/
-static inline void afb_req_success(struct afb_req req, struct json_object *obj, const char *info)
+static inline void afb_req_x1_reply(struct afb_req_x1 req, struct json_object *obj, const char *error, const char *info)
{
- req.itf->success(req.closure, obj, info);
+ req.itf->reply(req.closure, obj, error, info);
}
-/*
- * Same as 'afb_req_success' but the 'info' is a formatting
+/**
+ * @deprecated use bindings version 3
+ *
+ * Same as 'afb_req_x1_reply' but the 'info' is a formatting
* string followed by arguments.
*
* For convenience, the function calls 'json_object_put' for 'obj'.
* Thus, in the case where 'obj' should remain available after
* the function returns, the function 'json_object_get' shall be used.
*/
-static inline void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...) __attribute__((format(printf, 3, 4)));
-static inline void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...)
+static inline void afb_req_x1_reply_f(struct afb_req_x1 req, struct json_object *obj, const char *error, const char *info, ...) __attribute__((format(printf, 4, 5)));
+static inline void afb_req_x1_reply_f(struct afb_req_x1 req, struct json_object *obj, const char *error, const char *info, ...)
{
va_list args;
va_start(args, info);
- req.itf->vsuccess(req.closure, obj, info, args);
+ req.itf->vreply(req.closure, obj, error, info, args);
va_end(args);
}
-/*
- * Same as 'afb_req_success_f' but the arguments to the format 'info'
+/**
+ * @deprecated use bindings version 3
+ *
+ * Same as 'afb_req_x1_reply_f' but the arguments to the format 'info'
* are given as a variable argument list instance.
*
* For convenience, the function calls 'json_object_put' for 'obj'.
* Thus, in the case where 'obj' should remain available after
* the function returns, the function 'json_object_get' shall be used.
*/
-static inline void afb_req_success_v(struct afb_req req, struct json_object *obj, const char *info, va_list args)
+static inline void afb_req_x1_reply_v(struct afb_req_x1 req, struct json_object *obj, const char *error, const char *info, va_list args)
{
- req.itf->vsuccess(req.closure, obj, info, args);
+ req.itf->vreply(req.closure, obj, error, info, args);
}
-/*
- * Sends a reply of kind failure to the request 'req'.
- * The status of the reply is set to 'status' and an
- * informationnal comment 'info' (can also be NULL) can be added.
+/**
+ * @deprecated use bindings version 3
*
- * Note that calling afb_req_fail("success", info) is equivalent
- * to call afb_req_success(NULL, info). Thus even if possible it
- * is strongly recommanded to NEVER use "success" for status.
- */
-static inline void afb_req_fail(struct afb_req req, const char *status, const char *info)
-{
- req.itf->fail(req.closure, status, info);
-}
-
-/*
- * Same as 'afb_req_fail' but the 'info' is a formatting
- * string followed by arguments.
- */
-static inline void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...) __attribute__((format(printf, 3, 4)));
-static inline void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...)
-{
- va_list args;
- va_start(args, info);
- req.itf->vfail(req.closure, status, info, args);
- va_end(args);
-}
-
-/*
- * Same as 'afb_req_fail_f' but the arguments to the format 'info'
- * are given as a variable argument list instance.
- */
-static inline void afb_req_fail_v(struct afb_req req, const char *status, const char *info, va_list args)
-{
- req.itf->vfail(req.closure, status, info, args);
-}
-
-/*
* Gets the pointer stored by the binding for the session of 'req'.
* When the binding has not yet recorded a pointer, NULL is returned.
*/
-static inline void *afb_req_context_get(struct afb_req req)
+static inline void *afb_req_x1_context_get(struct afb_req_x1 req)
{
- return req.itf->context_get(req.closure);
+ return req.itf->context_make(req.closure, 0, 0, 0, 0);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Stores for the binding the pointer 'context' to the session of 'req'.
* The function 'free_context' will be called when the session is closed
* or if binding stores an other pointer.
*/
-static inline void afb_req_context_set(struct afb_req req, void *context, void (*free_context)(void*))
+static inline void afb_req_x1_context_set(struct afb_req_x1 req, void *context, void (*free_context)(void*))
{
- req.itf->context_set(req.closure, context, free_context);
+ req.itf->context_make(req.closure, 1, 0, free_context, context);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Gets the pointer stored by the binding for the session of 'req'.
* If the stored pointer is NULL, indicating that no pointer was
* already stored, afb_req_context creates a new context by calling
* the function 'create_context' and stores it with the freeing function
* 'free_context'.
*/
-static inline void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*))
+static inline void *afb_req_x1_context(struct afb_req_x1 req, void *(*create_context)(), void (*free_context)(void*))
{
return req.itf->context_make(req.closure, 0, (void *(*)(void*))(void*)create_context, free_context, 0);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Gets the pointer stored by the binding for the session of 'request'.
* If no previous pointer is stored or if 'replace' is not zero, a new value
* is generated using the function 'create_context' called with the 'closure'.
@@ -210,83 +200,99 @@ static inline void *afb_req_context(struct afb_req req, void *(*create_context)(
* it is not more used.
* This function is atomic: it ensures that 2 threads will not race together.
*/
-static inline void *afb_req_context_make(struct afb_req req, int replace, void *(*create_context)(void *closure), void (*free_context)(void*), void *closure)
+static inline void *afb_req_x1_context_make(struct afb_req_x1 req, int replace, void *(*create_context)(void *closure), void (*free_context)(void*), void *closure)
{
return req.itf->context_make(req.closure, replace, create_context, free_context, closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Frees the pointer stored by the binding for the session of 'req'
* and sets it to NULL.
*
* Shortcut for: afb_req_context_set(req, NULL, NULL)
*/
-static inline void afb_req_context_clear(struct afb_req req)
+static inline void afb_req_x1_context_clear(struct afb_req_x1 req)
{
- afb_req_context_set(req, 0, 0);
+ req.itf->context_make(req.closure, 1, 0, 0, 0);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Adds one to the count of references of 'req'.
* This function MUST be called by asynchronous implementations
* of verbs if no reply was sent before returning.
*/
-static inline void afb_req_addref(struct afb_req req)
+static inline void afb_req_x1_addref(struct afb_req_x1 req)
{
req.itf->addref(req.closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Substracts one to the count of references of 'req'.
* This function MUST be called by asynchronous implementations
* of verbs after sending the asynchronous reply.
*/
-static inline void afb_req_unref(struct afb_req req)
+static inline void afb_req_x1_unref(struct afb_req_x1 req)
{
req.itf->unref(req.closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Closes the session associated with 'req'
* and delete all associated contexts.
*/
-static inline void afb_req_session_close(struct afb_req req)
+static inline void afb_req_x1_session_close(struct afb_req_x1 req)
{
req.itf->session_close(req.closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Sets the level of assurance of the session of 'req'
* to 'level'. The effect of this function is subject of
* security policies.
* Returns 1 on success or 0 if failed.
*/
-static inline int afb_req_session_set_LOA(struct afb_req req, unsigned level)
+static inline int afb_req_x1_session_set_LOA(struct afb_req_x1 req, unsigned level)
{
- return req.itf->session_set_LOA(req.closure, level);
+ return 1 + req.itf->session_set_LOA(req.closure, level);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Establishes for the client link identified by 'req' a subscription
* to the 'event'.
* Returns 0 in case of successful subscription or -1 in case of error.
*/
-static inline int afb_req_subscribe(struct afb_req req, struct afb_event event)
+static inline int afb_req_x1_subscribe(struct afb_req_x1 req, struct afb_event_x1 event)
{
- return req.itf->subscribe(req.closure, event);
+ return req.itf->legacy_subscribe_event_x1(req.closure, event);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Revokes the subscription established to the 'event' for the client
* link identified by 'req'.
* Returns 0 in case of successful subscription or -1 in case of error.
*/
-static inline int afb_req_unsubscribe(struct afb_req req, struct afb_event event)
+static inline int afb_req_x1_unsubscribe(struct afb_req_x1 req, struct afb_event_x1 event)
{
- return req.itf->unsubscribe(req.closure, event);
+ return req.itf->legacy_unsubscribe_event_x1(req.closure, event);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Makes a call to the method of name 'api' / 'verb' with the object 'args'.
* This call is made in the context of the request 'req'.
* On completion, the function 'callback' is invoked with the
@@ -303,12 +309,14 @@ static inline int afb_req_unsubscribe(struct afb_req req, struct afb_event event
* - 'afb_req_subcall_req' that is convenient to keep request alive automatically.
* - 'afb_req_subcall_sync' the synchronous version
*/
-static inline void afb_req_subcall(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result), void *closure)
+static inline void afb_req_x1_subcall(struct afb_req_x1 req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result), void *closure)
{
- req.itf->subcall(req.closure, api, verb, args, callback, closure);
+ req.itf->legacy_subcall(req.closure, api, verb, args, callback, closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Makes a call to the method of name 'api' / 'verb' with the object 'args'.
* This call is made in the context of the request 'req'.
* On completion, the function 'callback' is invoked with the
@@ -326,12 +334,14 @@ static inline void afb_req_subcall(struct afb_req req, const char *api, const ch
* - 'afb_req_subcall' that doesn't keep request alive automatically.
* - 'afb_req_subcall_sync' the synchronous version
*/
-static inline void afb_req_subcall_req(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req req), void *closure)
+static inline void afb_req_x1_subcall_req(struct afb_req_x1 req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req_x1 req), void *closure)
{
- req.itf->subcall_req(req.closure, api, verb, args, callback, closure);
+ req.itf->legacy_subcall_req(req.closure, api, verb, args, callback, closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Makes a call to the method of name 'api' / 'verb' with the object 'args'.
* This call is made in the context of the request 'req'.
* This call is synchronous, it waits untill completion of the request.
@@ -347,12 +357,14 @@ static inline void afb_req_subcall_req(struct afb_req req, const char *api, cons
* - 'afb_req_subcall_req' that is convenient to keep request alive automatically.
* - 'afb_req_subcall' that doesn't keep request alive automatically.
*/
-static inline int afb_req_subcall_sync(struct afb_req req, const char *api, const char *verb, struct json_object *args, struct json_object **result)
+static inline int afb_req_x1_subcall_sync(struct afb_req_x1 req, const char *api, const char *verb, struct json_object *args, struct json_object **result)
{
- return req.itf->subcallsync(req.closure, api, verb, args, result);
+ return req.itf->legacy_subcallsync(req.closure, api, verb, args, result);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Send associated to 'req' a message described by 'fmt' and following parameters
* to the journal for the verbosity 'level'.
*
@@ -369,8 +381,8 @@ static inline int afb_req_subcall_sync(struct afb_req req, const char *api, cons
* INFO 6 Informational
* DEBUG 7 Debug-level messages
*/
-static inline void afb_req_verbose(struct afb_req req, int level, const char *file, int line, const char * func, const char *fmt, ...) __attribute__((format(printf, 6, 7)));
-static inline void afb_req_verbose(struct afb_req req, int level, const char *file, int line, const char * func, const char *fmt, ...)
+static inline void afb_req_x1_verbose(struct afb_req_x1 req, int level, const char *file, int line, const char * func, const char *fmt, ...) __attribute__((format(printf, 6, 7)));
+static inline void afb_req_x1_verbose(struct afb_req_x1 req, int level, const char *file, int line, const char * func, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
@@ -378,25 +390,22 @@ static inline void afb_req_verbose(struct afb_req req, int level, const char *fi
va_end(args);
}
-/* macro for setting file, line and function automatically */
-# if !defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS)
-#define AFB_REQ_VERBOSE(req,level,...) afb_req_verbose(req,level,__FILE__,__LINE__,__func__,__VA_ARGS__)
-#else
-#define AFB_REQ_VERBOSE(req,level,...) afb_req_verbose(req,level,NULL,0,NULL,__VA_ARGS__)
-#endif
-
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Check whether the 'permission' is granted or not to the client
* identified by 'req'.
*
* Returns 1 if the permission is granted or 0 otherwise.
*/
-static inline int afb_req_has_permission(struct afb_req req, const char *permission)
+static inline int afb_req_x1_has_permission(struct afb_req_x1 req, const char *permission)
{
return req.itf->has_permission(req.closure, permission);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Get the application identifier of the client application for the
* request 'req'.
*
@@ -405,19 +414,40 @@ static inline int afb_req_has_permission(struct afb_req req, const char *permiss
*
* The returned value if not NULL must be freed by the caller
*/
-static inline char *afb_req_get_application_id(struct afb_req req)
+static inline char *afb_req_x1_get_application_id(struct afb_req_x1 req)
{
return req.itf->get_application_id(req.closure);
}
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Get the user identifier (UID) of the client application for the
* request 'req'.
*
* Returns -1 when the application can not be identified.
*/
-static inline int afb_req_get_uid(struct afb_req req)
+static inline int afb_req_x1_get_uid(struct afb_req_x1 req)
{
return req.itf->get_uid(req.closure);
}
+/**
+ * @deprecated use bindings version 3
+ *
+ * Get informations about the client of the
+ * request 'req'.
+ *
+ * Returns an object with client informations:
+ * {
+ * "pid": int, "uid": int, "gid": int,
+ * "smack": string, "appid": string,
+ * "uuid": string, "LOA": int
+ * }
+ */
+static inline struct json_object *afb_req_x1_get_client_info(struct afb_req_x1 req)
+{
+ return req.itf->get_client_info(req.closure);
+}
+
+
diff --git a/include/afb/afb-req-x2-itf.h b/include/afb/afb-req-x2-itf.h
new file mode 100644
index 00000000..9de7a214
--- /dev/null
+++ b/include/afb/afb-req-x2-itf.h
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/* defined here */
+struct afb_req_x2;
+struct afb_req_x2_itf;
+
+/* referenced here */
+#include "afb-arg.h"
+struct afb_req_x1;
+struct afb_event_x1;
+struct afb_event_x2;
+struct afb_api_x3;
+struct afb_stored_req;
+
+/**
+ * structure for the request
+ */
+struct afb_req_x2
+{
+ /**
+ * interface for the request
+ */
+ const struct afb_req_x2_itf *itf;
+
+ /**
+ * current api (if any)
+ */
+ struct afb_api_x3 *api;
+
+ /**
+ * closure associated with the callback processing the verb of the request
+ * as given at its declaration
+ */
+ void *vcbdata;
+
+ /**
+ * the name of the called api
+ */
+ const char *called_api;
+
+ /**
+ * the name of the called verb
+ */
+ const char *called_verb;
+};
+
+/**
+ * subcall modes
+ *
+ * When making subcalls, it is now possible to explicitely set the subcall
+ * mode to a combination of the following mode using binary OR.
+ *
+ * In particular, the following combination of modes are to be known:
+ *
+ * - for **subcall** having a similar behaviour to the subcalls of bindings
+ * version 1 and 2: afb_req_x2_subcall_pass_events|afb_req_x2_subcall_on_behalf
+ * - for **subcall** having the behaviour of the **call**:
+ * afb_req_x2_subcall_catch_events|afb_req_x2_subcall_api_session
+ *
+ * Be aware that if none of mode afb_req_x2_subcall_catch_events or
+ * afb_req_x2_subcall_pass_events is set, subscrption to events will be ignored.
+ */
+enum afb_req_x2_subcall_flags
+{
+ /**
+ * the calling API wants to receive the events from subscription
+ */
+ afb_req_x2_subcall_catch_events = 1,
+
+ /**
+ * the original request will receive the events from subscription
+ */
+ afb_req_x2_subcall_pass_events = 2,
+
+ /**
+ * the calling API wants to use the credentials of the original request
+ */
+ afb_req_x2_subcall_on_behalf = 4,
+
+ /**
+ * the calling API wants to use its session instead of the one of the
+ * original request
+ */
+ afb_req_x2_subcall_api_session = 8,
+};
+
+/**
+ * Interface for handling requests.
+ *
+ * It records the functions to be called for the request.
+ * Don't use this structure directly, Use the helper functions instead.
+ */
+struct afb_req_x2_itf
+{
+ /* CAUTION: respect the order, add at the end */
+
+ /** get the json */
+ struct json_object *(*json)(
+ struct afb_req_x2 *req);
+
+ /** get an argument */
+ struct afb_arg (*get)(
+ struct afb_req_x2 *req,
+ const char *name);
+
+ /** reply a success @deprecated use @ref reply */
+ void (*legacy_success)(
+ struct afb_req_x2 *req,
+ struct json_object *obj,
+ const char *info);
+
+ /** reply a failure @deprecated use @ref reply */
+ void (*legacy_fail)(
+ struct afb_req_x2 *req,
+ const char *status,
+ const char *info);
+
+ /** reply a success @deprecated use @ref vreply */
+ void (*legacy_vsuccess)(
+ struct afb_req_x2 *req,
+ struct json_object *obj,
+ const char *fmt,
+ va_list args);
+
+ /** reply a failure @deprecated use @ref vreply */
+ void (*legacy_vfail)(
+ struct afb_req_x2 *req,
+ const char *status,
+ const char *fmt,
+ va_list args);
+
+ /** get a client context @deprecated use @ref context_make */
+ void *(*legacy_context_get)(
+ struct afb_req_x2 *req);
+
+ /** set a client context @deprecated use @ref context_make */
+ void (*legacy_context_set)(
+ struct afb_req_x2 *req,
+ void *value,
+ void (*free_value)(void*));
+
+ /** increase reference count of the request */
+ struct afb_req_x2 *(*addref)(
+ struct afb_req_x2 *req);
+
+ /** decrease reference count of the request */
+ void (*unref)(
+ struct afb_req_x2 *req);
+
+ /** close the client session related to the api of the request */
+ void (*session_close)(
+ struct afb_req_x2 *req);
+
+ /** set the levele of assurancy related to the api of the request */
+ int (*session_set_LOA)(
+ struct afb_req_x2 *req,
+ unsigned level);
+
+ /** make subscription of the client of the request to the event @deprecated use @ref subscribe_event_x2 */
+ int (*legacy_subscribe_event_x1)(
+ struct afb_req_x2 *req,
+ struct afb_event_x1 event);
+
+ /** remove subscription of the client of the request to the event @deprecated use @ref unsubscribe_event_x2 */
+ int (*legacy_unsubscribe_event_x1)(
+ struct afb_req_x2 *req,
+ struct afb_event_x1 event);
+
+ /** asynchronous subcall @deprecated use @ref subcall */
+ void (*legacy_subcall)(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *cb_closure);
+
+ /** synchronous subcall @deprecated use @ref subcallsync */
+ int (*legacy_subcallsync)(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result);
+
+ /** log a message for the request */
+ void (*vverbose)(
+ struct afb_req_x2 *req,
+ int level,
+ const char *file,
+ int line,
+ const char * func,
+ const char *fmt,
+ va_list args);
+
+ /** store the request @deprecated no more needed */
+ struct afb_stored_req *(*legacy_store_req)(
+ struct afb_req_x2 *req);
+
+ /** asynchronous subcall with request @deprecated use @ref subcall */
+ void (*legacy_subcall_req)(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x1),
+ void *cb_closure);
+
+ /** store the request @deprecated no more needed */
+ int (*has_permission)(
+ struct afb_req_x2 *req,
+ const char *permission);
+
+ /** get the application id of the client of the request */
+ char *(*get_application_id)(
+ struct afb_req_x2 *req);
+
+ /** handle client context of the api getting the request */
+ void *(*context_make)(
+ struct afb_req_x2 *req,
+ int replace,
+ void *(*create_value)(void *creation_closure),
+ void (*free_value)(void*),
+ void *creation_closure);
+
+ /** make subscription of the client of the request to the event */
+ int (*subscribe_event_x2)(
+ struct afb_req_x2 *req,
+ struct afb_event_x2 *event);
+
+ /** remove subscription of the client of the request to the event */
+ int (*unsubscribe_event_x2)(
+ struct afb_req_x2 *req,
+ struct afb_event_x2 *event);
+
+ /** asynchronous subcall with request @deprecated use @ref subcall */
+ void (*legacy_subcall_request)(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *req),
+ void *cb_closure);
+
+ /** get the user id (unix) of the client of the request */
+ int (*get_uid)(
+ struct afb_req_x2 *req);
+
+ /** reply to the request */
+ void (*reply)(
+ struct afb_req_x2 *req,
+ struct json_object *obj,
+ const char *error,
+ const char *info);
+
+ /** reply to the request with formating of info */
+ void (*vreply)(
+ struct afb_req_x2 *req,
+ struct json_object *obj,
+ const char *error,
+ const char *fmt,
+ va_list args);
+
+ /** get description of the client of the request */
+ struct json_object *(*get_client_info)(
+ struct afb_req_x2 *req);
+
+ /** asynchronous subcall */
+ void (*subcall)(
+ struct afb_req_x2 *req,
+ const char *apiname,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
+ void *closure);
+
+ /** synchronous subcall */
+ int (*subcallsync)(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct json_object **object,
+ char **error,
+ char **info);
+};
+
diff --git a/include/afb/afb-req-x2.h b/include/afb/afb-req-x2.h
new file mode 100644
index 00000000..70ffab80
--- /dev/null
+++ b/include/afb/afb-req-x2.h
@@ -0,0 +1,758 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "afb-req-x2-itf.h"
+#include "afb-api-x3.h"
+
+/**
+ * Checks whether the request 'req' is valid or not.
+ *
+ * @param req the request to check
+ *
+ * @return 0 if not valid or 1 if valid.
+ */
+static inline
+int afb_req_x2_is_valid(
+ struct afb_req_x2 *req)
+{
+ return !!req;
+}
+
+/**
+ * Retrieves the api that serves the request
+ *
+ * @param req the request whose serving api is queried
+ *
+ * @return the api serving the request
+ */
+static inline
+struct afb_api_x3 *afb_req_x2_get_api(
+ struct afb_req_x2 *req)
+{
+ return req->api;
+}
+
+/**
+ * Retrieves the callback data of the verb. This callback data is set
+ * when the verb is created.
+ *
+ * @param req whose verb vcbdata is queried
+ *
+ * @return the callback data attached to the verb description
+ */
+static inline
+void *afb_req_x2_get_vcbdata(
+ struct afb_req_x2 *req)
+{
+ return req->vcbdata;
+}
+
+/**
+ * Retrieve the name of the called api.
+ *
+ * @param req the request
+ *
+ * @return the name of the called api
+ *
+ * @see afb_api_x3_add_alias
+ */
+static inline
+const char *afb_req_x2_get_called_api(
+ struct afb_req_x2 *req)
+{
+ return req->called_api;
+}
+
+/**
+ * Retrieve the name of the called verb
+ *
+ * @param req the request
+ *
+ * @return the name of the called verb
+ */
+static inline
+const char *afb_req_x2_get_called_verb(
+ struct afb_req_x2 *req)
+{
+ return req->called_verb;
+}
+
+/**
+ * Is the log message of 'level (as defined for syslog) required for the
+ * request 'req'?
+ *
+ * @param req the request
+ * @param level the level to check as defined for syslog:
+ *
+ * EMERGENCY 0 System is unusable
+ * ALERT 1 Action must be taken immediately
+ * CRITICAL 2 Critical conditions
+ * ERROR 3 Error conditions
+ * WARNING 4 Warning conditions
+ * NOTICE 5 Normal but significant condition
+ * INFO 6 Informational
+ * DEBUG 7 Debug-level messages
+ *
+ * @return 0 if not required or a value not null if required
+ *
+ * @see syslog
+ */
+static inline
+int afb_req_x2_wants_log_level(
+ struct afb_req_x2 *req,
+ int level)
+{
+ return afb_api_x3_wants_log_level(afb_req_x2_get_api(req), level);
+}
+
+/**
+ * Gets from the request 'req' the argument of 'name'.
+ *
+ * Returns a PLAIN structure of type 'struct afb_arg'.
+ *
+ * When the argument of 'name' is not found, all fields of result are set to NULL.
+ *
+ * When the argument of 'name' is found, the fields are filled,
+ * in particular, the field 'result.name' is set to 'name'.
+ *
+ * There is a special name value: the empty string.
+ * The argument of name "" is defined only if the request was made using
+ * an HTTP POST of Content-Type "application/json". In that case, the
+ * argument of name "" receives the value of the body of the HTTP request.
+ *
+ * @param req the request
+ * @param name the name of the argument to get
+ *
+ * @return a structure describing the retrieved argument for the request
+ *
+ * @see afb_req_x2_value
+ * @see afb_req_x2_path
+ */
+static inline
+struct afb_arg afb_req_x2_get(
+ struct afb_req_x2 *req,
+ const char *name)
+{
+ return req->itf->get(req, name);
+}
+
+/**
+ * Gets from the request 'req' the string value of the argument of 'name'.
+ * Returns NULL if when there is no argument of 'name'.
+ * Returns the value of the argument of 'name' otherwise.
+ *
+ * Shortcut for: afb_req_x2_get(req, name).value
+ *
+ * @param req the request
+ * @param name the name of the argument's value to get
+ *
+ * @return the value as a string or NULL
+ *
+ * @see afb_req_x2_get
+ * @see afb_req_x2_path
+ */
+static inline
+const char *afb_req_x2_value(
+ struct afb_req_x2 *req,
+ const char *name)
+{
+ return afb_req_x2_get(req, name).value;
+}
+
+/**
+ * Gets from the request 'req' the path for file attached to the argument of 'name'.
+ * Returns NULL if when there is no argument of 'name' or when there is no file.
+ * Returns the path of the argument of 'name' otherwise.
+ *
+ * Shortcut for: afb_req_x2_get(req, name).path
+ *
+ * @param req the request
+ * @param name the name of the argument's path to get
+ *
+ * @return the path if any or NULL
+ *
+ * @see afb_req_x2_get
+ * @see afb_req_x2_value
+ */
+static inline
+const char *afb_req_x2_path(
+ struct afb_req_x2 *req,
+ const char *name)
+{
+ return afb_req_x2_get(req, name).path;
+}
+
+/**
+ * Gets from the request 'req' the json object hashing the arguments.
+ *
+ * The returned object must not be released using 'json_object_put'.
+ *
+ * @param req the request
+ *
+ * @return the JSON object of the query
+ *
+ * @see afb_req_x2_get
+ * @see afb_req_x2_value
+ * @see afb_req_x2_path
+ */
+static inline
+struct json_object *afb_req_x2_json(
+ struct afb_req_x2 *req)
+{
+ return req->itf->json(req);
+}
+
+/**
+ * Sends a reply to the request 'req'.
+ *
+ * The status of the reply is set to 'error' (that must be NULL on success).
+ * Its send the object 'obj' (can be NULL) with an
+ * informational comment 'info (can also be NULL).
+ *
+ * For convenience, the function calls 'json_object_put' for 'obj'.
+ * Thus, in the case where 'obj' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * @param req the request
+ * @param obj the replied object or NULL
+ * @param error the error message if it is a reply error or NULL
+ * @param info an informative text or NULL
+ *
+ * @see afb_req_x2_reply_v
+ * @see afb_req_x2_reply_f
+ */
+static inline
+void afb_req_x2_reply(
+ struct afb_req_x2 *req,
+ struct json_object *obj,
+ const char *error,
+ const char *info)
+{
+ req->itf->reply(req, obj, error, info);
+}
+
+/**
+ * Same as 'afb_req_x2_reply_f' but the arguments to the format 'info'
+ * are given as a variable argument list instance.
+ *
+ * For convenience, the function calls 'json_object_put' for 'obj'.
+ * Thus, in the case where 'obj' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * @param req the request
+ * @param obj the replied object or NULL
+ * @param error the error message if it is a reply error or NULL
+ * @param info an informative text containing a format as for vprintf
+ * @param args the va_list of arguments to the format as for vprintf
+ *
+ * @see afb_req_x2_reply
+ * @see afb_req_x2_reply_f
+ * @see vprintf
+ */
+static inline
+void afb_req_x2_reply_v(
+ struct afb_req_x2 *req,
+ struct json_object *obj,
+ const char *error,
+ const char *info,
+ va_list args)
+{
+ req->itf->vreply(req, obj, error, info, args);
+}
+
+/**
+ * Same as 'afb_req_x2_reply' but the 'info' is a formatting
+ * string followed by arguments.
+ *
+ * For convenience, the function calls 'json_object_put' for 'obj'.
+ * Thus, in the case where 'obj' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * @param req the request
+ * @param obj the replied object or NULL
+ * @param error the error message if it is a reply error or NULL
+ * @param info an informative text containing a format as for printf
+ * @param ... the arguments to the format as for printf
+ *
+ * @see afb_req_x2_reply
+ * @see afb_req_x2_reply_v
+ * @see printf
+ */
+__attribute__((format(printf, 4, 5)))
+static inline
+void afb_req_x2_reply_f(
+ struct afb_req_x2 *req,
+ struct json_object *obj,
+ const char *error,
+ const char *info,
+ ...)
+{
+ va_list args;
+ va_start(args, info);
+ afb_req_x2_reply_v(req, obj, error, info, args);
+ va_end(args);
+}
+
+/**
+ * Manage the pointer stored by the binding for the client session of 'req'.
+ *
+ * If no previous pointer is stored or if 'replace' is not zero, a new value
+ * is generated using the function 'create_context' called with the 'closure'.
+ * If 'create_context' is NULL the generated value is 'closure'.
+ *
+ * When a value is created, the function 'free_context' is recorded and will
+ * be called (with the created value as argument) to free the created value when
+ * it is not more used.
+ *
+ * This function is atomic: it ensures that 2 threads will not race together.
+ *
+ * @param req the request
+ * @param replace if not zero an existing value is replaced
+ * @param create_context the creation function or NULL
+ * @param free_context the destroying function or NULL
+ * @param closure the closure to the creation function
+ *
+ * @return the stored value
+ */
+static inline
+void *afb_req_x2_context(
+ struct afb_req_x2 *req,
+ int replace,
+ void *(*create_context)(void *closure),
+ void (*free_context)(void*),
+ void *closure)
+{
+ return req->itf->context_make(req, replace, create_context, free_context, closure);
+}
+
+/**
+ * Gets the pointer stored by the binding for the session of 'req'.
+ * When the binding has not yet recorded a pointer, NULL is returned.
+ *
+ * Shortcut for: afb_req_x2_context(req, 0, NULL, NULL, NULL)
+ *
+ * @param req the request
+ *
+ * @return the previously stored value
+ */
+static inline
+void *afb_req_x2_context_get(
+ struct afb_req_x2 *req)
+{
+ return afb_req_x2_context(req, 0, 0, 0, 0);
+}
+
+/**
+ * Stores for the binding the pointer 'context' to the session of 'req'.
+ * The function 'free_context' will be called when the session is closed
+ * or if binding stores an other pointer.
+ *
+ * Shortcut for: afb_req_x2_context(req, 1, NULL, free_context, context)
+ *
+ *
+ * @param req the request
+ * @param context the context value to store
+ * @param free_context the cleaning function for the stored context (can be NULL)
+ */
+static inline
+void afb_req_x2_context_set(
+ struct afb_req_x2 *req,
+ void *context,
+ void (*free_context)(void*))
+{
+ afb_req_x2_context(req, 1, 0, free_context, context);
+}
+
+/**
+ * Frees the pointer stored by the binding for the session of 'req'
+ * and sets it to NULL.
+ *
+ * Shortcut for: afb_req_x2_context_set(req, NULL, NULL)
+ *
+ * @param req the request
+ */
+static inline
+void afb_req_x2_context_clear(
+ struct afb_req_x2 *req)
+{
+ afb_req_x2_context(req, 1, 0, 0, 0);
+}
+
+/**
+ * Increments the count of references of 'req'.
+ *
+ * @param req the request
+ *
+ * @return returns the request req
+ */
+static inline
+struct afb_req_x2 *afb_req_x2_addref(
+ struct afb_req_x2 *req)
+{
+ return req->itf->addref(req);
+}
+
+/**
+ * Decrement the count of references of 'req'.
+ *
+ * @param req the request
+ */
+static inline
+void afb_req_x2_unref(
+ struct afb_req_x2 *req)
+{
+ req->itf->unref(req);
+}
+
+/**
+ * Closes the session associated with 'req'
+ * and delete all associated contexts.
+ *
+ * @param req the request
+ */
+static inline
+void afb_req_x2_session_close(
+ struct afb_req_x2 *req)
+{
+ req->itf->session_close(req);
+}
+
+/**
+ * Sets the level of assurance of the session of 'req'
+ * to 'level'. The effect of this function is subject of
+ * security policies.
+ *
+ * @param req the request
+ * @param level of assurance from 0 to 7
+ *
+ * @return 0 on success or -1 if failed.
+ */
+static inline
+int afb_req_x2_session_set_LOA(
+ struct afb_req_x2 *req,
+ unsigned level)
+{
+ return req->itf->session_set_LOA(req, level);
+}
+
+/**
+ * Establishes for the client link identified by 'req' a subscription
+ * to the 'event'.
+ *
+ * @param req the request
+ * @param event the event to subscribe
+ *
+ * @return 0 in case of successful subscription or -1 in case of error.
+ */
+static inline
+int afb_req_x2_subscribe(
+ struct afb_req_x2 *req,
+ struct afb_event_x2 *event)
+{
+ return req->itf->subscribe_event_x2(req, event);
+}
+
+/**
+ * Revokes the subscription established to the 'event' for the client
+ * link identified by 'req'.
+ * Returns 0 in case of successful subscription or -1 in case of error.
+ *
+ * @param req the request
+ * @param event the event to revoke
+ *
+ * @return 0 in case of successful subscription or -1 in case of error.
+ */
+static inline
+int afb_req_x2_unsubscribe(
+ struct afb_req_x2 *req,
+ struct afb_event_x2 *event)
+{
+ return req->itf->unsubscribe_event_x2(req, event);
+}
+
+/**
+ * @deprecated use @ref afb_req_x2_subcall
+ *
+ * Makes a call to the method of name 'api' / 'verb' with the object 'args'.
+ * This call is made in the context of the request 'req'.
+ * On completion, the function 'callback' is invoked with the
+ * 'closure' given at call and two other parameters: 'iserror' and 'result'.
+ * 'status' is 0 on success or negative when on an error reply.
+ * 'result' is the json object of the reply, you must not call json_object_put
+ * on the result.
+ *
+ * For convenience, the function calls 'json_object_put' for 'args'.
+ * Thus, in the case where 'args' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * @param req the request
+ * @param api the name of the api to call
+ * @param verb the name of the verb to call
+ * @param args the arguments of the call as a JSON object
+ * @param callback the call back that will receive the reply
+ * @param closure the closure passed back to the callback
+ *
+ * @see afb_req_x2_subcall
+ * @see afb_req_x2_subcall_sync
+ */
+static inline
+void afb_req_x2_subcall_legacy(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req_x2 *req),
+ void *closure)
+{
+ req->itf->legacy_subcall_request(req, api, verb, args, callback, closure);
+}
+
+/**
+ * @deprecated use @ref afb_req_x2_subcall_sync
+ *
+ * Makes a call to the method of name 'api' / 'verb' with the object 'args'.
+ * This call is made in the context of the request 'req'.
+ * This call is synchronous, it waits untill completion of the request.
+ * It returns 0 on success or a negative value on error answer.
+ * The object pointed by 'result' is filled and must be released by the caller
+ * after its use by calling 'json_object_put'.
+ *
+ * For convenience, the function calls 'json_object_put' for 'args'.
+ * Thus, in the case where 'args' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * @param req the request
+ * @param api the name of the api to call
+ * @param verb the name of the verb to call
+ * @param args the arguments of the call as a JSON object
+ * @param result the pointer to the JSON object pointer that will receive the result
+ *
+ * @return 0 on success or a negative value on error answer.
+ *
+ * @see afb_req_x2_subcall
+ * @see afb_req_x2_subcall_sync
+ */
+static inline
+int afb_req_x2_subcall_sync_legacy(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result)
+{
+ return req->itf->legacy_subcallsync(req, api, verb, args, result);
+}
+
+/**
+ * Send associated to 'req' a message described by 'fmt' and following parameters
+ * to the journal for the verbosity 'level'.
+ *
+ * 'file', 'line' and 'func' are indicators of position of the code in source files
+ * (see macros __FILE__, __LINE__ and __func__).
+ *
+ * 'level' is defined by syslog standard:
+ * EMERGENCY 0 System is unusable
+ * ALERT 1 Action must be taken immediately
+ * CRITICAL 2 Critical conditions
+ * ERROR 3 Error conditions
+ * WARNING 4 Warning conditions
+ * NOTICE 5 Normal but significant condition
+ * INFO 6 Informational
+ * DEBUG 7 Debug-level messages
+ *
+ * @param req the request
+ * @param level the level of the message
+ * @param file the source filename that emits the message or NULL
+ * @param line the line number in the source filename that emits the message
+ * @param func the name of the function that emits the message or NULL
+ * @param fmt the message format as for printf
+ * @param ... the arguments of the printf
+ *
+ * @see printf
+ */
+__attribute__((format(printf, 6, 7)))
+static inline
+void afb_req_x2_verbose(
+ struct afb_req_x2 *req,
+ int level, const char *file,
+ int line,
+ const char * func,
+ const char *fmt,
+ ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ req->itf->vverbose(req, level, file, line, func, fmt, args);
+ va_end(args);
+}
+
+/**
+ * Check whether the 'permission' is granted or not to the client
+ * identified by 'req'.
+ *
+ * @param req the request
+ * @param permission string to check
+ *
+ * @return 1 if the permission is granted or 0 otherwise.
+ */
+static inline
+int afb_req_x2_has_permission(
+ struct afb_req_x2 *req,
+ const char *permission)
+{
+ return req->itf->has_permission(req, permission);
+}
+
+/**
+ * Get the application identifier of the client application for the
+ * request 'req'.
+ *
+ * Returns the application identifier or NULL when the application
+ * can not be identified.
+ *
+ * The returned value if not NULL must be freed by the caller
+ *
+ * @param req the request
+ *
+ * @return the string for the application id of the client MUST BE FREED
+ */
+static inline
+char *afb_req_x2_get_application_id(
+ struct afb_req_x2 *req)
+{
+ return req->itf->get_application_id(req);
+}
+
+/**
+ * Get the user identifier (UID) of the client for the
+ * request 'req'.
+ *
+ * @param req the request
+ *
+ * @return -1 when the application can not be identified or the unix uid.
+ *
+ */
+static inline
+int afb_req_x2_get_uid(
+ struct afb_req_x2 *req)
+{
+ return req->itf->get_uid(req);
+}
+
+/**
+ * Get informations about the client of the
+ * request 'req'.
+ *
+ * Returns an object with client informations:
+ * {
+ * "pid": int, "uid": int, "gid": int,
+ * "label": string, "id": string, "user": string,
+ * "uuid": string, "LOA": int
+ * }
+ *
+ * If some of this information can't be computed, the field of the return
+ * object will not be set at all.
+ *
+ * @param req the request
+ *
+ * @return a JSON object that must be freed using @ref json_object_put
+ */
+static inline
+struct json_object *afb_req_x2_get_client_info(
+ struct afb_req_x2 *req)
+{
+ return req->itf->get_client_info(req);
+}
+
+/**
+ * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
+ * The result of the call is delivered to the 'callback' function with the 'callback_closure'.
+ *
+ * For convenience, the function calls 'json_object_put' for 'args'.
+ * Thus, in the case where 'args' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * The 'callback' receives 5 arguments:
+ * 1. 'closure' the user defined closure pointer 'closure',
+ * 2. 'object' a JSON object returned (can be NULL)
+ * 3. 'error' a string not NULL in case of error
+ * 4. 'info' a string handling some info (can be NULL)
+ * 5. 'req' the req
+ *
+ * @param req The request
+ * @param api The api name of the method to call
+ * @param verb The verb name of the method to call
+ * @param args The arguments to pass to the method
+ * @param flags The bit field of flags for the subcall as defined by @ref afb_req_x2_subcall_flags
+ * @param callback The to call on completion
+ * @param closure The closure to pass to the callback
+ *
+ * @see also 'afb_req_subcall_sync'
+ */
+static inline
+void afb_req_x2_subcall(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
+ void *closure)
+{
+ req->itf->subcall(req, api, verb, args, flags, callback, closure);
+}
+
+/**
+ * Makes a call to the method of name 'api' / 'verb' with the object 'args'.
+ * This call is made in the context of the request 'req'.
+ * This call is synchronous, it waits untill completion of the request.
+ * It returns 0 on success or a negative value on error answer.
+ *
+ * For convenience, the function calls 'json_object_put' for 'args'.
+ * Thus, in the case where 'args' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * See also:
+ * - 'afb_req_x2_subcall_req' that is convenient to keep request alive automatically.
+ * - 'afb_req_x2_subcall' that doesn't keep request alive automatically.
+ *
+ * @param req The request
+ * @param api The api name of the method to call
+ * @param verb The verb name of the method to call
+ * @param args The arguments to pass to the method
+ * @param flags The bit field of flags for the subcall as defined by @ref afb_req_x2_subcall_flags
+ * @param object a pointer where the replied JSON object is stored must be freed using @ref json_object_put (can be NULL)
+ * @param error a pointer where a copy of the replied error is stored must be freed using @ref free (can be NULL)
+ * @param info a pointer where a copy of the replied info is stored must be freed using @ref free (can be NULL)
+ *
+ * @return 0 in case of success or -1 in case of error
+ */
+static inline
+int afb_req_x2_subcall_sync(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct json_object **object,
+ char **error,
+ char **info)
+{
+ return req->itf->subcallsync(req, api, verb, args, flags, object, error, info);
+}
diff --git a/include/afb/afb-request-itf.h b/include/afb/afb-request-itf.h
deleted file mode 100644
index 44066c66..00000000
--- a/include/afb/afb-request-itf.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author: José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-/* defined here */
-struct afb_arg;
-struct afb_request;
-struct afb_request_itf;
-
-/* referenced here */
-#include <stdarg.h>
-struct json_object;
-struct afb_req;
-struct afb_event;
-struct afb_eventid;
-struct afb_dynapi;
-struct afb_stored_req;
-
-/*
- * Describes an argument (or parameter) of a request
- */
-struct afb_arg
-{
- const char *name; /* name of the argument or NULL if invalid */
- const char *value; /* string representation of the value of the argument */
- /* original filename of the argument if path != NULL */
- const char *path; /* if not NULL, path of the received file for the argument */
- /* when the request is finalized this file is removed */
-};
-
-/*
- * structure for the request
- */
-struct afb_request
-{
- /* interface for the request */
- const struct afb_request_itf *itf;
-
- /* current dynapi (if any) */
- struct afb_dynapi *dynapi;
-
- /* closure associated with the callback processing the verb of the request
- * as given at its declaration */
- void *vcbdata;
-
- /* the name of the called verb */
- const char *api;
-
- /* the name of the called verb */
- const char *verb;
-};
-
-/*
- * Interface for handling requests.
- * It records the functions to be called for the request.
- * Don't use this structure directly.
- * Use the helper functions
- */
-struct afb_request_itf
-{
- /* CAUTION: respect the order, add at the end */
-
- struct json_object *(*json)(
- struct afb_request *request);
-
- struct afb_arg (*get)(
- struct afb_request *request,
- const char *name);
-
- void (*success)(
- struct afb_request *request,
- struct json_object *obj,
- const char *info);
-
- void (*fail)(
- struct afb_request *request,
- const char *status,
- const char *info);
-
- void (*vsuccess)(
- struct afb_request *request,
- struct json_object *obj,
- const char *fmt,
- va_list args);
-
- void (*vfail)(
- struct afb_request *request,
- const char *status,
- const char *fmt,
- va_list args);
-
- void *(*context_get)(
- struct afb_request *request);
-
- void (*context_set)(
- struct afb_request *request,
- void *value,
- void (*free_value)(void*));
-
- struct afb_request *(*addref)(
- struct afb_request *request);
-
- void (*unref)(
- struct afb_request *request);
-
- void (*session_close)(
- struct afb_request *request);
-
- int (*session_set_LOA)(
- struct afb_request *request,
- unsigned level);
-
- int (*subscribe)(
- struct afb_request *request,
- struct afb_event event);
-
- int (*unsubscribe)(
- struct afb_request *request,
- struct afb_event event);
-
- void (*subcall)(
- struct afb_request *request,
- const char *api,
- const char *verb,
- struct json_object *args,
- void (*callback)(void*, int, struct json_object*),
- void *cb_closure);
-
- int (*subcallsync)(
- struct afb_request *request,
- const char *api,
- const char *verb,
- struct json_object *args,
- struct json_object **result);
-
- void (*vverbose)(
- struct afb_request *request,
- int level,
- const char *file,
- int line,
- const char * func,
- const char *fmt,
- va_list args);
-
- struct afb_stored_req *(*store)(
- struct afb_request *request);
-
- void (*subcall_req)(
- struct afb_request *request,
- const char *api,
- const char *verb,
- struct json_object *args,
- void (*callback)(void*, int, struct json_object*, struct afb_req),
- void *cb_closure);
-
- int (*has_permission)(
- struct afb_request *request,
- const char *permission);
-
- char *(*get_application_id)(
- struct afb_request *request);
-
- void *(*context_make)(
- struct afb_request *request,
- int replace,
- void *(*create_value)(void *creation_closure),
- void (*free_value)(void*),
- void *creation_closure);
-
- int (*subscribe_eventid)(
- struct afb_request *request,
- struct afb_eventid *eventid);
-
- int (*unsubscribe_eventid)(
- struct afb_request *request,
- struct afb_eventid *eventid);
-
- void (*subcall_request)(
- struct afb_request *request,
- const char *api,
- const char *verb,
- struct json_object *args,
- void (*callback)(void*, int, struct json_object*, struct afb_request *request),
- void *cb_closure);
-
- int (*get_uid)(
- struct afb_request *request);
-
-};
-
diff --git a/include/afb/afb-request.h b/include/afb/afb-request.h
deleted file mode 100644
index 8e909bba..00000000
--- a/include/afb/afb-request.h
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author: José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "afb-request-itf.h"
-
-static inline struct afb_dynapi *afb_request_get_dynapi(struct afb_request *request)
-{
- return request->dynapi;
-}
-
-static inline void *afb_request_get_vcbdata(struct afb_request *request)
-{
- return request->vcbdata;
-}
-
-static inline const char *afb_request_get_api(struct afb_request *request)
-{
- return request->api;
-}
-
-static inline const char *afb_request_get_verb(struct afb_request *request)
-{
- return request->verb;
-}
-
-/*
- * Gets from the request 'request' the argument of 'name'.
- * Returns a PLAIN structure of type 'struct afb_arg'.
- * When the argument of 'name' is not found, all fields of result are set to NULL.
- * When the argument of 'name' is found, the fields are filled,
- * in particular, the field 'result.name' is set to 'name'.
- *
- * There is a special name value: the empty string.
- * The argument of name "" is defined only if the request was made using
- * an HTTP POST of Content-Type "application/json". In that case, the
- * argument of name "" receives the value of the body of the HTTP request.
- */
-static inline struct afb_arg afb_request_get(struct afb_request *request, const char *name)
-{
- return request->itf->get(request, name);
-}
-
-/*
- * Gets from the request 'request' the string value of the argument of 'name'.
- * Returns NULL if when there is no argument of 'name'.
- * Returns the value of the argument of 'name' otherwise.
- *
- * Shortcut for: afb_request_get(request, name).value
- */
-static inline const char *afb_request_value(struct afb_request *request, const char *name)
-{
- return afb_request_get(request, name).value;
-}
-
-/*
- * Gets from the request 'request' the path for file attached to the argument of 'name'.
- * Returns NULL if when there is no argument of 'name' or when there is no file.
- * Returns the path of the argument of 'name' otherwise.
- *
- * Shortcut for: afb_request_get(request, name).path
- */
-static inline const char *afb_request_path(struct afb_request *request, const char *name)
-{
- return afb_request_get(request, name).path;
-}
-
-/*
- * Gets from the request 'request' the json object hashing the arguments.
- * The returned object must not be released using 'json_object_put'.
- */
-static inline struct json_object *afb_request_json(struct afb_request *request)
-{
- return request->itf->json(request);
-}
-
-/*
- * Sends a reply of kind success to the request 'request'.
- * The status of the reply is automatically set to "success".
- * Its send the object 'obj' (can be NULL) with an
- * informationnal comment 'info (can also be NULL).
- *
- * For convenience, the function calls 'json_object_put' for 'obj'.
- * Thus, in the case where 'obj' should remain available after
- * the function returns, the function 'json_object_get' shall be used.
- */
-static inline void afb_request_success(struct afb_request *request, struct json_object *obj, const char *info)
-{
- request->itf->success(request, obj, info);
-}
-
-/*
- * Same as 'afb_request_success' but the 'info' is a formatting
- * string followed by arguments.
- *
- * For convenience, the function calls 'json_object_put' for 'obj'.
- * Thus, in the case where 'obj' should remain available after
- * the function returns, the function 'json_object_get' shall be used.
- */
-static inline void afb_request_success_f(struct afb_request *request, struct json_object *obj, const char *info, ...) __attribute__((format(printf, 3, 4)));
-static inline void afb_request_success_f(struct afb_request *request, struct json_object *obj, const char *info, ...)
-{
- va_list args;
- va_start(args, info);
- request->itf->vsuccess(request, obj, info, args);
- va_end(args);
-}
-
-/*
- * Same as 'afb_request_success_f' but the arguments to the format 'info'
- * are given as a variable argument list instance.
- *
- * For convenience, the function calls 'json_object_put' for 'obj'.
- * Thus, in the case where 'obj' should remain available after
- * the function returns, the function 'json_object_get' shall be used.
- */
-static inline void afb_request_success_v(struct afb_request *request, struct json_object *obj, const char *info, va_list args)
-{
- request->itf->vsuccess(request, obj, info, args);
-}
-
-/*
- * Sends a reply of kind failure to the request 'request'.
- * The status of the reply is set to 'status' and an
- * informationnal comment 'info' (can also be NULL) can be added.
- *
- * Note that calling afb_request_fail("success", info) is equivalent
- * to call afb_request_success(NULL, info). Thus even if possible it
- * is strongly recommanded to NEVER use "success" for status.
- */
-static inline void afb_request_fail(struct afb_request *request, const char *status, const char *info)
-{
- request->itf->fail(request, status, info);
-}
-
-/*
- * Same as 'afb_request_fail' but the 'info' is a formatting
- * string followed by arguments.
- */
-static inline void afb_request_fail_f(struct afb_request *request, const char *status, const char *info, ...) __attribute__((format(printf, 3, 4)));
-static inline void afb_request_fail_f(struct afb_request *request, const char *status, const char *info, ...)
-{
- va_list args;
- va_start(args, info);
- request->itf->vfail(request, status, info, args);
- va_end(args);
-}
-
-/*
- * Same as 'afb_request_fail_f' but the arguments to the format 'info'
- * are given as a variable argument list instance.
- */
-static inline void afb_request_fail_v(struct afb_request *request, const char *status, const char *info, va_list args)
-{
- request->itf->vfail(request, status, info, args);
-}
-
-/*
- * Gets the pointer stored by the binding for the session of 'request'.
- * When the binding has not yet recorded a pointer, NULL is returned.
- */
-static inline void *afb_request_context_get(struct afb_request *request)
-{
- return request->itf->context_make(request, 0, 0, 0, 0);
-}
-
-/*
- * Stores for the binding the pointer 'context' to the session of 'request'.
- * The function 'free_context' will be called when the session is closed
- * or if binding stores an other pointer.
- */
-static inline void afb_request_context_set(struct afb_request *request, void *context, void (*free_context)(void*))
-{
- request->itf->context_make(request, 1, 0, free_context, context);
-}
-
-/*
- * Gets the pointer stored by the binding for the session of 'request'.
- * If no previous pointer is stored or if 'replace' is not zero, a new value
- * is generated using the function 'create_context' called with the 'closure'.
- * If 'create_context' is NULL the generated value is 'closure'.
- * When a value is created, the function 'free_context' is recorded and will
- * be called (with the created value as argument) to free the created value when
- * it is not more used.
- * This function is atomic: it ensures that 2 threads will not race together.
- */
-static inline void *afb_request_context(struct afb_request *request, int replace, void *(*create_context)(void *closure), void (*free_context)(void*), void *closure)
-{
- return request->itf->context_make(request, replace, create_context, free_context, closure);
-}
-
-/*
- * Frees the pointer stored by the binding for the session of 'request'
- * and sets it to NULL.
- *
- * Shortcut for: afb_request_context_set(request, NULL, NULL)
- */
-static inline void afb_request_context_clear(struct afb_request *request)
-{
- request->itf->context_make(request, 1, 0, 0, 0);
-}
-
-/*
- * Adds one to the count of references of 'request'.
- * This function MUST be called by asynchronous implementations
- * of verbs if no reply was sent before returning.
- */
-static inline struct afb_request *afb_request_addref(struct afb_request *request)
-{
- return request->itf->addref(request);
-}
-
-/*
- * Substracts one to the count of references of 'request'.
- * This function MUST be called by asynchronous implementations
- * of verbs after sending the asynchronous reply.
- */
-static inline void afb_request_unref(struct afb_request *request)
-{
- request->itf->unref(request);
-}
-
-/*
- * Closes the session associated with 'request'
- * and delete all associated contexts.
- */
-static inline void afb_request_session_close(struct afb_request *request)
-{
- request->itf->session_close(request);
-}
-
-/*
- * Sets the level of assurance of the session of 'request'
- * to 'level'. The effect of this function is subject of
- * security policies.
- * Returns 1 on success or 0 if failed.
- */
-static inline int afb_request_session_set_LOA(struct afb_request *request, unsigned level)
-{
- return request->itf->session_set_LOA(request, level);
-}
-
-/*
- * Establishes for the client link identified by 'request' a subscription
- * to the 'event'.
- * Returns 0 in case of successful subscription or -1 in case of error.
- */
-static inline int afb_request_subscribe(struct afb_request *request, struct afb_eventid *eventid)
-{
- return request->itf->subscribe_eventid(request, eventid);
-}
-
-/*
- * Revokes the subscription established to the 'event' for the client
- * link identified by 'request'.
- * Returns 0 in case of successful subscription or -1 in case of error.
- */
-static inline int afb_request_unsubscribe(struct afb_request *request, struct afb_eventid *eventid)
-{
- return request->itf->unsubscribe_eventid(request, eventid);
-}
-
-/*
- * Makes a call to the method of name 'api' / 'verb' with the object 'args'.
- * This call is made in the context of the request 'request'.
- * On completion, the function 'callback' is invoked with the
- * 'closure' given at call and two other parameters: 'iserror' and 'result'.
- * 'status' is 0 on success or negative when on an error reply.
- * 'result' is the json object of the reply, you must not call json_object_put
- * on the result.
- *
- * For convenience, the function calls 'json_object_put' for 'args'.
- * Thus, in the case where 'args' should remain available after
- * the function returns, the function 'json_object_get' shall be used.
- *
- * See also:
- * - 'afb_request_subcall_req' that is convenient to keep request alive automatically.
- * - 'afb_request_subcall_sync' the synchronous version
- */
-static inline void afb_request_subcall(struct afb_request *request, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_request *request), void *closure)
-{
- request->itf->subcall_request(request, api, verb, args, callback, closure);
-}
-
-/*
- * Makes a call to the method of name 'api' / 'verb' with the object 'args'.
- * This call is made in the context of the request 'request'.
- * This call is synchronous, it waits untill completion of the request.
- * It returns 0 on success or a negative value on error answer.
- * The object pointed by 'result' is filled and must be released by the caller
- * after its use by calling 'json_object_put'.
- *
- * For convenience, the function calls 'json_object_put' for 'args'.
- * Thus, in the case where 'args' should remain available after
- * the function returns, the function 'json_object_get' shall be used.
- *
- * See also:
- * - 'afb_request_subcall_req' that is convenient to keep request alive automatically.
- * - 'afb_request_subcall' that doesn't keep request alive automatically.
- */
-static inline int afb_request_subcall_sync(struct afb_request *request, const char *api, const char *verb, struct json_object *args, struct json_object **result)
-{
- return request->itf->subcallsync(request, api, verb, args, result);
-}
-
-/*
- * Send associated to 'request' a message described by 'fmt' and following parameters
- * to the journal for the verbosity 'level'.
- *
- * 'file', 'line' and 'func' are indicators of position of the code in source files
- * (see macros __FILE__, __LINE__ and __func__).
- *
- * 'level' is defined by syslog standard:
- * EMERGENCY 0 System is unusable
- * ALERT 1 Action must be taken immediately
- * CRITICAL 2 Critical conditions
- * ERROR 3 Error conditions
- * WARNING 4 Warning conditions
- * NOTICE 5 Normal but significant condition
- * INFO 6 Informational
- * DEBUG 7 Debug-level messages
- */
-static inline void afb_request_verbose(struct afb_request *request, int level, const char *file, int line, const char * func, const char *fmt, ...) __attribute__((format(printf, 6, 7)));
-static inline void afb_request_verbose(struct afb_request *request, int level, const char *file, int line, const char * func, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- request->itf->vverbose(request, level, file, line, func, fmt, args);
- va_end(args);
-}
-
-/* macro for setting file, line and function automatically */
-# if !defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS)
-#define AFB_REQUEST_VERBOSE(request,level,...) afb_request_verbose(request,level,__FILE__,__LINE__,__func__,__VA_ARGS__)
-#else
-#define AFB_REQUEST_VERBOSE(request,level,...) afb_request_verbose(request,level,NULL,0,NULL,__VA_ARGS__)
-#endif
-
-/*
- * Check whether the 'permission' is granted or not to the client
- * identified by 'request'.
- *
- * Returns 1 if the permission is granted or 0 otherwise.
- */
-static inline int afb_request_has_permission(struct afb_request *request, const char *permission)
-{
- return request->itf->has_permission(request, permission);
-}
-
-/*
- * Get the application identifier of the client application for the
- * request 'request'.
- *
- * Returns the application identifier or NULL when the application
- * can not be identified.
- *
- * The returned value if not NULL must be freed by the caller
- */
-static inline char *afb_request_get_application_id(struct afb_request *request)
-{
- return request->itf->get_application_id(request);
-}
-
-/*
- * Get the user identifier (UID) of the client for the
- * request 'request'.
- *
- * Returns -1 when the application can not be identified.
- */
-static inline int afb_request_get_uid(struct afb_request *request)
-{
- return request->itf->get_uid(request);
-}
-
diff --git a/include/afb/afb-service-itf.h b/include/afb/afb-service-itf-x1.h
index dd79bdde..fcdd08e1 100644
--- a/include/afb/afb-service-itf.h
+++ b/include/afb/afb-service-itf-x1.h
@@ -17,32 +17,35 @@
#pragma once
-/* avoid inclusion of <json-c/json.h> */
-struct json_object;
+struct afb_api_x3;
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Interface for internal of services
* It records the functions to be called for the request.
* Don't use this structure directly.
* Use the helper functions documented below.
*/
-struct afb_service_itf
+struct afb_service_itf_x1
{
/* CAUTION: respect the order, add at the end */
- void (*call)(void *closure, const char *api, const char *verb, struct json_object *args,
+ void (*call)(struct afb_api_x3 *closure, const char *api, const char *verb, struct json_object *args,
void (*callback)(void*, int, struct json_object*), void *callback_closure);
- int (*call_sync)(void *closure, const char *api, const char *verb, struct json_object *args,
+ int (*call_sync)(struct afb_api_x3 *closure, const char *api, const char *verb, struct json_object *args,
struct json_object **result);
};
-/*
+/**
+ * @deprecated use bindings version 3
+ *
* Object that encapsulate accesses to service items
*/
-struct afb_service
+struct afb_service_x1
{
- const struct afb_service_itf *itf;
- void *closure;
+ const struct afb_service_itf_x1 *itf;
+ struct afb_api_x3 *closure;
};
diff --git a/include/afb/afb-service-v1.h b/include/afb/afb-service-v1.h
index 6a24ecb0..a3265af8 100644
--- a/include/afb/afb-service-v1.h
+++ b/include/afb/afb-service-v1.h
@@ -17,9 +17,11 @@
#pragma once
-#include "afb-service-itf.h"
+#include "afb-service-itf-x1.h"
/**
+ * @deprecated use bindings version 3
+ *
* Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
* The result of the call is delivered to the 'callback' function with the 'callback_closure'.
*
@@ -42,7 +44,7 @@
* @see also 'afb_req_subcall'
*/
static inline void afb_service_call_v1(
- struct afb_service service,
+ struct afb_service_x1 service,
const char *api,
const char *verb,
struct json_object *args,
@@ -53,6 +55,8 @@ static inline void afb_service_call_v1(
}
/**
+ * @deprecated use bindings version 3
+ *
* Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
* 'result' will receive the response.
*
@@ -71,7 +75,7 @@ static inline void afb_service_call_v1(
* @see also 'afb_req_subcall'
*/
static inline int afb_service_call_sync_v1(
- struct afb_service service,
+ struct afb_service_x1 service,
const char *api,
const char *verb,
struct json_object *args,
diff --git a/include/afb/afb-service-v2.h b/include/afb/afb-service-v2.h
index df751bd5..da59786d 100644
--- a/include/afb/afb-service-v2.h
+++ b/include/afb/afb-service-v2.h
@@ -17,9 +17,11 @@
#pragma once
-#include "afb-service-itf.h"
+#include "afb-service-itf-x1.h"
/**
+ * @deprecated use bindings version 3
+ *
* Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
* The result of the call is delivered to the 'callback' function with the 'callback_closure'.
*
@@ -51,6 +53,8 @@ static inline void afb_service_call_v2(
}
/**
+ * @deprecated use bindings version 3
+ *
* Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding.
* 'result' will receive the response.
*
diff --git a/include/afb/afb-session-v1.h b/include/afb/afb-session-v1.h
deleted file mode 100644
index a606679b..00000000
--- a/include/afb/afb-session-v1.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author: José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-/*
- * Enum for Session/Token/Assurance middleware.
- */
-enum afb_session_flags_v1
-{
- AFB_SESSION_NONE_V1 = 0, /* nothing required */
- AFB_SESSION_CREATE_V1 = 1, /* Obsolete */
- AFB_SESSION_CLOSE_V1 = 2, /* After token authentification, closes the session at end */
- AFB_SESSION_RENEW_V1 = 4, /* After token authentification, refreshes the token at end */
- AFB_SESSION_CHECK_V1 = 8, /* Requires token authentification */
-
- AFB_SESSION_LOA_GE_V1 = 16, /* check that the LOA is greater or equal to the given value */
- AFB_SESSION_LOA_LE_V1 = 32, /* check that the LOA is lesser or equal to the given value */
- AFB_SESSION_LOA_EQ_V1 = 48, /* check that the LOA is equal to the given value */
-
- AFB_SESSION_LOA_SHIFT_V1 = 6, /* shift for LOA */
- AFB_SESSION_LOA_MASK_V1 = 7, /* mask for LOA */
-
- AFB_SESSION_LOA_0_V1 = 0, /* value for LOA of 0 */
- AFB_SESSION_LOA_1_V1 = 64, /* value for LOA of 1 */
- AFB_SESSION_LOA_2_V1 = 128, /* value for LOA of 2 */
- AFB_SESSION_LOA_3_V1 = 192, /* value for LOA of 3 */
- AFB_SESSION_LOA_4_V1 = 256, /* value for LOA of 4 */
-
- AFB_SESSION_LOA_LE_0_V1 = AFB_SESSION_LOA_LE_V1 | AFB_SESSION_LOA_0_V1, /* check LOA <= 0 */
- AFB_SESSION_LOA_LE_1_V1 = AFB_SESSION_LOA_LE_V1 | AFB_SESSION_LOA_1_V1, /* check LOA <= 1 */
- AFB_SESSION_LOA_LE_2_V1 = AFB_SESSION_LOA_LE_V1 | AFB_SESSION_LOA_2_V1, /* check LOA <= 2 */
- AFB_SESSION_LOA_LE_3_V1 = AFB_SESSION_LOA_LE_V1 | AFB_SESSION_LOA_3_V1, /* check LOA <= 3 */
-
- AFB_SESSION_LOA_EQ_0_V1 = AFB_SESSION_LOA_EQ_V1 | AFB_SESSION_LOA_0_V1, /* check LOA == 0 */
- AFB_SESSION_LOA_EQ_1_V1 = AFB_SESSION_LOA_EQ_V1 | AFB_SESSION_LOA_1_V1, /* check LOA == 1 */
- AFB_SESSION_LOA_EQ_2_V1 = AFB_SESSION_LOA_EQ_V1 | AFB_SESSION_LOA_2_V1, /* check LOA == 2 */
- AFB_SESSION_LOA_EQ_3_V1 = AFB_SESSION_LOA_EQ_V1 | AFB_SESSION_LOA_3_V1, /* check LOA == 3 */
-
- AFB_SESSION_LOA_GE_0_V1 = AFB_SESSION_LOA_GE_V1 | AFB_SESSION_LOA_0_V1, /* check LOA >= 0 */
- AFB_SESSION_LOA_GE_1_V1 = AFB_SESSION_LOA_GE_V1 | AFB_SESSION_LOA_1_V1, /* check LOA >= 1 */
- AFB_SESSION_LOA_GE_2_V1 = AFB_SESSION_LOA_GE_V1 | AFB_SESSION_LOA_2_V1, /* check LOA >= 2 */
- AFB_SESSION_LOA_GE_3_V1 = AFB_SESSION_LOA_GE_V1 | AFB_SESSION_LOA_3_V1 /* check LOA >= 3 */
-};
-
diff --git a/include/afb/afb-session-v2.h b/include/afb/afb-session-v2.h
deleted file mode 100644
index 3f940ed6..00000000
--- a/include/afb/afb-session-v2.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author: José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-/*
- * Enum for Session/Token/Assurance middleware.
- */
-enum afb_session_flags_v2
-{
- AFB_SESSION_LOA_MASK_V2 = 3, /* mask for LOA */
-
- AFB_SESSION_LOA_0_V2 = 0, /* value for LOA of 0 */
- AFB_SESSION_LOA_1_V2 = 1, /* value for LOA of 1 */
- AFB_SESSION_LOA_2_V2 = 2, /* value for LOA of 2 */
- AFB_SESSION_LOA_3_V2 = 3, /* value for LOA of 3 */
-
- AFB_SESSION_CHECK_V2 = 4, /* Requires token authentification */
- AFB_SESSION_REFRESH_V2 = 8, /* After token authentification, refreshes the token at end */
- AFB_SESSION_CLOSE_V2 = 16, /* After token authentification, closes the session at end */
-
- AFB_SESSION_NONE_V2 = 0 /* nothing required */
-};
-
diff --git a/include/afb/afb-session-x1.h b/include/afb/afb-session-x1.h
new file mode 100644
index 00000000..776cb8f5
--- /dev/null
+++ b/include/afb/afb-session-x1.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/**
+ * @deprecated use bindings version 3
+ *
+ * Enum for Session/Token/Assurance of bindings version 1.
+ */
+enum afb_session_flags_x1
+{
+ AFB_SESSION_NONE_X1 = 0, /**< nothing required */
+ AFB_SESSION_CREATE_X1 = 1, /**< Obsolete */
+ AFB_SESSION_CLOSE_X1 = 2, /**< After token authentification, closes the session at end */
+ AFB_SESSION_RENEW_X1 = 4, /**< After token authentification, refreshes the token at end */
+ AFB_SESSION_CHECK_X1 = 8, /**< Requires token authentification */
+
+ AFB_SESSION_LOA_GE_X1 = 16, /**< check that the LOA is greater or equal to the given value */
+ AFB_SESSION_LOA_LE_X1 = 32, /**< check that the LOA is lesser or equal to the given value */
+ AFB_SESSION_LOA_EQ_X1 = 48, /**< check that the LOA is equal to the given value */
+
+ AFB_SESSION_LOA_SHIFT_X1 = 6, /**< shift for LOA */
+ AFB_SESSION_LOA_MASK_X1 = 7, /**< mask for LOA */
+
+ AFB_SESSION_LOA_0_X1 = 0, /**< value for LOA of 0 */
+ AFB_SESSION_LOA_1_X1 = 64, /**< value for LOA of 1 */
+ AFB_SESSION_LOA_2_X1 = 128, /**< value for LOA of 2 */
+ AFB_SESSION_LOA_3_X1 = 192, /**< value for LOA of 3 */
+ AFB_SESSION_LOA_4_X1 = 256, /**< value for LOA of 4 */
+
+ AFB_SESSION_LOA_LE_0_X1 = AFB_SESSION_LOA_LE_X1 | AFB_SESSION_LOA_0_X1, /**< check LOA <= 0 */
+ AFB_SESSION_LOA_LE_1_X1 = AFB_SESSION_LOA_LE_X1 | AFB_SESSION_LOA_1_X1, /**< check LOA <= 1 */
+ AFB_SESSION_LOA_LE_2_X1 = AFB_SESSION_LOA_LE_X1 | AFB_SESSION_LOA_2_X1, /**< check LOA <= 2 */
+ AFB_SESSION_LOA_LE_3_X1 = AFB_SESSION_LOA_LE_X1 | AFB_SESSION_LOA_3_X1, /**< check LOA <= 3 */
+
+ AFB_SESSION_LOA_EQ_0_X1 = AFB_SESSION_LOA_EQ_X1 | AFB_SESSION_LOA_0_X1, /**< check LOA == 0 */
+ AFB_SESSION_LOA_EQ_1_X1 = AFB_SESSION_LOA_EQ_X1 | AFB_SESSION_LOA_1_X1, /**< check LOA == 1 */
+ AFB_SESSION_LOA_EQ_2_X1 = AFB_SESSION_LOA_EQ_X1 | AFB_SESSION_LOA_2_X1, /**< check LOA == 2 */
+ AFB_SESSION_LOA_EQ_3_X1 = AFB_SESSION_LOA_EQ_X1 | AFB_SESSION_LOA_3_X1, /**< check LOA == 3 */
+
+ AFB_SESSION_LOA_GE_0_X1 = AFB_SESSION_LOA_GE_X1 | AFB_SESSION_LOA_0_X1, /**< check LOA >= 0 */
+ AFB_SESSION_LOA_GE_1_X1 = AFB_SESSION_LOA_GE_X1 | AFB_SESSION_LOA_1_X1, /**< check LOA >= 1 */
+ AFB_SESSION_LOA_GE_2_X1 = AFB_SESSION_LOA_GE_X1 | AFB_SESSION_LOA_2_X1, /**< check LOA >= 2 */
+ AFB_SESSION_LOA_GE_3_X1 = AFB_SESSION_LOA_GE_X1 | AFB_SESSION_LOA_3_X1 /**< check LOA >= 3 */
+};
+
diff --git a/include/afb/afb-session-x2.h b/include/afb/afb-session-x2.h
new file mode 100644
index 00000000..b4a24c77
--- /dev/null
+++ b/include/afb/afb-session-x2.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/**
+ * Enum for Session/Token/Assurance middleware of bindings version 2 and 3.
+ */
+enum afb_session_flags_x2
+{
+ AFB_SESSION_LOA_MASK_X2 = 3, /**< mask for LOA */
+
+ AFB_SESSION_LOA_0_X2 = 0, /**< value for LOA of 0 */
+ AFB_SESSION_LOA_1_X2 = 1, /**< value for LOA of 1 */
+ AFB_SESSION_LOA_2_X2 = 2, /**< value for LOA of 2 */
+ AFB_SESSION_LOA_3_X2 = 3, /**< value for LOA of 3 */
+
+ AFB_SESSION_CHECK_X2 = 4, /**< Requires token authentification */
+ AFB_SESSION_REFRESH_X2 = 8, /**< After token authentification, refreshes the token at end */
+ AFB_SESSION_CLOSE_X2 = 16, /**< After token authentification, closes the session at end */
+
+ AFB_SESSION_NONE_X2 = 0 /**< nothing required */
+};
+
diff --git a/include/afb/afb-verbosity.h b/include/afb/afb-verbosity.h
index 9f122056..dd34f841 100644
--- a/include/afb/afb-verbosity.h
+++ b/include/afb/afb-verbosity.h
@@ -23,9 +23,42 @@
#define AFB_VERBOSITY_LEVEL_INFO 3
#define AFB_VERBOSITY_LEVEL_DEBUG 4
-#define _AFB_SYSLOG_LEVEL_ERROR_ 3
-#define _AFB_SYSLOG_LEVEL_WARNING_ 4
-#define _AFB_SYSLOG_LEVEL_NOTICE_ 5
-#define _AFB_SYSLOG_LEVEL_INFO_ 6
-#define _AFB_SYSLOG_LEVEL_DEBUG_ 7
+#define AFB_SYSLOG_LEVEL_EMERGENCY 0
+#define AFB_SYSLOG_LEVEL_ALERT 1
+#define AFB_SYSLOG_LEVEL_CRITICAL 2
+#define AFB_SYSLOG_LEVEL_ERROR 3
+#define AFB_SYSLOG_LEVEL_WARNING 4
+#define AFB_SYSLOG_LEVEL_NOTICE 5
+#define AFB_SYSLOG_LEVEL_INFO 6
+#define AFB_SYSLOG_LEVEL_DEBUG 7
+
+#define AFB_VERBOSITY_LEVEL_WANT(verbosity,level) ((verbosity) >= (level))
+
+#define AFB_VERBOSITY_LEVEL_WANT_ERROR(x) AFB_VERBOSITY_LEVEL_WANT(x,AFB_VERBOSITY_LEVEL_ERROR)
+#define AFB_VERBOSITY_LEVEL_WANT_WARNING(x) AFB_VERBOSITY_LEVEL_WANT(x,AFB_VERBOSITY_LEVEL_WARNING)
+#define AFB_VERBOSITY_LEVEL_WANT_NOTICE(x) AFB_VERBOSITY_LEVEL_WANT(x,AFB_VERBOSITY_LEVEL_NOTICE)
+#define AFB_VERBOSITY_LEVEL_WANT_INFO(x) AFB_VERBOSITY_LEVEL_WANT(x,AFB_VERBOSITY_LEVEL_INFO)
+#define AFB_VERBOSITY_LEVEL_WANT_DEBUG(x) AFB_VERBOSITY_LEVEL_WANT(x,AFB_VERBOSITY_LEVEL_DEBUG)
+
+#define AFB_SYSLOG_MASK_WANT(verbomask,level) ((verbomask) & (1 << (level)))
+
+#define AFB_SYSLOG_MASK_WANT_EMERGENCY(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_EMERGENCY)
+#define AFB_SYSLOG_MASK_WANT_ALERT(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_ALERT)
+#define AFB_SYSLOG_MASK_WANT_CRITICAL(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_CRITICAL)
+#define AFB_SYSLOG_MASK_WANT_ERROR(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_ERROR)
+#define AFB_SYSLOG_MASK_WANT_WARNING(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_WARNING)
+#define AFB_SYSLOG_MASK_WANT_NOTICE(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_NOTICE)
+#define AFB_SYSLOG_MASK_WANT_INFO(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_INFO)
+#define AFB_SYSLOG_MASK_WANT_DEBUG(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_DEBUG)
+
+#define AFB_SYSLOG_LEVEL_FROM_VERBOSITY(x) ((x) + (AFB_SYSLOG_LEVEL_ERROR - AFB_VERBOSITY_LEVEL_ERROR))
+#define AFB_SYSLOG_LEVEL_TO_VERBOSITY(x) ((x) + (AFB_VERBOSITY_LEVEL_ERROR - AFB_SYSLOG_LEVEL_ERROR))
+
+static inline int _afb_verbomask_to_upper_level_(int verbomask)
+{
+ int result = 0;
+ while ((verbomask >>= 1) && result < AFB_SYSLOG_LEVEL_DEBUG)
+ result++;
+ return result;
+}
diff --git a/memo-supervisor.txt b/memo-supervisor.txt
index ae1147aa..f38c05d8 100644
--- a/memo-supervisor.txt
+++ b/memo-supervisor.txt
@@ -282,3 +282,14 @@ ON-EVENT supervisor/trace:
}
+Usefull commands:
+-----------------
+
+ TARGET=...
+
+ afb-client-demo -H ws://$TARGET:1619/api?token=HELLO\&uuid=HELLO supervisor list
+
+ afb-client-demo -H ws://$TARGET:1619/api?token=HELLO\&uuid=HELLO config '{"pid":XXXX}'
+
+
+
diff --git a/memo-v3.txt b/memo-v3.txt
new file mode 100644
index 00000000..bf082306
--- /dev/null
+++ b/memo-v3.txt
@@ -0,0 +1,9 @@
+sub_verb -> del_verb
+hookable : $ -> .
+glob added every where
+event filtering facility
+incompatibility of afb-proto-ws
+afb_req_context -> signature changed to afb_req_context_make
+get_client_info
+
+
diff --git a/mkdocs.yml b/mkdocs.yml
index b2f24aca..b94263a1 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,4 +1,4 @@
-site_name: AGL Application Framework Binder
+site_name: AGL Framework Binder
theme: readthedocs
docs_dir: docs
pages:
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c789fca3..ed59ac0c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -24,16 +24,18 @@ ADD_DEFINITIONS(-DBINDING_INSTALL_DIR="${binding_install_dir}")
# Always add INFER_EXTENSION (more details in afb-hreq.c)
ADD_DEFINITIONS(-DINFER_EXTENSION)
-ADD_LIBRARY(afb-lib STATIC
+SET(AFB_LIB_SOURCES
afb-api.c
- afb-api-dyn.c
afb-api-so.c
- afb-api-so-v1.c
afb-api-so-v2.c
+ afb-api-so-v3.c
afb-api-so-vdyn.c
+ afb-api-v3.c
afb-api-ws.c
afb-apiset.c
afb-auth.c
+ afb-autoset.c
+ afb-calls.c
afb-common.c
afb-config.c
afb-context.c
@@ -66,6 +68,7 @@ ADD_LIBRARY(afb-lib STATIC
fdev-systemd.c
jobs.c
locale-root.c
+ pearson.c
process-name.c
sig-monitor.c
subpath.c
@@ -74,15 +77,26 @@ ADD_LIBRARY(afb-lib STATIC
wrap-json.c
)
+IF(INCLUDE_LEGACY_BINDING_V1)
+ ADD_DEFINITIONS(-DWITH_LEGACY_BINDING_V1)
+ SET(AFB_LIB_SOURCES ${AFB_LIB_SOURCES} afb-api-so-v1.c)
+ENDIF(INCLUDE_LEGACY_BINDING_V1)
+IF(INCLUDE_LEGACY_BINDING_VDYN)
+ ADD_DEFINITIONS(-DWITH_LEGACY_BINDING_VDYN)
+ SET(AFB_LIB_SOURCES ${AFB_LIB_SOURCES} afb-api-so-vdyn.c)
+ENDIF(INCLUDE_LEGACY_BINDING_VDYN)
+
IF(INCLUDE_DBUS_TRANSPARENCY)
ADD_DEFINITIONS(-DWITH_DBUS_TRANSPARENCY)
- TARGET_SOURCES(afb-lib PUBLIC afb-api-dbus.c)
+ SET(AFB_LIB_SOURCES ${AFB_LIB_SOURCES} afb-api-dbus.c)
ENDIF()
+ADD_LIBRARY(afb-lib STATIC ${AFB_LIB_SOURCES})
+
###########################################
# build and install afb-daemon
###########################################
-ADD_EXECUTABLE(afb-daemon main.c)
+ADD_EXECUTABLE(afb-daemon main-afb-daemon.c)
TARGET_LINK_LIBRARIES(afb-daemon
afb-lib
${link_libraries}
@@ -94,7 +108,7 @@ INSTALL(TARGETS afb-daemon
# build and install afb-daemon
###########################################
IF(INCLUDE_SUPERVISOR)
- ADD_EXECUTABLE(afs-supervisor afs-main.c afs-supervisor.c afs-discover.c afs-config.c)
+ ADD_EXECUTABLE(afs-supervisor main-afs-supervisor.c afs-supervisor.c afs-discover.c afs-config.c)
TARGET_LINK_LIBRARIES(afs-supervisor
afb-lib
${link_libraries}
@@ -124,7 +138,7 @@ INSTALL(FILES afb-wsj1.h afb-ws-client.h afb-proto-ws.h DESTINATION ${CMAKE_INST
###########################################
# build and install afb-client-demo
###########################################
-ADD_EXECUTABLE(afb-client-demo afb-client-demo.c)
+ADD_EXECUTABLE(afb-client-demo main-afb-client-demo.c)
TARGET_LINK_LIBRARIES(afb-client-demo
afbwsc
${link_libraries}
diff --git a/src/afb-api-dbus.c b/src/afb-api-dbus.c
index 98c26930..a1e15fd3 100644
--- a/src/afb-api-dbus.c
+++ b/src/afb-api-dbus.c
@@ -27,7 +27,7 @@
#include <systemd/sd-bus.h>
#include <json-c/json.h>
-#include <afb/afb-event.h>
+#include <afb/afb-event-x2.h>
#include "afb-systemd.h"
@@ -76,9 +76,6 @@ struct api_dbus
};
};
-#define RETOK 1
-#define RETERR 2
-
/******************* common part **********************************/
/*
@@ -113,7 +110,7 @@ static struct api_dbus *make_api_dbus_3(int system, const char *path, size_t pat
goto error2;
}
api->api++;
- if (!afb_api_is_valid_name(api->api, 1)) {
+ if (!afb_api_is_valid_name(api->api)) {
errno = EINVAL;
goto error2;
}
@@ -226,7 +223,7 @@ struct dbus_memo {
struct dbus_event
{
struct dbus_event *next;
- struct afb_eventid *eventid;
+ struct afb_event_x2 *event;
int id;
int refcount;
};
@@ -283,32 +280,19 @@ static int api_dbus_client_on_reply(sd_bus_message *message, void *userdata, sd_
{
int rc;
struct dbus_memo *memo;
- const char *first, *second;
- uint8_t type;
- uint32_t flags;
+ const char *json, *error, *info;
/* retrieve the recorded data */
memo = userdata;
/* get the answer */
- rc = sd_bus_message_read(message, "yssu", &type, &first, &second, &flags);
+ rc = sd_bus_message_read(message, "sss", &json, &error, &info);
if (rc < 0) {
/* failing to have the answer */
- afb_xreq_fail(memo->xreq, "error", "dbus error");
+ afb_xreq_reply(memo->xreq, NULL, "error", "dbus error");
} else {
/* report the answer */
- memo->xreq->context.flags = (unsigned)flags;
- switch(type) {
- case RETOK:
- afb_xreq_success(memo->xreq, json_tokener_parse(first), *second ? second : NULL);
- break;
- case RETERR:
- afb_xreq_fail(memo->xreq, first, *second ? second : NULL);
- break;
- default:
- afb_xreq_fail(memo->xreq, "error", "dbus link broken");
- break;
- }
+ afb_xreq_reply(memo->xreq, *json ? json_tokener_parse(json) : NULL, *error ? error : NULL, *info ? info : NULL);
}
api_dbus_client_memo_destroy(memo);
return 1;
@@ -322,24 +306,27 @@ static void api_dbus_client_call(void *closure, struct afb_xreq *xreq)
int rc;
struct dbus_memo *memo;
struct sd_bus_message *msg;
+ const char *creds;
/* create the recording data */
memo = api_dbus_client_memo_make(api, xreq);
if (memo == NULL) {
- afb_xreq_fail(xreq, "error", "out of memory");
+ afb_xreq_reply(memo->xreq, NULL, "error", "out of memory");
return;
}
/* creates the message */
msg = NULL;
- rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, xreq->request.verb);
+ rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, xreq->request.called_verb);
if (rc < 0)
goto error;
- rc = sd_bus_message_append(msg, "ssu",
+ creds = xreq_on_behalf_cred_export(xreq);
+ rc = sd_bus_message_append(msg, "ssus",
afb_xreq_raw(xreq, &size),
afb_session_uuid(xreq->context.session),
- (uint32_t)xreq->context.flags);
+ (uint32_t)xreq->context.flags,
+ creds ?: "");
if (rc < 0)
goto error;
@@ -355,7 +342,7 @@ static void api_dbus_client_call(void *closure, struct afb_xreq *xreq)
error:
/* if there was an error report it directly */
errno = -rc;
- afb_xreq_fail(xreq, "error", "dbus error");
+ afb_xreq_reply(memo->xreq, NULL, "error", "dbus error");
api_dbus_client_memo_destroy(memo);
end:
sd_bus_message_unref(msg);
@@ -382,7 +369,7 @@ static struct dbus_event *api_dbus_client_event_search(struct api_dbus *api, int
struct dbus_event *ev;
ev = api->client.events;
- while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_eventid_fullname(ev->eventid), name)))
+ while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_event_x2_fullname(ev->event), name)))
ev = ev->next;
return ev;
@@ -403,8 +390,8 @@ static void api_dbus_client_event_create(struct api_dbus *api, int id, const cha
/* no conflict, try to add it */
ev = malloc(sizeof *ev);
if (ev != NULL) {
- ev->eventid = afb_evt_eventid_create(name);
- if (ev->eventid == NULL)
+ ev->event = afb_evt_event_x2_create(name);
+ if (ev->event == NULL)
free(ev);
else {
ev->refcount = 1;
@@ -440,7 +427,7 @@ static void api_dbus_client_event_drop(struct api_dbus *api, int id, const char
*prv = ev->next;
/* destroys the event */
- afb_evt_eventid_unref(ev->eventid);
+ afb_evt_event_x2_unref(ev->event);
free(ev);
}
@@ -459,7 +446,7 @@ static void api_dbus_client_event_push(struct api_dbus *api, int id, const char
/* destroys the event */
object = json_tokener_parse(data);
- afb_evt_eventid_push(ev->eventid, object);
+ afb_evt_event_x2_push(ev->event, object);
}
/* subscribes an event */
@@ -484,7 +471,7 @@ static void api_dbus_client_event_subscribe(struct api_dbus *api, int id, const
}
/* subscribe the request to the event */
- rc = afb_xreq_subscribe(memo->xreq, ev->eventid);
+ rc = afb_xreq_subscribe(memo->xreq, ev->event);
if (rc < 0)
ERROR("can't subscribe: %m");
}
@@ -511,7 +498,7 @@ static void api_dbus_client_event_unsubscribe(struct api_dbus *api, int id, cons
}
/* unsubscribe the request from the event */
- rc = afb_xreq_unsubscribe(memo->xreq, ev->eventid);
+ rc = afb_xreq_unsubscribe(memo->xreq, ev->event);
if (rc < 0)
ERROR("can't unsubscribe: %m");
}
@@ -572,11 +559,11 @@ static struct afb_api_itf dbus_api_itf = {
};
/* adds a afb-dbus-service client api */
-int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset)
+int afb_api_dbus_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
{
int rc;
struct api_dbus *api;
- struct afb_api afb_api;
+ struct afb_api_item afb_api;
char *match;
/* create the dbus client api */
@@ -611,7 +598,7 @@ int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset)
afb_api.closure = api;
afb_api.itf = &dbus_api_itf;
afb_api.group = NULL;
- if (afb_apiset_add(apiset, api->api, afb_api) < 0)
+ if (afb_apiset_add(declare_set, api->api, afb_api) < 0)
goto error2;
return 0;
@@ -816,77 +803,51 @@ static struct json_object *dbus_req_json(struct afb_xreq *xreq)
return dreq->json;
}
-/* get the argument of the request of 'name' */
-static void dbus_req_reply(struct dbus_req *dreq, uint8_t type, const char *first, const char *second)
+void dbus_req_raw_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info)
{
+ struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
int rc;
- rc = sd_bus_reply_method_return(dreq->message,
- "yssu", type, first ? : "", second ? : "", (uint32_t)dreq->xreq.context.flags);
+
+ rc = sd_bus_reply_method_return(dreq->message, "sss",
+ obj ? json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN) : "",
+ error ? : "",
+ info ? : "");
if (rc < 0)
ERROR("sending the reply failed");
}
-static void dbus_req_success(struct afb_xreq *xreq, struct json_object *obj, const char *info)
-{
- struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
-
- dbus_req_reply(dreq, RETOK, json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN), info);
-}
-
-static void dbus_req_fail(struct afb_xreq *xreq, const char *status, const char *info)
-{
- struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
-
- dbus_req_reply(dreq, RETERR, status, info);
-}
-
static void afb_api_dbus_server_event_send(struct origin *origin, char order, const char *event, int eventid, const char *data, uint64_t msgid);
-static int dbus_req_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid)
+static int dbus_req_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event)
{
struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
uint64_t msgid;
int rc;
- rc = afb_evt_eventid_add_watch(dreq->listener->listener, eventid);
+ rc = afb_evt_event_x2_add_watch(dreq->listener->listener, event);
sd_bus_message_get_cookie(dreq->message, &msgid);
- afb_api_dbus_server_event_send(dreq->listener->origin, 'S', afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), "", msgid);
+ afb_api_dbus_server_event_send(dreq->listener->origin, 'S', afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event), "", msgid);
return rc;
}
-static int dbus_req_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid)
+static int dbus_req_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event)
{
struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
uint64_t msgid;
int rc;
sd_bus_message_get_cookie(dreq->message, &msgid);
- afb_api_dbus_server_event_send(dreq->listener->origin, 'U', afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), "", msgid);
- rc = afb_evt_eventid_remove_watch(dreq->listener->listener, eventid);
+ afb_api_dbus_server_event_send(dreq->listener->origin, 'U', afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event), "", msgid);
+ rc = afb_evt_event_x2_remove_watch(dreq->listener->listener, event);
return rc;
}
-static void dbus_req_subcall(
- struct afb_xreq *xreq,
- const char *api,
- const char *verb,
- struct json_object *args,
- void (*callback)(void*, int, struct json_object*),
- void *cb_closure)
-{
- ERROR("DBUS API doesn't support subcalls, info: %s/%s(%s)", api, verb, json_object_to_json_string(args));
- callback(cb_closure, 1, afb_msg_json_reply_error("error", "subcall isn't supported", NULL, NULL));
- json_object_put(args);
-}
-
const struct afb_xreq_query_itf afb_api_dbus_xreq_itf = {
.json = dbus_req_json,
- .success = dbus_req_success,
- .fail = dbus_req_fail,
+ .reply = dbus_req_raw_reply,
.unref = dbus_req_destroy,
.subscribe = dbus_req_subscribe,
.unsubscribe = dbus_req_unsubscribe,
- .subcall = dbus_req_subcall
};
/******************* server part **********************************/
@@ -954,6 +915,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd
int rc;
const char *method;
const char *uuid;
+ const char *creds;
struct dbus_req *dreq;
struct api_dbus *api = userdata;
uint32_t flags;
@@ -973,7 +935,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd
goto out_of_memory;
/* get the data */
- rc = sd_bus_message_read(message, "ssu", &dreq->request, &uuid, &flags);
+ rc = sd_bus_message_read(message, "ssus", &dreq->request, &uuid, &flags, &creds);
if (rc < 0) {
sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_SIGNATURE, "invalid signature");
goto error;
@@ -992,6 +954,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd
/* fulfill the request and emit it */
dreq->xreq.context.flags = flags;
+ dreq->xreq.cred = afb_cred_mixed_on_behalf_import(listener->origin->cred, uuid, creds && creds[0] ? creds : NULL);
dreq->message = sd_bus_message_ref(message);
dreq->json = json_tokener_parse(dreq->request);
if (dreq->json == NULL && strcmp(dreq->request, "null")) {
@@ -999,8 +962,8 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd
dreq->json = json_object_new_string(dreq->request);
}
dreq->listener = listener;
- dreq->xreq.request.api = api->api;
- dreq->xreq.request.verb = method;
+ dreq->xreq.request.called_api = api->api;
+ dreq->xreq.request.called_verb = method;
afb_xreq_process(&dreq->xreq, api->server.apiset);
return 1;
@@ -1012,7 +975,7 @@ error:
}
/* create the service */
-int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset)
+int afb_api_dbus_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
{
int rc;
struct api_dbus *api;
@@ -1040,7 +1003,7 @@ int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset)
INFO("afb service over dbus installed, name %s, path %s", api->name, api->path);
api->server.listener = afb_evt_listener_create(&evt_broadcast_itf, api);
- api->server.apiset = afb_apiset_addref(apiset);
+ api->server.apiset = afb_apiset_addref(call_set);
return 0;
error3:
sd_bus_release_name(api->sdbus, api->name);
diff --git a/src/afb-api-dbus.h b/src/afb-api-dbus.h
index 90f20c16..1c47685b 100644
--- a/src/afb-api-dbus.h
+++ b/src/afb-api-dbus.h
@@ -20,8 +20,8 @@
struct afb_req_itf;
-extern int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset);
+extern int afb_api_dbus_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set);
-extern int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset);
+extern int afb_api_dbus_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set);
diff --git a/src/afb-api-dyn.c b/src/afb-api-dyn.c
deleted file mode 100644
index c2d6cdc4..00000000
--- a/src/afb-api-dyn.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _GNU_SOURCE
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <json-c/json.h>
-
-#define AFB_BINDING_VERSION 0
-#include <afb/afb-binding.h>
-
-#include "afb-api.h"
-#include "afb-api-dyn.h"
-#include "afb-apiset.h"
-#include "afb-auth.h"
-#include "afb-export.h"
-#include "afb-xreq.h"
-#include "verbose.h"
-
-/*
- * Description of a binding
- */
-struct afb_api_dyn {
- int count;
- struct afb_api_dyn_verb **verbs;
- const struct afb_verb_v2 *verbsv2;
- struct afb_export *export;
- char info[1];
-};
-
-void afb_api_dyn_set_verbs_v2(
- struct afb_api_dyn *dynapi,
- const struct afb_verb_v2 *verbs)
-{
- dynapi->verbsv2 = verbs;
-}
-
-int afb_api_dyn_add_verb(
- struct afb_api_dyn *dynapi,
- const char *verb,
- const char *info,
- void (*callback)(struct afb_request *request),
- void *vcbdata,
- const struct afb_auth *auth,
- uint32_t session)
-{
- struct afb_api_dyn_verb *v, **vv;
-
- afb_api_dyn_sub_verb(dynapi, verb);
-
- vv = realloc(dynapi->verbs, (1 + dynapi->count) * sizeof *vv);
- if (!vv)
- goto oom;
- dynapi->verbs = vv;
-
- v = malloc(sizeof *v + strlen(verb) + (info ? 1 + strlen(info) : 0));
- if (!v)
- goto oom;
-
- v->callback = callback;
- v->vcbdata = vcbdata;
- v->auth = auth;
- v->session = session;
-
- v->info = 1 + stpcpy(v->verb, verb);
- if (info)
- strcpy((char*)v->info, info);
- else
- v->info = NULL;
-
- dynapi->verbs[dynapi->count++] = v;
- return 0;
-oom:
- errno = ENOMEM;
- return -1;
-}
-
-int afb_api_dyn_sub_verb(
- struct afb_api_dyn *dynapi,
- const char *verb)
-{
- struct afb_api_dyn_verb *v;
- int i;
-
- /* look first in dyna mic verbs */
- for (i = 0 ; i < dynapi->count ; i++) {
- v = dynapi->verbs[i];
- if (!strcasecmp(v->verb, verb)) {
- if (i != --dynapi->count)
- dynapi->verbs[i] = dynapi->verbs[dynapi->count];
- free(v);
- return 0;
- }
- }
-
- errno = ENOENT;
- return -1;
-}
-
-static void call_cb(void *closure, struct afb_xreq *xreq)
-{
- struct afb_api_dyn *dynapi = closure;
- struct afb_api_dyn_verb **verbs, *v;
- const struct afb_verb_v2 *verbsv2;
- int i;
- const char *name;
-
- name = xreq->request.verb;
- xreq->request.dynapi = (void*)dynapi->export; /* hack: this avoids to export afb_export structure */
-
- /* look first in dyna mic verbs */
- verbs = dynapi->verbs;
- i = dynapi->count;
- while (i) {
- v = verbs[--i];
- if (!strcasecmp(v->verb, name)) {
- xreq->request.vcbdata = v->vcbdata;
- afb_xreq_call_verb_vdyn(xreq, verbs[i]);
- return;
- }
- }
-
- verbsv2 = dynapi->verbsv2;
- if (verbsv2) {
- while (verbsv2->verb) {
- if (strcasecmp(verbsv2->verb, name))
- verbsv2++;
- else {
- afb_xreq_call_verb_v2(xreq, verbsv2);
- return;
- }
- }
- }
-
- afb_xreq_fail_unknown_verb(xreq);
-}
-
-static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset)
-{
- struct afb_api_dyn *dynapi = closure;
- return afb_export_start(dynapi->export, share_session, onneed, apiset);
-}
-
-static void update_hooks_cb(void *closure)
-{
- struct afb_api_dyn *dynapi = closure;
- afb_export_update_hook(dynapi->export);
-}
-
-static int get_verbosity_cb(void *closure)
-{
- struct afb_api_dyn *dynapi = closure;
- return afb_export_verbosity_get(dynapi->export);
-}
-
-static void set_verbosity_cb(void *closure, int level)
-{
- struct afb_api_dyn *dynapi = closure;
- afb_export_verbosity_set(dynapi->export, level);
-}
-
-static struct json_object *make_description_openAPIv3(struct afb_api_dyn *dynapi)
-{
- char buffer[256];
- struct afb_api_dyn_verb **iter, **end, *verb;
- struct json_object *r, *f, *a, *i, *p, *g;
-
- r = json_object_new_object();
- json_object_object_add(r, "openapi", json_object_new_string("3.0.0"));
-
- i = json_object_new_object();
- json_object_object_add(r, "info", i);
- json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(dynapi->export)));
- json_object_object_add(i, "version", json_object_new_string("0.0.0"));
- json_object_object_add(i, "description", json_object_new_string(dynapi->info));
-
- p = json_object_new_object();
- json_object_object_add(r, "paths", p);
- iter = dynapi->verbs;
- end = iter + dynapi->count;
- while (iter != end) {
- verb = *iter++;
- buffer[0] = '/';
- strncpy(buffer + 1, verb->verb, sizeof buffer - 1);
- buffer[sizeof buffer - 1] = 0;
- f = json_object_new_object();
- json_object_object_add(p, buffer, f);
- g = json_object_new_object();
- json_object_object_add(f, "get", g);
-
- a = afb_auth_json_v2(verb->auth, verb->session);
- if (a)
- json_object_object_add(g, "x-permissions", a);
-
- a = json_object_new_object();
- json_object_object_add(g, "responses", a);
- f = json_object_new_object();
- json_object_object_add(a, "200", f);
- json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb));
- }
- return r;
-}
-
-static struct json_object *describe_cb(void *closure)
-{
- struct afb_api_dyn *dynapi = closure;
- struct json_object *r = make_description_openAPIv3(dynapi);
- return r;
-}
-
-static struct afb_api_itf dyn_api_itf = {
- .call = call_cb,
- .service_start = service_start_cb,
- .update_hooks = update_hooks_cb,
- .get_verbosity = get_verbosity_cb,
- .set_verbosity = set_verbosity_cb,
- .describe = describe_cb
-};
-
-int afb_api_dyn_add(struct afb_apiset *apiset, const char *name, const char *info, int noconcurrency, int (*preinit)(void*, struct afb_dynapi*), void *closure)
-{
- int rc;
- struct afb_api_dyn *dynapi;
- struct afb_api afb_api;
- struct afb_export *export;
-
- INFO("Starting creation of dynamic API %s", name);
-
- /* allocates the description */
- info = info ?: "";
- dynapi = calloc(1, sizeof *dynapi + strlen(info));
- export = afb_export_create_vdyn(apiset, name, dynapi);
- if (!dynapi || !export) {
- ERROR("out of memory");
- goto error;
- }
- strcpy(dynapi->info, info);
- dynapi->export = export;
-
- /* preinit the api */
- rc = afb_export_preinit_vdyn(export, preinit, closure);
- if (rc < 0) {
- ERROR("dynamic api %s preinit function failed, ABORTING it!",
- afb_export_apiname(dynapi->export));
- goto error;
- }
-
- /* records the binding */
- afb_api.closure = dynapi;
- afb_api.itf = &dyn_api_itf;
- afb_api.group = noconcurrency ? dynapi : NULL;
- if (afb_apiset_add(apiset, afb_export_apiname(dynapi->export), afb_api) < 0) {
- ERROR("dynamic api %s can't be registered to set %s, ABORTING it!",
- afb_export_apiname(dynapi->export),
- afb_apiset_name(apiset));
- goto error;
- }
- INFO("binding %s added to set %s", afb_export_apiname(dynapi->export), afb_apiset_name(apiset));
- return 0;
-
-error:
- afb_export_destroy(export);
- free(dynapi);
-
- return -1;
-}
-
diff --git a/src/afb-api-dyn.h b/src/afb-api-dyn.h
deleted file mode 100644
index 107d944e..00000000
--- a/src/afb-api-dyn.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author: José Bollo <jose.bollo@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#pragma once
-
-struct afb_apiset;
-struct afb_dynapi;
-struct afb_auth;
-struct afb_request;
-struct afb_verb_v2;
-
-struct afb_api_dyn_verb
-{
- void (*callback)(struct afb_request *request);
- void *vcbdata;
- const struct afb_auth *auth;
- const char *info;
- int session;
- char verb[1];
-};
-
-struct afb_api_dyn;
-
-extern int afb_api_dyn_add(
- struct afb_apiset *apiset,
- const char *name,
- const char *info,
- int noconcurrency,
- int (*preinit)(void*, struct afb_dynapi*),
- void *closure);
-
-extern void afb_api_dyn_set_verbs_v2(
- struct afb_api_dyn *dynapi,
- const struct afb_verb_v2 *verbs);
-
-extern int afb_api_dyn_add_verb(
- struct afb_api_dyn *dynapi,
- const char *verb,
- const char *info,
- void (*callback)(struct afb_request *request),
- void *vcbdata,
- const struct afb_auth *auth,
- uint32_t session);
-
-extern int afb_api_dyn_sub_verb(
- struct afb_api_dyn *dynapi,
- const char *verb);
-
diff --git a/src/afb-api-so-v1.c b/src/afb-api-so-v1.c
index 985a113d..7db686d8 100644
--- a/src/afb-api-so-v1.c
+++ b/src/afb-api-so-v1.c
@@ -21,9 +21,9 @@
#include <string.h>
#include <dlfcn.h>
#include <assert.h>
+#include <stdarg.h>
#include <json-c/json.h>
-
#include <afb/afb-binding-v1.h>
#include "afb-api.h"
@@ -43,59 +43,24 @@ static const char afb_api_so_v1_register[] = "afbBindingV1Register";
static const char afb_api_so_v1_service_init[] = "afbBindingV1ServiceInit";
static const char afb_api_so_v1_service_event[] = "afbBindingV1ServiceEvent";
-/*
- * Description of a binding
- */
-struct api_so_v1 {
- struct afb_binding_v1 *binding; /* descriptor */
- void *handle; /* context of dlopen */
- struct afb_export *export; /* export */
-};
-
-static const struct afb_verb_desc_v1 *search(struct api_so_v1 *desc, const char *name)
+static const struct afb_verb_desc_v1 *search(struct afb_binding_v1 *binding, const char *name)
{
const struct afb_verb_desc_v1 *verb;
- verb = desc->binding->v1.verbs;
+ verb = binding->v1.verbs;
while (verb->name && strcasecmp(verb->name, name))
verb++;
return verb->name ? verb : NULL;
}
-static void call_cb(void *closure, struct afb_xreq *xreq)
+void afb_api_so_v1_process_call(struct afb_binding_v1 *binding, struct afb_xreq *xreq)
{
const struct afb_verb_desc_v1 *verb;
- struct api_so_v1 *desc = closure;
- xreq->request.dynapi = (void*)desc->export; /* hack: this avoids to export afb_export structure */
- verb = search(desc, xreq->request.verb);
+ verb = search(binding, xreq->request.called_verb);
afb_xreq_call_verb_v1(xreq, verb);
}
-static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset)
-{
- struct api_so_v1 *desc = closure;
- return afb_export_start(desc->export, share_session, onneed, apiset);
-}
-
-static void update_hooks_cb(void *closure)
-{
- struct api_so_v1 *desc = closure;
- afb_export_update_hook(desc->export);
-}
-
-static int get_verbosity_cb(void *closure)
-{
- struct api_so_v1 *desc = closure;
- return afb_export_verbosity_get(desc->export);
-}
-
-static void set_verbosity_cb(void *closure, int level)
-{
- struct api_so_v1 *desc = closure;
- afb_export_verbosity_set(desc->export, level);
-}
-
static struct json_object *addperm(struct json_object *o, struct json_object *x)
{
struct json_object *a;
@@ -130,7 +95,7 @@ static struct json_object *addperm_key_valint(struct json_object *o, const char
return addperm_key_val(o, key, json_object_new_int(val));
}
-static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc)
+struct json_object *afb_api_so_v1_make_description_openAPIv3(struct afb_binding_v1 *binding, const char *apiname)
{
char buffer[256];
const struct afb_verb_desc_v1 *verb;
@@ -141,13 +106,13 @@ static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc)
i = json_object_new_object();
json_object_object_add(r, "info", i);
- json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(desc->export)));
+ json_object_object_add(i, "title", json_object_new_string(apiname));
json_object_object_add(i, "version", json_object_new_string("0.0.0"));
- json_object_object_add(i, "description", json_object_new_string(desc->binding->v1.info ?: afb_export_apiname(desc->export)));
+ json_object_object_add(i, "description", json_object_new_string(binding->v1.info ?: apiname));
p = json_object_new_object();
json_object_object_add(r, "paths", p);
- verb = desc->binding->v1.verbs;
+ verb = binding->v1.verbs;
while (verb->name) {
buffer[0] = '/';
strncpy(buffer + 1, verb->name, sizeof buffer - 1);
@@ -158,14 +123,14 @@ static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc)
json_object_object_add(f, "get", g);
a = NULL;
- if (verb->session & AFB_SESSION_CLOSE_V1)
+ if (verb->session & AFB_SESSION_CLOSE_X1)
a = addperm_key_valstr(a, "session", "close");
- if (verb->session & AFB_SESSION_CHECK_V1)
+ if (verb->session & AFB_SESSION_CHECK_X1)
a = addperm_key_valstr(a, "session", "check");
- if (verb->session & AFB_SESSION_RENEW_V1)
+ if (verb->session & AFB_SESSION_RENEW_X1)
a = addperm_key_valstr(a, "token", "refresh");
- if (verb->session & AFB_SESSION_LOA_MASK_V1)
- a = addperm_key_valint(a, "LOA", (verb->session >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1);
+ if (verb->session & AFB_SESSION_LOA_MASK_X1)
+ a = addperm_key_valint(a, "LOA", (verb->session >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1);
if (a)
json_object_object_add(g, "x-permissions", a);
@@ -179,95 +144,75 @@ static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc)
return r;
}
-static struct json_object *describe_cb(void *closure)
+int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set)
{
- struct api_so_v1 *desc = closure;
-
- return make_description_openAPIv3(desc);
-}
-
-static struct afb_api_itf so_v1_api_itf = {
- .call = call_cb,
- .service_start = service_start_cb,
- .update_hooks = update_hooks_cb,
- .get_verbosity = get_verbosity_cb,
- .set_verbosity = set_verbosity_cb,
- .describe = describe_cb
-};
-
-int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *apiset)
-{
- struct api_so_v1 *desc;
+ struct afb_binding_v1 *binding; /* descriptor */
struct afb_binding_v1 *(*register_function) (const struct afb_binding_interface_v1 *interface);
- int (*init)(struct afb_service service);
+ int (*init)(struct afb_service_x1 service);
void (*onevent)(const char *event, struct json_object *object);
- struct afb_api afb_api;
struct afb_export *export;
/* retrieves the register function */
register_function = dlsym(handle, afb_api_so_v1_register);
if (!register_function)
return 0;
+
INFO("binding [%s] is a valid AFB binding V1", path);
/* allocates the description */
init = dlsym(handle, afb_api_so_v1_service_init);
onevent = dlsym(handle, afb_api_so_v1_service_event);
- export = afb_export_create_v1(apiset, path, init, onevent);
- desc = calloc(1, sizeof *desc);
- if (desc == NULL || export == NULL) {
- ERROR("out of memory");
+ export = afb_export_create_v1(declare_set, call_set, path, init, onevent);
+ if (export == NULL) {
+ ERROR("binding [%s] creation failure...", path);
goto error;
}
- desc->export = export;
- desc->handle = handle;
-
- /* init the binding */
- INFO("binding [%s] calling registering function %s", path, afb_api_so_v1_register);
- desc->binding = afb_export_register_v1(desc->export, register_function);
- if (desc->binding == NULL) {
- ERROR("binding [%s] register function failed. continuing...", path);
+ binding = afb_export_register_v1(export, register_function);
+ if (binding == NULL) {
+ ERROR("binding [%s] register failure...", path);
goto error;
}
/* check the returned structure */
- if (desc->binding->type != AFB_BINDING_VERSION_1) {
- ERROR("binding [%s] invalid type %d...", path, desc->binding->type);
+ if (binding->type != AFB_BINDING_VERSION_1) {
+ ERROR("binding [%s] invalid type %d...", path, binding->type);
goto error;
}
- if (desc->binding->v1.prefix == NULL || *desc->binding->v1.prefix == 0) {
+ if (binding->v1.prefix == NULL || *binding->v1.prefix == 0) {
ERROR("binding [%s] bad prefix...", path);
goto error;
}
- if (!afb_api_is_valid_name(desc->binding->v1.prefix, 1)) {
+ if (!afb_api_is_valid_name(binding->v1.prefix)) {
ERROR("binding [%s] invalid prefix...", path);
goto error;
}
- if (desc->binding->v1.info == NULL || *desc->binding->v1.info == 0) {
+ if (binding->v1.info == NULL || *binding->v1.info == 0) {
ERROR("binding [%s] bad description...", path);
goto error;
}
- if (desc->binding->v1.verbs == NULL) {
- ERROR("binding [%s] no APIs...", path);
+ if (binding->v1.verbs == NULL) {
+ ERROR("binding [%s] no verbs...", path);
goto error;
}
/* records the binding */
- if (!strcmp(path, afb_export_apiname(desc->export)))
- afb_export_rename(desc->export, desc->binding->v1.prefix);
- afb_api.closure = desc;
- afb_api.itf = &so_v1_api_itf;
- afb_api.group = NULL;
- if (afb_apiset_add(apiset, afb_export_apiname(desc->export), afb_api) < 0) {
+ if (!strcmp(path, afb_export_apiname(export))) {
+ if (afb_export_rename(export, binding->v1.prefix) < 0) {
+ ERROR("binding [%s] can't be renamed to %s", path, binding->v1.prefix);
+ goto error;
+ }
+ }
+
+ if (afb_export_declare(export, 0) < 0) {
ERROR("binding [%s] can't be registered...", path);
goto error;
}
- INFO("binding %s loaded with API prefix %s", path, afb_export_apiname(desc->export));
+ INFO("binding %s loaded with API prefix %s", path, afb_export_apiname(export));
+ afb_export_unref(export);
return 1;
error:
- afb_export_destroy(export);
- free(desc);
+ afb_export_unref(export);
return -1;
}
diff --git a/src/afb-api-so-v1.h b/src/afb-api-so-v1.h
index 42f18a19..ebe00950 100644
--- a/src/afb-api-so-v1.h
+++ b/src/afb-api-so-v1.h
@@ -18,4 +18,12 @@
#pragma once
-extern int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *apiset);
+struct afb_apiset;
+struct afb_binding_v1;
+struct afb_xreq;
+struct json_object;
+
+extern int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set);
+
+extern void afb_api_so_v1_process_call(struct afb_binding_v1 *binding, struct afb_xreq *xreq);
+extern struct json_object *afb_api_so_v1_make_description_openAPIv3(struct afb_binding_v1 *binding, const char *apiname);
diff --git a/src/afb-api-so-v2.c b/src/afb-api-so-v2.c
index fb901f58..a13c00e4 100644
--- a/src/afb-api-so-v2.c
+++ b/src/afb-api-so-v2.c
@@ -21,9 +21,10 @@
#include <string.h>
#include <dlfcn.h>
#include <assert.h>
+#include <stdarg.h>
-#include <afb/afb-binding-v2.h>
#include <json-c/json.h>
+#include <afb/afb-binding-v2.h>
#include "afb-api.h"
#include "afb-api-so-v2.h"
@@ -42,78 +43,50 @@
static const char afb_api_so_v2_descriptor[] = "afbBindingV2";
static const char afb_api_so_v2_data[] = "afbBindingV2data";
-/*
- * Description of a binding
- */
-struct api_so_v2 {
- const struct afb_binding_v2 *binding; /* descriptor */
- void *handle; /* context of dlopen */
- struct afb_export *export; /* exportations */
-};
-
-static const struct afb_verb_v2 *search(struct api_so_v2 *desc, const char *name)
+static const struct afb_verb_v2 *search(const struct afb_binding_v2 *binding, const char *name)
{
const struct afb_verb_v2 *verb;
- verb = desc->binding->verbs;
+ verb = binding->verbs;
while (verb->verb && strcasecmp(verb->verb, name))
verb++;
return verb->verb ? verb : NULL;
return NULL;
}
-static void call_cb(void *closure, struct afb_xreq *xreq)
+void afb_api_so_v2_process_call(const struct afb_binding_v2 *binding, struct afb_xreq *xreq)
{
- struct api_so_v2 *desc = closure;
const struct afb_verb_v2 *verb;
- xreq->request.dynapi = (void*)desc->export; /* hack: this avoids to export afb_export structure */
- verb = search(desc, xreq->request.verb);
+ verb = search(binding, xreq->request.called_verb);
afb_xreq_call_verb_v2(xreq, verb);
}
-static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset)
-{
- struct api_so_v2 *desc = closure;
- return afb_export_start(desc->export, share_session, onneed, apiset);
-}
-
-static void update_hooks_cb(void *closure)
-{
- struct api_so_v2 *desc = closure;
- afb_export_update_hook(desc->export);
-}
-
-static int get_verbosity_cb(void *closure)
-{
- struct api_so_v2 *desc = closure;
- return afb_export_verbosity_get(desc->export);
-}
-
-static void set_verbosity_cb(void *closure, int level)
-{
- struct api_so_v2 *desc = closure;
- afb_export_verbosity_set(desc->export, level);
-}
-
-static struct json_object *make_description_openAPIv3(struct api_so_v2 *desc)
+struct json_object *afb_api_so_v2_make_description_openAPIv3(const struct afb_binding_v2 *binding, const char *apiname)
{
char buffer[256];
const struct afb_verb_v2 *verb;
struct json_object *r, *f, *a, *i, *p, *g;
+
+ if (binding->specification) {
+ r = json_tokener_parse(binding->specification);
+ if (r)
+ return r;
+ }
+
r = json_object_new_object();
json_object_object_add(r, "openapi", json_object_new_string("3.0.0"));
i = json_object_new_object();
json_object_object_add(r, "info", i);
- json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(desc->export)));
+ json_object_object_add(i, "title", json_object_new_string(apiname));
json_object_object_add(i, "version", json_object_new_string("0.0.0"));
- json_object_object_add(i, "description", json_object_new_string(desc->binding->info ?: afb_export_apiname(desc->export)));
+ json_object_object_add(i, "description", json_object_new_string(binding->info ?: apiname));
p = json_object_new_object();
json_object_object_add(r, "paths", p);
- verb = desc->binding->verbs;
+ verb = binding->verbs;
while (verb->verb) {
buffer[0] = '/';
strncpy(buffer + 1, verb->verb, sizeof buffer - 1);
@@ -137,29 +110,9 @@ static struct json_object *make_description_openAPIv3(struct api_so_v2 *desc)
return r;
}
-static struct json_object *describe_cb(void *closure)
-{
- struct api_so_v2 *desc = closure;
- struct json_object *r = desc->binding->specification ? json_tokener_parse(desc->binding->specification) : NULL;
- if (!r)
- r = make_description_openAPIv3(desc);
- return r;
-}
-
-static struct afb_api_itf so_v2_api_itf = {
- .call = call_cb,
- .service_start = service_start_cb,
- .update_hooks = update_hooks_cb,
- .get_verbosity = get_verbosity_cb,
- .set_verbosity = set_verbosity_cb,
- .describe = describe_cb
-};
-
-int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *apiset, struct afb_binding_data_v2 *data)
+int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set, struct afb_binding_data_v2 *data)
{
int rc;
- struct api_so_v2 *desc;
- struct afb_api afb_api;
struct afb_export *export;
/* basic checks */
@@ -169,45 +122,38 @@ int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle
assert(data);
/* allocates the description */
- export = afb_export_create_v2(apiset, binding->api, data, binding->init, binding->onevent);
- desc = calloc(1, sizeof *desc);
- if (!desc || !export) {
+ export = afb_export_create_v2(declare_set, call_set, binding->api, binding, data, binding->init, binding->onevent);
+ if (!export) {
ERROR("out of memory");
goto error;
}
- desc->binding = binding;
- desc->handle = handle;
- desc->export = export;
+ /* records the binding */
+ if (afb_export_declare(export, binding->noconcurrency) < 0) {
+ ERROR("binding %s can't be registered to set %s...", afb_export_apiname(export), afb_apiset_name(declare_set));
+ goto error;
+ }
/* init the binding */
if (binding->preinit) {
INFO("binding %s calling preinit function", binding->api);
rc = binding->preinit();
if (rc < 0) {
- ERROR("binding %s preinit function failed...", afb_export_apiname(desc->export));
+ ERROR("binding %s preinit function failed...", afb_export_apiname(export));
+ afb_export_undeclare(export);
goto error;
}
}
- /* records the binding */
- afb_api.closure = desc;
- afb_api.itf = &so_v2_api_itf;
- afb_api.group = binding->noconcurrency ? export : NULL;
- if (afb_apiset_add(apiset, afb_export_apiname(desc->export), afb_api) < 0) {
- ERROR("binding %s can't be registered to set %s...", afb_export_apiname(desc->export), afb_apiset_name(apiset));
- goto error;
- }
- INFO("binding %s added to set %s", afb_export_apiname(desc->export), afb_apiset_name(apiset));
+ INFO("binding %s added to set %s", afb_export_apiname(export), afb_apiset_name(declare_set));
return 1;
error:
- afb_export_destroy(export);
- free(desc);
+ afb_export_unref(export);
return -1;
}
-int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset)
+int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set)
{
const struct afb_binding_v2 *binding;
struct afb_binding_data_v2 *data;
@@ -230,22 +176,17 @@ int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset)
ERROR("binding [%s] bad api name...", path);
goto error;
}
- if (!afb_api_is_valid_name(binding->api, 1)) {
+ if (!afb_api_is_valid_name(binding->api)) {
ERROR("binding [%s] invalid api name...", path);
goto error;
}
-#if 0
- if (binding->specification == NULL || *binding->specification == 0) {
- ERROR("binding [%s] bad specification...", path);
- goto error;
- }
-#endif
+
if (binding->verbs == NULL) {
ERROR("binding [%s] no verbs...", path);
goto error;
}
- return afb_api_so_v2_add_binding(binding, handle, apiset, data);
+ return afb_api_so_v2_add_binding(binding, handle, declare_set, call_set, data);
error:
return -1;
diff --git a/src/afb-api-so-v2.h b/src/afb-api-so-v2.h
index 87cd80d5..d53206d3 100644
--- a/src/afb-api-so-v2.h
+++ b/src/afb-api-so-v2.h
@@ -21,6 +21,11 @@
struct afb_apiset;
struct afb_binding_v2;
struct afb_binding_data_v2;
+struct afb_xreq;
+struct json_object;
-extern int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset);
-extern int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *apiset, struct afb_binding_data_v2 *data);
+extern int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set);
+extern int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set, struct afb_binding_data_v2 *data);
+
+extern void afb_api_so_v2_process_call(const struct afb_binding_v2 *binding, struct afb_xreq *xreq);
+extern struct json_object *afb_api_so_v2_make_description_openAPIv3(const struct afb_binding_v2 *binding, const char *apiname);
diff --git a/src/afb-api-so-v3.c b/src/afb-api-so-v3.c
new file mode 100644
index 00000000..415c13d9
--- /dev/null
+++ b/src/afb-api-so-v3.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include <json-c/json.h>
+#include <afb/afb-binding-v3.h>
+
+#include "afb-api.h"
+#include "afb-api-so-v3.h"
+#include "afb-api-v3.h"
+#include "afb-apiset.h"
+#include "afb-export.h"
+#include "verbose.h"
+
+/*
+ * names of symbols
+ */
+static const char afb_api_so_v3_desc[] = "afbBindingV3";
+static const char afb_api_so_v3_root[] = "afbBindingV3root";
+static const char afb_api_so_v3_entry[] = "afbBindingV3entry";
+
+struct args
+{
+ struct afb_api_x3 **root;
+ const struct afb_binding_v3 *desc;
+ int (*entry)(struct afb_api_x3 *);
+};
+
+static int init(void *closure, struct afb_api_x3 *api)
+{
+ const struct args *a = closure;
+ int rc = 0;
+
+ *a->root = api;
+ if (a->desc) {
+ api->userdata = a->desc->userdata;
+ rc = afb_api_v3_set_binding_fields(a->desc, api);
+ }
+
+ if (rc >= 0 && a->entry)
+ rc = a->entry(api);
+
+ if (rc >= 0)
+ afb_api_x3_seal(api);
+
+ return rc;
+}
+
+int afb_api_so_v3_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set)
+{
+ struct args a;
+ struct afb_api_v3 *api;
+ struct afb_export *export;
+
+ /* retrieves the register function */
+ a.root = dlsym(handle, afb_api_so_v3_root);
+ a.desc = dlsym(handle, afb_api_so_v3_desc);
+ a.entry = dlsym(handle, afb_api_so_v3_entry);
+ if (!a.root && !a.desc && !a.entry)
+ return 0;
+
+ INFO("binding [%s] looks like an AFB binding V3", path);
+
+ /* basic checks */
+ if (!a.root) {
+ ERROR("binding [%s] incomplete symbol set: %s is missing",
+ path, afb_api_so_v3_root);
+ goto error;
+ }
+ if (a.desc) {
+ if (a.desc->api == NULL || *a.desc->api == 0) {
+ ERROR("binding [%s] bad api name...", path);
+ goto error;
+ }
+ if (!afb_api_is_valid_name(a.desc->api)) {
+ ERROR("binding [%s] invalid api name...", path);
+ goto error;
+ }
+ if (!a.entry)
+ a.entry = a.desc->preinit;
+ else if (a.desc->preinit) {
+ ERROR("binding [%s] clash: you can't define %s and %s.preinit, choose only one",
+ path, afb_api_so_v3_entry, afb_api_so_v3_desc);
+ goto error;
+ }
+
+ api = afb_api_v3_create(declare_set, call_set, a.desc->api, a.desc->info, a.desc->noconcurrency, init, &a, 0);
+ if (api)
+ return 1;
+ } else {
+ if (!a.entry) {
+ ERROR("binding [%s] incomplete symbol set: %s is missing",
+ path, afb_api_so_v3_entry);
+ goto error;
+ }
+
+ export = afb_export_create_none_for_path(declare_set, call_set, path, init, &a);
+ if (export)
+ return 1;
+ }
+
+ ERROR("binding [%s] initialisation failed", path);
+
+error:
+ return -1;
+}
+
diff --git a/src/afb-api-so-v3.h b/src/afb-api-so-v3.h
new file mode 100644
index 00000000..52ec22ac
--- /dev/null
+++ b/src/afb-api-so-v3.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+struct afb_apiset;
+
+extern int afb_api_so_v3_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set);
diff --git a/src/afb-api-so-vdyn.c b/src/afb-api-so-vdyn.c
index 300aa130..17344945 100644
--- a/src/afb-api-so-vdyn.c
+++ b/src/afb-api-so-vdyn.c
@@ -20,6 +20,10 @@
#include <stdlib.h>
#include <dlfcn.h>
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
+
+#include "afb-api-so-v3.h"
#include "afb-api-so-vdyn.h"
#include "afb-export.h"
#include "verbose.h"
@@ -29,19 +33,15 @@
*/
static const char afb_api_so_vdyn_entry[] = "afbBindingVdyn";
-/*
- * Description of a binding
- */
-static int vdyn_preinit(void *closure, struct afb_dynapi *dynapi)
+static int preinit(void *closure, struct afb_api_x3 *api)
{
- int (*entry)(struct afb_dynapi*) = closure;
- return entry(dynapi);
+ int (*entry)(struct afb_api_x3*) = closure;
+ return entry(api);
}
-int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *apiset)
+int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set)
{
- int rc;
- int (*entry)(void*, struct afb_dynapi*);
+ int (*entry)(struct afb_api_x3*);
struct afb_export *export;
entry = dlsym(handle, afb_api_so_vdyn_entry);
@@ -50,15 +50,12 @@ int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *apise
INFO("binding [%s] looks like an AFB binding Vdyn", path);
- export = afb_export_create_vdyn(apiset, path, NULL);
+ export = afb_export_create_none_for_path(declare_set, call_set, path, preinit, entry);
if (!export) {
- ERROR("can't create export for %s", path);
+ INFO("binding [%s] creation failed", path);
return -1;
}
- INFO("binding [%s] calling dynamic initialisation %s", path, afb_api_so_vdyn_entry);
- rc = afb_export_preinit_vdyn(export, vdyn_preinit, entry);
- afb_export_destroy(export);
- return rc < 0 ? rc : 1;
+ return 1;
}
diff --git a/src/afb-api-so-vdyn.h b/src/afb-api-so-vdyn.h
index 05d96235..d8a43f75 100644
--- a/src/afb-api-so-vdyn.h
+++ b/src/afb-api-so-vdyn.h
@@ -20,4 +20,4 @@
struct afb_apiset;
-extern int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *apiset);
+extern int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set);
diff --git a/src/afb-api-so.c b/src/afb-api-so.c
index 87916cbb..3167ffad 100644
--- a/src/afb-api-so.c
+++ b/src/afb-api-so.c
@@ -25,12 +25,18 @@
#include <sys/stat.h>
#include "afb-api-so.h"
-#include "afb-api-so-v1.h"
#include "afb-api-so-v2.h"
-#include "afb-api-so-vdyn.h"
+#include "afb-api-so-v3.h"
#include "verbose.h"
#include "sig-monitor.h"
+#if defined(WITH_LEGACY_BINDING_V1)
+# include "afb-api-so-v1.h"
+#endif
+#if defined(WITH_LEGACY_BINDING_VDYN)
+# include "afb-api-so-vdyn.h"
+#endif
+
struct safe_dlopen
{
const char *path;
@@ -59,8 +65,9 @@ static void *safe_dlopen(const char *filename, int flags)
return sd.handle;
}
-static int load_binding(const char *path, int force, struct afb_apiset *apiset)
+static int load_binding(const char *path, int force, struct afb_apiset *declare_set, struct afb_apiset * call_set)
{
+ int obsolete = 0;
int rc;
void *handle;
@@ -76,7 +83,16 @@ static int load_binding(const char *path, int force, struct afb_apiset *apiset)
}
/* try the version 2 */
- rc = afb_api_so_v2_add(path, handle, apiset);
+ rc = afb_api_so_v3_add(path, handle, declare_set, call_set);
+ if (rc < 0) {
+ /* error when loading a valid v3 binding */
+ goto error2;
+ }
+ if (rc)
+ return 0; /* yes version 2 */
+
+ /* try the version 2 */
+ rc = afb_api_so_v2_add(path, handle, declare_set, call_set);
if (rc < 0) {
/* error when loading a valid v2 binding */
goto error2;
@@ -84,29 +100,41 @@ static int load_binding(const char *path, int force, struct afb_apiset *apiset)
if (rc)
return 0; /* yes version 2 */
+#if defined(WITH_LEGACY_BINDING_VDYN)
/* try the version dyn */
- rc = afb_api_so_vdyn_add(path, handle, apiset);
+ rc = afb_api_so_vdyn_add(path, handle, declare_set, call_set);
if (rc < 0) {
/* error when loading a valid dyn binding */
goto error2;
}
if (rc)
return 0; /* yes version dyn */
+#else
+ if (dlsym(handle, "afbBindingVdyn")) {
+ WARNING("binding [%s]: version DYN not supported", path);
+ obsolete = 1;
+ }
+#endif
+#if defined(WITH_LEGACY_BINDING_V1)
/* try the version 1 */
- rc = afb_api_so_v1_add(path, handle, apiset);
+ rc = afb_api_so_v1_add(path, handle, declare_set, call_set);
if (rc < 0) {
/* error when loading a valid v1 binding */
goto error2;
}
if (rc)
return 0; /* yes version 1 */
+#else
+ if (dlsym(handle, "afbBindingV1Register")) {
+ WARNING("binding [%s]: version 1 not supported", path);
+ obsolete = 1;
+ }
+#endif
/* not a valid binding */
- if (force)
- ERROR("binding [%s] is not an AFB binding", path);
- else
- INFO("binding [%s] is not an AFB binding", path);
+ _VERBOSE_(force ? Log_Level_Error : Log_Level_Info, "binding [%s] %s",
+ path, obsolete ? "is obsolete" : "isn't an AFB binding");
error2:
dlclose(handle);
@@ -115,12 +143,12 @@ error:
}
-int afb_api_so_add_binding(const char *path, struct afb_apiset *apiset)
+int afb_api_so_add_binding(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set)
{
- return load_binding(path, 1, apiset);
+ return load_binding(path, 1, declare_set, call_set);
}
-static int adddirs(char path[PATH_MAX], size_t end, struct afb_apiset *apiset, int failstops)
+static int adddirs(char path[PATH_MAX], size_t end, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops)
{
DIR *dir;
struct dirent *dent;
@@ -159,12 +187,12 @@ static int adddirs(char path[PATH_MAX], size_t end, struct afb_apiset *apiset, i
Exclude from the search of bindings any
directory starting with a dot (.) by default.
-It is possible to reactivate the prvious behaviour
+It is possible to reactivate the prvious behaviour
by defining the following preprocessor variables
- AFB_API_SO_ACCEPT_DOT_PREFIXED_DIRS
- When this variable is defined, the directories
+ When this variable is defined, the directories
starting with a dot are searched except
if their name is "." or ".." or ".debug"
@@ -181,7 +209,7 @@ This change is intended to definitely solve the issue
SPEC-662. Yocto installed the debugging symbols in the
subdirectory .debug. For example the binding.so also
had a .debug/binding.so file attached. Opening that
-debug file made dlopen crashing.
+debug file made dlopen crashing.
See https://sourceware.org/bugzilla/show_bug.cgi?id=22101
*/
#if !defined(AFB_API_SO_ACCEPT_DOT_PREFIXED_DIRS) /* not defined by default */
@@ -203,13 +231,13 @@ See https://sourceware.org/bugzilla/show_bug.cgi?id=22101
#endif
}
memcpy(&path[end], dent->d_name, len+1);
- rc = adddirs(path, end+len, apiset, failstops);
+ rc = adddirs(path, end+len, declare_set, call_set, failstops);
} else if (dent->d_type == DT_REG) {
/* case of files */
if (memcmp(&dent->d_name[len - 3], ".so", 4))
continue;
memcpy(&path[end], dent->d_name, len+1);
- rc = load_binding(path, 0, apiset);
+ rc = load_binding(path, 0, declare_set, call_set);
}
if (rc < 0 && failstops) {
closedir(dir);
@@ -220,7 +248,7 @@ See https://sourceware.org/bugzilla/show_bug.cgi?id=22101
return 0;
}
-int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset, int failstops)
+int afb_api_so_add_directory(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops)
{
size_t length;
char buffer[PATH_MAX];
@@ -232,10 +260,10 @@ int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset, int fa
}
memcpy(buffer, path, length + 1);
- return adddirs(buffer, length, apiset, failstops);
+ return adddirs(buffer, length, declare_set, call_set, failstops);
}
-int afb_api_so_add_path(const char *path, struct afb_apiset *apiset, int failstops)
+int afb_api_so_add_path(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops)
{
struct stat st;
int rc;
@@ -244,15 +272,15 @@ int afb_api_so_add_path(const char *path, struct afb_apiset *apiset, int failsto
if (rc < 0)
ERROR("Invalid binding path [%s]: %m", path);
else if (S_ISDIR(st.st_mode))
- rc = afb_api_so_add_directory(path, apiset, failstops);
+ rc = afb_api_so_add_directory(path, declare_set, call_set, failstops);
else if (strstr(path, ".so"))
- rc = load_binding(path, 0, apiset);
+ rc = load_binding(path, 0, declare_set, call_set);
else
INFO("not a binding [%s], skipped", path);
return rc;
}
-int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset, int failstops)
+int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops)
{
static char sep[] = ":";
char *ps, *p;
@@ -263,19 +291,19 @@ int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset, int f
p = strsep(&ps, sep);
if (!p)
return 0;
- rc = afb_api_so_add_path(p, apiset, failstops);
+ rc = afb_api_so_add_path(p, declare_set, call_set, failstops);
if (rc < 0)
return rc;
}
}
-int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *apiset)
+int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set)
{
- return afb_api_so_add_pathset(pathset, apiset, 1);
+ return afb_api_so_add_pathset(pathset, declare_set, call_set, 1);
}
-int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *apiset)
+int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set)
{
- return afb_api_so_add_pathset(pathset, apiset, 0);
+ return afb_api_so_add_pathset(pathset, declare_set, call_set, 0);
}
diff --git a/src/afb-api-so.h b/src/afb-api-so.h
index d37f77c6..e6527469 100644
--- a/src/afb-api-so.h
+++ b/src/afb-api-so.h
@@ -20,15 +20,15 @@
struct afb_apiset;
-extern int afb_api_so_add_binding(const char *path, struct afb_apiset *apiset);
+extern int afb_api_so_add_binding(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set);
-extern int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset, int failstops);
+extern int afb_api_so_add_directory(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops);
-extern int afb_api_so_add_path(const char *path, struct afb_apiset *apiset, int failstops);
+extern int afb_api_so_add_path(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops);
-extern int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset, int failstops);
+extern int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops);
-extern int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *apiset);
-extern int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *apiset);
+extern int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set);
+extern int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set);
diff --git a/src/afb-api-v3.c b/src/afb-api-v3.c
new file mode 100644
index 00000000..8c755f94
--- /dev/null
+++ b/src/afb-api-v3.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <fnmatch.h>
+
+#include <json-c/json.h>
+
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
+
+#include "afb-api.h"
+#include "afb-api-v3.h"
+#include "afb-apiset.h"
+#include "afb-auth.h"
+#include "afb-export.h"
+#include "afb-xreq.h"
+#include "verbose.h"
+
+/*
+ * Description of a binding
+ */
+struct afb_api_v3 {
+ int refcount;
+ int count;
+ struct afb_verb_v3 **verbs;
+ const struct afb_verb_v2 *verbsv2;
+ const struct afb_verb_v3 *verbsv3;
+ struct afb_export *export;
+ const char *info;
+};
+
+static const char nulchar = 0;
+
+static int verb_name_compare(const struct afb_verb_v3 *verb, const char *name)
+{
+ return verb->glob
+ ? fnmatch(verb->verb, name, FNM_NOESCAPE|FNM_PATHNAME|FNM_CASEFOLD|FNM_PERIOD)
+ : strcasecmp(verb->verb, name);
+}
+
+static struct afb_verb_v3 *search_dynamic_verb(struct afb_api_v3 *api, const char *name)
+{
+ struct afb_verb_v3 **v, **e, *i;
+
+ v = api->verbs;
+ e = &v[api->count];
+ while (v != e) {
+ i = *v;
+ if (!verb_name_compare(i, name))
+ return i;
+ v++;
+ }
+ return 0;
+}
+
+void afb_api_v3_process_call(struct afb_api_v3 *api, struct afb_xreq *xreq)
+{
+ const struct afb_verb_v3 *verbsv3;
+ const struct afb_verb_v2 *verbsv2;
+ const char *name;
+
+ name = xreq->request.called_verb;
+
+ /* look first in dynamic set */
+ verbsv3 = search_dynamic_verb(api, name);
+ if (!verbsv3) {
+ /* look then in static set */
+ verbsv3 = api->verbsv3;
+ while (verbsv3) {
+ if (!verbsv3->verb)
+ verbsv3 = 0;
+ else if (!verb_name_compare(verbsv3, name))
+ break;
+ else
+ verbsv3++;
+ }
+ }
+ /* is it a v3 verb ? */
+ if (verbsv3) {
+ /* yes */
+ xreq->request.vcbdata = verbsv3->vcbdata;
+ afb_xreq_call_verb_v3(xreq, verbsv3);
+ return;
+ }
+
+ /* look in legacy set */
+ verbsv2 = api->verbsv2;
+ if (verbsv2) {
+ while (verbsv2->verb) {
+ if (strcasecmp(verbsv2->verb, name))
+ verbsv2++;
+ else {
+ afb_xreq_call_verb_v2(xreq, verbsv2);
+ return;
+ }
+ }
+ }
+
+ afb_xreq_reply_unknown_verb(xreq);
+}
+
+struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname)
+{
+ char buffer[256];
+ struct afb_verb_v3 **iter, **end, *verb;
+ struct json_object *r, *f, *a, *i, *p, *g;
+
+ r = json_object_new_object();
+ json_object_object_add(r, "openapi", json_object_new_string("3.0.0"));
+
+ i = json_object_new_object();
+ json_object_object_add(r, "info", i);
+ json_object_object_add(i, "title", json_object_new_string(apiname));
+ json_object_object_add(i, "version", json_object_new_string("0.0.0"));
+ json_object_object_add(i, "description", json_object_new_string(api->info));
+
+ p = json_object_new_object();
+ json_object_object_add(r, "paths", p);
+ iter = api->verbs;
+ end = iter + api->count;
+ while (iter != end) {
+ verb = *iter++;
+ buffer[0] = '/';
+ strncpy(buffer + 1, verb->verb, sizeof buffer - 1);
+ buffer[sizeof buffer - 1] = 0;
+ f = json_object_new_object();
+ json_object_object_add(p, buffer, f);
+ g = json_object_new_object();
+ json_object_object_add(f, "get", g);
+
+ a = afb_auth_json_v2(verb->auth, verb->session);
+ if (a)
+ json_object_object_add(g, "x-permissions", a);
+
+ a = json_object_new_object();
+ json_object_object_add(g, "responses", a);
+ f = json_object_new_object();
+ json_object_object_add(a, "200", f);
+ json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb));
+ }
+ return r;
+}
+
+struct afb_api_v3 *afb_api_v3_create(
+ struct afb_apiset *declare_set,
+ struct afb_apiset *call_set,
+ const char *apiname,
+ const char *info,
+ int noconcurrency,
+ int (*preinit)(void*, struct afb_api_x3 *),
+ void *closure,
+ int copy_info
+)
+{
+ struct afb_api_v3 *api;
+
+ /* allocates the description */
+ api = calloc(1, sizeof *api + (copy_info && info ? 1 + strlen(info) : 0));
+ if (!api)
+ goto oom;
+ api->refcount = 1;
+ if (!info)
+ api->info = &nulchar;
+ else if (copy_info)
+ api->info = strcpy((char*)(api + 1), info);
+ else
+ api->info = info;
+
+ api->export = afb_export_create_v3(declare_set, call_set, apiname, api);
+ if (!api->export)
+ goto oom2;
+
+ if (afb_export_declare(api->export, noconcurrency) < 0)
+ goto oom3;
+
+ if (preinit && afb_export_preinit_x3(api->export, preinit, closure) < 0)
+ goto oom4;
+
+ return api;
+
+oom4:
+ afb_export_undeclare(api->export);
+oom3:
+ afb_export_unref(api->export);
+oom2:
+ free(api);
+oom:
+ ERROR("out of memory");
+ return NULL;
+}
+
+struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api)
+{
+ if (api)
+ __atomic_add_fetch(&api->refcount, 1, __ATOMIC_RELAXED);
+ return api;
+}
+
+void afb_api_v3_unref(struct afb_api_v3 *api)
+{
+ if (api && !__atomic_sub_fetch(&api->refcount, 1, __ATOMIC_RELAXED)) {
+ afb_export_destroy(api->export);
+ free(api);
+ }
+}
+
+struct afb_export *afb_api_v3_export(struct afb_api_v3 *api)
+{
+ return api->export;
+}
+
+void afb_api_v3_set_verbs_v2(
+ struct afb_api_v3 *api,
+ const struct afb_verb_v2 *verbs)
+{
+ api->verbsv2 = verbs;
+}
+
+void afb_api_v3_set_verbs_v3(
+ struct afb_api_v3 *api,
+ const struct afb_verb_v3 *verbs)
+{
+ api->verbsv3 = verbs;
+}
+
+int afb_api_v3_add_verb(
+ struct afb_api_v3 *api,
+ const char *verb,
+ const char *info,
+ void (*callback)(struct afb_req_x2 *req),
+ void *vcbdata,
+ const struct afb_auth *auth,
+ uint16_t session,
+ int glob)
+{
+ struct afb_verb_v3 *v, **vv;
+ char *txt;
+ int i;
+
+ for (i = 0 ; i < api->count ; i++) {
+ v = api->verbs[i];
+ if (glob == v->glob && !strcasecmp(verb, v->verb)) {
+ /* refuse to redefine a dynamic verb */
+ errno = EEXIST;
+ return -1;
+ }
+ }
+
+ vv = realloc(api->verbs, (1 + api->count) * sizeof *vv);
+ if (!vv)
+ goto oom;
+ api->verbs = vv;
+
+ v = malloc(sizeof *v + (1 + strlen(verb)) + (info ? 1 + strlen(info) : 0));
+ if (!v)
+ goto oom;
+
+ v->callback = callback;
+ v->vcbdata = vcbdata;
+ v->auth = auth;
+ v->session = session;
+ v->glob = !!glob;
+
+ txt = (char*)(v + 1);
+ v->verb = txt;
+ txt = stpcpy(txt, verb);
+ if (!info)
+ v->info = NULL;
+ else {
+ v->info = ++txt;
+ strcpy(txt, info);
+ }
+
+ api->verbs[api->count++] = v;
+ return 0;
+oom:
+ errno = ENOMEM;
+ return -1;
+}
+
+int afb_api_v3_del_verb(
+ struct afb_api_v3 *api,
+ const char *verb,
+ void **vcbdata)
+{
+ struct afb_verb_v3 **v, **e, *i;
+
+ v = api->verbs;
+ e = &v[api->count];
+ while (v != e) {
+ i = *v++;
+ if (!strcasecmp(i->verb, verb)) {
+ api->count--;
+ if (vcbdata)
+ *vcbdata = i->vcbdata;
+ if (v != e)
+ *--v = *--e;
+ free(i);
+ return 0;
+ }
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api)
+{
+ int rc = 0;
+ if (desc->verbs)
+ rc = afb_api_x3_set_verbs_v3(api, desc->verbs);
+ if (!rc && desc->onevent)
+ rc = afb_api_x3_on_event(api, desc->onevent);
+ if (!rc && desc->init)
+ rc = afb_api_x3_on_init(api, desc->init);
+ if (!rc && desc->provide_class)
+ rc = afb_api_x3_provide_class(api, desc->provide_class);
+ if (!rc && desc->require_class)
+ rc = afb_api_x3_require_class(api, desc->require_class);
+ if (!rc && desc->require_api)
+ rc = afb_api_x3_require_api(api, desc->require_api, 1);
+ return rc;
+}
+
+static int init_binding(void *closure, struct afb_api_x3 *api)
+{
+ const struct afb_binding_v3 *desc = closure;
+ int rc = afb_api_v3_set_binding_fields(desc, api);
+ if (!rc && desc->preinit)
+ rc = desc->preinit(api);
+ return rc;
+}
+
+struct afb_api_v3 *afb_api_v3_from_binding(const struct afb_binding_v3 *desc, struct afb_apiset *declare_set, struct afb_apiset * call_set)
+{
+ return afb_api_v3_create(declare_set, call_set, desc->api, desc->info, desc->noconcurrency, init_binding, (void*)desc, 0);
+}
+
diff --git a/src/afb-api-v3.h b/src/afb-api-v3.h
new file mode 100644
index 00000000..33649f35
--- /dev/null
+++ b/src/afb-api-v3.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+struct afb_apiset;
+struct afb_api_v3;
+struct afb_api_x3;
+struct afb_auth;
+struct afb_req_x2;
+struct afb_verb_v2;
+struct afb_verb_v3;
+struct afb_binding_v3;
+struct afb_xreq;
+struct json_object;
+struct afb_export;
+
+extern struct afb_api_v3 *afb_api_v3_create(
+ struct afb_apiset *declare_set,
+ struct afb_apiset *call_set,
+ const char *apiname,
+ const char *info,
+ int noconcurrency,
+ int (*preinit)(void*, struct afb_api_x3 *),
+ void *closure,
+ int copy_info
+);
+
+extern struct afb_api_v3 *afb_api_v3_from_binding(
+ const struct afb_binding_v3 *desc,
+ struct afb_apiset *declare_set,
+ struct afb_apiset * call_set);
+
+extern int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api);
+
+extern struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api);
+extern void afb_api_v3_unref(struct afb_api_v3 *api);
+
+extern struct afb_export *afb_api_v3_export(struct afb_api_v3 *api);
+
+extern void afb_api_v3_set_verbs_v2(
+ struct afb_api_v3 *api,
+ const struct afb_verb_v2 *verbs);
+
+extern void afb_api_v3_set_verbs_v3(
+ struct afb_api_v3 *api,
+ const struct afb_verb_v3 *verbs);
+
+extern int afb_api_v3_add_verb(
+ struct afb_api_v3 *api,
+ const char *verb,
+ const char *info,
+ void (*callback)(struct afb_req_x2 *req),
+ void *vcbdata,
+ const struct afb_auth *auth,
+ uint16_t session,
+ int glob);
+
+extern int afb_api_v3_del_verb(
+ struct afb_api_v3 *api,
+ const char *verb,
+ void **vcbdata);
+
+extern void afb_api_v3_process_call(struct afb_api_v3 *api, struct afb_xreq *xreq);
+extern struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname);
+
diff --git a/src/afb-api-ws.c b/src/afb-api-ws.c
index 190c2fd8..c1ccd329 100644
--- a/src/afb-api-ws.c
+++ b/src/afb-api-ws.c
@@ -34,6 +34,7 @@
#include "afb-systemd.h"
#include "afb-api.h"
#include "afb-apiset.h"
+#include "afb-api-ws.h"
#include "afb-stub-ws.h"
#include "verbose.h"
#include "fdev.h"
@@ -72,7 +73,7 @@ static struct api_ws *api_ws_make(const char *path)
while (length && path[length - 1] != '/' && path[length - 1] != ':')
length = length - 1;
api->api = &api->path[length];
- if (api->api == NULL || !afb_api_is_valid_name(api->api, 1)) {
+ if (api->api == NULL || !afb_api_is_valid_name(api->api)) {
errno = EINVAL;
goto error2;
}
@@ -219,7 +220,7 @@ static struct fdev *api_ws_socket_fdev(const char *path, int server)
/**********************************************************************************/
-int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int strong)
+int afb_api_ws_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set, int strong)
{
struct api_ws *apiws;
struct afb_stub_ws *stubws;
@@ -234,12 +235,12 @@ int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int stron
if (!apiws->fdev)
goto error2;
- stubws = afb_stub_ws_create_client(apiws->fdev, apiws->api, apiset);
+ stubws = afb_stub_ws_create_client(apiws->fdev, apiws->api, call_set);
if (!stubws) {
ERROR("can't setup client ws service to %s", apiws->path);
goto error3;
}
- if (afb_stub_ws_client_add(stubws, apiset) < 0) {
+ if (afb_stub_ws_client_add(stubws, declare_set) < 0) {
ERROR("can't add the client to the apiset for service %s", apiws->path);
goto error3;
}
@@ -253,14 +254,14 @@ error:
return -!!strong;
}
-int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *apiset)
+int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
{
- return afb_api_ws_add_client(path, apiset, 1);
+ return afb_api_ws_add_client(path, declare_set, call_set, 1);
}
-int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *apiset)
+int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
{
- return afb_api_ws_add_client(path, apiset, 0);
+ return afb_api_ws_add_client(path, declare_set, call_set, 0);
}
static int api_ws_server_accept_client(struct api_ws *apiws, struct fdev *fdev)
@@ -329,7 +330,7 @@ static int api_ws_server_connect(struct api_ws *apiws)
}
/* create the service */
-int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset)
+int afb_api_ws_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
{
int rc;
struct api_ws *apiws;
@@ -340,7 +341,7 @@ int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset)
goto error;
/* check api name */
- if (!afb_apiset_lookup(apiset, apiws->api, 1)) {
+ if (!afb_apiset_lookup(call_set, apiws->api, 1)) {
ERROR("Can't provide ws-server for %s: API %s doesn't exist", path, apiws->api);
goto error2;
}
@@ -350,7 +351,7 @@ int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset)
if (rc < 0)
goto error2;
- apiws->apiset = afb_apiset_addref(apiset);
+ apiws->apiset = afb_apiset_addref(call_set);
return 0;
error2:
diff --git a/src/afb-api-ws.h b/src/afb-api-ws.h
index 123efb73..812cff59 100644
--- a/src/afb-api-ws.h
+++ b/src/afb-api-ws.h
@@ -20,10 +20,10 @@
struct afb_apiset;
-extern int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int strong);
-extern int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *apiset);
-extern int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *apiset);
+extern int afb_api_ws_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set, int strong);
+extern int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set);
+extern int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set);
-extern int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset);
+extern int afb_api_ws_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set);
diff --git a/src/afb-api.c b/src/afb-api.c
index 54ee5945..de603d3e 100644
--- a/src/afb-api.c
+++ b/src/afb-api.c
@@ -29,7 +29,7 @@
* Checks wether 'name' is a valid API name.
* @return 1 if valid, 0 otherwise
*/
-int afb_api_is_valid_name(const char *name, int hookable)
+int afb_api_is_valid_name(const char *name)
{
unsigned char c;
@@ -60,6 +60,6 @@ int afb_api_is_valid_name(const char *name, int hookable)
}
c = (unsigned char)*++name;
} while(c != 0);
- return !hookable || afb_api_is_hookable(name);
+ return 1;
}
diff --git a/src/afb-api.h b/src/afb-api.h
index 3f2e7f15..d03aaca5 100644
--- a/src/afb-api.h
+++ b/src/afb-api.h
@@ -24,24 +24,21 @@ struct json_object;
struct afb_api_itf
{
void (*call)(void *closure, struct afb_xreq *xreq);
- int (*service_start)(void *closure, int share_session, int onneed, struct afb_apiset *apiset);
+ int (*service_start)(void *closure, int share_session, int onneed);
void (*update_hooks)(void *closure);
- int (*get_verbosity)(void *closure);
- void (*set_verbosity)(void *closure, int level);
+ int (*get_logmask)(void *closure);
+ void (*set_logmask)(void *closure, int level);
struct json_object *(*describe)(void *closure);
void (*unref)(void *closure);
};
-struct afb_api
+struct afb_api_item
{
void *closure;
struct afb_api_itf *itf;
const void *group;
};
-extern int afb_api_is_valid_name(const char *name, int hookable);
+extern int afb_api_is_valid_name(const char *name);
-#define AFB_API_UNHOOKABLE_PREFIX_CHAR '$'
-#define AFB_API_UNHOOKABLE_PREFIX_STRING "$"
-#define afb_api_is_hookable(api) ((api)[0] != AFB_API_UNHOOKABLE_PREFIX_CHAR)
diff --git a/src/afb-apiset.c b/src/afb-apiset.c
index 8d76bbfe..af5a8652 100644
--- a/src/afb-apiset.c
+++ b/src/afb-apiset.c
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2016, 2017, 2018 "IoT.bzh"
- * Author "Fulup Ar Foll"
* Author José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,14 +31,68 @@
#define INCR 8 /* CAUTION: must be a power of 2 */
+struct afb_apiset;
+struct api_desc;
+struct api_class;
+struct api_alias;
+struct api_depend;
+
+/**
+ * array of items
+ */
+struct api_array {
+ int count; /* count of items */
+ union {
+ void **anys;
+ struct api_desc **apis;
+ struct api_class **classes;
+ struct api_alias **aliases;
+ struct api_depend **depends;
+ };
+};
+
/**
* Internal description of an api
*/
struct api_desc
{
- int status;
- const char *name; /**< name of the api */
- struct afb_api api; /**< handler of the api */
+ struct api_desc *next;
+ const char *name; /**< name of the api */
+ int status; /**< initialisation status */
+ struct afb_api_item api; /**< handler of the api */
+ struct {
+ struct api_array classes;
+ struct api_array apis;
+ } require;
+};
+
+/**
+ * internal description of aliases
+ */
+struct api_alias
+{
+ struct api_alias *next;
+ struct api_desc *api;
+ char name[1];
+};
+
+/**
+ *
+ */
+struct api_class
+{
+ struct api_class *next;
+ struct api_array providers;
+ char name[1];
+};
+
+/**
+ *
+ */
+struct api_depend
+{
+ struct afb_apiset *set;
+ char name[1];
};
/**
@@ -47,15 +100,133 @@ struct api_desc
*/
struct afb_apiset
{
- struct api_desc *apis; /**< description of apis */
+ struct api_array apis; /**< the apis */
+ struct api_alias *aliases; /**< the aliases */
struct afb_apiset *subset; /**< subset if any */
- int count; /**< count of apis in the set */
+ struct {
+ int (*callback)(void*, struct afb_apiset*, const char*); /* not found handler */
+ void *closure;
+ void (*cleanup)(void*);
+ } onlack; /** not found handler */
int timeout; /**< the timeout in second for the apiset */
int refcount; /**< reference count for freeing resources */
char name[1]; /**< name of the apiset */
};
/**
+ * global apis
+ */
+static struct api_desc *all_apis;
+
+/**
+ * global classes
+ */
+static struct api_class *all_classes;
+
+/**
+ * Ensure enough room in 'array' for 'count' items
+ */
+static int api_array_ensure_count(struct api_array *array, int count)
+{
+ int c;
+ void **anys;
+
+ c = (count + INCR - 1) & ~(INCR - 1);
+ anys = realloc(array->anys, c * sizeof *anys);
+ if (!anys) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ array->count = count;
+ array->anys = anys;
+ return 0;
+}
+
+/**
+ * Insert in 'array' the item 'any' at the 'index'
+ */
+static int api_array_insert(struct api_array *array, void *any, int index)
+{
+ int n = array->count;
+
+ if (api_array_ensure_count(array, n + 1) < 0)
+ return -1;
+
+ while (index < n) {
+ array->anys[n] = array->anys[n - 1];
+ n--;
+ }
+
+ array->anys[index] = any;
+ return 0;
+}
+
+/**
+ * Add the item 'any' to the 'array'
+ */
+static int api_array_add(struct api_array *array, void *any)
+{
+ int i, n = array->count;
+
+ for (i = 0 ; i < n ; i++) {
+ if (array->anys[i] == any)
+ return 0;
+ }
+
+ if (api_array_ensure_count(array, n + 1) < 0)
+ return -1;
+
+ array->anys[n] = any;
+ return 0;
+}
+
+/**
+ * Delete the 'api' from the 'array'
+ * Returns 1 if delete or 0 if not found
+ */
+static int api_array_del(struct api_array *array, void *any)
+{
+ int i = array->count;
+ while (i) {
+ if (array->anys[--i] == any) {
+ array->anys[i] = array->anys[--array->count];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Search the class of 'name' and return it.
+ * In case where the class of 'namle' isn't found, it returns
+ * NULL when 'create' is null or a fresh created instance if 'create' isn't
+ * zero (but NULL on allocation failure).
+ */
+static struct api_class *class_search(const char *name, int create)
+{
+ struct api_class *c;
+
+ for (c= all_classes ; c ; c = c->next) {
+ if (!strcasecmp(name, c->name))
+ return c;
+ }
+
+ if (!create)
+ return NULL;
+
+ c = calloc(1, strlen(name) + sizeof *c);
+ if (!c)
+ errno = ENOMEM;
+ else {
+ strcpy(c->name, name);
+ c->next = all_classes;
+ all_classes = c;
+ }
+ return c;
+}
+
+/**
* Search the api of 'name'.
* @param set the api set
* @param name the api name to search
@@ -65,20 +236,16 @@ static struct api_desc *search(struct afb_apiset *set, const char *name)
{
int i, c, up, lo;
struct api_desc *a;
+ struct api_alias *aliases;
/* dichotomic search of the api */
/* initial slice */
lo = 0;
- up = set->count;
- for (;;) {
- /* check remaining slice */
- if (lo >= up) {
- /* not found */
- return NULL;
- }
+ up = set->apis.count;
+ while (lo < up) {
/* check the mid of the slice */
i = (lo + up) >> 1;
- a = &set->apis[i];
+ a = set->apis.apis[i];
c = strcasecmp(a->name, name);
if (c == 0) {
/* found */
@@ -90,6 +257,37 @@ static struct api_desc *search(struct afb_apiset *set, const char *name)
else
up = i;
}
+
+ /* linear search of aliases */
+ aliases = set->aliases;
+ for(;;) {
+ if (!aliases)
+ break;
+ c = strcasecmp(aliases->name, name);
+ if (!c)
+ return aliases->api;
+ if (c > 0)
+ break;
+ aliases = aliases->next;
+ }
+ return NULL;
+}
+
+/**
+ * Search the api of 'name' in the apiset and in its subsets.
+ * @param set the api set
+ * @param name the api name to search
+ * @return the descriptor if found or NULL otherwise
+ */
+static struct api_desc *searchrec(struct afb_apiset *set, const char *name)
+{
+ struct api_desc *result;
+
+ do {
+ result = search(set, name);
+ } while (result == NULL && (set = set->subset) != NULL);
+
+ return result;
}
/**
@@ -111,9 +309,24 @@ struct afb_apiset *afb_apiset_addref(struct afb_apiset *set)
*/
void afb_apiset_unref(struct afb_apiset *set)
{
+ struct api_alias *a;
+ struct api_desc *d;
+
if (set && !__atomic_sub_fetch(&set->refcount, 1, __ATOMIC_RELAXED)) {
afb_apiset_unref(set->subset);
- free(set->apis);
+ if (set->onlack.cleanup)
+ set->onlack.cleanup(set->onlack.closure);
+ while((a = set->aliases)) {
+ set->aliases = a->next;
+ free(a);
+ }
+ while (set->apis.count) {
+ d = set->apis.apis[--set->apis.count];
+ if (d->api.itf->unref)
+ d->api.itf->unref(d->api.closure);
+ free(d);
+ }
+ free(set->apis.apis);
free(set);
}
}
@@ -128,22 +341,49 @@ struct afb_apiset *afb_apiset_create(const char *name, int timeout)
{
struct afb_apiset *set;
- set = malloc((name ? strlen(name) : 0) + sizeof *set);
+ set = calloc(1, (name ? strlen(name) : 0) + sizeof *set);
if (set) {
- set->apis = malloc(INCR * sizeof *set->apis);
- set->count = 0;
set->timeout = timeout;
set->refcount = 1;
- set->subset = NULL;
if (name)
strcpy(set->name, name);
- else
- set->name[0] = 0;
}
return set;
}
/**
+ * Create an apiset being the last subset of 'set'
+ * @param set the set to extend with the created subset (can be NULL)
+ * @param name the name of the created apiset (can be NULL)
+ * @param timeout the default timeout in seconds for the created apiset
+ * @return the created apiset or NULL in case of error
+ */
+struct afb_apiset *afb_apiset_create_subset_last(struct afb_apiset *set, const char *name, int timeout)
+{
+ if (set)
+ while (set->subset)
+ set = set->subset;
+ return afb_apiset_create_subset_first(set, name, timeout);
+}
+
+/**
+ * Create an apiset being the first subset of 'set'
+ * @param set the set to extend with the created subset (can be NULL)
+ * @param name the name of the created apiset (can be NULL)
+ * @param timeout the default timeout in seconds for the created apiset
+ * @return the created apiset or NULL in case of error
+ */
+struct afb_apiset *afb_apiset_create_subset_first(struct afb_apiset *set, const char *name, int timeout)
+{
+ struct afb_apiset *result = afb_apiset_create(name, timeout);
+ if (result && set) {
+ result->subset = set->subset;
+ set->subset = result;
+ }
+ return result;
+}
+
+/**
* the name of the apiset
* @param set the api set
* @return the name of the set
@@ -200,6 +440,15 @@ void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset)
afb_apiset_unref(tmp);
}
+void afb_apiset_onlack_set(struct afb_apiset *set, int (*callback)(void*, struct afb_apiset*, const char*), void *closure, void (*cleanup)(void*))
+{
+ if (set->onlack.cleanup)
+ set->onlack.cleanup(set->onlack.closure);
+ set->onlack.callback = callback;
+ set->onlack.closure = closure;
+ set->onlack.cleanup = cleanup;
+}
+
/**
* Adds the api of 'name' described by 'api'.
* @param set the api set
@@ -210,52 +459,117 @@ void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset)
* - EEXIST if name already registered
* - ENOMEM when out of memory
*/
-int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api)
+int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api_item api)
{
- struct api_desc *apis;
+ struct api_desc *desc;
int i, c;
- /* check previously existing plugin */
- for (i = 0 ; i < set->count ; i++) {
- c = strcasecmp(set->apis[i].name, name);
- if (c == 0) {
- ERROR("api of name %s already exists", name);
- errno = EEXIST;
- goto error;
- }
+ /* check whether it exists already */
+ if (search(set, name)) {
+ ERROR("api of name %s already exists", name);
+ errno = EEXIST;
+ goto error;
+ }
+
+ /* search insertion place */
+ for (i = 0 ; i < set->apis.count ; i++) {
+ c = strcasecmp(set->apis.apis[i]->name, name);
if (c > 0)
break;
}
- /* allocates enough memory */
- c = (set->count + INCR) & ~(INCR - 1);
- apis = realloc(set->apis, ((unsigned)c) * sizeof * apis);
- if (apis == NULL) {
- ERROR("out of memory");
- errno = ENOMEM;
+ /* allocates memory */
+ desc = calloc(1, sizeof *desc);
+ if (!desc)
+ goto oom;
+
+ desc->status = -1;
+ desc->api = api;
+ desc->name = name;
+
+ if (api_array_insert(&set->apis, desc, i) < 0) {
+ free(desc);
goto error;
}
- set->apis = apis;
- /* copy higher part of the array */
- apis += i;
- if (i != set->count)
- memmove(apis + 1, apis, ((unsigned)(set->count - i)) * sizeof *apis);
-
- /* record the plugin */
- apis->status = -1;
- apis->api = api;
- apis->name = name;
- set->count++;
+ desc->next = all_apis;
+ all_apis = desc;
INFO("API %s added", name);
return 0;
+oom:
+ ERROR("out of memory");
+ errno = ENOMEM;
+error:
+ return -1;
+}
+
+/**
+ * Adds a the 'alias' name to the api of 'name'.
+ * @params set the api set
+ * @param name the name of the api to alias
+ * @param alias the aliased name to add to the api of name
+ * @returns 0 in case of success or -1 in case
+ * of error with errno set:
+ * - ENOENT if the api doesn't exist
+ * - EEXIST if name (of alias) already registered
+ * - ENOMEM when out of memory
+ */
+int afb_apiset_add_alias(struct afb_apiset *set, const char *name, const char *alias)
+{
+ struct api_desc *api;
+ struct api_alias *ali, **pali;
+
+ /* check alias doesn't already exist */
+ if (search(set, alias)) {
+ ERROR("api of name %s already exists", alias);
+ errno = EEXIST;
+ goto error;
+ }
+
+ /* check aliased api exists */
+ api = search(set, name);
+ if (api == NULL) {
+ ERROR("api of name %s doesn't exists", name);
+ errno = ENOENT;
+ goto error;
+ }
+
+ /* allocates and init the struct */
+ ali = malloc(sizeof *ali + strlen(alias));
+ if (ali == NULL) {
+ ERROR("out of memory");
+ errno = ENOMEM;
+ goto error;
+ }
+ ali->api = api;
+ strcpy(ali->name, alias);
+
+ /* insert the alias in the sorted order */
+ pali = &set->aliases;
+ while(*pali && strcmp((*pali)->name, alias) < 0)
+ pali = &(*pali)->next;
+ ali->next = *pali;
+ *pali = ali;
+ return 0;
error:
return -1;
}
+int afb_apiset_is_alias(struct afb_apiset *set, const char *name)
+{
+ struct api_desc *api = searchrec(set, name);
+ return api && strcasecmp(api->name, name);
+}
+
+const char *afb_apiset_unalias(struct afb_apiset *set, const char *name)
+{
+ struct api_desc *api = searchrec(set, name);
+ return api ? api->name : NULL;
+}
+
/**
* Delete from the 'set' the api of 'name'.
* @param set the set to be changed
@@ -264,28 +578,72 @@ error:
*/
int afb_apiset_del(struct afb_apiset *set, const char *name)
{
- struct api_desc *i, *e;
- int c;
+ struct api_class *cla;
+ struct api_alias *ali, **pali;
+ struct api_desc *desc, **pdesc, *odesc;
+ int i, c;
+
+ /* search the alias */
+ pali = &set->aliases;
+ while ((ali = *pali)) {
+ c = strcasecmp(ali->name, name);
+ if (!c) {
+ *pali = ali->next;
+ free(ali);
+ return 0;
+ }
+ if (c > 0)
+ break;
+ pali = &ali->next;
+ }
/* search the api */
- i = set->apis;
- e = i + set->count;
- while (i != e) {
- c = strcasecmp(i->name, name);
+ for (i = 0 ; i < set->apis.count ; i++) {
+ desc = set->apis.apis[i];
+ c = strcasecmp(desc->name, name);
if (c == 0) {
- if (i->api.itf->unref)
- i->api.itf->unref(i->api.closure);
- set->count--;
- e--;
- while (i != e) {
- i[0] = i[1];
+ /* remove from classes */
+ for (cla = all_classes ; cla ; cla = cla->next)
+ api_array_del(&cla->providers, desc);
+
+ /* unlink from the whole set and their requires */
+ pdesc = &all_apis;
+ while ((odesc = *pdesc) != desc) {
+ pdesc = &odesc->next;
+ }
+ *pdesc = odesc = desc->next;
+ while (odesc) {
+ odesc = odesc->next;
+ }
+
+ /* remove references from classes */
+ free(desc->require.classes.classes);
+
+ /* drop the aliases */
+ pali = &set->aliases;
+ while ((ali = *pali)) {
+ if (ali->api != desc)
+ pali = &ali->next;
+ else {
+ *pali = ali->next;
+ free(ali);
+ }
+ }
+
+ /* unref the api */
+ if (desc->api.itf->unref)
+ desc->api.itf->unref(desc->api.closure);
+
+ set->apis.count--;
+ while(i < set->apis.count) {
+ set->apis.apis[i] = set->apis.apis[i + 1];
i++;
}
+ free(desc);
return 0;
}
if (c > 0)
break;
- i++;
}
errno = ENOENT;
return -1;
@@ -300,8 +658,21 @@ int afb_apiset_del(struct afb_apiset *set, const char *name)
*/
static struct api_desc *lookup(struct afb_apiset *set, const char *name, int rec)
{
- struct api_desc *i = search(set, name);
- return i || !rec || !set->subset ? i : lookup(set->subset, name, rec);
+ struct api_desc *result;
+
+ result = search(set, name);
+ while (!result) {
+ /* lacking the api, try onlack behaviour */
+ if (set->onlack.callback && set->onlack.callback(set->onlack.closure, set, name) > 0) {
+ result = search(set, name);
+ if (result)
+ break;
+ }
+ if (!rec || !(set = set->subset))
+ break;
+ result = search(set, name);
+ }
+ return result;
}
/**
@@ -311,7 +682,7 @@ static struct api_desc *lookup(struct afb_apiset *set, const char *name, int rec
* @param rec if not zero look also recursively in subsets
* @return the api pointer in case of success or NULL in case of error
*/
-const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec)
+const struct afb_api_item *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec)
{
struct api_desc *i;
@@ -322,6 +693,78 @@ const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name
return NULL;
}
+static int start_api(struct api_desc *api, int share_session, int onneed);
+
+/**
+ * Start the apis of the 'array'
+ * The attribute 'share_session' is sent to the start function.
+ */
+static int start_array_apis(struct api_array *array, int share_session)
+{
+ int i, rc = 0, rc2;
+
+ i = array->count;
+ while (i) {
+ rc2 = start_api(array->apis[--i], share_session, 1);
+ if (rc2 < 0) {
+ rc = rc2;
+ }
+ }
+ return rc;
+}
+
+/**
+ * Start the class 'cla' (start the apis that provide it).
+ * The attribute 'share_session' is sent to the start function.
+ */
+static int start_class(struct api_class *cla, int share_session)
+{
+ return start_array_apis(&cla->providers, share_session);
+}
+
+/**
+ * Start the classes of the 'array'
+ * The attribute 'share_session' is sent to the start function.
+ */
+static int start_array_classes(struct api_array *array, int share_session)
+{
+ int i, rc = 0, rc2;
+
+ i = array->count;
+ while (i) {
+ rc2 = start_class(array->classes[--i], share_session);
+ if (rc2 < 0) {
+ rc = rc2;
+ }
+ }
+ return rc;
+}
+
+/**
+ * Start the depends of the 'array'
+ * The attribute 'share_session' is sent to the start function.
+ */
+static int start_array_depends(struct api_array *array, int share_session)
+{
+ struct api_desc *api;
+ int i, rc = 0, rc2;
+
+ i = array->count;
+ while (i) {
+ i--;
+ api = searchrec(array->depends[i]->set, array->depends[i]->name);
+ if (!api)
+ rc = -1;
+ else {
+ rc2 = start_api(api, share_session, 1);
+ if (rc2 < 0) {
+ rc = rc2;
+ }
+ }
+ }
+ return rc;
+}
+
/**
* Starts the service 'api'.
* @param api the api
@@ -331,7 +774,7 @@ const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name
* must be a service
* @return a positive number on success
*/
-static int start_api(struct afb_apiset *set, struct api_desc *api, int share_session, int onneed)
+static int start_api(struct api_desc *api, int share_session, int onneed)
{
int rc;
@@ -343,9 +786,11 @@ static int start_api(struct afb_apiset *set, struct api_desc *api, int share_ses
}
INFO("API %s starting...", api->name);
+ rc = start_array_classes(&api->require.classes, share_session);
+ rc = start_array_depends(&api->require.apis, share_session);
if (api->api.itf->service_start) {
api->status = EBUSY;
- rc = api->api.itf->service_start(api->api.closure, share_session, onneed, set);
+ rc = api->api.itf->service_start(api->api.closure, share_session, onneed);
if (rc < 0) {
api->status = errno ?: ECANCELED;
ERROR("The api %s failed to start (%d)", api->name, rc);
@@ -369,13 +814,13 @@ static int start_api(struct afb_apiset *set, struct api_desc *api, int share_ses
* @param rec if not zero look also recursively in subsets
* @return 0 in case of success or -1 in case of error
*/
-const struct afb_api *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec)
+const struct afb_api_item *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec)
{
struct api_desc *i;
i = lookup(set, name, rec);
if (i)
- return i->status && start_api(set, i, 1, 1) ? NULL : &i->api;
+ return i->status && start_api(i, 1, 1) ? NULL : &i->api;
errno = ENOENT;
return NULL;
}
@@ -394,14 +839,14 @@ int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share
{
struct api_desc *a;
- a = search(set, name);
+ a = searchrec(set, name);
if (!a) {
ERROR("can't find service %s", name);
errno = ENOENT;
return -1;
}
- return start_api(set, a, share_session, onneed);
+ return start_api(a, share_session, onneed);
}
/**
@@ -414,18 +859,19 @@ int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share
int afb_apiset_start_all_services(struct afb_apiset *set, int share_session)
{
int rc;
- struct api_desc *i, *e;
+ int i;
- i = set->apis;
- e = &set->apis[set->count];
- while (i != e) {
- rc = start_api(set, i, share_session, 1);
- if (rc < 0)
- return rc;
- i++;
+ while (set) {
+ i = 0;
+ while (i < set->apis.count) {
+ rc = start_api(set->apis.apis[i], share_session, 1);
+ if (rc < 0)
+ return rc;
+ i++;
+ }
+ set = set->subset;
}
-
- return set->subset ? afb_apiset_start_all_services(set->subset, share_session) : 0;
+ return 0;
}
/**
@@ -435,65 +881,66 @@ int afb_apiset_start_all_services(struct afb_apiset *set, int share_session)
*/
void afb_apiset_update_hooks(struct afb_apiset *set, const char *name)
{
- const struct api_desc *i, *e;
+ struct api_desc **i, **e, *d;
if (!name) {
- i = set->apis;
- e = &set->apis[set->count];
+ i = set->apis.apis;
+ e = &set->apis.apis[set->apis.count];
+ while (i != e) {
+ d = *i++;
+ if (d->api.itf->update_hooks)
+ d->api.itf->update_hooks(d->api.closure);
+ }
} else {
- i = search(set, name);
- e = &i[!!i];
- }
- while (i != e) {
- if (i->api.itf->update_hooks)
- i->api.itf->update_hooks(i->api.closure);
- i++;
+ d = searchrec(set, name);
+ if (d && d->api.itf->update_hooks)
+ d->api.itf->update_hooks(d->api.closure);
}
}
/**
- * Set the verbosity level of the 'api'
+ * Set the logmask of the 'api' to 'mask'
* @param set the api set
* @param name the api to set (NULL set all)
*/
-void afb_apiset_set_verbosity(struct afb_apiset *set, const char *name, int level)
+void afb_apiset_set_logmask(struct afb_apiset *set, const char *name, int mask)
{
- const struct api_desc *i, *e;
+ int i;
+ struct api_desc *d;
if (!name) {
- i = set->apis;
- e = &set->apis[set->count];
+ for (i = 0 ; i < set->apis.count ; i++) {
+ d = set->apis.apis[i];;
+ if (d->api.itf->set_logmask)
+ d->api.itf->set_logmask(d->api.closure, mask);
+ }
} else {
- i = search(set, name);
- e = &i[!!i];
- }
- while (i != e) {
- if (i->api.itf->set_verbosity)
- i->api.itf->set_verbosity(i->api.closure, level);
- i++;
+ d = searchrec(set, name);
+ if (d && d->api.itf->set_logmask)
+ d->api.itf->set_logmask(d->api.closure, mask);
}
}
/**
- * Get the verbosity level of the 'api'
+ * Get the logmask level of the 'api'
* @param set the api set
* @param name the api to get
- * @return the verbosity level or -1 in case of error
+ * @return the logmask level or -1 in case of error
*/
-int afb_apiset_get_verbosity(struct afb_apiset *set, const char *name)
+int afb_apiset_get_logmask(struct afb_apiset *set, const char *name)
{
const struct api_desc *i;
- i = name ? search(set, name) : NULL;
+ i = name ? searchrec(set, name) : NULL;
if (!i) {
errno = ENOENT;
return -1;
}
- if (!i->api.itf->get_verbosity)
- return verbosity;
+ if (!i->api.itf->get_logmask)
+ return logmask;
- return i->api.itf->get_verbosity(i->api.closure);
+ return i->api.itf->get_logmask(i->api.closure);
}
/**
@@ -506,36 +953,79 @@ struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name
{
const struct api_desc *i;
- i = name ? search(set, name) : NULL;
+ i = name ? searchrec(set, name) : NULL;
return i && i->api.itf->describe ? i->api.itf->describe(i->api.closure) : NULL;
}
+struct get_names {
+ union {
+ struct {
+ size_t count;
+ size_t size;
+ };
+ struct {
+ const char **ptr;
+ char *data;
+ };
+ };
+ int type;
+};
+
+static void get_names_count(void *closure, struct afb_apiset *set, const char *name, int isalias)
+{
+ struct get_names *gc = closure;
+ if ((1 + isalias) & gc->type) {
+ gc->size += strlen(name);
+ gc->count++;
+ }
+}
+
+static void get_names_value(void *closure, struct afb_apiset *set, const char *name, int isalias)
+{
+ struct get_names *gc = closure;
+ if ((1 + isalias) & gc->type) {
+ *gc->ptr++ = gc->data;
+ gc->data = stpcpy(gc->data, name) + 1;
+ }
+}
+
+#if !defined(APISET_NO_SORT)
+static int get_names_sortcb(const void *a, const void *b)
+{
+ return strcasecmp(*(const char **)a, *(const char **)b);
+}
+#endif
+
/**
* Get the list of api names
* @param set the api set
+ * @param rec recursive
+ * @param type expected type: 1 names, 3 names+aliases, 2 aliases
* @return a NULL terminated array of api names. Must be freed.
*/
-const char **afb_apiset_get_names(struct afb_apiset *set)
+const char **afb_apiset_get_names(struct afb_apiset *set, int rec, int type)
{
+ struct get_names gc;
size_t size;
- char *dest;
const char **names;
- int i;
- size = set->count * (1 + sizeof(*names)) + sizeof(*names);
- for (i = 0 ; i < set->count ; i++)
- size += strlen(set->apis[i].name);
+ gc.count = gc.size = 0;
+ gc.type = type >= 1 && type <= 3 ? type : 1;
+ afb_apiset_enum(set, rec, get_names_count, &gc);
+ size = gc.size + gc.count * (1 + sizeof *names) + sizeof(*names);
names = malloc(size);
+
if (!names)
errno = ENOMEM;
else {
- dest = (void*)&names[set->count+1];
- for (i = 0 ; i < set->count ; i++) {
- names[i] = dest;
- dest = stpcpy(dest, set->apis[i].name) + 1;
- }
- names[i] = NULL;
+ gc.data = (char*)&names[gc.count + 1];
+ gc.ptr = names;
+ afb_apiset_enum(set, rec, get_names_value, &gc);
+#if !defined(APISET_NO_SORT)
+ qsort(names, gc.ptr - names, sizeof *names, get_names_sortcb);
+#endif
+ *gc.ptr = NULL;
}
return names;
}
@@ -543,24 +1033,97 @@ const char **afb_apiset_get_names(struct afb_apiset *set)
/**
* Enumerate the api names to a callback.
* @param set the api set
+ * @param rec should the enumeration be recursive
* @param callback the function to call for each name
* @param closure the closure for the callback
*/
-void afb_apiset_enum(struct afb_apiset *set, int rec, void (*callback)(struct afb_apiset *set, const char *name, void *closure), void *closure)
+void afb_apiset_enum(
+ struct afb_apiset *set,
+ int rec,
+ void (*callback)(void *closure, struct afb_apiset *set, const char *name, int isalias),
+ void *closure)
{
+ int i;
struct afb_apiset *iset;
- struct api_desc *i, *e;
+ struct api_desc *d;
+ struct api_alias *a;
iset = set;
while (iset) {
- i = iset->apis;
- e = &i[iset->count];
- while (i != e) {
- if (lookup(set, i->name, 1) == i)
- callback(iset, i->name, closure);
- i++;
+ for (i = 0 ; i < set->apis.count ; i++) {
+ d = set->apis.apis[i];;
+ if (searchrec(set, d->name) == d)
+ callback(closure, iset, d->name, 0);
+ }
+ a = iset->aliases;
+ while (a) {
+ if (searchrec(set, a->name) == a->api)
+ callback(closure, iset, a->name, 1);
+ a = a->next;
}
iset = rec ? iset->subset : NULL;
}
}
+/**
+ * Declare that the api of 'name' requires the api of name 'required'.
+ * The api is searched in the apiset 'set' and if 'rec' isn't null also in its subset.
+ * Returns 0 if the declaration successed or -1 in case of failure
+ * (ENOMEM: allocation failure, ENOENT: api name not found)
+ */
+int afb_apiset_require(struct afb_apiset *set, const char *name, const char *required)
+{
+ struct api_desc *a;
+ struct api_depend *d;
+ int rc = -1;
+
+ a = searchrec(set, name);
+ if (!a)
+ errno = ENOENT;
+ else {
+ d = malloc(strlen(required) + sizeof *d);
+ if (!d)
+ errno = ENOMEM;
+ else {
+ d->set = set;
+ strcpy(d->name, required);
+ rc = api_array_add(&a->require.apis, d);
+ }
+ }
+ return rc;
+}
+
+/**
+ * Declare that the api of name 'apiname' requires the class of name 'classname'.
+ * Returns 0 if the declaration successed or -1 in case of failure
+ * (ENOMEM: allocation failure, ENOENT: api name not found)
+ */
+int afb_apiset_require_class(struct afb_apiset *set, const char *apiname, const char *classname)
+{
+ struct api_desc *a = searchrec(set, apiname);
+ struct api_class *c = class_search(classname, 1);
+ return a && c ? api_array_add(&a->require.classes, c) : (errno = ENOENT, -1);
+}
+
+/**
+ * Declare that the api of name 'apiname' provides the class of name 'classname'
+ * Returns 0 if the declaration successed or -1 in case of failure
+ * (ENOMEM: allocation failure, ENOENT: api name not found)
+ */
+int afb_apiset_provide_class(struct afb_apiset *set, const char *apiname, const char *classname)
+{
+ struct api_desc *a = searchrec(set, apiname);
+ struct api_class *c = class_search(classname, 1);
+ return a && c ? api_array_add(&c->providers, a) : (errno = ENOENT, -1);
+}
+
+/**
+ * Start any API that provides the class of name 'classname'
+ * The attribute 'share_session' is sent to the start function.
+ */
+int afb_apiset_class_start(const char *classname, int share_session)
+{
+ struct api_class *cla = class_search(classname, 0);
+ return cla ? start_class(cla, share_session) : (errno = ENOENT, -1);
+}
+
diff --git a/src/afb-apiset.h b/src/afb-apiset.h
index 55068dd3..fc8bc266 100644
--- a/src/afb-apiset.h
+++ b/src/afb-apiset.h
@@ -17,28 +17,57 @@
#pragma once
-struct afb_api;
+struct afb_api_item;
struct afb_apiset;
struct json_object;
+extern struct afb_apiset *afb_apiset_create(const char *name, int timeout);
+extern struct afb_apiset *afb_apiset_create_subset_last(struct afb_apiset *set, const char *name, int timeout);
+extern struct afb_apiset *afb_apiset_create_subset_first(struct afb_apiset *set, const char *name, int timeout);
extern struct afb_apiset *afb_apiset_addref(struct afb_apiset *set);
extern void afb_apiset_unref(struct afb_apiset *set);
-extern struct afb_apiset *afb_apiset_create(const char *name, int timeout);
+
extern const char *afb_apiset_name(struct afb_apiset *set);
+
extern int afb_apiset_timeout_get(struct afb_apiset *set);
extern void afb_apiset_timeout_set(struct afb_apiset *set, int to);
+
+extern void afb_apiset_onlack_set(
+ struct afb_apiset *set,
+ int (*callback)(void *closure, struct afb_apiset *set, const char *name),
+ void *closure,
+ void (*cleanup)(void*closure));
+
extern void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset);
extern struct afb_apiset *afb_apiset_subset_get(struct afb_apiset *set);
-extern int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api);
+
+extern int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api_item api);
extern int afb_apiset_del(struct afb_apiset *set, const char *name);
-extern const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec);
-extern const struct afb_api *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec);
+
+extern int afb_apiset_add_alias(struct afb_apiset *set, const char *name, const char *alias);
+extern int afb_apiset_is_alias(struct afb_apiset *set, const char *name);
+extern const char *afb_apiset_unalias(struct afb_apiset *set, const char *name);
+
+extern const struct afb_api_item *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec);
+extern const struct afb_api_item *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec);
+
extern int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share_session, int onneed);
extern int afb_apiset_start_all_services(struct afb_apiset *set, int share_session);
+
extern void afb_apiset_update_hooks(struct afb_apiset *set, const char *name);
-extern void afb_apiset_set_verbosity(struct afb_apiset *set, const char *name, int level);
-extern int afb_apiset_get_verbosity(struct afb_apiset *set, const char *name);
+extern void afb_apiset_set_logmask(struct afb_apiset *set, const char *name, int mask);
+extern int afb_apiset_get_logmask(struct afb_apiset *set, const char *name);
+
extern struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name);
-extern const char **afb_apiset_get_names(struct afb_apiset *set);
-extern void afb_apiset_enum(struct afb_apiset *set, int rec, void (*callback)(struct afb_apiset *set, const char *name, void *closure), void *closure);
+extern const char **afb_apiset_get_names(struct afb_apiset *set, int rec, int type);
+extern void afb_apiset_enum(
+ struct afb_apiset *set,
+ int rec,
+ void (*callback)(void *closure, struct afb_apiset *set, const char *name, int isalias),
+ void *closure);
+
+extern int afb_apiset_require(struct afb_apiset *set, const char *name, const char *required);
+extern int afb_apiset_require_class(struct afb_apiset *set, const char *apiname, const char *classname);
+extern int afb_apiset_provide_class(struct afb_apiset *set, const char *apiname, const char *classname);
+extern int afb_apiset_class_start(const char *classname, int share_session);
diff --git a/src/afb-auth.c b/src/afb-auth.c
index 47a98d5a..4a3c445f 100644
--- a/src/afb-auth.c
+++ b/src/afb-auth.c
@@ -22,7 +22,7 @@
#include <json-c/json.h>
#include <afb/afb-auth.h>
-#include <afb/afb-session-v2.h>
+#include <afb/afb-session-x2.h>
#include "afb-auth.h"
#include "afb-context.h"
@@ -60,56 +60,10 @@ int afb_auth_check(struct afb_xreq *xreq, const struct afb_auth *auth)
}
}
-/*********************************************************************************/
-#ifdef BACKEND_PERMISSION_IS_CYNARA
-
-#include <pthread.h>
-#include <cynara-client.h>
-
-static cynara *handle;
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
-int afb_auth_has_permission(struct afb_xreq *xreq, const char *permission)
-{
- int rc;
-
- if (!xreq->cred) {
- /* case of permission for self */
- return 1;
- }
- if (!permission) {
- ERROR("Got a null permission!");
- return 0;
- }
-
- /* cynara isn't reentrant */
- pthread_mutex_lock(&mutex);
-
- /* lazy initialisation */
- if (!handle) {
- rc = cynara_initialize(&handle, NULL);
- if (rc != CYNARA_API_SUCCESS) {
- handle = NULL;
- ERROR("cynara initialisation failed with code %d", rc);
- return 0;
- }
- }
-
- /* query cynara permission */
- rc = cynara_check(handle, xreq->cred->label, afb_context_uuid(&xreq->context), xreq->cred->user, permission);
-
- pthread_mutex_unlock(&mutex);
- return rc == CYNARA_API_ACCESS_ALLOWED;
-}
-
-/*********************************************************************************/
-#else
int afb_auth_has_permission(struct afb_xreq *xreq, const char *permission)
{
- WARNING("Granting permission %s by default of backend", permission ?: "(null)");
- return !!permission;
+ return afb_cred_has_permission(xreq->cred, permission, afb_context_uuid(&xreq->context));
}
-#endif
/*********************************************************************************/
@@ -180,17 +134,17 @@ struct json_object *afb_auth_json_v2(const struct afb_auth *auth, int session)
{
struct json_object *result = NULL;
- if (session & AFB_SESSION_CLOSE_V2)
+ if (session & AFB_SESSION_CLOSE_X2)
result = addperm_key_valstr(result, "session", "close");
- if (session & AFB_SESSION_CHECK_V2)
+ if (session & AFB_SESSION_CHECK_X2)
result = addperm_key_valstr(result, "session", "check");
- if (session & AFB_SESSION_REFRESH_V2)
+ if (session & AFB_SESSION_REFRESH_X2)
result = addperm_key_valstr(result, "token", "refresh");
- if (session & AFB_SESSION_LOA_MASK_V2)
- result = addperm_key_valint(result, "LOA", session & AFB_SESSION_LOA_MASK_V2);
+ if (session & AFB_SESSION_LOA_MASK_X2)
+ result = addperm_key_valint(result, "LOA", session & AFB_SESSION_LOA_MASK_X2);
if (auth)
result = addauth(result, auth);
diff --git a/src/afb-autoset.c b/src/afb-autoset.c
new file mode 100644
index 00000000..102830cb
--- /dev/null
+++ b/src/afb-autoset.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "verbose.h"
+#include "afb-api-ws.h"
+#include "afb-api-so.h"
+#include "afb-apiset.h"
+#include "afb-autoset.h"
+
+static void cleanup(void *closure)
+{
+ struct afb_apiset *call_set = closure;
+ afb_apiset_unref(call_set);
+}
+
+static int onlack(void *closure, struct afb_apiset *set, const char *name, int (*create)(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set))
+{
+ struct afb_apiset *call_set = closure;
+ char *path;
+ const char *base;
+ size_t lbase, lname;
+
+ base = afb_apiset_name(set);
+ lbase = strlen(base);
+ lname = strlen(name);
+
+ path = alloca(2 + lbase + lname);
+ memcpy(path, base, lbase);
+ path[lbase] = '/';
+ memcpy(&path[lbase + 1], name, lname + 1);
+
+ return create(path, set, call_set);
+}
+
+static int add(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set, int (*callback)(void *, struct afb_apiset *, const char*))
+{
+ struct afb_apiset *ownset;
+
+ /* create a sub-apiset */
+ ownset = afb_apiset_create_subset_last(declare_set, path, 3600);
+ if (!ownset) {
+ ERROR("Can't create apiset autoset-ws %s", path);
+ return -1;
+ }
+
+ /* set the onlack behaviour on this set */
+ afb_apiset_onlack_set(ownset, callback, afb_apiset_addref(call_set), cleanup);
+ return 0;
+}
+
+static int create_ws(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
+{
+ return afb_api_ws_add_client(path, declare_set, call_set, 0) >= 0;
+}
+
+static int onlack_ws(void *closure, struct afb_apiset *set, const char *name)
+{
+ return onlack(closure, set, name, create_ws);
+}
+
+int afb_autoset_add_ws(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
+{
+ return add(path, declare_set, call_set, onlack_ws);
+}
+
+static int create_so(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
+{
+ return afb_api_so_add_binding(path, declare_set, call_set) >= 0;
+}
+
+static int onlack_so(void *closure, struct afb_apiset *set, const char *name)
+{
+ return onlack(closure, set, name, create_so);
+}
+
+int afb_autoset_add_so(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
+{
+ return add(path, declare_set, call_set, onlack_so);
+}
diff --git a/src/afb-autoset.h b/src/afb-autoset.h
new file mode 100644
index 00000000..50fdec1a
--- /dev/null
+++ b/src/afb-autoset.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+struct afb_apiset;
+
+extern int afb_autoset_add_ws(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set);
+extern int afb_autoset_add_so(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set);
diff --git a/src/afb-calls.c b/src/afb-calls.c
new file mode 100644
index 00000000..73b89bf0
--- /dev/null
+++ b/src/afb-calls.c
@@ -0,0 +1,818 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <json-c/json.h>
+
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
+
+#include "afb-calls.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 "jobs.h"
+#include "verbose.h"
+
+#define CALLFLAGS (afb_req_x2_subcall_api_session|afb_req_x2_subcall_catch_events)
+#define LEGACY_SUBCALLFLAGS (afb_req_x2_subcall_pass_events|afb_req_x2_subcall_on_behalf)
+
+
+/************************************************************************/
+
+struct modes
+{
+ unsigned hooked: 1;
+ unsigned sync: 1;
+ unsigned legacy: 1;
+};
+
+#define mode_sync ((struct modes){ .hooked=0, .sync=1, .legacy=0 })
+#define mode_async ((struct modes){ .hooked=0, .sync=0, .legacy=0 })
+#define mode_legacy_sync ((struct modes){ .hooked=0, .sync=1, .legacy=1 })
+#define mode_legacy_async ((struct modes){ .hooked=0, .sync=0, .legacy=1 })
+#define mode_hooked_sync ((struct modes){ .hooked=1, .sync=1, .legacy=0 })
+#define mode_hooked_async ((struct modes){ .hooked=1, .sync=0, .legacy=0 })
+#define mode_hooked_legacy_sync ((struct modes){ .hooked=1, .sync=1, .legacy=1 })
+#define mode_hooked_legacy_async ((struct modes){ .hooked=1, .sync=0, .legacy=1 })
+
+union callback {
+ void *any;
+ union {
+ void (*legacy_v1)(void*, int, struct json_object*);
+ void (*legacy_v2)(void*, int, struct json_object*, struct afb_req_x1);
+ void (*legacy_v3)(void*, int, struct json_object*, struct afb_req_x2*);
+ void (*x3)(void*, struct json_object*, const char*, const char *, struct afb_req_x2*);
+ } subcall;
+ union {
+ void (*legacy_v12)(void*, int, struct json_object*);
+ void (*legacy_v3)(void*, int, struct json_object*, struct afb_api_x3*);
+ void (*x3)(void*, struct json_object*, const char*, const char*, struct afb_api_x3*);
+ } call;
+};
+
+struct callreq
+{
+ struct afb_xreq xreq;
+
+ struct afb_export *export;
+
+ struct modes mode;
+
+ int flags;
+
+ union {
+ struct {
+ struct jobloop *jobloop;
+ int returned;
+ int status;
+ struct json_object **object;
+ char **error;
+ char **info;
+ };
+ struct {
+ union callback callback;
+ void *closure;
+ union {
+ void (*final)(void*, struct json_object*, const char*, const char*, union callback, struct afb_export*,struct afb_xreq*);
+ void (*legacy_final)(void*, int, struct json_object*, union callback, struct afb_export*,struct afb_xreq*);
+ };
+ };
+ };
+};
+
+/******************************************************************************/
+
+static int store_reply(
+ struct json_object *iobject, const char *ierror, const char *iinfo,
+ struct json_object **sobject, char **serror, char **sinfo)
+{
+ if (serror) {
+ if (!ierror)
+ *serror = NULL;
+ else if (!(*serror = strdup(ierror))) {
+ ERROR("can't report error %s", ierror);
+ json_object_put(iobject);
+ iobject = NULL;
+ iinfo = NULL;
+ }
+ }
+
+ if (sobject)
+ *sobject = iobject;
+ else
+ json_object_put(iobject);
+
+ if (sinfo) {
+ if (!iinfo)
+ *sinfo = NULL;
+ else if (!(*sinfo = strdup(iinfo)))
+ ERROR("can't report info %s", iinfo);
+ }
+
+ return -!!ierror;
+}
+
+/******************************************************************************/
+
+static void sync_leave(struct callreq *callreq)
+{
+ struct jobloop *jobloop = __atomic_exchange_n(&callreq->jobloop, NULL, __ATOMIC_RELAXED);
+ if (jobloop)
+ jobs_leave(jobloop);
+}
+
+static void sync_enter(int signum, void *closure, struct jobloop *jobloop)
+{
+ struct callreq *callreq = closure;
+ if (!signum) {
+ callreq->jobloop = jobloop;
+ afb_export_process_xreq(callreq->export, &callreq->xreq);
+ } else {
+ afb_xreq_reply(&callreq->xreq, NULL, "internal-error", NULL);
+ }
+}
+
+/******************************************************************************/
+
+static void callreq_destroy_cb(struct afb_xreq *xreq)
+{
+ struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, 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_cb(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
+{
+ struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
+
+ /* centralized hooking */
+ if (callreq->mode.hooked) {
+ if (callreq->mode.sync) {
+ if (callreq->xreq.caller)
+ afb_hook_xreq_subcallsync_result(callreq->xreq.caller, -!!error, object, error, info);
+ else
+ afb_hook_api_callsync_result(callreq->export, -!!error, object, error, info);
+ } else {
+ if (callreq->xreq.caller)
+ afb_hook_xreq_subcall_result(callreq->xreq.caller, object, error, info);
+ else
+ afb_hook_api_call_result(callreq->export, object, error, info);
+ }
+ }
+
+ /* true report of the result */
+ if (callreq->mode.sync) {
+ callreq->returned = 1;
+ if (callreq->mode.legacy) {
+ callreq->status = -!!error;
+ if (callreq->object)
+ *callreq->object = afb_msg_json_reply(object, error, info, NULL);
+ else
+ json_object_put(object);
+ } else {
+ callreq->status = store_reply(object, error, info,
+ callreq->object, callreq->error, callreq->info);
+ }
+ sync_leave(callreq);
+ } else {
+ if (callreq->mode.legacy) {
+ object = afb_msg_json_reply(object, error, info, NULL);
+ callreq->legacy_final(callreq->closure, -!!error, object, callreq->callback, callreq->export, callreq->xreq.caller);
+ } else {
+ callreq->final(callreq->closure, object, error, info, callreq->callback, callreq->export, callreq->xreq.caller);
+ }
+ json_object_put(object);
+ }
+}
+
+static int callreq_subscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event)
+{
+ int rc = 0, rc2;
+ struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
+
+ if (callreq->flags & afb_req_x2_subcall_pass_events)
+ rc = afb_xreq_subscribe(callreq->xreq.caller, event);
+ if (callreq->flags & afb_req_x2_subcall_catch_events) {
+ rc2 = afb_export_subscribe(callreq->export, event);
+ if (rc2 < 0)
+ rc = rc2;
+ }
+ return rc;
+}
+
+static int callreq_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event)
+{
+ int rc = 0, rc2;
+ struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
+
+ if (callreq->flags & afb_req_x2_subcall_pass_events)
+ rc = afb_xreq_unsubscribe(callreq->xreq.caller, event);
+ if (callreq->flags & afb_req_x2_subcall_catch_events) {
+ rc2 = afb_export_unsubscribe(callreq->export, event);
+ if (rc2 < 0)
+ rc = rc2;
+ }
+ return rc;
+}
+
+/******************************************************************************/
+
+const struct afb_xreq_query_itf afb_calls_xreq_itf = {
+ .unref = callreq_destroy_cb,
+ .reply = callreq_reply_cb,
+ .subscribe = callreq_subscribe_cb,
+ .unsubscribe = callreq_unsubscribe_cb
+};
+
+/******************************************************************************/
+
+static struct callreq *callreq_create(
+ struct afb_export *export,
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct modes mode)
+{
+ struct callreq *callreq;
+ size_t lenapi, lenverb;
+ char *api2, *verb2;
+
+ lenapi = 1 + strlen(api);
+ lenverb = 1 + strlen(verb);
+ callreq = malloc(lenapi + lenverb + sizeof *callreq);
+ if (!callreq) {
+ ERROR("out of memory");
+ json_object_put(args);
+ errno = ENOMEM;
+ } else {
+ afb_xreq_init(&callreq->xreq, &afb_calls_xreq_itf);
+ callreq->xreq.context.validated = 1;
+ api2 = (char*)&callreq[1];
+ callreq->xreq.request.called_api = memcpy(api2, api, lenapi);;
+ verb2 = &api2[lenapi];
+ callreq->xreq.request.called_verb = memcpy(verb2, verb, lenverb);
+ callreq->xreq.json = args;
+ callreq->mode = mode;
+ if (caller) {
+ export = afb_export_from_api_x3(caller->request.api);
+ if (flags & afb_req_x2_subcall_on_behalf)
+ callreq->xreq.cred = afb_cred_addref(caller->cred);
+ callreq->xreq.caller = caller;
+ afb_xreq_unhooked_addref(caller);
+ }
+ if (caller && (flags & afb_req_x2_subcall_api_session))
+ afb_context_subinit(&callreq->xreq.context, &caller->context);
+ else
+ afb_export_context_init(export, &callreq->xreq.context);
+ callreq->export = export;
+ callreq->flags = flags;
+ }
+ return callreq;
+}
+
+/******************************************************************************/
+
+static int do_sync(
+ struct afb_export *export,
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct json_object **object,
+ char **error,
+ char **info,
+ struct modes mode)
+{
+ struct callreq *callreq;
+ int rc;
+
+ /* allocates the request */
+ callreq = callreq_create(export, caller, api, verb, args, flags, mode);
+ if (!callreq)
+ goto interr;
+
+ /* initializes the request */
+ callreq->jobloop = NULL;
+ callreq->returned = 0;
+ callreq->status = 0;
+ callreq->object = object;
+ callreq->error = error;
+ callreq->info = info;
+
+ afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */
+
+ rc = jobs_enter(NULL, 0, sync_enter, callreq);
+ if (rc >= 0 && callreq->returned) {
+ rc = callreq->status;
+ afb_xreq_unhooked_unref(&callreq->xreq);
+ return rc;
+ }
+
+ afb_xreq_unhooked_unref(&callreq->xreq);
+interr:
+ return store_reply(NULL, "internal-error", NULL, object, info, error);
+}
+
+/******************************************************************************/
+
+static void do_async(
+ struct afb_export *export,
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void *callback,
+ void *closure,
+ void (*final)(void*, struct json_object*, const char*, const char*, union callback, struct afb_export*,struct afb_xreq*),
+ struct modes mode)
+{
+ struct callreq *callreq;
+
+ callreq = callreq_create(export, caller, api, verb, args, flags, mode);
+
+ if (!callreq)
+ final(closure, NULL, "internal-error", NULL, (union callback){ .any = callback }, export, caller);
+ else {
+ callreq->callback.any = callback;
+ callreq->closure = closure;
+ callreq->final = final;
+
+ afb_export_process_xreq(callreq->export, &callreq->xreq);
+ }
+}
+
+/******************************************************************************/
+
+static void final_call(
+ void *closure,
+ struct json_object *object,
+ const char *error,
+ const char *info,
+ union callback callback,
+ struct afb_export *export,
+ struct afb_xreq *caller)
+{
+ if (callback.call.x3)
+ callback.call.x3(closure, object, error, info, afb_export_to_api_x3(export));
+}
+
+static void final_subcall(
+ void *closure,
+ struct json_object *object,
+ const char *error,
+ const char *info,
+ union callback callback,
+ struct afb_export *export,
+ struct afb_xreq *caller)
+{
+ if (callback.subcall.x3)
+ callback.subcall.x3(closure, object, error, info, xreq_to_req_x2(caller));
+}
+
+/******************************************************************************/
+
+void afb_calls_call(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*),
+ void *closure)
+{
+ do_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_call, mode_async);
+}
+
+void afb_calls_hooked_call(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*),
+ void *closure)
+{
+ afb_hook_api_call(export, api, verb, args);
+ do_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_call, mode_hooked_async);
+}
+
+int afb_calls_call_sync(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **object,
+ char **error,
+ char **info)
+{
+ return do_sync(export, NULL, api, verb, args, CALLFLAGS, object, error, info, mode_sync);
+}
+
+int afb_calls_hooked_call_sync(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **object,
+ char **error,
+ char **info)
+{
+ afb_hook_api_callsync(export, api, verb, args);
+ return do_sync(export, NULL, api, verb, args, CALLFLAGS, object, error, info, mode_hooked_sync);
+}
+
+void afb_calls_subcall(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
+ void *closure)
+{
+ do_async(NULL, xreq, api, verb, args, flags, callback, closure, final_subcall, mode_async);
+}
+
+void afb_calls_hooked_subcall(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
+ void *closure)
+{
+ afb_hook_xreq_subcall(xreq, api, verb, args, flags);
+ do_async(NULL, xreq, api, verb, args, flags, callback, closure, final_subcall, mode_hooked_async);
+}
+
+int afb_calls_subcall_sync(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct json_object **object,
+ char **error,
+ char **info)
+{
+ return do_sync(NULL, xreq, api, verb, args, flags, object, error, info, mode_sync);
+}
+
+int afb_calls_hooked_subcall_sync(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct json_object **object,
+ char **error,
+ char **info)
+{
+ afb_hook_xreq_subcallsync(xreq, api, verb, args, flags);
+ return do_sync(NULL, xreq, api, verb, args, flags, object, error, info, mode_hooked_sync);
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+static int do_legacy_sync(
+ struct afb_export *export,
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct json_object **object,
+ struct modes mode)
+{
+ struct callreq *callreq;
+ int rc;
+
+ /* allocates the request */
+ callreq = callreq_create(export, caller, api, verb, args, flags, mode);
+ if (!callreq)
+ goto interr;
+
+ /* initializes the request */
+ callreq->jobloop = NULL;
+ callreq->returned = 0;
+ callreq->status = 0;
+ callreq->object = object;
+
+ afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */
+
+ rc = jobs_enter(NULL, 0, sync_enter, callreq);
+ if (rc >= 0 && callreq->returned) {
+ rc = callreq->status;
+ afb_xreq_unhooked_unref(&callreq->xreq);
+ return rc;
+ }
+
+ afb_xreq_unhooked_unref(&callreq->xreq);
+interr:
+ if (object)
+ *object = afb_msg_json_internal_error();
+ return -1;
+}
+
+/******************************************************************************/
+
+static void do_legacy_async(
+ struct afb_export *export,
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void *callback,
+ void *closure,
+ void (*final)(void*, int, struct json_object*, union callback, struct afb_export*,struct afb_xreq*),
+ struct modes mode)
+{
+ struct callreq *callreq;
+ struct json_object *ie;
+
+ callreq = callreq_create(export, caller, api, verb, args, flags, mode);
+
+ if (!callreq) {
+ ie = afb_msg_json_internal_error();
+ final(closure, -1, ie, (union callback){ .any = callback }, export, caller);
+ json_object_put(ie);
+ } else {
+ callreq->callback.any = callback;
+ callreq->closure = closure;
+ callreq->legacy_final = final;
+
+ afb_export_process_xreq(callreq->export, &callreq->xreq);
+ }
+}
+
+/******************************************************************************/
+
+static void final_legacy_call_v12(
+ void *closure,
+ int status,
+ struct json_object *object,
+ union callback callback,
+ struct afb_export *export,
+ struct afb_xreq *caller)
+{
+ if (callback.call.legacy_v12)
+ callback.call.legacy_v12(closure, status, object);
+}
+
+static void final_legacy_call_v3(
+ void *closure,
+ int status,
+ struct json_object *object,
+ union callback callback,
+ struct afb_export *export,
+ struct afb_xreq *caller)
+{
+ if (callback.call.legacy_v3)
+ callback.call.legacy_v3(closure, status, object, afb_export_to_api_x3(export));
+}
+
+/******************************************************************************/
+
+void afb_calls_legacy_call_v12(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *closure)
+{
+ do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v12, mode_legacy_async);
+}
+
+void afb_calls_legacy_hooked_call_v12(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *closure)
+{
+ afb_hook_api_call(export, api, verb, args);
+ do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v12, mode_hooked_legacy_async);
+}
+
+void afb_calls_legacy_call_v3(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *),
+ void *closure)
+{
+ do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v3, mode_legacy_async);
+}
+
+void afb_calls_legacy_hooked_call_v3(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *),
+ void *closure)
+{
+ afb_hook_api_call(export, api, verb, args);
+ do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v3, mode_hooked_legacy_async);
+}
+
+int afb_calls_legacy_call_sync(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result)
+{
+ return do_legacy_sync(export, NULL, api, verb, args, CALLFLAGS, result, mode_legacy_sync);
+}
+
+int afb_calls_legacy_hooked_call_sync(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result)
+{
+ int rc;
+ struct json_object *object;
+
+ afb_hook_api_callsync(export, api, verb, args);
+ rc = do_legacy_sync(export, NULL, api, verb, args, CALLFLAGS, &object, mode_hooked_legacy_sync);
+ if (result)
+ *result = object;
+ else
+ json_object_put(object);
+ return rc;
+}
+
+/******************************************************************************/
+
+static void final_legacy_subcall_v1(
+ void *closure,
+ int status,
+ struct json_object *object,
+ union callback callback,
+ struct afb_export *export,
+ struct afb_xreq *caller)
+{
+ if (callback.subcall.legacy_v1)
+ callback.subcall.legacy_v1(closure, status, object);
+}
+
+static void final_legacy_subcall_v2(
+ void *closure,
+ int status,
+ struct json_object *object,
+ union callback callback,
+ struct afb_export *export,
+ struct afb_xreq *caller)
+{
+ if (callback.subcall.legacy_v2)
+ callback.subcall.legacy_v2(closure, status, object, xreq_to_req_x1(caller));
+}
+
+static void final_legacy_subcall_v3(
+ void *closure,
+ int status,
+ struct json_object *object,
+ union callback callback,
+ struct afb_export *export,
+ struct afb_xreq *caller)
+{
+ if (callback.subcall.legacy_v3)
+ callback.subcall.legacy_v3(closure, status, object, xreq_to_req_x2(caller));
+}
+
+/******************************************************************************/
+
+void afb_calls_legacy_subcall_v1(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *closure)
+{
+ do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v1, mode_legacy_async);
+}
+
+void afb_calls_legacy_hooked_subcall_v1(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *closure)
+{
+ afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
+ do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v1, mode_hooked_legacy_async);
+}
+
+void afb_calls_legacy_subcall_v2(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x1),
+ void *closure)
+{
+ do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v2, mode_legacy_async);
+}
+
+void afb_calls_legacy_hooked_subcall_v2(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x1),
+ void *closure)
+{
+ afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
+ do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v2, mode_hooked_legacy_async);
+}
+
+void afb_calls_legacy_subcall_v3(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *),
+ void *closure)
+{
+ do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v3, mode_legacy_async);
+}
+
+void afb_calls_legacy_hooked_subcall_v3(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *),
+ void *closure)
+{
+ afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
+ do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v3, mode_hooked_legacy_async);
+}
+
+int afb_calls_legacy_subcall_sync(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result)
+{
+ return do_legacy_sync(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, result, mode_legacy_sync);
+}
+
+int afb_calls_legacy_hooked_subcall_sync(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result)
+{
+ afb_hook_xreq_subcallsync(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
+ return do_legacy_sync(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, result, mode_hooked_legacy_sync);
+}
diff --git a/src/afb-calls.h b/src/afb-calls.h
new file mode 100644
index 00000000..15b71bf2
--- /dev/null
+++ b/src/afb-calls.h
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+struct json_object;
+
+struct afb_export;
+struct afb_xreq;
+
+struct afb_api_x3;
+struct afb_req_x1;
+struct afb_req_x2;
+
+/******************************************************************************/
+
+extern
+void afb_calls_call(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*),
+ void *closure);
+
+extern
+void afb_calls_hooked_call(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*),
+ void *closure);
+
+extern
+int afb_calls_call_sync(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **object,
+ char **error,
+ char **info);
+
+extern
+int afb_calls_hooked_call_sync(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **object,
+ char **error,
+ char **info);
+
+extern
+void afb_calls_subcall(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
+ void *closure);
+
+extern
+void afb_calls_hooked_subcall(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
+ void *closure);
+
+extern
+int afb_calls_subcall_sync(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct json_object **object,
+ char **error,
+ char **info);
+
+extern
+int afb_calls_hooked_subcall_sync(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct json_object **object,
+ char **error,
+ char **info);
+
+/******************************************************************************/
+
+extern
+void afb_calls_legacy_call_v12(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *closure);
+
+extern
+void afb_calls_legacy_hooked_call_v12(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *closure);
+
+extern
+void afb_calls_legacy_call_v3(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *),
+ void *closure);
+
+extern
+void afb_calls_legacy_hooked_call_v3(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *),
+ void *closure);
+
+extern
+int afb_calls_legacy_call_sync(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result);
+
+extern
+int afb_calls_legacy_hooked_call_sync(
+ struct afb_export *export,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result);
+
+/******************************************************************************/
+
+extern
+void afb_calls_legacy_subcall_v1(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *closure);
+
+extern
+void afb_calls_legacy_hooked_subcall_v1(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *closure);
+
+extern
+void afb_calls_legacy_subcall_v2(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x1),
+ void *closure);
+
+extern
+void afb_calls_legacy_hooked_subcall_v2(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x1),
+ void *closure);
+
+extern
+void afb_calls_legacy_subcall_v3(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *),
+ void *closure);
+
+extern
+void afb_calls_legacy_hooked_subcall_v3(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *),
+ void *closure);
+
+extern
+int afb_calls_legacy_subcall_sync(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result);
+
+extern
+int afb_calls_legacy_hooked_subcall_sync(
+ struct afb_xreq *caller,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **result);
diff --git a/src/afb-config.c b/src/afb-config.c
index 2a6f931f..f3f48fd6 100644
--- a/src/afb-config.c
+++ b/src/afb-config.c
@@ -23,6 +23,7 @@
#include <getopt.h>
#include <limits.h>
#include <unistd.h>
+#include <ctype.h>
#include <json-c/json.h>
@@ -30,8 +31,6 @@
#include "afb-config.h"
#include "afb-hook.h"
-#include <afb/afb-binding-v1.h>
-
#if !defined(BINDING_INSTALL_DIR)
#error "you should define BINDING_INSTALL_DIR"
#endif
@@ -51,17 +50,25 @@
# define HAS_DBUS 0
#endif
-// default
-#define DEFLT_CNTX_TIMEOUT 32000000 // default Client Connection
- // Timeout: few more than one year
-#define DEFLT_API_TIMEOUT 20 // default Plugin API Timeout [0=NoLimit
- // for Debug Only]
-#define DEFLT_CACHE_TIMEOUT 100000 // default Static File Chache
- // [Client Side Cache
- // 100000~=1day]
-#define CTX_NBCLIENTS 10 // allow a default of 10 authenticated
- // clients
+/**
+ * The default timeout of sessions in seconds
+ */
+#define DEFAULT_SESSION_TIMEOUT 32000000
+
+/**
+ * The default timeout of api calls in seconds
+ */
+#define DEFAULT_API_TIMEOUT 20
+
+/**
+ * The default timeout of cache in seconds
+ */
+#define DEFAULT_CACHE_TIMEOUT 100000
+/**
+ * The default maximum count of sessions
+ */
+#define DEFAULT_MAX_SESSION_COUNT 200
// Define command line option
#define SET_BACKGROUND 2
@@ -81,14 +88,15 @@
#define SET_WEAK_LDPATH 16
#define NO_LDPATH 17
+#if defined(KEEP_LEGACY_MODE)
#define SET_MODE 18
+#endif
#if HAS_DBUS
# define DBUS_CLIENT 20
# define DBUS_SERVICE 21
#endif
-#define SO_BINDING 22
#define SET_SESSIONMAX 23
@@ -99,11 +107,18 @@
#define SET_NO_HTTPD 28
+#define AUTO_WS 'a'
+#define AUTO_LINK 'A'
+#define SO_BINDING 'b'
#define ADD_CALL 'c'
+#if !defined(REMOVE_LEGACY_TRACE)
#define SET_TRACEDITF 'D'
+#endif
#define SET_TRACEEVT 'E'
#define SET_EXEC 'e'
#define DISPLAY_HELP 'h'
+#define SET_LOG 'l'
+#define SET_TRACEAPI 'I'
#if HAS_MONITORING
# define SET_MONITORING 'M'
#endif
@@ -111,7 +126,9 @@
#define SET_TCP_PORT 'p'
#define SET_QUIET 'q'
#define SET_RNDTOKEN 'r'
+#if !defined(REMOVE_LEGACY_TRACE)
#define SET_TRACESVC 'S'
+#endif
#define SET_TRACESES 's'
#define SET_TRACEREQ 'T'
#define SET_AUTH_TOKEN 't'
@@ -121,7 +138,15 @@
#define SET_WORK_DIR 'w'
const char shortopts[] =
- "c:D:E:ehn:p:qrS:s:T:t:u:Vvw:"
+ "a:A:b:c:"
+#if !defined(REMOVE_LEGACY_TRACE)
+ "D:"
+#endif
+ "E:ehl:n:p:qr"
+#if !defined(REMOVE_LEGACY_TRACE)
+ "S:"
+#endif
+ "s:T:t:u:Vvw:"
#if HAS_MONITORING
"M"
#endif
@@ -140,6 +165,7 @@ static AFB_options cliOptions[] = {
/* *INDENT-OFF* */
{SET_VERBOSE, 0, "verbose", "Verbose Mode, repeat to increase verbosity"},
{SET_QUIET, 0, "quiet", "Quiet Mode, repeat to decrease verbosity"},
+ {SET_LOG, 1, "log", "tune log level"},
{SET_FORGROUND, 0, "foreground", "Get all in foreground mode"},
{SET_BACKGROUND, 0, "daemon", "Get all in background mode"},
@@ -172,7 +198,9 @@ static AFB_options cliOptions[] = {
{DISPLAY_VERSION, 0, "version", "Display version and copyright"},
{DISPLAY_HELP, 0, "help", "Display this help"},
+#if defined(KEEP_LEGACY_MODE)
{SET_MODE, 1, "mode", "Set the mode: either local, remote or global"},
+#endif
#if HAS_DBUS
{DBUS_CLIENT, 1, "dbus-client", "Bind to an afb service through dbus"},
@@ -181,13 +209,19 @@ static AFB_options cliOptions[] = {
{WS_CLIENT, 1, "ws-client", "Bind to an afb service through websocket"},
{WS_SERVICE, 1, "ws-server", "Provides an afb service through websockets"},
+ {AUTO_WS, 1, "auto-ws", "Automatic bind on need to remote service through websocket"},
+ {AUTO_LINK, 1, "auto-link", "Automatic load on need to binding shared objects"},
+
{SET_SESSIONMAX, 1, "session-max", "Max count of session simultaneously [default 10]"},
{SET_TRACEREQ, 1, "tracereq", "Log the requests: no, common, extra, all"},
- {SET_TRACEDITF, 1, "traceditf", "Log the requests: no, common, extra, all"},
- {SET_TRACESVC, 1, "tracesvc", "Log the requests: no, all"},
- {SET_TRACEEVT, 1, "traceevt", "Log the requests: no, common, extra, all"},
+#if !defined(REMOVE_LEGACY_TRACE)
+ {SET_TRACEDITF, 1, "traceditf", "Log the daemons: no, common, all"},
+ {SET_TRACESVC, 1, "tracesvc", "Log the services: no, all"},
+#endif
+ {SET_TRACEEVT, 1, "traceevt", "Log the events: no, common, extra, all"},
{SET_TRACESES, 1, "traceses", "Log the sessions: no, all"},
+ {SET_TRACEAPI, 1, "traceapi", "Log the apis: no, common, api, event, all"},
{ADD_CALL, 1, "call", "call at start format of val: API/VERB:json-args"},
@@ -216,19 +250,20 @@ static struct enumdesc tracereq_desc[] = {
{ NULL, 0 }
};
+#if !defined(REMOVE_LEGACY_TRACE)
static struct enumdesc traceditf_desc[] = {
{ "no", 0 },
- { "common", afb_hook_flags_ditf_common },
- { "extra", afb_hook_flags_ditf_extra },
- { "all", afb_hook_flags_ditf_all },
+ { "common", afb_hook_flags_api_ditf_common },
+ { "all", afb_hook_flags_api_ditf_all },
{ NULL, 0 }
};
static struct enumdesc tracesvc_desc[] = {
{ "no", 0 },
- { "all", afb_hook_flags_svc_all },
+ { "all", afb_hook_flags_api_svc_all },
{ NULL, 0 }
};
+#endif
static struct enumdesc traceevt_desc[] = {
{ "no", 0 },
@@ -245,12 +280,25 @@ static struct enumdesc traceses_desc[] = {
{ NULL, 0 }
};
+static struct enumdesc traceapi_desc[] = {
+ { "no", 0 },
+ { "common", afb_hook_flags_api_common },
+ { "api", afb_hook_flags_api_api|afb_hook_flag_api_start },
+ { "event", afb_hook_flags_api_event|afb_hook_flag_api_start },
+ { "all", afb_hook_flags_api_all },
+ { NULL, 0 }
+};
+
+#if defined(KEEP_LEGACY_MODE)
+#include <afb/afb-binding-v1.h>
+
static struct enumdesc mode_desc[] = {
{ "local", AFB_MODE_LOCAL },
{ "remote", AFB_MODE_REMOTE },
{ "global", AFB_MODE_GLOBAL },
{ NULL, 0 }
};
+#endif
/*----------------------------------------------------------
| printversion
@@ -453,6 +501,53 @@ static char **make_exec(char **argv)
}
/*---------------------------------------------------------
+ | set the log levels
+ +--------------------------------------------------------- */
+
+static void set_log(char *args)
+{
+ char o = 0, s, *p, *i = args;
+ int lvl;
+
+ for(;;) switch (*i) {
+ case 0:
+ return;
+ case '+':
+ case '-':
+ o = *i;
+ /*@fallthrough@*/
+ case ' ':
+ case ',':
+ i++;
+ break;
+ default:
+ p = i;
+ while (isalpha(*p)) p++;
+ s = *p;
+ *p = 0;
+ lvl = verbose_level_of_name(i);
+ if (lvl < 0) {
+ i = strdupa(p);
+ *p = s;
+ ERROR("Bad log name '%s' in %s", i, args);
+ exit(1);
+ }
+ *p = s;
+ i = p;
+ if (o == '-')
+ verbose_sub(lvl);
+ else {
+ if (!o) {
+ verbose_clear();
+ o = '+';
+ }
+ verbose_add(lvl);
+ }
+ break;
+ }
+}
+
+/*---------------------------------------------------------
| Parse option and launch action
+--------------------------------------------------------- */
@@ -479,23 +574,27 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config)
while ((optc = getopt_long(argc, argv, shortopts, gnuOptions, NULL)) != EOF) {
switch (optc) {
case SET_VERBOSE:
- verbosity++;
+ verbose_inc();
break;
case SET_QUIET:
- verbosity--;
+ verbose_dec();
+ break;
+
+ case SET_LOG:
+ set_log(argvalstr(optc));
break;
case SET_TCP_PORT:
- config->httpdPort = argvalintdec(optc, 1024, 32767);
+ config->http_port = argvalintdec(optc, 1024, 32767);
break;
case SET_APITIMEOUT:
- config->apiTimeout = argvalintdec(optc, 0, INT_MAX);
+ config->api_timeout = argvalintdec(optc, 0, INT_MAX);
break;
case SET_CNTXTIMEOUT:
- config->cntxTimeout = argvalintdec(optc, 0, INT_MAX);
+ config->session_timeout = argvalintdec(optc, 0, INT_MAX);
break;
case SET_ROOT_DIR:
@@ -557,11 +656,11 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config)
break;
case SET_CACHE_TIMEOUT:
- config->cacheTimeout = argvalintdec(optc, 0, INT_MAX);
+ config->cache_timeout = argvalintdec(optc, 0, INT_MAX);
break;
case SET_SESSIONMAX:
- config->nbSessionMax = argvalintdec(optc, 1, INT_MAX);
+ config->max_session_count = argvalintdec(optc, 1, INT_MAX);
break;
case SET_FORGROUND:
@@ -578,9 +677,11 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config)
config->name = argvalstr(optc);
break;
+#if defined(KEEP_LEGACY_MODE)
case SET_MODE:
config->mode = argvalenum(optc, mode_desc);
break;
+#endif
#if HAS_DBUS
case DBUS_CLIENT:
@@ -604,10 +705,19 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config)
list_add(&config->so_bindings, argvalstr(optc));
break;
+ case AUTO_WS:
+ list_add(&config->auto_ws, argvalstr(optc));
+ break;
+
+ case AUTO_LINK:
+ list_add(&config->auto_link, argvalstr(optc));
+ break;
+
case SET_TRACEREQ:
config->tracereq = argvalenum(optc, tracereq_desc);
break;
+#if !defined(REMOVE_LEGACY_TRACE)
case SET_TRACEDITF:
config->traceditf = argvalenum(optc, traceditf_desc);
break;
@@ -615,6 +725,7 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config)
case SET_TRACESVC:
config->tracesvc = argvalenum(optc, tracesvc_desc);
break;
+#endif
case SET_TRACEEVT:
config->traceevt = argvalenum(optc, traceevt_desc);
@@ -624,9 +735,13 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config)
config->traceses = argvalenum(optc, traceses_desc);
break;
+ case SET_TRACEAPI:
+ config->traceapi = argvalenum(optc, traceapi_desc);
+ break;
+
case SET_NO_HTTPD:
noarg(optc);
- config->noHttpd = 1;
+ config->no_httpd = 1;
break;
case SET_EXEC:
@@ -663,28 +778,28 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config)
static void fulfill_config(struct afb_config *config)
{
// default HTTP port
- if (config->httpdPort == 0)
- config->httpdPort = 1234;
+ if (config->http_port == 0)
+ config->http_port = 1234;
// default binding API timeout
- if (config->apiTimeout == 0)
- config->apiTimeout = DEFLT_API_TIMEOUT;
+ if (config->api_timeout == 0)
+ config->api_timeout = DEFAULT_API_TIMEOUT;
// default AUTH_TOKEN
if (config->random_token)
config->token = NULL;
// cache timeout default one hour
- if (config->cacheTimeout == 0)
- config->cacheTimeout = DEFLT_CACHE_TIMEOUT;
+ if (config->cache_timeout == 0)
+ config->cache_timeout = DEFAULT_CACHE_TIMEOUT;
// cache timeout default one hour
- if (config->cntxTimeout == 0)
- config->cntxTimeout = DEFLT_CNTX_TIMEOUT;
+ if (config->session_timeout == 0)
+ config->session_timeout = DEFAULT_SESSION_TIMEOUT;
// max count of sessions
- if (config->nbSessionMax == 0)
- config->nbSessionMax = CTX_NBCLIENTS;
+ if (config->max_session_count == 0)
+ config->max_session_count = DEFAULT_MAX_SESSION_COUNT;
/* set directories */
if (config->workdir == NULL)
@@ -717,6 +832,10 @@ static void fulfill_config(struct afb_config *config)
strncpy(config->console, config->uploaddir, 512);
strncat(config->console, "/AFB-console.out", 512);
}
+
+#if !defined(REMOVE_LEGACY_TRACE)
+ config->traceapi |= config->traceditf | config->tracesvc;
+#endif
}
void afb_config_dump(struct afb_config *config)
@@ -761,21 +880,26 @@ void afb_config_dump(struct afb_config *config)
V(exec)
- D(httpdPort)
- D(cacheTimeout)
- D(apiTimeout)
- D(cntxTimeout)
- D(nbSessionMax)
+ D(http_port)
+ D(cache_timeout)
+ D(api_timeout)
+ D(session_timeout)
+ D(max_session_count)
+#if defined(KEEP_LEGACY_MODE)
E(mode,mode_desc)
+#endif
E(tracereq,tracereq_desc)
+#if !defined(REMOVE_LEGACY_TRACE)
E(traceditf,traceditf_desc)
E(tracesvc,tracesvc_desc)
+#endif
E(traceevt,traceevt_desc)
E(traceses,traceses_desc)
+ E(traceapi,traceapi_desc)
B(no_ldpaths)
- B(noHttpd)
+ B(no_httpd)
B(background)
#if HAS_MONITORING
B(monitoring)
@@ -823,10 +947,13 @@ static void on_environment_enum(int *to, const char *name, struct enumdesc *desc
static void parse_environment(struct afb_config *config)
{
on_environment_enum(&config->tracereq, "AFB_TRACEREQ", tracereq_desc);
+#if !defined(REMOVE_LEGACY_TRACE)
on_environment_enum(&config->traceditf, "AFB_TRACEDITF", traceditf_desc);
on_environment_enum(&config->tracesvc, "AFB_TRACESVC", tracesvc_desc);
+#endif
on_environment_enum(&config->traceevt, "AFB_TRACEEVT", traceevt_desc);
on_environment_enum(&config->traceses, "AFB_TRACESES", traceses_desc);
+ on_environment_enum(&config->traceapi, "AFB_TRACEAPI", traceapi_desc);
on_environment_list(&config->ldpaths, "AFB_LDPATHS");
}
@@ -839,7 +966,7 @@ struct afb_config *afb_config_parse_arguments(int argc, char **argv)
parse_environment(result);
parse_arguments(argc, argv, result);
fulfill_config(result);
- if (verbosity >= 3)
+ if (verbose_wants(Log_Level_Info))
afb_config_dump(result);
return result;
}
@@ -895,21 +1022,26 @@ struct json_object *afb_config_json(struct afb_config *config)
V(exec)
- D(httpdPort)
- D(cacheTimeout)
- D(apiTimeout)
- D(cntxTimeout)
- D(nbSessionMax)
+ D(http_port)
+ D(cache_timeout)
+ D(api_timeout)
+ D(session_timeout)
+ D(max_session_count)
+#if defined(KEEP_LEGACY_MODE)
E(mode,mode_desc)
+#endif
E(tracereq,tracereq_desc)
+#if !defined(REMOVE_LEGACY_TRACE)
E(traceditf,traceditf_desc)
E(tracesvc,tracesvc_desc)
+#endif
E(traceevt,traceevt_desc)
E(traceses,traceses_desc)
+ E(traceapi,traceapi_desc)
B(no_ldpaths)
- B(noHttpd)
+ B(no_httpd)
B(background)
#if HAS_MONITORING
B(monitoring)
diff --git a/src/afb-config.h b/src/afb-config.h
index 89b1f78e..30fd398c 100644
--- a/src/afb-config.h
+++ b/src/afb-config.h
@@ -22,22 +22,27 @@ struct json_object;
* other definitions ---------------------------------------------------
*/
+/**
+ * list of configuration values
+ */
struct afb_config_list {
struct afb_config_list *next;
char *value;
};
-// main config structure
+/**
+ * main config structure
+ */
struct afb_config {
- char *console; // console device name (can be a file or a tty)
- char *rootdir; // base dir for files
- char *roothttp; // directory for http files
- char *rootbase; // Angular HTML5 base URL
- char *rootapi; // Base URL for REST APIs
- char *workdir; // where to run the program
- char *uploaddir; // where to store transient files
- char *token; // initial authentication token [default NULL no session]
- char *name; /* name to set to the daemon */
+ char *console; /*< console device name (can be a file or a tty) */
+ char *rootdir; /*< base dir for files */
+ char *roothttp; /*< directory for http files */
+ char *rootbase; /*< Angular HTML5 base URL */
+ char *rootapi; /*< Base URL for REST APIs */
+ char *workdir; /*< where to run the program */
+ char *uploaddir; /*< where to store transient files */
+ char *token; /*< initial authentication token [default NULL no session] */
+ char *name; /*< name to set to the daemon */
struct afb_config_list *aliases;
#if defined(WITH_DBUS_TRANSPARENCY)
@@ -50,32 +55,39 @@ struct afb_config {
struct afb_config_list *ldpaths;
struct afb_config_list *weak_ldpaths;
struct afb_config_list *calls;
+ struct afb_config_list *auto_ws;
+ struct afb_config_list *auto_link;
char **exec;
/* integers */
- int httpdPort;
- int cacheTimeout;
- int apiTimeout;
- int cntxTimeout; // Client Session Context timeout
- int nbSessionMax; // max count of sessions
+ int http_port;
+ int cache_timeout;
+ int api_timeout;
+ int session_timeout; /*< session timeout */
+ int max_session_count; /*< max count of sessions */
/* enums */
+#if defined(KEEP_LEGACY_MODE)
int mode; // mode of listening
+#endif
int tracereq;
+#if !defined(REMOVE_LEGACY_TRACE)
int traceditf;
int tracesvc;
+#endif
int traceevt;
int traceses;
+ int traceapi;
/* booleans */
- unsigned no_ldpaths: 1; /* disable default ldpaths */
- unsigned noHttpd: 1;
- unsigned background: 1; /* run in backround mode */
+ unsigned no_ldpaths: 1; /**< disable default ldpaths */
+ unsigned no_httpd: 1;
+ unsigned background: 1; /**< run in backround mode */
+ unsigned random_token: 1; /**< expects a random token */
#if defined(WITH_MONITORING_OPTION)
- unsigned monitoring: 1; /* activates monitoring */
+ unsigned monitoring: 1; /**< activates monitoring */
#endif
- unsigned random_token: 1; /* expects a random token */
};
extern struct afb_config *afb_config_parse_arguments(int argc, char **argv);
diff --git a/src/afb-context.c b/src/afb-context.c
index 13733ce6..6b3d6e9d 100644
--- a/src/afb-context.c
+++ b/src/afb-context.c
@@ -21,6 +21,7 @@
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
+#include <errno.h>
#include "afb-session.h"
#include "afb-context.h"
@@ -184,10 +185,12 @@ static inline unsigned ptr2loa(void *ptr)
int afb_context_change_loa(struct afb_context *context, unsigned loa)
{
- if (!context->validated || loa > 7)
- return 0;
+ if (!context->validated || loa > 7) {
+ errno = EINVAL;
+ return -1;
+ }
- return 0 <= afb_session_set_cookie(context->session, loa_key(context), loa2ptr(loa), NULL);
+ return afb_session_set_cookie(context->session, loa_key(context), loa2ptr(loa), NULL);
}
unsigned afb_context_get_loa(struct afb_context *context)
@@ -195,5 +198,3 @@ unsigned afb_context_get_loa(struct afb_context *context)
assert(context->session != NULL);
return ptr2loa(afb_session_get_cookie(context->session, loa_key(context)));
}
-
-
diff --git a/src/afb-cred.c b/src/afb-cred.c
index f09d4441..b7b3175e 100644
--- a/src/afb-cred.c
+++ b/src/afb-cred.c
@@ -18,6 +18,7 @@
#define _GNU_SOURCE
#include <stdlib.h>
+#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
@@ -26,6 +27,8 @@
#include <sys/socket.h>
#include "afb-cred.h"
+#include "verbose.h"
+
#define MAX_LABEL_LENGTH 1024
@@ -46,6 +49,10 @@
# define DEFAULT_PEERCRED_PID 0 /* no process */
#endif
+static char on_behalf_credential_permission[] = "urn:AGL:permission:*:partner:on-behalf-credentials";
+static char export_format[] = "%x:%x:%x-%s";
+static char import_format[] = "%x:%x:%x-%n";
+
static struct afb_cred *current;
static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *label, size_t size)
@@ -70,6 +77,7 @@ static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *labe
cred->uid = uid;
cred->gid = gid;
cred->pid = pid;
+ cred->exported = NULL;
dest = (char*)(&cred[1]);
cred->user = dest;
while(i)
@@ -175,3 +183,105 @@ struct afb_cred *afb_cred_current()
return afb_cred_addref(current);
}
+const char *afb_cred_export(struct afb_cred *cred)
+{
+ int rc;
+
+ if (!cred->exported) {
+ rc = asprintf((char**)&cred->exported,
+ export_format,
+ (int)cred->uid,
+ (int)cred->gid,
+ (int)cred->pid,
+ cred->label);
+ if (rc < 0) {
+ errno = ENOMEM;
+ cred->exported = NULL;
+ }
+ }
+ return cred->exported;
+}
+
+struct afb_cred *afb_cred_import(const char *string)
+{
+ struct afb_cred *cred;
+ int rc, uid, gid, pid, pos;
+
+ rc = sscanf(string, import_format, &uid, &gid, &pid, &pos);
+ if (rc == 3)
+ cred = afb_cred_create((uid_t)uid, (gid_t)gid, (pid_t)pid, &string[pos]);
+ else {
+ errno = EINVAL;
+ cred = NULL;
+ }
+ return cred;
+}
+
+struct afb_cred *afb_cred_mixed_on_behalf_import(struct afb_cred *cred, const char *context, const char *exported)
+
+{
+ struct afb_cred *imported;
+ if (exported) {
+ if (afb_cred_has_permission(cred, on_behalf_credential_permission, context)) {
+ imported = afb_cred_import(exported);
+ if (imported)
+ return imported;
+ ERROR("Can't import on behalf credentials: %m");
+ } else {
+ ERROR("On behalf credentials refused");
+ }
+ }
+ return afb_cred_addref(cred);
+}
+
+/*********************************************************************************/
+#ifdef BACKEND_PERMISSION_IS_CYNARA
+
+#include <pthread.h>
+#include <cynara-client.h>
+
+static cynara *handle;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context)
+{
+ int rc;
+
+ if (!cred) {
+ /* case of permission for self */
+ return 1;
+ }
+ if (!permission) {
+ ERROR("Got a null permission!");
+ return 0;
+ }
+
+ /* cynara isn't reentrant */
+ pthread_mutex_lock(&mutex);
+
+ /* lazy initialisation */
+ if (!handle) {
+ rc = cynara_initialize(&handle, NULL);
+ if (rc != CYNARA_API_SUCCESS) {
+ handle = NULL;
+ ERROR("cynara initialisation failed with code %d", rc);
+ return 0;
+ }
+ }
+
+ /* query cynara permission */
+ rc = cynara_check(handle, cred->label, context ?: "", cred->user, permission);
+
+ pthread_mutex_unlock(&mutex);
+ return rc == CYNARA_API_ACCESS_ALLOWED;
+}
+
+/*********************************************************************************/
+#else
+int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context)
+{
+ WARNING("Granting permission %s by default of backend", permission ?: "(null)");
+ return !!permission;
+}
+#endif
+
diff --git a/src/afb-cred.h b/src/afb-cred.h
index 7ee4723c..614fa4bc 100644
--- a/src/afb-cred.h
+++ b/src/afb-cred.h
@@ -28,6 +28,7 @@ struct afb_cred
const char *user;
const char *label;
const char *id;
+ const char *exported;
};
extern struct afb_cred *afb_cred_current();
@@ -36,4 +37,10 @@ extern struct afb_cred *afb_cred_create_for_socket(int fd);
extern struct afb_cred *afb_cred_addref(struct afb_cred *cred);
extern void afb_cred_unref(struct afb_cred *cred);
+extern int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context);
+
+extern const char *afb_cred_export(struct afb_cred *cred);
+extern struct afb_cred *afb_cred_import(const char *string);
+
+extern struct afb_cred *afb_cred_mixed_on_behalf_import(struct afb_cred *cred, const char *context, const char *exported);
diff --git a/src/afb-evt.c b/src/afb-evt.c
index 6b94ce8c..ed3e4672 100644
--- a/src/afb-evt.c
+++ b/src/afb-evt.c
@@ -24,8 +24,8 @@
#include <pthread.h>
#include <json-c/json.h>
-#include <afb/afb-eventid-itf.h>
-#include <afb/afb-event.h>
+#include <afb/afb-event-x2-itf.h>
+#include <afb/afb-event-x1.h>
#include "afb-evt.h"
#include "afb-hook.h"
@@ -50,8 +50,8 @@ struct afb_evt_listener {
/* head of the list of events listened */
struct afb_evt_watch *watchs;
- /* mutex of the listener */
- pthread_mutex_t mutex;
+ /* rwlock of the listener */
+ pthread_rwlock_t rwlock;
/* count of reference to the listener */
int refcount;
@@ -63,7 +63,7 @@ struct afb_evt_listener {
struct afb_evtid {
/* interface */
- struct afb_eventid eventid;
+ struct afb_event_x2 eventid;
/* next event */
struct afb_evtid *next;
@@ -71,8 +71,8 @@ struct afb_evtid {
/* head of the list of listeners watching the event */
struct afb_evt_watch *watchs;
- /* mutex of the event */
- pthread_mutex_t mutex;
+ /* rwlock of the event */
+ pthread_rwlock_t rwlock;
/* hooking */
int hookflags;
@@ -109,7 +109,7 @@ struct afb_evt_watch {
};
/* the interface for events */
-static struct afb_eventid_itf afb_evt_eventid_itf = {
+static struct afb_event_x2_itf afb_evt_event_x2_itf = {
.broadcast = (void*)afb_evt_evtid_broadcast,
.push = (void*)afb_evt_evtid_push,
.unref = (void*)afb_evt_evtid_unref,
@@ -118,7 +118,7 @@ static struct afb_eventid_itf afb_evt_eventid_itf = {
};
/* the interface for events */
-static struct afb_eventid_itf afb_evt_hooked_eventid_itf = {
+static struct afb_event_x2_itf afb_evt_hooked_eventid_itf = {
.broadcast = (void*)afb_evt_evtid_hooked_broadcast,
.push = (void*)afb_evt_evtid_hooked_push,
.unref = (void*)afb_evt_evtid_hooked_unref,
@@ -127,11 +127,11 @@ static struct afb_eventid_itf afb_evt_hooked_eventid_itf = {
};
/* head of the list of listeners */
-static pthread_mutex_t listeners_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_rwlock_t listeners_rwlock = PTHREAD_RWLOCK_INITIALIZER;
static struct afb_evt_listener *listeners = NULL;
/* handling id of events */
-static pthread_mutex_t events_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_rwlock_t events_rwlock = PTHREAD_RWLOCK_INITIALIZER;
static struct afb_evtid *evtids = NULL;
static int event_id_counter = 0;
static int event_id_wrapped = 0;
@@ -147,7 +147,8 @@ static int broadcast(const char *event, struct json_object *obj, int id)
struct afb_evt_listener *listener;
result = 0;
- pthread_mutex_lock(&listeners_mutex);
+
+ pthread_rwlock_rdlock(&listeners_rwlock);
listener = listeners;
while(listener) {
if (listener->itf->broadcast != NULL) {
@@ -156,7 +157,7 @@ static int broadcast(const char *event, struct json_object *obj, int id)
}
listener = listener->next;
}
- pthread_mutex_unlock(&listeners_mutex);
+ pthread_rwlock_unlock(&listeners_rwlock);
json_object_put(obj);
return result;
}
@@ -228,7 +229,7 @@ int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj)
struct afb_evt_listener *listener;
result = 0;
- pthread_mutex_lock(&evtid->mutex);
+ pthread_rwlock_rdlock(&evtid->rwlock);
watch = evtid->watchs;
while(watch) {
listener = watch->listener;
@@ -239,7 +240,7 @@ int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj)
}
watch = watch->next_by_evtid;
}
- pthread_mutex_unlock(&evtid->mutex);
+ pthread_rwlock_unlock(&evtid->rwlock);
json_object_put(obj);
return result;
}
@@ -252,6 +253,7 @@ int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj)
*/
int afb_evt_evtid_hooked_push(struct afb_evtid *evtid, struct json_object *obj)
{
+
int result;
/* lease the object */
@@ -319,7 +321,7 @@ struct afb_evtid *afb_evt_evtid_create(const char *fullname)
goto error;
/* allocates the id */
- pthread_mutex_lock(&events_mutex);
+ pthread_rwlock_wrlock(&events_rwlock);
do {
if (++event_id_counter < 0) {
event_id_wrapped = 1;
@@ -335,15 +337,16 @@ struct afb_evtid *afb_evt_evtid_create(const char *fullname)
/* initialize the event */
memcpy(evtid->fullname, fullname, len + 1);
evtid->next = evtids;
+ evtid->refcount = 1;
evtid->watchs = NULL;
evtid->id = event_id_counter;
- pthread_mutex_init(&evtid->mutex, NULL);
+ pthread_rwlock_init(&evtid->rwlock, NULL);
evtids = evtid;
evtid->hookflags = afb_hook_flags_evt(evtid->fullname);
- evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_eventid_itf;
+ evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_event_x2_itf;
if (evtid->hookflags & afb_hook_flag_evt_create)
afb_hook_evt_create(evtid->fullname, evtid->id);
- pthread_mutex_unlock(&events_mutex);
+ pthread_rwlock_unlock(&events_rwlock);
/* returns the event */
return evtid;
@@ -402,14 +405,14 @@ void afb_evt_evtid_unref(struct afb_evtid *evtid)
if (!__atomic_sub_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED)) {
/* unlinks the event if valid! */
- pthread_mutex_lock(&events_mutex);
+ pthread_rwlock_wrlock(&events_rwlock);
found = 0;
prv = &evtids;
while (*prv && !(found = (*prv == evtid)))
prv = &(*prv)->next;
if (found)
*prv = evtid->next;
- pthread_mutex_unlock(&events_mutex);
+ pthread_rwlock_unlock(&events_rwlock);
/* destroys the event */
if (!found)
@@ -418,15 +421,15 @@ void afb_evt_evtid_unref(struct afb_evtid *evtid)
/* removes all watchers */
while(evtid->watchs != NULL) {
listener = evtid->watchs->listener;
- pthread_mutex_lock(&listener->mutex);
- pthread_mutex_lock(&evtid->mutex);
+ pthread_rwlock_wrlock(&listener->rwlock);
+ pthread_rwlock_wrlock(&evtid->rwlock);
remove_watch(evtid->watchs);
- pthread_mutex_unlock(&evtid->mutex);
- pthread_mutex_unlock(&listener->mutex);
+ pthread_rwlock_unlock(&evtid->rwlock);
+ pthread_rwlock_unlock(&listener->rwlock);
}
/* free */
- pthread_mutex_destroy(&evtid->mutex);
+ pthread_rwlock_destroy(&evtid->rwlock);
free(evtid);
}
}
@@ -489,7 +492,7 @@ struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf,
struct afb_evt_listener *listener;
/* search if an instance already exists */
- pthread_mutex_lock(&listeners_mutex);
+ pthread_rwlock_wrlock(&listeners_rwlock);
listener = listeners;
while (listener != NULL) {
if (listener->itf == itf && listener->closure == closure) {
@@ -507,12 +510,12 @@ struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf,
listener->closure = closure;
listener->watchs = NULL;
listener->refcount = 1;
- pthread_mutex_init(&listener->mutex, NULL);
+ pthread_rwlock_init(&listener->rwlock, NULL);
listener->next = listeners;
listeners = listener;
}
found:
- pthread_mutex_unlock(&listeners_mutex);
+ pthread_rwlock_unlock(&listeners_rwlock);
return listener;
}
@@ -537,25 +540,25 @@ void afb_evt_listener_unref(struct afb_evt_listener *listener)
if (!__atomic_sub_fetch(&listener->refcount, 1, __ATOMIC_RELAXED)) {
/* unlink the listener */
- pthread_mutex_lock(&listeners_mutex);
+ pthread_rwlock_wrlock(&listeners_rwlock);
prv = &listeners;
while (*prv != listener)
prv = &(*prv)->next;
*prv = listener->next;
- pthread_mutex_unlock(&listeners_mutex);
+ pthread_rwlock_unlock(&listeners_rwlock);
/* remove the watchers */
- pthread_mutex_lock(&listener->mutex);
+ pthread_rwlock_wrlock(&listener->rwlock);
while (listener->watchs != NULL) {
evtid = listener->watchs->evtid;
- pthread_mutex_lock(&evtid->mutex);
+ pthread_rwlock_wrlock(&evtid->rwlock);
remove_watch(listener->watchs);
- pthread_mutex_unlock(&evtid->mutex);
+ pthread_rwlock_unlock(&evtid->rwlock);
}
- pthread_mutex_unlock(&listener->mutex);
+ pthread_rwlock_unlock(&listener->rwlock);
/* free the listener */
- pthread_mutex_destroy(&listener->mutex);
+ pthread_rwlock_destroy(&listener->rwlock);
free(listener);
}
}
@@ -575,7 +578,7 @@ int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid
}
/* search the existing watch for the listener */
- pthread_mutex_lock(&listener->mutex);
+ pthread_rwlock_wrlock(&listener->rwlock);
watch = listener->watchs;
while(watch != NULL) {
if (watch->evtid == evtid)
@@ -586,7 +589,7 @@ int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid
/* not found, allocate a new */
watch = malloc(sizeof *watch);
if (watch == NULL) {
- pthread_mutex_unlock(&listener->mutex);
+ pthread_rwlock_unlock(&listener->rwlock);
errno = ENOMEM;
return -1;
}
@@ -597,16 +600,16 @@ int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid
watch->listener = listener;
watch->next_by_listener = listener->watchs;
listener->watchs = watch;
- pthread_mutex_lock(&evtid->mutex);
+ pthread_rwlock_wrlock(&evtid->rwlock);
watch->next_by_evtid = evtid->watchs;
evtid->watchs = watch;
- pthread_mutex_unlock(&evtid->mutex);
+ pthread_rwlock_unlock(&evtid->rwlock);
found:
if (watch->activity == 0 && listener->itf->add != NULL)
listener->itf->add(listener->closure, evtid->fullname, evtid->id);
watch->activity++;
- pthread_mutex_unlock(&listener->mutex);
+ pthread_rwlock_unlock(&listener->rwlock);
return 0;
}
@@ -620,7 +623,7 @@ int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb_evtid
struct afb_evt_watch *watch;
/* search the existing watch */
- pthread_mutex_lock(&listener->mutex);
+ pthread_rwlock_wrlock(&listener->rwlock);
watch = listener->watchs;
while(watch != NULL) {
if (watch->evtid == evtid) {
@@ -629,12 +632,12 @@ int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb_evtid
if (watch->activity == 0 && listener->itf->remove != NULL)
listener->itf->remove(listener->closure, evtid->fullname, evtid->id);
}
- pthread_mutex_unlock(&listener->mutex);
+ pthread_rwlock_unlock(&listener->rwlock);
return 0;
}
watch = watch->next_by_listener;
}
- pthread_mutex_unlock(&listener->mutex);
+ pthread_rwlock_unlock(&listener->rwlock);
errno = ENOENT;
return -1;
}
@@ -646,20 +649,20 @@ void afb_evt_update_hooks()
{
struct afb_evtid *evtid;
- pthread_mutex_lock(&events_mutex);
+ pthread_rwlock_rdlock(&events_rwlock);
for (evtid = evtids ; evtid ; evtid = evtid->next) {
evtid->hookflags = afb_hook_flags_evt(evtid->fullname);
- evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_eventid_itf;
+ evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_event_x2_itf;
}
- pthread_mutex_unlock(&events_mutex);
+ pthread_rwlock_unlock(&events_rwlock);
}
-inline struct afb_evtid *afb_evt_eventid_to_evtid(struct afb_eventid *eventid)
+inline struct afb_evtid *afb_evt_event_x2_to_evtid(struct afb_event_x2 *eventid)
{
return (struct afb_evtid*)eventid;
}
-inline struct afb_eventid *afb_evt_eventid_from_evtid(struct afb_evtid *evtid)
+inline struct afb_event_x2 *afb_evt_event_x2_from_evtid(struct afb_evtid *evtid)
{
return &evtid->eventid;
}
@@ -668,35 +671,35 @@ inline struct afb_eventid *afb_evt_eventid_from_evtid(struct afb_evtid *evtid)
* Creates an event of 'fullname' and returns it.
* Returns an event with closure==NULL in case of error.
*/
-struct afb_eventid *afb_evt_eventid_create(const char *fullname)
+struct afb_event_x2 *afb_evt_event_x2_create(const char *fullname)
{
- return afb_evt_eventid_from_evtid(afb_evt_evtid_create(fullname));
+ return afb_evt_event_x2_from_evtid(afb_evt_evtid_create(fullname));
}
/*
* Creates an event of name 'prefix'/'name' and returns it.
* Returns an event with closure==NULL in case of error.
*/
-struct afb_eventid *afb_evt_eventid_create2(const char *prefix, const char *name)
+struct afb_event_x2 *afb_evt_event_x2_create2(const char *prefix, const char *name)
{
- return afb_evt_eventid_from_evtid(afb_evt_evtid_create2(prefix, name));
+ return afb_evt_event_x2_from_evtid(afb_evt_evtid_create2(prefix, name));
}
/*
* Returns the fullname of the 'eventid'
*/
-const char *afb_evt_eventid_fullname(struct afb_eventid *eventid)
+const char *afb_evt_event_x2_fullname(struct afb_event_x2 *eventid)
{
- struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid);
+ struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
return evtid ? evtid->fullname : NULL;
}
/*
* Returns the id of the 'eventid'
*/
-int afb_evt_eventid_id(struct afb_eventid *eventid)
+int afb_evt_event_x2_id(struct afb_event_x2 *eventid)
{
- struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid);
+ struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
return evtid ? evtid->id : 0;
}
@@ -704,9 +707,9 @@ int afb_evt_eventid_id(struct afb_eventid *eventid)
* Makes the 'listener' watching 'eventid'
* Returns 0 in case of success or else -1.
*/
-int afb_evt_eventid_add_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid)
+int afb_evt_event_x2_add_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid)
{
- struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid);
+ struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
/* check parameter */
if (!evtid) {
@@ -722,9 +725,9 @@ int afb_evt_eventid_add_watch(struct afb_evt_listener *listener, struct afb_even
* Avoids the 'listener' to watch 'eventid'
* Returns 0 in case of success or else -1.
*/
-int afb_evt_eventid_remove_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid)
+int afb_evt_event_x2_remove_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid)
{
- struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid);
+ struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
/* check parameter */
if (!evtid) {
@@ -736,41 +739,41 @@ int afb_evt_eventid_remove_watch(struct afb_evt_listener *listener, struct afb_e
return afb_evt_watch_sub_evtid(listener, evtid);
}
-int afb_evt_eventid_push(struct afb_eventid *eventid, struct json_object *object)
+int afb_evt_event_x2_push(struct afb_event_x2 *eventid, struct json_object *object)
{
- struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid);
+ struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
if (evtid)
return afb_evt_evtid_hooked_push(evtid, object);
json_object_put(object);
return 0;
}
-int afb_evt_eventid_unhooked_push(struct afb_eventid *eventid, struct json_object *object)
+int afb_evt_event_x2_unhooked_push(struct afb_event_x2 *eventid, struct json_object *object)
{
- struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid);
+ struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
if (evtid)
return afb_evt_evtid_push(evtid, object);
json_object_put(object);
return 0;
}
-struct afb_event afb_evt_event_from_evtid(struct afb_evtid *evtid)
+struct afb_event_x1 afb_evt_event_from_evtid(struct afb_evtid *evtid)
{
return evtid
- ? (struct afb_event){ .itf = &afb_evt_hooked_eventid_itf, .closure = &evtid->eventid }
- : (struct afb_event){ .itf = NULL, .closure = NULL };
+ ? (struct afb_event_x1){ .itf = &afb_evt_hooked_eventid_itf, .closure = &evtid->eventid }
+ : (struct afb_event_x1){ .itf = NULL, .closure = NULL };
}
-void afb_evt_eventid_unref(struct afb_eventid *eventid)
+void afb_evt_event_x2_unref(struct afb_event_x2 *eventid)
{
- struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid);
+ struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
if (evtid)
afb_evt_evtid_unref(evtid);
}
-struct afb_eventid *afb_evt_eventid_addref(struct afb_eventid *eventid)
+struct afb_event_x2 *afb_evt_event_x2_addref(struct afb_event_x2 *eventid)
{
- struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid);
+ struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
if (evtid)
afb_evt_evtid_addref(evtid);
return eventid;
diff --git a/src/afb-evt.h b/src/afb-evt.h
index c3999df2..ceb1b1b9 100644
--- a/src/afb-evt.h
+++ b/src/afb-evt.h
@@ -17,8 +17,8 @@
#pragma once
-struct afb_event;
-struct afb_eventid;
+struct afb_event_x1;
+struct afb_event_x2;
struct afb_evtid;
struct afb_session;
struct json_object;
@@ -66,20 +66,20 @@ extern int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb
extern void afb_evt_update_hooks();
-extern struct afb_eventid *afb_evt_eventid_create(const char *fullname);
-extern struct afb_eventid *afb_evt_eventid_create2(const char *prefix, const char *name);
-extern const char *afb_evt_eventid_fullname(struct afb_eventid *eventid);
-extern int afb_evt_eventid_id(struct afb_eventid *eventid);
-extern struct afb_eventid *afb_evt_eventid_addref(struct afb_eventid *eventid);
-extern void afb_evt_eventid_unref(struct afb_eventid *eventid);
+extern struct afb_event_x2 *afb_evt_event_x2_create(const char *fullname);
+extern struct afb_event_x2 *afb_evt_event_x2_create2(const char *prefix, const char *name);
+extern const char *afb_evt_event_x2_fullname(struct afb_event_x2 *event);
+extern int afb_evt_event_x2_id(struct afb_event_x2 *eventid);
+extern struct afb_event_x2 *afb_evt_event_x2_addref(struct afb_event_x2 *eventid);
+extern void afb_evt_event_x2_unref(struct afb_event_x2 *eventid);
-extern int afb_evt_eventid_push(struct afb_eventid *eventid, struct json_object *object);
-extern int afb_evt_eventid_unhooked_push(struct afb_eventid *eventid, struct json_object *object);
+extern int afb_evt_event_x2_push(struct afb_event_x2 *eventid, struct json_object *object);
+extern int afb_evt_event_x2_unhooked_push(struct afb_event_x2 *eventid, struct json_object *object);
-extern int afb_evt_eventid_add_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid);
-extern int afb_evt_eventid_remove_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid);
+extern int afb_evt_event_x2_add_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid);
+extern int afb_evt_event_x2_remove_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid);
-extern struct afb_evtid *afb_evt_eventid_to_evtid(struct afb_eventid *eventid);
-extern struct afb_eventid *afb_evt_eventid_from_evtid(struct afb_evtid *evtid);
-extern struct afb_event afb_evt_event_from_evtid(struct afb_evtid *evtid);
+extern struct afb_evtid *afb_evt_event_x2_to_evtid(struct afb_event_x2 *eventid);
+extern struct afb_event_x2 *afb_evt_event_x2_from_evtid(struct afb_evtid *evtid);
+extern struct afb_event_x1 afb_evt_event_from_evtid(struct afb_evtid *evtid);
diff --git a/src/afb-export.c b/src/afb-export.c
index 12adf08d..fbf77f86 100644
--- a/src/afb-export.c
+++ b/src/afb-export.c
@@ -20,6 +20,8 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
+#include <fnmatch.h>
+#include <ctype.h>
#include <json-c/json.h>
@@ -28,7 +30,11 @@
#include "afb-api.h"
#include "afb-apiset.h"
-#include "afb-api-dyn.h"
+#if defined(WITH_LEGACY_BINDING_V1)
+#include "afb-api-so-v1.h"
+#endif
+#include "afb-api-so-v2.h"
+#include "afb-api-v3.h"
#include "afb-common.h"
#include "afb-systemd.h"
#include "afb-cred.h"
@@ -38,20 +44,48 @@
#include "afb-msg-json.h"
#include "afb-session.h"
#include "afb-xreq.h"
+#include "afb-calls.h"
#include "jobs.h"
#include "verbose.h"
/*************************************************************************
- * internal types and structures
+ * 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_Dyn = 0,
+ Api_Version_None = 0,
+#if defined(WITH_LEGACY_BINDING_V1)
Api_Version_1 = 1,
+#endif
Api_Version_2 = 2,
+ Api_Version_3 = 3
};
+/*
+ * The states of exported APIs
+ */
enum afb_api_state
{
Api_State_Pre_Init,
@@ -59,13 +93,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;
@@ -73,124 +110,157 @@ struct afb_export
/* current state */
unsigned state: 4;
+ /* declared */
+ unsigned declared: 1;
+
+ /* unsealed */
+ unsigned unsealed: 1;
+
/* hooking flags */
int hookditf;
int hooksvc;
- /* dynamic api */
- struct afb_api_dyn *apidyn;
-
/* 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 event_handler *event_handlers;
+
+ /* internal descriptors */
+ union {
+#if defined(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 defined(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 defined(WITH_LEGACY_BINDING_V1)
struct afb_binding_interface_v1 v1;
+#endif
struct afb_binding_data_v2 *v2;
} export;
+
+ /* initial name */
+ char name[1];
};
-/************************************************************************************************************/
+/*****************************************************************************/
+
+static inline struct afb_api_x3 *to_api_x3(struct afb_export *export)
+{
+ return (struct afb_api_x3*)export;
+}
-static inline struct afb_dynapi *to_dynapi(struct afb_export *export)
+static inline struct afb_export *from_api_x3(struct afb_api_x3 *api)
{
- return (struct afb_dynapi*)export;
+ return (struct afb_export*)api;
}
-static inline struct afb_export *from_dynapi(struct afb_dynapi *dynapi)
+struct afb_export *afb_export_from_api_x3(struct afb_api_x3 *api)
{
- return (struct afb_export*)dynapi;
+ return from_api_x3(api);
}
-/*************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
+struct afb_api_x3 *afb_export_to_api_x3(struct afb_export *export)
+{
+ return to_api_x3(export);
+}
+
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
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, "[API %s] %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)
+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_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)
+static struct afb_event_x1 legacy_event_x1_make_cb(struct afb_api_x3 *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));
+ 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(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(object));
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);
@@ -198,190 +268,218 @@ 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 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);
}
-static int queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
+static int queue_job_cb(struct afb_api_x3 *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
{
return jobs_queue(group, timeout, callback, argument);
}
-static struct afb_req unstore_req_cb(void *closure, struct afb_stored_req *sreq)
+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(void *closure, const char *name, int initialized)
-{
- 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;
+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;
+
+ /* 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, name);
+ else
+ rc2 = -!((initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->call_set, iter, 1));
+ if (rc2 < 0)
+ rc = rc2;
+
+ *end = save;
+ iter = end;
}
- return -!(initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->apiset, name, 1);
}
-static int rename_api_cb(void *closure, const char *name)
+static int add_alias_cb(struct afb_api_x3 *closure, const char *apiname, const char *aliasname)
{
- 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);
- 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);
+ 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?:"<null>", 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);
+ 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)
+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 = closure;
+ 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_ditf_vverbose(export, level, file, line, function, fmt, ap);
+ afb_hook_api_vverbose(export, level, file, line, function, fmt, ap);
va_end(ap);
}
-static void hooked_old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
+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_eventid *hooked_eventid_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_export *export = closure;
- struct afb_eventid *r = eventid_make_cb(closure, name);
- afb_hook_ditf_event_make(export, name, r);
+ 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 struct afb_event hooked_event_make_cb(void *closure, const char *name)
+static struct afb_event_x1 legacy_hooked_event_x1_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_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(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 afb_export *export = from_api_x3(closure);
struct sd_event *r = afb_systemd_get_event_loop();
- return afb_hook_ditf_get_event_loop(export, r);
+ 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 afb_export *export = from_api_x3(closure);
struct sd_bus *r = afb_systemd_get_user_bus();
- return afb_hook_ditf_get_user_bus(export, r);
+ 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 afb_export *export = from_api_x3(closure);
struct sd_bus *r = afb_systemd_get_system_bus();
- return afb_hook_ditf_get_system_bus(export, r);
+ 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);
+ return afb_hook_api_queue_job(export, callback, argument, group, timeout, r);
}
-static struct afb_req hooked_unstore_req_cb(void *closure, struct afb_stored_req *sreq)
+static struct afb_req_x1 legacy_hooked_unstore_req_cb(struct afb_api_x3 *closure, struct afb_stored_req *sreq)
{
- struct afb_export *export = closure;
- afb_hook_ditf_unstore_req(export, sreq);
- return unstore_req_cb(closure, 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(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,
+static const struct afb_daemon_itf_x1 daemon_itf = {
+ .vverbose_v1 = legacy_vverbose_v1_cb,
.vverbose_v2 = vverbose_cb,
- .event_make = event_make_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,
@@ -389,16 +487,16 @@ static const struct afb_daemon_itf daemon_itf = {
.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,
+ .unstore_req = legacy_unstore_req_cb,
.require_api = require_api_cb,
- .rename_api = rename_api_cb,
+ .add_alias = add_alias_cb,
.new_api = api_new_api_cb,
};
-static const struct afb_daemon_itf hooked_daemon_itf = {
- .vverbose_v1 = hooked_old_vverbose_cb,
+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,
@@ -406,422 +504,185 @@ 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,
};
-/*************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
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)
+static void 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 *error, const char *info, struct afb_api_x3*),
+ void *closure)
{
- 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);
- }
+ struct afb_export *export = from_api_x3(apix3);
+ return afb_calls_call(export, api, verb, args, callback, closure);
}
-/* 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 int call_sync_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 = &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;
+ struct json_object **object,
+ char **error,
+ char **info)
+{
+ struct afb_export *export = from_api_x3(apix3);
+ return afb_calls_call_sync(export, api, verb, args, object, error, info);
}
-/*
- * Initiates a call for the service
- */
-static void svc_call(
- void *closure,
+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 *cbclosure)
+ void *closure)
{
- 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);
+ afb_calls_legacy_call_v12(export, api, verb, args, callback, closure);
}
-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;
-};
-
-static void svc_hooked_call_result(void *closure, int status, struct json_object *result)
+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(hc->cbclosure, status, result);
- 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_dynapi_result(void *closure, int status, struct json_object *result, struct afb_dynapi *dynapi)
+static int hooked_call_sync_x3(
+ struct afb_api_x3 *apix3,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ struct json_object **object,
+ char **error,
+ char **info)
{
- 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);
+ return afb_calls_hooked_call_sync(export, api, verb, args, object, error, info);
}
-static void svc_hooked_call(
- void *closure,
+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 *cbclosure)
+ void *closure)
{
- 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);
+ afb_calls_legacy_hooked_call_v12(export, api, verb, args, callback, closure);
}
-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);
-
- if (result)
- *result = resu;
- else
- json_object_put(resu);
-
- return rc;
+ struct afb_export *export = from_api_x3(apix3);
+ return afb_calls_legacy_hooked_call_sync(export, api, verb, args, result);
}
/* 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 service_itf = {
+ .call = legacy_call_v12,
+ .call_sync = legacy_call_sync
};
/* the interface for services */
-static const struct afb_service_itf hooked_service_itf = {
- .call = svc_hooked_call,
- .call_sync = svc_hooked_call_sync
+static const struct afb_service_itf_x1 hooked_service_itf = {
+ .call = legacy_hooked_call_v12,
+ .call_sync = legacy_hooked_call_sync
};
-/*************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
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);
+ 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;
}
@@ -829,115 +690,292 @@ static int api_set_verbs_v2_cb(
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_api_x3(api);
+
+ export->unsealed = 0;
+}
+
+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)
+{
+ struct afb_export *export = from_api_x3(api);
+
+ return afb_export_event_handler_add(export, pattern, callback, closure);
+}
+
+static int event_handler_del_cb(
+ struct afb_api_x3 *api,
+ const char *pattern,
+ void **closure)
+{
+ struct afb_export *export = from_api_x3(api);
+
+ return afb_export_event_handler_del(export, pattern, closure);
+}
+
+static int class_provide_cb(struct afb_api_x3 *api, const char *name)
+{
+ 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 class_require_cb(struct afb_api_x3 *api, const char *name)
+{
+ 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 delete_api_cb(struct afb_api_x3 *api)
{
- struct afb_export *export = from_dynapi(dynapi);
+ struct afb_export *export = from_api_x3(api);
+
+ if (!export->unsealed) {
+ errno = EPERM;
+ return -1;
+ }
- export->apidyn = NULL;
+ afb_export_undeclare(export);
+ afb_export_unref(export);
+ return 0;
}
static int hooked_api_set_verbs_v2_cb(
- struct afb_dynapi *dynapi,
+ struct afb_api_x3 *api,
const struct afb_verb_v2 *verbs)
{
- /* TODO */
- return api_set_verbs_v2_cb(dynapi, 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_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)
{
- /* TODO */
- return api_add_verb_cb(dynapi, verb, info, callback, vcbdata, auth, session);
+ 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_sub_verb_cb(
- struct afb_dynapi *dynapi,
- const char *verb)
+static int hooked_api_del_verb_cb(
+ struct afb_api_x3 *api,
+ const char *verb,
+ void **vcbdata)
{
- /* TODO */
- return api_sub_verb_cb(dynapi, verb);
+ 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_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))
{
- /* TODO */
- return api_set_on_event_cb(dynapi, onevent);
+ 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_dynapi *dynapi,
- int (*oninit)(struct afb_dynapi *dynapi))
+ struct afb_api_x3 *api,
+ int (*oninit)(struct afb_api_x3 *api))
{
- /* TODO */
- return api_set_on_init_cb(dynapi, oninit);
+ 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_dynapi *dynapi)
+ struct afb_api_x3 *api)
{
- /* TODO */
- api_seal_cb(dynapi);
+ struct afb_export *export = from_api_x3(api);
+ afb_hook_api_api_seal(export);
+ api_seal_cb(api);
}
-static const struct afb_dynapi_itf dynapi_itf = {
+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 const struct afb_api_x3_itf api_x3_itf = {
.vverbose = (void*)vverbose_cb,
@@ -949,24 +987,35 @@ static const struct afb_dynapi_itf dynapi_itf = {
.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,
};
-static const struct afb_dynapi_itf hooked_dynapi_itf = {
+static const struct afb_api_x3_itf hooked_api_x3_itf = {
.vverbose = hooked_vverbose_cb,
@@ -978,86 +1027,187 @@ 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,
+
+ .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,
};
-/*************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- F R O M S V C
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************/
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ 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, int eventid, struct json_object *object)
+{
+ struct event_handler *handler;
+ struct afb_export *export = from_api_x3(closure);
+
+ /* hook the event before */
+ if (export->hooksvc & afb_hook_flag_api_on_event)
+ afb_hook_api_on_event_before(export, event, eventid, object);
+
+ /* 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 = handler->next;
+ }
+
+ /* 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);
+ /* hook the event after */
+ if (export->hooksvc & afb_hook_flag_api_on_event)
+ afb_hook_api_on_event_after(export, event, eventid, object);
json_object_put(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_events,
+ .push = listener_of_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;
+ struct event_handler *handler, **previous;
+
+ 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;
+ }
+
+ /* create the event */
+ handler = malloc(strlen(pattern) + strlen(pattern));
+ if (!handler) {
+ ERROR("[API %s] can't allocate event handler %s", export->api.apiname, pattern);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* init and record */
+ handler->next = NULL;
+ handler->callback = callback;
+ handler->closure = closure;
+ strcpy(handler->pattern, pattern);
+ export->event_handlers = handler;
+
+ return 0;
}
-/* 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)
+{
+ 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;
+
+ *previous = handler->next;
+ free(handler);
+ return 0;
+}
+
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
M E R G E D
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************/
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
-static struct afb_export *create(struct afb_apiset *apiset, const char *apiname, enum afb_api_version version)
+static struct afb_export *create(
+ struct afb_apiset *declare_set,
+ struct afb_apiset *call_set,
+ const char *apiname,
+ enum afb_api_version version)
{
struct afb_export *export;
@@ -1067,96 +1217,179 @@ static struct afb_export *create(struct afb_apiset *apiset, const char *apiname,
if (common_session == NULL)
return NULL;
}
- export = calloc(1, sizeof *export);
+ export = calloc(1, sizeof *export + strlen(apiname));
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;
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)
{
+ struct event_handler *handler;
+
if (export) {
+ while ((handler = export->event_handlers)) {
+ export->event_handlers = handler->next;
+ free(handler);
+ }
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);
+ 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, Api_Version_None);
+ if (export) {
+ afb_export_logmask_set(export, logmask);
+ afb_export_update_hooks(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,
+ struct afb_apiset *call_set,
+ const char *apiname,
+ int (*init)(struct afb_service_x1),
+ void (*onevent)(const char*, struct json_object*))
+{
+ struct afb_export *export = create(declare_set, call_set, apiname, 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);
+ afb_export_update_hooks(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*))
+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*))
{
- struct afb_export *export = create(apiset, apiname, Api_Version_2);
+ struct afb_export *export = create(declare_set, call_set, apiname, 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);
+ afb_export_update_hooks(export);
}
return export;
}
-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 *export = create(apiset, apiname, Api_Version_Dyn);
+ struct afb_export *export = create(declare_set, call_set, apiname, 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;
+ afb_export_logmask_set(export, logmask);
+ afb_export_update_hooks(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)
+{
+ return afb_apiset_add_alias(export->declare_set, apiname ?: export->api.apiname, aliasname);
+}
+
+int afb_export_rename(struct afb_export *export, const char *apiname)
{
- free(export->apiname);
- export->apiname = strdup(apiname);
- export->dynapi.apiname = export->apiname;
- afb_export_update_hook(export);
+ char *name;
+
+ if (export->declared) {
+ errno = EBUSY;
+ return -1;
+ }
+
+ /* 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;
+
+ afb_export_update_hooks(export);
+ return 0;
}
const char *afb_export_apiname(const struct afb_export *export)
{
- return export->apiname;
+ return export->api.apiname;
}
-void afb_export_update_hook(struct afb_export *export)
+void afb_export_update_hooks(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;
+ 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;
@@ -1164,11 +1397,6 @@ void afb_export_update_hook(struct afb_export *export)
}
}
-struct afb_binding_interface_v1 *afb_export_get_interface_v1(struct afb_export *export)
-{
- return export->version == Api_Version_1 ? &export->export.v1 : NULL;
-}
-
int afb_export_unshare_session(struct afb_export *export)
{
if (export->session == common_session) {
@@ -1183,126 +1411,107 @@ 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;
-}
-
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 defined(WITH_LEGACY_BINDING_V1)
+ case Api_Version_1:
+#endif
+ case Api_Version_2:
+ break;
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);
}
-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 defined(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 defined(WITH_LEGACY_BINDING_V1)
+ case Api_Version_1: export->export.v1.verbosity = verbosity_from_mask(mask); break;
+#endif
+ case Api_Version_2: export->export.v2->verbosity = verbosity_from_mask(mask); break;
}
}
-/*************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
+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
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************/
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
-int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset)
+int afb_export_start(struct afb_export *export, int share_session, int onneed)
{
int rc;
@@ -1313,7 +1522,7 @@ int afb_export_start(struct afb_export *export, int share_session, int onneed, s
goto done;
/* already started: it is an error */
- ERROR("Service of API %s already started", export->apiname);
+ ERROR("Service of API %s already started", export->api.apiname);
return -1;
}
@@ -1321,49 +1530,59 @@ int afb_export_start(struct afb_export *export, int share_session, int onneed, s
if (!share_session) {
rc = afb_export_unshare_session(export);
if (rc < 0) {
- ERROR("Can't unshare the session for %s", export->apiname);
+ ERROR("Can't unshare the session for %s", export->api.apiname);
return -1;
}
}
/* set event handling */
switch (export->version) {
+#if defined(WITH_LEGACY_BINDING_V1)
case Api_Version_1:
+#endif
case Api_Version_2:
- rc = afb_export_handle_events_v12(export, export->on_event.v12);
+ if (export->on_any_event_v12)
+ rc = afb_export_handle_events_v12(export, export->on_any_event_v12);
break;
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;
}
/* 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);
+
export->state = Api_State_Init;
switch (export->version) {
+#if defined(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;
+ rc = export->init.v1 ? export->init.v1((struct afb_service_x1){ .itf = &hooked_service_itf, .closure = to_api_x3(export) }) : 0;
break;
+#endif
case Api_Version_2:
rc = export->init.v2 ? export->init.v2() : 0;
break;
- case Api_Version_Dyn:
- rc = export->init.vdyn ? export->init.vdyn(to_dynapi(export)) : 0;
+ case Api_Version_3:
+ rc = export->init.v3 ? export->init.v3(to_api_x3(export)) : 0;
break;
default:
+ errno = EINVAL;
+ rc = -1;
break;
}
export->state = Api_State_Run;
- if (export->hooksvc & afb_hook_flag_svc_start_after)
- afb_hook_svc_start_after(export, rc);
+
+ if (export->hooksvc & afb_hook_flag_api_start)
+ afb_hook_api_start_after(export, rc);
+
if (rc < 0) {
/* initialisation error */
- ERROR("Initialisation of service API %s failed (%d): %m", export->apiname, rc);
+ ERROR("Initialisation of service API %s failed (%d): %m", export->api.apiname, rc);
return rc;
}
@@ -1371,3 +1590,154 @@ done:
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 defined(WITH_LEGACY_BINDING_V1)
+ case Api_Version_1:
+ afb_api_so_v1_process_call(export->desc.v1, xreq);
+ break;
+#endif
+ case Api_Version_2:
+ afb_api_so_v2_process_call(export->desc.v2, xreq);
+ break;
+ case Api_Version_3:
+ afb_api_v3_process_call(export->desc.v3, xreq);
+ break;
+ default:
+ afb_xreq_reply(xreq, NULL, "bad-api-type", NULL);
+ break;
+ }
+}
+
+static struct json_object *api_describe_cb(void *closure)
+{
+ struct afb_export *export = closure;
+ struct json_object *result;
+
+ switch (export->version) {
+#if defined(WITH_LEGACY_BINDING_V1)
+ case Api_Version_1:
+ result = afb_api_so_v1_make_description_openAPIv3(export->desc.v1, export->api.apiname);
+ break;
+#endif
+ case Api_Version_2:
+ result = afb_api_so_v2_make_description_openAPIv3(export->desc.v2, export->api.apiname);
+ break;
+ case Api_Version_3:
+ result = afb_api_v3_make_description_openAPIv3(export->desc.v3, export->api.apiname);
+ break;
+ default:
+ result = NULL;
+ break;
+ }
+ return result;
+}
+
+static int api_service_start_cb(void *closure, int share_session, int onneed)
+{
+ struct afb_export *export = closure;
+
+ return afb_export_start(export, share_session, onneed);
+}
+
+static void api_update_hooks_cb(void *closure)
+{
+ struct afb_export *export = closure;
+
+ afb_export_update_hooks(export);
+}
+
+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,
+ .update_hooks = api_update_hooks_cb,
+ .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_addref(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_event_x2_add_watch(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);
+}
+
+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(context, export->session, NULL);
+}
+
diff --git a/src/afb-export.h b/src/afb-export.h
index 5acca207..c9046be8 100644
--- a/src/afb-export.h
+++ b/src/afb-export.h
@@ -21,36 +21,111 @@ struct json_object;
struct afb_export;
struct afb_apiset;
-struct afb_api_dyn;
+struct afb_context;
+struct afb_xreq;
-struct afb_service;
+struct afb_binding_v2;
struct afb_binding_data_v2;
-struct afb_binding_interface_v1;
-struct afb_dynapi;
+struct afb_api_v3;
+struct afb_api_x3;
+struct afb_event_x2;
+
+extern 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);
+
+extern 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*));
-extern 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*));
-extern 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*));
-extern struct afb_export *afb_export_create_vdyn(struct afb_apiset *apiset, const char *apiname, struct afb_api_dyn *dynapi);
+extern struct afb_export *afb_export_create_v3(struct afb_apiset *declare_set,
+ struct afb_apiset *call_set,
+ const char *apiname,
+ struct afb_api_v3 *api);
+
+extern struct afb_export *afb_export_addref(struct afb_export *export);
+extern void afb_export_unref(struct afb_export *export);
extern void afb_export_destroy(struct afb_export *export);
+extern int afb_export_declare(struct afb_export *export, int noconcurrency);
+extern void afb_export_undeclare(struct afb_export *export);
+
extern const char *afb_export_apiname(const struct afb_export *export);
-extern void afb_export_rename(struct afb_export *export, const char *apiname);
-extern void afb_export_update_hook(struct afb_export *export);
+extern int afb_export_add_alias(struct afb_export *export, const char *apiname, const char *aliasname);
+extern int afb_export_rename(struct afb_export *export, const char *apiname);
+extern void afb_export_update_hooks(struct afb_export *export);
extern int afb_export_unshare_session(struct afb_export *export);
-extern void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset);
-extern struct afb_apiset *afb_export_get_apiset(struct afb_export *export);
-
-extern struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*));
-extern int afb_export_preinit_vdyn(struct afb_export *export, int (*preinit)(void*, struct afb_dynapi*), void *closure);
-extern int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object));
-extern int afb_export_handle_events_vdyn(struct afb_export *export, void (*on_event)(struct afb_dynapi *dynapi, const char *event, struct json_object *object));
-extern int afb_export_handle_init_vdyn(struct afb_export *export, int (*oninit)(struct afb_dynapi *dynapi));
+extern int afb_export_preinit_x3(
+ struct afb_export *export,
+ int (*preinit)(void *,struct afb_api_x3*),
+ void *closure);
+
+extern int afb_export_handle_events_v12(
+ struct afb_export *export,
+ void (*on_event)(const char *event, struct json_object *object));
+
+
+extern 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));
+
+
+extern int afb_export_handle_init_v3(
+ struct afb_export *export,
+ int (*oninit)(struct afb_api_x3 *api));
+
+extern int afb_export_start(struct afb_export *export, int share_session, int onneed);
+
+extern int afb_export_logmask_get(const struct afb_export *export);
+extern void afb_export_logmask_set(struct afb_export *export, int mask);
+
+extern void *afb_export_userdata_get(const struct afb_export *export);
+extern void afb_export_userdata_set(struct afb_export *export, void *data);
+
+extern 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);
+
+extern int afb_export_event_handler_del(
+ struct afb_export *export,
+ const char *pattern,
+ void **closure);
+
+extern int afb_export_subscribe(struct afb_export *export, struct afb_event_x2 *event);
+extern int afb_export_unsubscribe(struct afb_export *export, struct afb_event_x2 *event);
+extern void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq);
+extern void afb_export_context_init(struct afb_export *export, struct afb_context *context);
+extern struct afb_export *afb_export_from_api_x3(struct afb_api_x3 *api);
+extern struct afb_api_x3 *afb_export_to_api_x3(struct afb_export *export);
+
+#if defined(WITH_LEGACY_BINDING_V1)
+
+struct afb_service_x1;
+struct afb_binding_interface_v1;
+
+extern 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*));
-extern int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset);
+extern struct afb_binding_v1 *afb_export_register_v1(
+ struct afb_export *export,
+ struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*));
-extern int afb_export_verbosity_get(const struct afb_export *export);
-extern void afb_export_verbosity_set(struct afb_export *export, int level);
+#endif
diff --git a/src/afb-hook.c b/src/afb-hook.c
index f5868b18..75e8a691 100644
--- a/src/afb-hook.c
+++ b/src/afb-hook.c
@@ -27,8 +27,8 @@
#include <json-c/json.h>
-#include <afb/afb-req.h>
-#include <afb/afb-event.h>
+#include <afb/afb-req-x1.h>
+#include <afb/afb-event-x2.h>
#include "afb-context.h"
#include "afb-hook.h"
@@ -38,10 +38,19 @@
#include "afb-export.h"
#include "afb-evt.h"
#include "afb-api.h"
+#include "afb-msg-json.h"
#include "verbose.h"
#include <fnmatch.h>
-#define MATCH(pattern,string) (!fnmatch((pattern),(string),FNM_CASEFOLD|FNM_EXTMATCH))
+#define MATCH(pattern,string) (\
+ pattern \
+ ? !fnmatch((pattern),(string),FNM_CASEFOLD|FNM_EXTMATCH|FNM_PERIOD) \
+ : (string)[0] != '.')
+
+#define MATCH_API(pattern,string) MATCH(pattern,string)
+#define MATCH_VERB(pattern,string) MATCH(pattern,string)
+#define MATCH_EVENT(pattern,string) MATCH(pattern,string)
+#define MATCH_SESSION(pattern,string) MATCH(pattern,string)
/**
* Definition of a hook for xreq
@@ -60,24 +69,12 @@ struct afb_hook_xreq {
/**
* Definition of a hook for export
*/
-struct afb_hook_ditf {
- struct afb_hook_ditf *next; /**< next hook */
+struct afb_hook_api {
+ struct afb_hook_api *next; /**< next hook */
unsigned refcount; /**< reference count */
unsigned flags; /**< hook flags */
char *api; /**< api hooked or NULL for any */
- struct afb_hook_ditf_itf *itf; /**< interface of hook */
- void *closure; /**< closure for callbacks */
-};
-
-/**
- * Definition of a hook for export
- */
-struct afb_hook_svc {
- struct afb_hook_svc *next; /**< next hook */
- unsigned refcount; /**< reference count */
- unsigned flags; /**< hook flags */
- char *api; /**< api hooked or NULL for any */
- struct afb_hook_svc_itf *itf; /**< interface of hook */
+ struct afb_hook_api_itf *itf; /**< interface of hook */
void *closure; /**< closure for callbacks */
};
@@ -123,10 +120,7 @@ static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
static struct afb_hook_xreq *list_of_xreq_hooks = NULL;
/* list of hooks for export */
-static struct afb_hook_ditf *list_of_ditf_hooks = NULL;
-
-/* list of hooks for export */
-static struct afb_hook_svc *list_of_svc_hooks = NULL;
+static struct afb_hook_api *list_of_api_hooks = NULL;
/* list of hooks for evt */
static struct afb_hook_evt *list_of_evt_hooks = NULL;
@@ -225,11 +219,11 @@ static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...)
{
va_list ap;
va_start(ap, format);
- _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->request.api, xreq->request.verb);
+ _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->request.called_api, xreq->request.called_verb);
va_end(ap);
}
-static void hook_xreq_begin_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+static void hook_xreq_begin_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
{
if (!xreq->cred)
_hook_xreq_(xreq, "BEGIN");
@@ -244,92 +238,87 @@ static void hook_xreq_begin_default_cb(void *closure, const struct afb_hookid *h
);
}
-static void hook_xreq_end_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+static void hook_xreq_end_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
{
_hook_xreq_(xreq, "END");
}
-static void hook_xreq_json_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj)
+static void hook_xreq_json_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj)
{
_hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj));
}
-static void hook_xreq_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
+static void hook_xreq_get_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
{
_hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
}
-static void hook_xreq_success_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
-{
- _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info);
-}
-
-static void hook_xreq_fail_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info)
+static void hook_xreq_reply_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info)
{
- _hook_xreq_(xreq, "fail(%s, %s)", status, info);
+ _hook_xreq_(xreq, "reply[%s](%s, %s)", error?:"success", json_object_to_json_string(obj), info);
}
-static void hook_xreq_context_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value)
+static void hook_xreq_legacy_context_get_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value)
{
_hook_xreq_(xreq, "context_get() -> %p", value);
}
-static void hook_xreq_context_set_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
+static void hook_xreq_legacy_context_set_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
{
_hook_xreq_(xreq, "context_set(%p, %p)", value, free_value);
}
-static void hook_xreq_addref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+static void hook_xreq_addref_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
{
_hook_xreq_(xreq, "addref()");
}
-static void hook_xreq_unref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+static void hook_xreq_unref_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
{
_hook_xreq_(xreq, "unref()");
}
-static void hook_xreq_session_close_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+static void hook_xreq_session_close_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
{
_hook_xreq_(xreq, "session_close()");
}
-static void hook_xreq_session_set_LOA_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result)
+static void hook_xreq_session_set_LOA_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result)
{
_hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result);
}
-static void hook_xreq_subscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result)
+static void hook_xreq_subscribe_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result)
{
- _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), result);
+ _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_event_x2_fullname(event_x2), afb_evt_event_x2_id(event_x2), result);
}
-static void hook_xreq_unsubscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result)
+static void hook_xreq_unsubscribe_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result)
{
- _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), result);
+ _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_event_x2_fullname(event_x2), afb_evt_event_x2_id(event_x2), result);
}
-static void hook_xreq_subcall_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
+static void hook_xreq_subcall_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
{
_hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
}
-static void hook_xreq_subcall_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
+static void hook_xreq_subcall_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
{
- _hook_xreq_(xreq, " ...subcall... -> %d: %s", status, json_object_to_json_string(result));
+ _hook_xreq_(xreq, " ...subcall... [%s] -> %s (%s)", error?:"success", json_object_to_json_string(object), info?:"");
}
-static void hook_xreq_subcallsync_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
+static void hook_xreq_subcallsync_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
{
_hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
}
-static void hook_xreq_subcallsync_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
+static void hook_xreq_subcallsync_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info)
{
- _hook_xreq_(xreq, " ...subcallsync... -> %d: %s", status, json_object_to_json_string(result));
+ _hook_xreq_(xreq, " ...subcallsync... %d [%s] -> %s (%s)", status, error?:"success", json_object_to_json_string(object), info?:"");
}
-static void hook_xreq_vverbose_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
+static void hook_xreq_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
{
int len;
char *msg;
@@ -340,105 +329,99 @@ static void hook_xreq_vverbose_default_cb(void *closure, const struct afb_hookid
va_end(ap);
if (len < 0)
- _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt);
+ _hook_xreq_(xreq, "vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, func, fmt);
else {
- _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg);
+ _hook_xreq_(xreq, "vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, func, msg);
free(msg);
}
}
-static void hook_xreq_store_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq)
+static void hook_xreq_legacy_store_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq)
{
_hook_xreq_(xreq, "store() -> %p", sreq);
}
-static void hook_xreq_unstore_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+static void hook_xreq_legacy_unstore_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
{
_hook_xreq_(xreq, "unstore()");
}
-static void hook_xreq_subcall_req_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
-{
- _hook_xreq_(xreq, "subcall_req(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
-}
-
-static void hook_xreq_subcall_req_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
-{
- _hook_xreq_(xreq, " ...subcall_req... -> %d: %s", status, json_object_to_json_string(result));
-}
-
-static void hook_xreq_has_permission_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result)
+static void hook_xreq_has_permission_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result)
{
_hook_xreq_(xreq, "has_permission(%s) -> %d", permission, result);
}
-static void hook_xreq_get_application_id_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result)
+static void hook_xreq_get_application_id_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result)
{
_hook_xreq_(xreq, "get_application_id() -> %s", result);
}
-static void hook_xreq_context_make_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result)
+static void hook_xreq_context_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result)
{
_hook_xreq_(xreq, "context_make(replace=%s, %p, %p, %p) -> %p", replace?"yes":"no", create_value, free_value, create_closure, result);
}
-static void hook_xreq_get_uid_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result)
+static void hook_xreq_get_uid_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result)
{
_hook_xreq_(xreq, "get_uid() -> %d", result);
}
+static void hook_xreq_get_client_info_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *result)
+{
+ _hook_xreq_(xreq, "get_client_info() -> %s", json_object_to_json_string(result));
+}
+
static struct afb_hook_xreq_itf hook_xreq_default_itf = {
- .hook_xreq_begin = hook_xreq_begin_default_cb,
- .hook_xreq_end = hook_xreq_end_default_cb,
- .hook_xreq_json = hook_xreq_json_default_cb,
- .hook_xreq_get = hook_xreq_get_default_cb,
- .hook_xreq_success = hook_xreq_success_default_cb,
- .hook_xreq_fail = hook_xreq_fail_default_cb,
- .hook_xreq_context_get = hook_xreq_context_get_default_cb,
- .hook_xreq_context_set = hook_xreq_context_set_default_cb,
- .hook_xreq_addref = hook_xreq_addref_default_cb,
- .hook_xreq_unref = hook_xreq_unref_default_cb,
- .hook_xreq_session_close = hook_xreq_session_close_default_cb,
- .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_default_cb,
- .hook_xreq_subscribe = hook_xreq_subscribe_default_cb,
- .hook_xreq_unsubscribe = hook_xreq_unsubscribe_default_cb,
- .hook_xreq_subcall = hook_xreq_subcall_default_cb,
- .hook_xreq_subcall_result = hook_xreq_subcall_result_default_cb,
- .hook_xreq_subcallsync = hook_xreq_subcallsync_default_cb,
- .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb,
- .hook_xreq_vverbose = hook_xreq_vverbose_default_cb,
- .hook_xreq_store = hook_xreq_store_default_cb,
- .hook_xreq_unstore = hook_xreq_unstore_default_cb,
- .hook_xreq_subcall_req = hook_xreq_subcall_req_default_cb,
- .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result_default_cb,
- .hook_xreq_has_permission = hook_xreq_has_permission_default_cb,
- .hook_xreq_get_application_id = hook_xreq_get_application_id_default_cb,
- .hook_xreq_context_make = hook_xreq_context_make_default_cb,
- .hook_xreq_get_uid = hook_xreq_get_uid_default_cb,
+ .hook_xreq_begin = hook_xreq_begin_cb,
+ .hook_xreq_end = hook_xreq_end_cb,
+ .hook_xreq_json = hook_xreq_json_cb,
+ .hook_xreq_get = hook_xreq_get_cb,
+ .hook_xreq_reply = hook_xreq_reply_cb,
+ .hook_xreq_legacy_context_get = hook_xreq_legacy_context_get_cb,
+ .hook_xreq_legacy_context_set = hook_xreq_legacy_context_set_cb,
+ .hook_xreq_addref = hook_xreq_addref_cb,
+ .hook_xreq_unref = hook_xreq_unref_cb,
+ .hook_xreq_session_close = hook_xreq_session_close_cb,
+ .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_cb,
+ .hook_xreq_subscribe = hook_xreq_subscribe_cb,
+ .hook_xreq_unsubscribe = hook_xreq_unsubscribe_cb,
+ .hook_xreq_subcall = hook_xreq_subcall_cb,
+ .hook_xreq_subcall_result = hook_xreq_subcall_result_cb,
+ .hook_xreq_subcallsync = hook_xreq_subcallsync_cb,
+ .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_cb,
+ .hook_xreq_vverbose = hook_xreq_vverbose_cb,
+ .hook_xreq_legacy_store = hook_xreq_legacy_store_cb,
+ .hook_xreq_legacy_unstore = hook_xreq_legacy_unstore_cb,
+ .hook_xreq_has_permission = hook_xreq_has_permission_cb,
+ .hook_xreq_get_application_id = hook_xreq_get_application_id_cb,
+ .hook_xreq_context_make = hook_xreq_context_make_cb,
+ .hook_xreq_get_uid = hook_xreq_get_uid_cb,
+ .hook_xreq_get_client_info = hook_xreq_get_client_info_cb,
};
/******************************************************************************
* section: hooks for tracing requests
*****************************************************************************/
-#define _HOOK_XREQ_(what,...) \
+#define _HOOK_XREQ_2_(flag,func,...) \
struct afb_hook_xreq *hook; \
struct afb_hookid hookid; \
pthread_rwlock_rdlock(&rwlock); \
init_hookid(&hookid); \
hook = list_of_xreq_hooks; \
while (hook) { \
- if (hook->itf->hook_xreq_##what \
- && (hook->flags & afb_hook_flag_req_##what) != 0 \
+ if (hook->itf->hook_xreq_##func \
+ && (hook->flags & afb_hook_flag_req_##flag) != 0 \
&& (!hook->session || hook->session == xreq->context.session) \
- && (!hook->api || !strcasecmp(hook->api, xreq->request.api)) \
- && (!hook->verb || !strcasecmp(hook->verb, xreq->request.verb))) { \
- hook->itf->hook_xreq_##what(hook->closure, &hookid, __VA_ARGS__); \
+ && MATCH_API(hook->api, xreq->request.called_api) \
+ && MATCH_VERB(hook->verb, xreq->request.called_verb)) { \
+ hook->itf->hook_xreq_##func(hook->closure, &hookid, __VA_ARGS__); \
} \
hook = hook->next; \
} \
pthread_rwlock_unlock(&rwlock);
+#define _HOOK_XREQ_(what,...) _HOOK_XREQ_2_(what,what,__VA_ARGS__)
void afb_hook_xreq_begin(const struct afb_xreq *xreq)
{
@@ -462,25 +445,20 @@ struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name,
return arg;
}
-void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info)
+void afb_hook_xreq_reply(const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info)
{
- _HOOK_XREQ_(success, xreq, obj, info);
+ _HOOK_XREQ_(reply, xreq, obj, error, info);
}
-void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info)
+void *afb_hook_xreq_legacy_context_get(const struct afb_xreq *xreq, void *value)
{
- _HOOK_XREQ_(fail, xreq, status, info);
-}
-
-void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value)
-{
- _HOOK_XREQ_(context_get, xreq, value);
+ _HOOK_XREQ_(legacy_context_get, xreq, value);
return value;
}
-void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
+void afb_hook_xreq_legacy_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
{
- _HOOK_XREQ_(context_set, xreq, value, free_value);
+ _HOOK_XREQ_(legacy_context_set, xreq, value, free_value);
}
void afb_hook_xreq_addref(const struct afb_xreq *xreq)
@@ -504,36 +482,36 @@ int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, i
return result;
}
-int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result)
+int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result)
{
- _HOOK_XREQ_(subscribe, xreq, eventid, result);
+ _HOOK_XREQ_(subscribe, xreq, event_x2, result);
return result;
}
-int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result)
+int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result)
{
- _HOOK_XREQ_(unsubscribe, xreq, eventid, result);
+ _HOOK_XREQ_(unsubscribe, xreq, event_x2, result);
return result;
}
-void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
+void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags)
{
_HOOK_XREQ_(subcall, xreq, api, verb, args);
}
-void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result)
+void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
{
- _HOOK_XREQ_(subcall_result, xreq, status, result);
+ _HOOK_XREQ_(subcall_result, xreq, object, error, info);
}
-void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
+void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags)
{
_HOOK_XREQ_(subcallsync, xreq, api, verb, args);
}
-int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result)
+int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info)
{
- _HOOK_XREQ_(subcallsync_result, xreq, status, result);
+ _HOOK_XREQ_(subcallsync_result, xreq, status, object, error, info);
return status;
}
@@ -542,24 +520,14 @@ void afb_hook_xreq_vverbose(const struct afb_xreq *xreq, int level, const char *
_HOOK_XREQ_(vverbose, xreq, level, file ?: "?", line, func ?: "?", fmt, args);
}
-void afb_hook_xreq_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq)
-{
- _HOOK_XREQ_(store, xreq, sreq);
-}
-
-void afb_hook_xreq_unstore(const struct afb_xreq *xreq)
-{
- _HOOK_XREQ_(unstore, xreq);
-}
-
-void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
+void afb_hook_xreq_legacy_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq)
{
- _HOOK_XREQ_(subcall_req, xreq, api, verb, args);
+ _HOOK_XREQ_(legacy_store, xreq, sreq);
}
-void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result)
+void afb_hook_xreq_legacy_unstore(const struct afb_xreq *xreq)
{
- _HOOK_XREQ_(subcall_req_result, xreq, status, result);
+ _HOOK_XREQ_(legacy_unstore, xreq);
}
int afb_hook_xreq_has_permission(const struct afb_xreq *xreq, const char *permission, int result)
@@ -586,6 +554,12 @@ int afb_hook_xreq_get_uid(const struct afb_xreq *xreq, int result)
return result;
}
+struct json_object *afb_hook_xreq_get_client_info(const struct afb_xreq *xreq, struct json_object *result)
+{
+ _HOOK_XREQ_(get_client_info, xreq, result);
+ return result;
+}
+
/******************************************************************************
* section: hooking xreqs
*****************************************************************************/
@@ -600,21 +574,19 @@ void afb_hook_init_xreq(struct afb_xreq *xreq)
/* scan hook list to get the expected flags */
flags = 0;
- if (afb_api_is_hookable(xreq->request.api)) {
- pthread_rwlock_rdlock(&rwlock);
- hook = list_of_xreq_hooks;
- while (hook) {
- f = hook->flags & afb_hook_flags_req_all;
- add = f != 0
- && (!hook->session || hook->session == xreq->context.session)
- && (!hook->api || !strcasecmp(hook->api, xreq->request.api))
- && (!hook->verb || !strcasecmp(hook->verb, xreq->request.verb));
- if (add)
- flags |= f;
- hook = hook->next;
- }
- pthread_rwlock_unlock(&rwlock);
+ pthread_rwlock_rdlock(&rwlock);
+ hook = list_of_xreq_hooks;
+ while (hook) {
+ f = hook->flags & afb_hook_flags_req_all;
+ add = f != 0
+ && (!hook->session || hook->session == xreq->context.session)
+ && MATCH_API(hook->api, xreq->request.called_api)
+ && MATCH_VERB(hook->verb, xreq->request.called_verb);
+ if (add)
+ flags |= f;
+ hook = hook->next;
}
+ pthread_rwlock_unlock(&rwlock);
/* store the hooking data */
xreq->hookflags = flags;
@@ -705,40 +677,40 @@ void afb_hook_unref_xreq(struct afb_hook_xreq *hook)
* section: default callbacks for tracing daemon interface
*****************************************************************************/
-static void _hook_ditf_(const struct afb_export *export, const char *format, ...)
+static void _hook_api_(const struct afb_export *export, const char *format, ...)
{
va_list ap;
va_start(ap, format);
- _hook_("export-%s", format, ap, afb_export_apiname(export));
+ _hook_("api-%s", format, ap, afb_export_apiname(export));
va_end(ap);
}
-static void hook_ditf_event_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object)
+static void hook_api_event_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object)
{
- _hook_ditf_(export, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object));
+ _hook_api_(export, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object));
}
-static void hook_ditf_event_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result)
+static void hook_api_event_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result)
{
- _hook_ditf_(export, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result);
+ _hook_api_(export, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result);
}
-static void hook_ditf_get_event_loop_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result)
+static void hook_api_get_event_loop_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result)
{
- _hook_ditf_(export, "get_event_loop() -> %p", result);
+ _hook_api_(export, "get_event_loop() -> %p", result);
}
-static void hook_ditf_get_user_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
+static void hook_api_get_user_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
{
- _hook_ditf_(export, "get_user_bus() -> %p", result);
+ _hook_api_(export, "get_user_bus() -> %p", result);
}
-static void hook_ditf_get_system_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
+static void hook_api_get_system_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
{
- _hook_ditf_(export, "get_system_bus() -> %p", result);
+ _hook_api_(export, "get_system_bus() -> %p", result);
}
-static void hook_ditf_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
+static void hook_api_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
{
int len;
char *msg;
@@ -749,427 +721,489 @@ static void hook_ditf_vverbose_cb(void *closure, const struct afb_hookid *hookid
va_end(ap);
if (len < 0)
- _hook_ditf_(export, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, function, fmt);
+ _hook_api_(export, "vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, function, fmt);
else {
- _hook_ditf_(export, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, function, msg);
+ _hook_api_(export, "vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, function, msg);
free(msg);
}
}
-static void hook_ditf_event_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_eventid *result)
+static void hook_api_event_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_event_x2 *result)
{
- _hook_ditf_(export, "event_make(%s) -> %s:%d", name, afb_evt_eventid_fullname(result), afb_evt_eventid_id(result));
+ _hook_api_(export, "event_make(%s) -> %s:%d", name, afb_evt_event_x2_fullname(result), afb_evt_event_x2_id(result));
}
-static void hook_ditf_rootdir_get_fd_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
+static void hook_api_rootdir_get_fd_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
{
char path[PATH_MAX];
if (result < 0)
- _hook_ditf_(export, "rootdir_get_fd() -> %d, %m", result);
+ _hook_api_(export, "rootdir_get_fd() -> %d, %m", result);
else {
sprintf(path, "/proc/self/fd/%d", result);
readlink(path, path, sizeof path);
- _hook_ditf_(export, "rootdir_get_fd() -> %d = %s", result, path);
+ _hook_api_(export, "rootdir_get_fd() -> %d = %s", result, path);
}
}
-static void hook_ditf_rootdir_open_locale_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result)
+static void hook_api_rootdir_open_locale_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result)
{
char path[PATH_MAX];
if (!locale)
locale = "(null)";
if (result < 0)
- _hook_ditf_(export, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result);
+ _hook_api_(export, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result);
else {
sprintf(path, "/proc/self/fd/%d", result);
readlink(path, path, sizeof path);
- _hook_ditf_(export, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path);
+ _hook_api_(export, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path);
}
}
-static void hook_ditf_queue_job_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
+static void hook_api_queue_job_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
+{
+ _hook_api_(export, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result);
+}
+
+static void hook_api_unstore_req_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq)
+{
+ _hook_api_(export, "unstore_req(%p)", sreq);
+}
+
+static void hook_api_require_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized)
+{
+ _hook_api_(export, "require_api(%s, %d)...", name, initialized);
+}
+
+static void hook_api_require_api_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result)
+{
+ _hook_api_(export, "...require_api(%s, %d) -> %d", name, initialized, result);
+}
+
+static void hook_api_add_alias_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *alias, int result)
+{
+ _hook_api_(export, "add_alias(%s -> %s) -> %d", api, alias?:"<null>", result);
+}
+
+static void hook_api_start_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
+{
+ _hook_api_(export, "start.before");
+}
+
+static void hook_api_start_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status)
+{
+ _hook_api_(export, "start.after -> %d", status);
+}
+
+static void hook_api_on_event_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object)
+{
+ _hook_api_(export, "on_event.before(%s, %d, %s)", event, event_x2, json_object_to_json_string(object));
+}
+
+static void hook_api_on_event_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object)
+{
+ _hook_api_(export, "on_event.after(%s, %d, %s)", event, event_x2, json_object_to_json_string(object));
+}
+
+static void hook_api_call_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
+{
+ _hook_api_(export, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
+}
+
+static void hook_api_call_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object, const char *error, const char *info)
+{
+ _hook_api_(export, " ...call... [%s] -> %s (%s)", error?:"success", json_object_to_json_string(object), info?:"");
+}
+
+static void hook_api_callsync_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
+{
+ _hook_api_(export, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
+}
+
+static void hook_api_callsync_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info)
+{
+ _hook_api_(export, " ...callsync... %d [%s] -> %s (%s)", status, error?:"success", json_object_to_json_string(object), info?:"");
+}
+
+static void hook_api_new_api_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *info, int noconcurrency)
+{
+ _hook_api_(export, "new_api.before %s (%s)%s ...", api, info?:"", noconcurrency?" no-concurrency" : "");
+}
+
+static void hook_api_new_api_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *api)
+{
+ _hook_api_(export, "... new_api.after %s -> %s (%d)", api, result >= 0 ? "OK" : "ERROR", result);
+}
+
+static void hook_api_api_set_verbs_v2_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v2 *verbs)
+{
+ _hook_api_(export, "set_verbs_v2 -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
+}
+
+static void hook_api_api_set_verbs_v3_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v3 *verbs)
+{
+ _hook_api_(export, "set_verbs_v3 -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
+}
+
+static void hook_api_api_add_verb_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb, const char *info, int glob)
+{
+ _hook_api_(export, "add_verb(%s%s [%s]) -> %s (%d)", verb, glob?" (GLOB)":"", info?:"", result >= 0 ? "OK" : "ERROR", result);
+}
+
+static void hook_api_api_del_verb_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb)
+{
+ _hook_api_(export, "del_verb(%s) -> %s (%d)", verb, result >= 0 ? "OK" : "ERROR", result);
+}
+
+static void hook_api_api_set_on_event_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
+{
+ _hook_api_(export, "set_on_event -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
+}
+
+static void hook_api_api_set_on_init_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
+{
+ _hook_api_(export, "set_on_init -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
+}
+
+static void hook_api_api_seal_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
+{
+ _hook_api_(export, "seal");
+}
+
+static void hook_api_event_handler_add_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern)
+{
+ _hook_api_(export, "event_handler_add(%s) -> %s (%d)", pattern, result >= 0 ? "OK" : "ERROR", result);
+}
+
+static void hook_api_event_handler_del_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern)
+{
+ _hook_api_(export, "event_handler_del(%s) -> %s (%d)", pattern, result >= 0 ? "OK" : "ERROR", result);
+}
+
+static void hook_api_class_provide_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name)
{
- _hook_ditf_(export, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result);
+ _hook_api_(export, "class_provide(%s) -> %s (%d)", name, result >= 0 ? "OK" : "ERROR", result);
}
-static void hook_ditf_unstore_req_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq)
+static void hook_api_class_require_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name)
{
- _hook_ditf_(export, "unstore_req(%p)", sreq);
+ _hook_api_(export, "class_require(%s) -> %s (%d)", name, result >= 0 ? "OK" : "ERROR", result);
}
-static void hook_ditf_require_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized)
+static void hook_api_delete_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
{
- _hook_ditf_(export, "require_api(%s, %d)...", name, initialized);
+ _hook_api_(export, "delete_api -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
}
-static void hook_ditf_require_api_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result)
+static void hook_api_on_event_handler_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern)
{
- _hook_ditf_(export, "...require_api(%s, %d) -> %d", name, initialized, result);
+ _hook_api_(export, "on_event_handler[%s].before(%s, %d, %s)", pattern, event, event_x2, json_object_to_json_string(object));
}
-static void hook_ditf_rename_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *oldname, const char *newname, int result)
+static void hook_api_on_event_handler_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern)
{
- _hook_ditf_(export, "rename_api(%s -> %s) -> %d", oldname, newname, result);
+ _hook_api_(export, "on_event_handler[%s].after(%s, %d, %s)", pattern, event, event_x2, json_object_to_json_string(object));
}
-static struct afb_hook_ditf_itf hook_ditf_default_itf = {
- .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before_cb,
- .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after_cb,
- .hook_ditf_get_event_loop = hook_ditf_get_event_loop_cb,
- .hook_ditf_get_user_bus = hook_ditf_get_user_bus_cb,
- .hook_ditf_get_system_bus = hook_ditf_get_system_bus_cb,
- .hook_ditf_vverbose = hook_ditf_vverbose_cb,
- .hook_ditf_event_make = hook_ditf_event_make_cb,
- .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd_cb,
- .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale_cb,
- .hook_ditf_queue_job = hook_ditf_queue_job_cb,
- .hook_ditf_unstore_req = hook_ditf_unstore_req_cb,
- .hook_ditf_require_api = hook_ditf_require_api_cb,
- .hook_ditf_require_api_result = hook_ditf_require_api_result_cb,
- .hook_ditf_rename_api = hook_ditf_rename_api_cb
+static struct afb_hook_api_itf hook_api_default_itf = {
+ .hook_api_event_broadcast_before = hook_api_event_broadcast_before_cb,
+ .hook_api_event_broadcast_after = hook_api_event_broadcast_after_cb,
+ .hook_api_get_event_loop = hook_api_get_event_loop_cb,
+ .hook_api_get_user_bus = hook_api_get_user_bus_cb,
+ .hook_api_get_system_bus = hook_api_get_system_bus_cb,
+ .hook_api_vverbose = hook_api_vverbose_cb,
+ .hook_api_event_make = hook_api_event_make_cb,
+ .hook_api_rootdir_get_fd = hook_api_rootdir_get_fd_cb,
+ .hook_api_rootdir_open_locale = hook_api_rootdir_open_locale_cb,
+ .hook_api_queue_job = hook_api_queue_job_cb,
+ .hook_api_legacy_unstore_req = hook_api_unstore_req_cb,
+ .hook_api_require_api = hook_api_require_api_cb,
+ .hook_api_require_api_result = hook_api_require_api_result_cb,
+ .hook_api_add_alias = hook_api_add_alias_cb,
+ .hook_api_start_before = hook_api_start_before_cb,
+ .hook_api_start_after = hook_api_start_after_cb,
+ .hook_api_on_event_before = hook_api_on_event_before_cb,
+ .hook_api_on_event_after = hook_api_on_event_after_cb,
+ .hook_api_call = hook_api_call_cb,
+ .hook_api_call_result = hook_api_call_result_cb,
+ .hook_api_callsync = hook_api_callsync_cb,
+ .hook_api_callsync_result = hook_api_callsync_result_cb,
+ .hook_api_new_api_before = hook_api_new_api_before_cb,
+ .hook_api_new_api_after = hook_api_new_api_after_cb,
+ .hook_api_api_set_verbs_v2 = hook_api_api_set_verbs_v2_cb,
+ .hook_api_api_set_verbs_v3 = hook_api_api_set_verbs_v3_cb,
+ .hook_api_api_add_verb = hook_api_api_add_verb_cb,
+ .hook_api_api_del_verb = hook_api_api_del_verb_cb,
+ .hook_api_api_set_on_event = hook_api_api_set_on_event_cb,
+ .hook_api_api_set_on_init = hook_api_api_set_on_init_cb,
+ .hook_api_api_seal = hook_api_api_seal_cb,
+ .hook_api_event_handler_add = hook_api_event_handler_add_cb,
+ .hook_api_event_handler_del = hook_api_event_handler_del_cb,
+ .hook_api_class_provide = hook_api_class_provide_cb,
+ .hook_api_class_require = hook_api_class_require_cb,
+ .hook_api_delete_api = hook_api_delete_api_cb,
+ .hook_api_on_event_handler_before = hook_api_on_event_handler_before_cb,
+ .hook_api_on_event_handler_after = hook_api_on_event_handler_after_cb,
};
/******************************************************************************
* section: hooks for tracing daemon interface (export)
*****************************************************************************/
-#define _HOOK_DITF_(what,...) \
- struct afb_hook_ditf *hook; \
+#define _HOOK_API_2_(flag,func,...) \
+ struct afb_hook_api *hook; \
struct afb_hookid hookid; \
const char *apiname = afb_export_apiname(export); \
pthread_rwlock_rdlock(&rwlock); \
init_hookid(&hookid); \
- hook = list_of_ditf_hooks; \
+ hook = list_of_api_hooks; \
while (hook) { \
- if (hook->itf->hook_ditf_##what \
- && (hook->flags & afb_hook_flag_ditf_##what) != 0 \
- && (!hook->api || !strcasecmp(hook->api, apiname))) { \
- hook->itf->hook_ditf_##what(hook->closure, &hookid, __VA_ARGS__); \
+ if (hook->itf->hook_api_##func \
+ && (hook->flags & afb_hook_flag_api_##flag) != 0 \
+ && MATCH_API(hook->api, apiname)) { \
+ hook->itf->hook_api_##func(hook->closure, &hookid, __VA_ARGS__); \
} \
hook = hook->next; \
} \
pthread_rwlock_unlock(&rwlock);
-void afb_hook_ditf_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object)
+#define _HOOK_API_(what,...) _HOOK_API_2_(what,what,__VA_ARGS__)
+
+void afb_hook_api_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object)
{
- _HOOK_DITF_(event_broadcast_before, export, name, object);
+ _HOOK_API_2_(event_broadcast, event_broadcast_before, export, name, object);
}
-int afb_hook_ditf_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result)
+int afb_hook_api_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result)
{
- _HOOK_DITF_(event_broadcast_after, export, name, object, result);
+ _HOOK_API_2_(event_broadcast, event_broadcast_after, export, name, object, result);
return result;
}
-struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_export *export, struct sd_event *result)
+struct sd_event *afb_hook_api_get_event_loop(const struct afb_export *export, struct sd_event *result)
{
- _HOOK_DITF_(get_event_loop, export, result);
+ _HOOK_API_(get_event_loop, export, result);
return result;
}
-struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_export *export, struct sd_bus *result)
+struct sd_bus *afb_hook_api_get_user_bus(const struct afb_export *export, struct sd_bus *result)
{
- _HOOK_DITF_(get_user_bus, export, result);
+ _HOOK_API_(get_user_bus, export, result);
return result;
}
-struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_export *export, struct sd_bus *result)
+struct sd_bus *afb_hook_api_get_system_bus(const struct afb_export *export, struct sd_bus *result)
{
- _HOOK_DITF_(get_system_bus, export, result);
+ _HOOK_API_(get_system_bus, export, result);
return result;
}
-void afb_hook_ditf_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
+void afb_hook_api_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
{
- _HOOK_DITF_(vverbose, export, level, file, line, function, fmt, args);
+ _HOOK_API_(vverbose, export, level, file, line, function, fmt, args);
}
-struct afb_eventid *afb_hook_ditf_event_make(const struct afb_export *export, const char *name, struct afb_eventid *result)
+struct afb_event_x2 *afb_hook_api_event_make(const struct afb_export *export, const char *name, struct afb_event_x2 *result)
{
- _HOOK_DITF_(event_make, export, name, result);
+ _HOOK_API_(event_make, export, name, result);
return result;
}
-int afb_hook_ditf_rootdir_get_fd(const struct afb_export *export, int result)
+int afb_hook_api_rootdir_get_fd(const struct afb_export *export, int result)
{
- _HOOK_DITF_(rootdir_get_fd, export, result);
+ _HOOK_API_(rootdir_get_fd, export, result);
return result;
}
-int afb_hook_ditf_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result)
+int afb_hook_api_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result)
{
- _HOOK_DITF_(rootdir_open_locale, export, filename, flags, locale, result);
+ _HOOK_API_(rootdir_open_locale, export, filename, flags, locale, result);
return result;
}
-int afb_hook_ditf_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
+int afb_hook_api_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
{
- _HOOK_DITF_(queue_job, export, callback, argument, group, timeout, result);
+ _HOOK_API_(queue_job, export, callback, argument, group, timeout, result);
return result;
}
-void afb_hook_ditf_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq)
+void afb_hook_api_legacy_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq)
{
- _HOOK_DITF_(unstore_req, export, sreq);
+ _HOOK_API_(legacy_unstore_req, export, sreq);
}
-void afb_hook_ditf_require_api(const struct afb_export *export, const char *name, int initialized)
+void afb_hook_api_require_api(const struct afb_export *export, const char *name, int initialized)
{
- _HOOK_DITF_(require_api, export, name, initialized);
+ _HOOK_API_(require_api, export, name, initialized);
}
-int afb_hook_ditf_require_api_result(const struct afb_export *export, const char *name, int initialized, int result)
+int afb_hook_api_require_api_result(const struct afb_export *export, const char *name, int initialized, int result)
{
- _HOOK_DITF_(require_api_result, export, name, initialized, result);
+ _HOOK_API_2_(require_api, require_api_result, export, name, initialized, result);
return result;
}
-int afb_hook_ditf_rename_api(const struct afb_export *export, const char *oldname, const char *newname, int result)
+int afb_hook_api_add_alias(const struct afb_export *export, const char *api, const char *alias, int result)
{
- _HOOK_DITF_(rename_api, export, oldname, newname, result);
+ _HOOK_API_(add_alias, export, api, alias, result);
return result;
}
-/******************************************************************************
- * section: hooking export
- *****************************************************************************/
-
-int afb_hook_flags_ditf(const char *api)
+void afb_hook_api_start_before(const struct afb_export *export)
{
- int flags;
- struct afb_hook_ditf *hook;
-
- flags = 0;
- if (!api || afb_api_is_hookable(api)) {
- pthread_rwlock_rdlock(&rwlock);
- hook = list_of_ditf_hooks;
- while (hook) {
- if (!api || !hook->api || !strcasecmp(hook->api, api))
- flags |= hook->flags;
- hook = hook->next;
- }
- pthread_rwlock_unlock(&rwlock);
- }
- return flags;
+ _HOOK_API_2_(start, start_before, export);
}
-struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure)
+int afb_hook_api_start_after(const struct afb_export *export, int status)
{
- struct afb_hook_ditf *hook;
-
- /* alloc the result */
- hook = calloc(1, sizeof *hook);
- if (hook == NULL)
- return NULL;
-
- /* get a copy of the names */
- hook->api = api ? strdup(api) : NULL;
- if (api && !hook->api) {
- free(hook);
- return NULL;
- }
-
- /* initialise the rest */
- hook->refcount = 1;
- hook->flags = flags;
- hook->itf = itf ? itf : &hook_ditf_default_itf;
- hook->closure = closure;
+ _HOOK_API_2_(start, start_after, export, status);
+ return status;
+}
- /* record the hook */
- pthread_rwlock_wrlock(&rwlock);
- hook->next = list_of_ditf_hooks;
- list_of_ditf_hooks = hook;
- pthread_rwlock_unlock(&rwlock);
+void afb_hook_api_on_event_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object)
+{
+ _HOOK_API_2_(on_event, on_event_before, export, event, event_x2, object);
+}
- /* returns it */
- return hook;
+void afb_hook_api_on_event_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object)
+{
+ _HOOK_API_2_(on_event, on_event_after, export, event, event_x2, object);
}
-struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook)
+void afb_hook_api_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
{
- pthread_rwlock_wrlock(&rwlock);
- hook->refcount++;
- pthread_rwlock_unlock(&rwlock);
- return hook;
+ _HOOK_API_(call, export, api, verb, args);
}
-void afb_hook_unref_ditf(struct afb_hook_ditf *hook)
+void afb_hook_api_call_result(const struct afb_export *export, struct json_object *object, const char*error, const char *info)
{
- struct afb_hook_ditf **prv;
+ _HOOK_API_2_(call, call_result, export, object, error, info);
- if (hook) {
- pthread_rwlock_wrlock(&rwlock);
- if (--hook->refcount)
- hook = NULL;
- else {
- /* unlink */
- prv = &list_of_ditf_hooks;
- while (*prv && *prv != hook)
- prv = &(*prv)->next;
- if(*prv)
- *prv = hook->next;
- }
- pthread_rwlock_unlock(&rwlock);
- if (hook) {
- /* free */
- free(hook->api);
- free(hook);
- }
- }
}
-/******************************************************************************
- * section: default callbacks for tracing service interface (export)
- *****************************************************************************/
-
-static void _hook_svc_(const struct afb_export *export, const char *format, ...)
+void afb_hook_api_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
{
- va_list ap;
- va_start(ap, format);
- _hook_("export-%s", format, ap, afb_export_apiname(export));
- va_end(ap);
+ _HOOK_API_(callsync, export, api, verb, args);
}
-static void hook_svc_start_before_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
+int afb_hook_api_callsync_result(const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info)
{
- _hook_svc_(export, "start.before");
+ _HOOK_API_2_(callsync, callsync_result, export, status, object, error, info);
+ return status;
}
-static void hook_svc_start_after_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status)
+void afb_hook_api_new_api_before(const struct afb_export *export, const char *api, const char *info, int noconcurrency)
{
- _hook_svc_(export, "start.after -> %d", status);
+ _HOOK_API_2_(new_api, new_api_before, export, api, info, noconcurrency);
}
-static void hook_svc_on_event_before_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object)
+int afb_hook_api_new_api_after(const struct afb_export *export, int result, const char *api)
{
- _hook_svc_(export, "on_event.before(%s, %d, %s)", event, eventid, json_object_to_json_string(object));
+ _HOOK_API_2_(new_api, new_api_after, export, result, api);
+ return result;
}
-static void hook_svc_on_event_after_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object)
+int afb_hook_api_api_set_verbs_v2(const struct afb_export *export, int result, const struct afb_verb_v2 *verbs)
{
- _hook_svc_(export, "on_event.after(%s, %d, %s)", event, eventid, json_object_to_json_string(object));
+ _HOOK_API_2_(api_set_verbs, api_set_verbs_v2, export, result, verbs);
+ return result;
}
-static void hook_svc_call_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
+int afb_hook_api_api_set_verbs_v3(const struct afb_export *export, int result, const struct afb_verb_v3 *verbs)
{
- _hook_svc_(export, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
+ _HOOK_API_2_(api_set_verbs, api_set_verbs_v3, export, result, verbs);
+ return result;
}
-static void hook_svc_call_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result)
+int afb_hook_api_api_add_verb(const struct afb_export *export, int result, const char *verb, const char *info, int glob)
{
- _hook_svc_(export, " ...call... -> %d: %s", status, json_object_to_json_string(result));
+ _HOOK_API_(api_add_verb, export, result, verb, info, glob);
+ return result;
}
-static void hook_svc_callsync_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
+int afb_hook_api_api_del_verb(const struct afb_export *export, int result, const char *verb)
{
- _hook_svc_(export, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
+ _HOOK_API_(api_del_verb, export, result, verb);
+ return result;
}
-static void hook_svc_callsync_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result)
+int afb_hook_api_api_set_on_event(const struct afb_export *export, int result)
{
- _hook_svc_(export, " ...callsync... -> %d: %s", status, json_object_to_json_string(result));
+ _HOOK_API_(api_set_on_event, export, result);
+ return result;
}
-static struct afb_hook_svc_itf hook_svc_default_itf = {
- .hook_svc_start_before = hook_svc_start_before_default_cb,
- .hook_svc_start_after = hook_svc_start_after_default_cb,
- .hook_svc_on_event_before = hook_svc_on_event_before_default_cb,
- .hook_svc_on_event_after = hook_svc_on_event_after_default_cb,
- .hook_svc_call = hook_svc_call_default_cb,
- .hook_svc_call_result = hook_svc_call_result_default_cb,
- .hook_svc_callsync = hook_svc_callsync_default_cb,
- .hook_svc_callsync_result = hook_svc_callsync_result_default_cb
-};
-
-/******************************************************************************
- * section: hooks for tracing service interface (export)
- *****************************************************************************/
-
-#define _HOOK_SVC_(what,...) \
- struct afb_hook_svc *hook; \
- struct afb_hookid hookid; \
- const char *apiname = afb_export_apiname(export); \
- pthread_rwlock_rdlock(&rwlock); \
- init_hookid(&hookid); \
- hook = list_of_svc_hooks; \
- while (hook) { \
- if (hook->itf->hook_svc_##what \
- && (hook->flags & afb_hook_flag_svc_##what) != 0 \
- && (!hook->api || !strcasecmp(hook->api, apiname))) { \
- hook->itf->hook_svc_##what(hook->closure, &hookid, __VA_ARGS__); \
- } \
- hook = hook->next; \
- } \
- pthread_rwlock_unlock(&rwlock);
-
-void afb_hook_svc_start_before(const struct afb_export *export)
+int afb_hook_api_api_set_on_init(const struct afb_export *export, int result)
{
- _HOOK_SVC_(start_before, export);
+ _HOOK_API_(api_set_on_init, export, result);
+ return result;
}
-int afb_hook_svc_start_after(const struct afb_export *export, int status)
+void afb_hook_api_api_seal(const struct afb_export *export)
{
- _HOOK_SVC_(start_after, export, status);
- return status;
+ _HOOK_API_(api_seal, export);
}
-void afb_hook_svc_on_event_before(const struct afb_export *export, const char *event, int eventid, struct json_object *object)
+int afb_hook_api_event_handler_add(const struct afb_export *export, int result, const char *pattern)
{
- _HOOK_SVC_(on_event_before, export, event, eventid, object);
+ _HOOK_API_(event_handler_add, export, result, pattern);
+ return result;
}
-
-void afb_hook_svc_on_event_after(const struct afb_export *export, const char *event, int eventid, struct json_object *object)
+int afb_hook_api_event_handler_del(const struct afb_export *export, int result, const char *pattern)
{
- _HOOK_SVC_(on_event_after, export, event, eventid, object);
+ _HOOK_API_(event_handler_del, export, result, pattern);
+ return result;
}
-
-void afb_hook_svc_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
+int afb_hook_api_class_provide(const struct afb_export *export, int result, const char *name)
{
- _HOOK_SVC_(call, export, api, verb, args);
+ _HOOK_API_(class_provide, export, result, name);
+ return result;
+}
+int afb_hook_api_class_require(const struct afb_export *export, int result, const char *name)
+{
+ _HOOK_API_(class_require, export, result, name);
+ return result;
}
-void afb_hook_svc_call_result(const struct afb_export *export, int status, struct json_object *result)
+int afb_hook_api_delete_api(const struct afb_export *export, int result)
{
- _HOOK_SVC_(call_result, export, status, result);
+ _HOOK_API_(delete_api, export, result);
+ return result;
}
-void afb_hook_svc_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
+void afb_hook_api_on_event_handler_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern)
{
- _HOOK_SVC_(callsync, export, api, verb, args);
+ _HOOK_API_2_(on_event_handler, on_event_handler_before, export, event, event_x2, object, pattern);
}
-int afb_hook_svc_callsync_result(const struct afb_export *export, int status, struct json_object *result)
+void afb_hook_api_on_event_handler_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern)
{
- _HOOK_SVC_(callsync_result, export, status, result);
- return status;
+ _HOOK_API_2_(on_event_handler, on_event_handler_after, export, event, event_x2, object, pattern);
}
/******************************************************************************
- * section: hooking services (export)
+ * section: hooking export
*****************************************************************************/
-int afb_hook_flags_svc(const char *api)
+int afb_hook_flags_api(const char *api)
{
int flags;
- struct afb_hook_svc *hook;
+ struct afb_hook_api *hook;
flags = 0;
- if (!api || afb_api_is_hookable(api)) {
- pthread_rwlock_rdlock(&rwlock);
- hook = list_of_svc_hooks;
- while (hook) {
- if (!api || !hook->api || !strcasecmp(hook->api, api))
- flags |= hook->flags;
- hook = hook->next;
- }
- pthread_rwlock_unlock(&rwlock);
+ pthread_rwlock_rdlock(&rwlock);
+ hook = list_of_api_hooks;
+ while (hook) {
+ if (!api || MATCH_API(hook->api, api))
+ flags |= hook->flags;
+ hook = hook->next;
}
+ pthread_rwlock_unlock(&rwlock);
return flags;
}
-struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_hook_svc_itf *itf, void *closure)
+struct afb_hook_api *afb_hook_create_api(const char *api, int flags, struct afb_hook_api_itf *itf, void *closure)
{
- struct afb_hook_svc *hook;
+ struct afb_hook_api *hook;
/* alloc the result */
hook = calloc(1, sizeof *hook);
@@ -1186,20 +1220,20 @@ struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_
/* initialise the rest */
hook->refcount = 1;
hook->flags = flags;
- hook->itf = itf ? itf : &hook_svc_default_itf;
+ hook->itf = itf ? itf : &hook_api_default_itf;
hook->closure = closure;
/* record the hook */
pthread_rwlock_wrlock(&rwlock);
- hook->next = list_of_svc_hooks;
- list_of_svc_hooks = hook;
+ hook->next = list_of_api_hooks;
+ list_of_api_hooks = hook;
pthread_rwlock_unlock(&rwlock);
/* returns it */
return hook;
}
-struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook)
+struct afb_hook_api *afb_hook_addref_api(struct afb_hook_api *hook)
{
pthread_rwlock_wrlock(&rwlock);
hook->refcount++;
@@ -1207,9 +1241,9 @@ struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook)
return hook;
}
-void afb_hook_unref_svc(struct afb_hook_svc *hook)
+void afb_hook_unref_api(struct afb_hook_api *hook)
{
- struct afb_hook_svc **prv;
+ struct afb_hook_api **prv;
if (hook) {
pthread_rwlock_wrlock(&rwlock);
@@ -1217,7 +1251,7 @@ void afb_hook_unref_svc(struct afb_hook_svc *hook)
hook = NULL;
else {
/* unlink */
- prv = &list_of_svc_hooks;
+ prv = &list_of_api_hooks;
while (*prv && *prv != hook)
prv = &(*prv)->next;
if(*prv)
@@ -1244,56 +1278,56 @@ static void _hook_evt_(const char *evt, int id, const char *format, ...)
va_end(ap);
}
-static void hook_evt_create_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
+static void hook_evt_create_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
{
_hook_evt_(evt, id, "create");
}
-static void hook_evt_push_before_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
+static void hook_evt_push_before_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
{
_hook_evt_(evt, id, "push.before(%s)", json_object_to_json_string(obj));
}
-static void hook_evt_push_after_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
+static void hook_evt_push_after_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
{
_hook_evt_(evt, id, "push.after(%s) -> %d", json_object_to_json_string(obj), result);
}
-static void hook_evt_broadcast_before_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
+static void hook_evt_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
{
_hook_evt_(evt, id, "broadcast.before(%s)", json_object_to_json_string(obj));
}
-static void hook_evt_broadcast_after_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
+static void hook_evt_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
{
_hook_evt_(evt, id, "broadcast.after(%s) -> %d", json_object_to_json_string(obj), result);
}
-static void hook_evt_name_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, const char *result)
+static void hook_evt_name_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, const char *result)
{
_hook_evt_(evt, id, "name -> %s", result);
}
-static void hook_evt_addref_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
+static void hook_evt_addref_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
{
_hook_evt_(evt, id, "addref");
}
-static void hook_evt_unref_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
+static void hook_evt_unref_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
{
_hook_evt_(evt, id, "unref");
}
static struct afb_hook_evt_itf hook_evt_default_itf = {
- .hook_evt_create = hook_evt_create_default_cb,
- .hook_evt_push_before = hook_evt_push_before_default_cb,
- .hook_evt_push_after = hook_evt_push_after_default_cb,
- .hook_evt_broadcast_before = hook_evt_broadcast_before_default_cb,
- .hook_evt_broadcast_after = hook_evt_broadcast_after_default_cb,
- .hook_evt_name = hook_evt_name_default_cb,
- .hook_evt_addref = hook_evt_addref_default_cb,
- .hook_evt_unref = hook_evt_unref_default_cb
+ .hook_evt_create = hook_evt_create_cb,
+ .hook_evt_push_before = hook_evt_push_before_cb,
+ .hook_evt_push_after = hook_evt_push_after_cb,
+ .hook_evt_broadcast_before = hook_evt_broadcast_before_cb,
+ .hook_evt_broadcast_after = hook_evt_broadcast_after_cb,
+ .hook_evt_name = hook_evt_name_cb,
+ .hook_evt_addref = hook_evt_addref_cb,
+ .hook_evt_unref = hook_evt_unref_cb
};
/******************************************************************************
@@ -1309,7 +1343,7 @@ static struct afb_hook_evt_itf hook_evt_default_itf = {
while (hook) { \
if (hook->itf->hook_evt_##what \
&& (hook->flags & afb_hook_flag_evt_##what) != 0 \
- && (!hook->pattern || MATCH(hook->pattern, evt))) { \
+ && MATCH_EVENT(hook->pattern, evt)) { \
hook->itf->hook_evt_##what(hook->closure, &hookid, __VA_ARGS__); \
} \
hook = hook->next; \
@@ -1368,16 +1402,14 @@ int afb_hook_flags_evt(const char *name)
struct afb_hook_evt *hook;
flags = 0;
- if (!name || afb_api_is_hookable(name)) {
- pthread_rwlock_rdlock(&rwlock);
- hook = list_of_evt_hooks;
- while (hook) {
- if (!name || !hook->pattern || MATCH(hook->pattern, name))
- flags |= hook->flags;
- hook = hook->next;
- }
- pthread_rwlock_unlock(&rwlock);
+ pthread_rwlock_rdlock(&rwlock);
+ hook = list_of_evt_hooks;
+ while (hook) {
+ if (!name || MATCH_EVENT(hook->pattern, name))
+ flags |= hook->flags;
+ hook = hook->next;
}
+ pthread_rwlock_unlock(&rwlock);
return flags;
}
@@ -1458,43 +1490,43 @@ static void _hook_session_(struct afb_session *session, const char *format, ...)
va_end(ap);
}
-static void hook_session_create_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
+static void hook_session_create_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
{
_hook_session_(session, "create -> token=%s", afb_session_token(session));
}
-static void hook_session_close_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
+static void hook_session_close_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
{
_hook_session_(session, "close");
}
-static void hook_session_destroy_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
+static void hook_session_destroy_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
{
_hook_session_(session, "destroy");
}
-static void hook_session_renew_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
+static void hook_session_renew_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
{
_hook_session_(session, "renew -> token=%s", afb_session_token(session));
}
-static void hook_session_addref_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
+static void hook_session_addref_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
{
_hook_session_(session, "addref");
}
-static void hook_session_unref_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
+static void hook_session_unref_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
{
_hook_session_(session, "unref");
}
static struct afb_hook_session_itf hook_session_default_itf = {
- .hook_session_create = hook_session_create_default_cb,
- .hook_session_close = hook_session_close_default_cb,
- .hook_session_destroy = hook_session_destroy_default_cb,
- .hook_session_renew = hook_session_renew_default_cb,
- .hook_session_addref = hook_session_addref_default_cb,
- .hook_session_unref = hook_session_unref_default_cb
+ .hook_session_create = hook_session_create_cb,
+ .hook_session_close = hook_session_close_cb,
+ .hook_session_destroy = hook_session_destroy_cb,
+ .hook_session_renew = hook_session_renew_cb,
+ .hook_session_addref = hook_session_addref_cb,
+ .hook_session_unref = hook_session_unref_cb
};
/******************************************************************************
@@ -1511,7 +1543,7 @@ static struct afb_hook_session_itf hook_session_default_itf = {
while (hook) { \
if (hook->itf->hook_session_##what \
&& (hook->flags & afb_hook_flag_session_##what) != 0 \
- && (!hook->pattern || MATCH(hook->pattern, (sessid?:(sessid=afb_session_uuid(session)))))) { \
+ && MATCH_SESSION(hook->pattern, (sessid?:(sessid=afb_session_uuid(session))))) { \
hook->itf->hook_session_##what(hook->closure, &hookid, __VA_ARGS__); \
} \
hook = hook->next; \
@@ -1630,7 +1662,7 @@ static void _hook_global_(const char *format, ...)
va_end(ap);
}
-static void hook_global_vverbose_default_cb(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
+static void hook_global_vverbose_cb(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
{
int len;
char *msg;
@@ -1641,15 +1673,15 @@ static void hook_global_vverbose_default_cb(void *closure, const struct afb_hook
va_end(ap);
if (len < 0)
- _hook_global_("vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt);
+ _hook_global_("vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, func, fmt);
else {
- _hook_global_("vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg);
+ _hook_global_("vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, func, msg);
free(msg);
}
}
static struct afb_hook_global_itf hook_global_default_itf = {
- .hook_global_vverbose = hook_global_vverbose_default_cb
+ .hook_global_vverbose = hook_global_vverbose_cb
};
/******************************************************************************
diff --git a/src/afb-hook.h b/src/afb-hook.h
index 52d83355..f315cc08 100644
--- a/src/afb-hook.h
+++ b/src/afb-hook.h
@@ -24,7 +24,9 @@ struct req;
struct afb_context;
struct json_object;
struct afb_arg;
-struct afb_eventid;
+struct afb_event_x2;
+struct afb_verb_v2;
+struct afb_verb_v3;
struct afb_session;
struct afb_xreq;
struct afb_export;
@@ -32,8 +34,7 @@ struct afb_stored_req;
struct sd_bus;
struct sd_event;
struct afb_hook_xreq;
-struct afb_hook_ditf;
-struct afb_hook_svc;
+struct afb_hook_api;
struct afb_hook_evt;
struct afb_hook_session;
struct afb_hook_global;
@@ -56,10 +57,10 @@ struct afb_hookid
#define afb_hook_flag_req_end 0x00000002
#define afb_hook_flag_req_json 0x00000004
#define afb_hook_flag_req_get 0x00000008
-#define afb_hook_flag_req_success 0x00000010
-#define afb_hook_flag_req_fail 0x00000020
-#define afb_hook_flag_req_context_get 0x00000040
-#define afb_hook_flag_req_context_set 0x00000080
+#define afb_hook_flag_req_reply 0x00000010
+#define afb_hook_flag_req_get_client_info 0x00000020
+#define afb_hook_flag_req_legacy_context_get 0x00000040
+#define afb_hook_flag_req_legacy_context_set 0x00000080
#define afb_hook_flag_req_addref 0x00000100
#define afb_hook_flag_req_unref 0x00000200
#define afb_hook_flag_req_session_close 0x00000400
@@ -71,35 +72,31 @@ struct afb_hookid
#define afb_hook_flag_req_subcallsync 0x00010000
#define afb_hook_flag_req_subcallsync_result 0x00020000
#define afb_hook_flag_req_vverbose 0x00040000
-#define afb_hook_flag_req_store 0x00080000
-#define afb_hook_flag_req_unstore 0x00100000
-#define afb_hook_flag_req_subcall_req 0x00200000
-#define afb_hook_flag_req_subcall_req_result 0x00400000
-#define afb_hook_flag_req_has_permission 0x00800000
-#define afb_hook_flag_req_get_application_id 0x01000000
-#define afb_hook_flag_req_context_make 0x02000000
-#define afb_hook_flag_req_get_uid 0x04000000
+#define afb_hook_flag_req_legacy_store 0x00080000
+#define afb_hook_flag_req_legacy_unstore 0x00100000
+#define afb_hook_flag_req_has_permission 0x00200000
+#define afb_hook_flag_req_get_application_id 0x00400000
+#define afb_hook_flag_req_context_make 0x00800000
+#define afb_hook_flag_req_get_uid 0x01000000
/* common flags */
#define afb_hook_flags_req_life (afb_hook_flag_req_begin|afb_hook_flag_req_end)
#define afb_hook_flags_req_args (afb_hook_flag_req_json|afb_hook_flag_req_get)
-#define afb_hook_flags_req_result (afb_hook_flag_req_success|afb_hook_flag_req_fail)
#define afb_hook_flags_req_session (afb_hook_flag_req_session_close|afb_hook_flag_req_session_set_LOA)
#define afb_hook_flags_req_event (afb_hook_flag_req_subscribe|afb_hook_flag_req_unsubscribe)
#define afb_hook_flags_req_subcalls (afb_hook_flag_req_subcall|afb_hook_flag_req_subcall_result\
- |afb_hook_flag_req_subcall_req|afb_hook_flag_req_subcall_req_result\
|afb_hook_flag_req_subcallsync|afb_hook_flag_req_subcallsync_result)
#define afb_hook_flags_req_security (afb_hook_flag_req_has_permission|afb_hook_flag_req_get_application_id\
- |afb_hook_flag_req_get_uid)
+ |afb_hook_flag_req_get_uid|afb_hook_flag_req_get_client_info)
/* extra flags */
#define afb_hook_flags_req_ref (afb_hook_flag_req_addref|afb_hook_flag_req_unref)
-#define afb_hook_flags_req_context (afb_hook_flag_req_context_get|afb_hook_flag_req_context_set\
+#define afb_hook_flags_req_context (afb_hook_flag_req_legacy_context_get|afb_hook_flag_req_legacy_context_set\
|afb_hook_flag_req_context_make)
-#define afb_hook_flags_req_stores (afb_hook_flag_req_store|afb_hook_flag_req_unstore)
+#define afb_hook_flags_req_stores (afb_hook_flag_req_legacy_store|afb_hook_flag_req_legacy_unstore)
/* predefined groups */
-#define afb_hook_flags_req_common (afb_hook_flags_req_life|afb_hook_flags_req_args|afb_hook_flags_req_result\
+#define afb_hook_flags_req_common (afb_hook_flags_req_life|afb_hook_flags_req_args|afb_hook_flag_req_reply\
|afb_hook_flags_req_session|afb_hook_flags_req_event|afb_hook_flags_req_subcalls\
|afb_hook_flag_req_vverbose|afb_hook_flags_req_security)
#define afb_hook_flags_req_extra (afb_hook_flags_req_common|afb_hook_flags_req_ref|afb_hook_flags_req_context\
@@ -111,29 +108,27 @@ struct afb_hook_xreq_itf {
void (*hook_xreq_end)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq);
void (*hook_xreq_json)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj);
void (*hook_xreq_get)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg);
- void (*hook_xreq_success)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info);
- void (*hook_xreq_fail)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info);
- void (*hook_xreq_context_get)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value);
- void (*hook_xreq_context_set)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*));
+ void (*hook_xreq_reply)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info);
+ void (*hook_xreq_legacy_context_get)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value);
+ void (*hook_xreq_legacy_context_set)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*));
void (*hook_xreq_addref)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq);
void (*hook_xreq_unref)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq);
void (*hook_xreq_session_close)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq);
void (*hook_xreq_session_set_LOA)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result);
- void (*hook_xreq_subscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result);
- void (*hook_xreq_unsubscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result);
+ void (*hook_xreq_subscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result);
+ void (*hook_xreq_unsubscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result);
void (*hook_xreq_subcall)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args);
- void (*hook_xreq_subcall_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result);
+ void (*hook_xreq_subcall_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info);
void (*hook_xreq_subcallsync)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args);
- void (*hook_xreq_subcallsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result);
+ void (*hook_xreq_subcallsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info);
void (*hook_xreq_vverbose)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args);
- void (*hook_xreq_store)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq);
- void (*hook_xreq_unstore)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq);
- void (*hook_xreq_subcall_req)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args);
- void (*hook_xreq_subcall_req_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result);
+ void (*hook_xreq_legacy_store)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq);
+ void (*hook_xreq_legacy_unstore)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq);
void (*hook_xreq_has_permission)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result);
void (*hook_xreq_get_application_id)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result);
void (*hook_xreq_context_make)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result);
void (*hook_xreq_get_uid)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result);
+ void (*hook_xreq_get_client_info)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *result);
};
extern void afb_hook_init_xreq(struct afb_xreq *xreq);
@@ -147,145 +142,220 @@ extern void afb_hook_xreq_begin(const struct afb_xreq *xreq);
extern void afb_hook_xreq_end(const struct afb_xreq *xreq);
extern struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj);
extern struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg);
-extern void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info);
-extern void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info);
-extern void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value);
-extern void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*));
+extern void afb_hook_xreq_reply(const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info);
+extern void *afb_hook_xreq_legacy_context_get(const struct afb_xreq *xreq, void *value);
+extern void afb_hook_xreq_legacy_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*));
extern void afb_hook_xreq_addref(const struct afb_xreq *xreq);
extern void afb_hook_xreq_unref(const struct afb_xreq *xreq);
extern void afb_hook_xreq_session_close(const struct afb_xreq *xreq);
extern int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result);
-extern int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result);
-extern int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result);
-extern void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args);
-extern void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result);
-extern void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args);
-extern int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result);
+extern int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result);
+extern int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result);
+extern void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags);
+extern void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info);
+extern void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags);
+extern int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info);
extern void afb_hook_xreq_vverbose(const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args);
-extern void afb_hook_xreq_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq);
-extern void afb_hook_xreq_unstore(const struct afb_xreq *xreq);
-extern void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args);
-extern void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result);
+extern void afb_hook_xreq_legacy_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq);
+extern void afb_hook_xreq_legacy_unstore(const struct afb_xreq *xreq);
extern int afb_hook_xreq_has_permission(const struct afb_xreq *xreq, const char *permission, int result);
extern char *afb_hook_xreq_get_application_id(const struct afb_xreq *xreq, char *result);
extern void *afb_hook_xreq_context_make(const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result);
extern int afb_hook_xreq_get_uid(const struct afb_xreq *xreq, int result);
+extern struct json_object *afb_hook_xreq_get_client_info(const struct afb_xreq *xreq, struct json_object *result);
/*********************************************************
-* section hooking export (daemon interface)
+* section hooking apis
*********************************************************/
-#define afb_hook_flag_ditf_vverbose 0x000001
-#define afb_hook_flag_ditf_event_make 0x000002
-#define afb_hook_flag_ditf_event_broadcast_before 0x000004
-#define afb_hook_flag_ditf_event_broadcast_after 0x000008
-#define afb_hook_flag_ditf_get_event_loop 0x000010
-#define afb_hook_flag_ditf_get_user_bus 0x000020
-#define afb_hook_flag_ditf_get_system_bus 0x000040
-#define afb_hook_flag_ditf_rootdir_get_fd 0x000080
-#define afb_hook_flag_ditf_rootdir_open_locale 0x000100
-#define afb_hook_flag_ditf_queue_job 0x000200
-#define afb_hook_flag_ditf_unstore_req 0x000400
-#define afb_hook_flag_ditf_require_api 0x000800
-#define afb_hook_flag_ditf_require_api_result 0x001000
-#define afb_hook_flag_ditf_rename_api 0x002000
-
-#define afb_hook_flags_ditf_common (afb_hook_flag_ditf_vverbose\
- |afb_hook_flag_ditf_event_make\
- |afb_hook_flag_ditf_event_broadcast_before\
- |afb_hook_flag_ditf_event_broadcast_after\
- |afb_hook_flag_ditf_rename_api)
-#define afb_hook_flags_ditf_extra (afb_hook_flag_ditf_get_event_loop\
- |afb_hook_flag_ditf_get_user_bus\
- |afb_hook_flag_ditf_get_system_bus\
- |afb_hook_flag_ditf_rootdir_get_fd\
- |afb_hook_flag_ditf_rootdir_open_locale\
- |afb_hook_flag_ditf_queue_job\
- |afb_hook_flag_ditf_unstore_req\
- |afb_hook_flag_ditf_require_api\
- |afb_hook_flag_ditf_require_api_result)
-
-#define afb_hook_flags_ditf_all (afb_hook_flags_ditf_common|afb_hook_flags_ditf_extra)
-
-struct afb_hook_ditf_itf {
- void (*hook_ditf_event_broadcast_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object);
- void (*hook_ditf_event_broadcast_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result);
- void (*hook_ditf_get_event_loop)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result);
- void (*hook_ditf_get_user_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result);
- void (*hook_ditf_get_system_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result);
- void (*hook_ditf_vverbose)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args);
- void (*hook_ditf_event_make)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_eventid *result);
- void (*hook_ditf_rootdir_get_fd)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result);
- void (*hook_ditf_rootdir_open_locale)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result);
- void (*hook_ditf_queue_job)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result);
- void (*hook_ditf_unstore_req)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq);
- void (*hook_ditf_require_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized);
- void (*hook_ditf_require_api_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result);
- void (*hook_ditf_rename_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *oldname, const char *newname, int result);
-};
+#define afb_hook_flag_api_vverbose 0x00000001
+#define afb_hook_flag_api_get_event_loop 0x00000002
+#define afb_hook_flag_api_get_user_bus 0x00000004
+#define afb_hook_flag_api_get_system_bus 0x00000008
+#define afb_hook_flag_api_rootdir_get_fd 0x00000010
+#define afb_hook_flag_api_rootdir_open_locale 0x00000020
+#define afb_hook_flag_api_queue_job 0x00000040
+#define afb_hook_flag_api_require_api 0x00000080
+#define afb_hook_flag_api_add_alias 0x00000100
+#define afb_hook_flag_api_event_broadcast 0x00000200
+#define afb_hook_flag_api_event_make 0x00000400
+#define afb_hook_flag_api_new_api 0x00000800
+#define afb_hook_flag_api_api_set_verbs 0x00001000
+#define afb_hook_flag_api_api_add_verb 0x00002000
+#define afb_hook_flag_api_api_del_verb 0x00004000
+#define afb_hook_flag_api_api_set_on_event 0x00008000
+#define afb_hook_flag_api_api_set_on_init 0x00010000
+#define afb_hook_flag_api_api_seal 0x00020000
+#define afb_hook_flag_api_event_handler_add 0x00040000
+#define afb_hook_flag_api_event_handler_del 0x00080000
+#define afb_hook_flag_api_call 0x00100000
+#define afb_hook_flag_api_callsync 0x00200000
+#define afb_hook_flag_api_class_provide 0x00400000
+#define afb_hook_flag_api_class_require 0x00800000
+#define afb_hook_flag_api_delete_api 0x01000000
+#define afb_hook_flag_api_start 0x02000000
+#define afb_hook_flag_api_on_event 0x04000000
+#define afb_hook_flag_api_legacy_unstore_req 0x08000000
+#define afb_hook_flag_api_on_event_handler 0x10000000
+
+/* common flags */
+/* extra flags */
+/* predefined groups */
-extern void afb_hook_ditf_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object);
-extern int afb_hook_ditf_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result);
-extern struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_export *export, struct sd_event *result);
-extern struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_export *export, struct sd_bus *result);
-extern struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_export *export, struct sd_bus *result);
-extern void afb_hook_ditf_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args);
-extern struct afb_eventid *afb_hook_ditf_event_make(const struct afb_export *export, const char *name, struct afb_eventid *result);
-extern int afb_hook_ditf_rootdir_get_fd(const struct afb_export *export, int result);
-extern int afb_hook_ditf_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result);
-extern int afb_hook_ditf_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result);
-extern void afb_hook_ditf_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq);
-extern void afb_hook_ditf_require_api(const struct afb_export *export, const char *name, int initialized);
-extern int afb_hook_ditf_require_api_result(const struct afb_export *export, const char *name, int initialized, int result);
-extern int afb_hook_ditf_rename_api(const struct afb_export *export, const char *oldname, const char *newname, int result);
-
-extern int afb_hook_flags_ditf(const char *api);
-extern struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure);
-extern struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook);
-extern void afb_hook_unref_ditf(struct afb_hook_ditf *hook);
+#define afb_hook_flags_api_common (afb_hook_flag_api_vverbose\
+ |afb_hook_flag_api_event_broadcast\
+ |afb_hook_flag_api_event_make\
+ |afb_hook_flag_api_call\
+ |afb_hook_flag_api_callsync\
+ |afb_hook_flag_api_start\
+ |afb_hook_flag_api_queue_job)
+
+
+#define afb_hook_flags_api_extra (afb_hook_flag_api_get_event_loop\
+ |afb_hook_flag_api_get_user_bus\
+ |afb_hook_flag_api_get_system_bus\
+ |afb_hook_flag_api_rootdir_get_fd\
+ |afb_hook_flag_api_rootdir_open_locale\
+ |afb_hook_flag_api_legacy_unstore_req)
+
+
+#define afb_hook_flags_api_api (afb_hook_flag_api_new_api\
+ |afb_hook_flag_api_api_set_verbs\
+ |afb_hook_flag_api_api_add_verb\
+ |afb_hook_flag_api_api_del_verb\
+ |afb_hook_flag_api_api_set_on_event\
+ |afb_hook_flag_api_api_set_on_init\
+ |afb_hook_flag_api_api_seal\
+ |afb_hook_flag_api_class_provide\
+ |afb_hook_flag_api_class_require\
+ |afb_hook_flag_api_require_api\
+ |afb_hook_flag_api_add_alias\
+ |afb_hook_flag_api_delete_api)
+
+#define afb_hook_flags_api_event (afb_hook_flag_api_event_broadcast\
+ |afb_hook_flag_api_event_make\
+ |afb_hook_flag_api_event_handler_add\
+ |afb_hook_flag_api_event_handler_del\
+ |afb_hook_flag_api_on_event\
+ |afb_hook_flag_api_on_event_handler)
+
+#define afb_hook_flags_api_all (afb_hook_flags_api_common\
+ |afb_hook_flags_api_extra\
+ |afb_hook_flags_api_api\
+ |afb_hook_flags_api_event)
/*********************************************************
-* section hooking export (service interface)
+*********************************************************/
+#define afb_hook_flags_api_svc_all (afb_hook_flag_api_start|afb_hook_flag_api_start\
+ |afb_hook_flag_api_on_event|afb_hook_flag_api_on_event\
+ |afb_hook_flag_api_call|afb_hook_flag_api_call\
+ |afb_hook_flag_api_callsync|afb_hook_flag_api_callsync)
+
+#define afb_hook_flags_api_ditf_common (afb_hook_flag_api_vverbose\
+ |afb_hook_flag_api_event_make\
+ |afb_hook_flag_api_event_broadcast\
+ |afb_hook_flag_api_event_broadcast\
+ |afb_hook_flag_api_add_alias)
+
+#define afb_hook_flags_api_ditf_extra (afb_hook_flag_api_get_event_loop\
+ |afb_hook_flag_api_get_user_bus\
+ |afb_hook_flag_api_get_system_bus\
+ |afb_hook_flag_api_rootdir_get_fd\
+ |afb_hook_flag_api_rootdir_open_locale\
+ |afb_hook_flag_api_queue_job\
+ |afb_hook_flag_api_legacy_unstore_req\
+ |afb_hook_flag_api_require_api\
+ |afb_hook_flag_api_require_api)
+
+#define afb_hook_flags_api_ditf_all (afb_hook_flags_api_ditf_common|afb_hook_flags_api_ditf_extra)
+/*********************************************************
*********************************************************/
-#define afb_hook_flag_svc_start_before 0x000001
-#define afb_hook_flag_svc_start_after 0x000002
-#define afb_hook_flag_svc_on_event_before 0x000004
-#define afb_hook_flag_svc_on_event_after 0x000008
-#define afb_hook_flag_svc_call 0x000010
-#define afb_hook_flag_svc_call_result 0x000020
-#define afb_hook_flag_svc_callsync 0x000040
-#define afb_hook_flag_svc_callsync_result 0x000080
-
-#define afb_hook_flags_svc_all (afb_hook_flag_svc_start_before|afb_hook_flag_svc_start_after\
- |afb_hook_flag_svc_on_event_before|afb_hook_flag_svc_on_event_after\
- |afb_hook_flag_svc_call|afb_hook_flag_svc_call_result\
- |afb_hook_flag_svc_callsync|afb_hook_flag_svc_callsync_result)
-
-struct afb_hook_svc_itf {
- void (*hook_svc_start_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export);
- void (*hook_svc_start_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status);
- void (*hook_svc_on_event_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object);
- void (*hook_svc_on_event_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object);
- void (*hook_svc_call)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args);
- void (*hook_svc_call_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result);
- void (*hook_svc_callsync)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args);
- void (*hook_svc_callsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result);
-};
-extern void afb_hook_svc_start_before(const struct afb_export *export);
-extern int afb_hook_svc_start_after(const struct afb_export *export, int status);
-extern void afb_hook_svc_on_event_before(const struct afb_export *export, const char *event, int eventid, struct json_object *object);
-extern void afb_hook_svc_on_event_after(const struct afb_export *export, const char *event, int eventid, struct json_object *object);
-extern void afb_hook_svc_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args);
-extern void afb_hook_svc_call_result(const struct afb_export *export, int status, struct json_object *result);
-extern void afb_hook_svc_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args);
-extern int afb_hook_svc_callsync_result(const struct afb_export *export, int status, struct json_object *result);
+struct afb_hook_api_itf {
+ void (*hook_api_event_broadcast_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object);
+ void (*hook_api_event_broadcast_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result);
+ void (*hook_api_get_event_loop)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result);
+ void (*hook_api_get_user_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result);
+ void (*hook_api_get_system_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result);
+ void (*hook_api_vverbose)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args);
+ void (*hook_api_event_make)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_event_x2 *result);
+ void (*hook_api_rootdir_get_fd)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result);
+ void (*hook_api_rootdir_open_locale)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result);
+ void (*hook_api_queue_job)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result);
+ void (*hook_api_legacy_unstore_req)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq);
+ void (*hook_api_require_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized);
+ void (*hook_api_require_api_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result);
+ void (*hook_api_add_alias)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *oldname, const char *newname, int result);
+ void (*hook_api_start_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export);
+ void (*hook_api_start_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status);
+ void (*hook_api_on_event_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object);
+ void (*hook_api_on_event_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object);
+ void (*hook_api_call)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args);
+ void (*hook_api_call_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object, const char *error, const char *info);
+ void (*hook_api_callsync)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args);
+ void (*hook_api_callsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, struct json_object *object, const char *error, const char *info);
+ void (*hook_api_new_api_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *info, int noconcurrency);
+ void (*hook_api_new_api_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *api);
+ void (*hook_api_api_set_verbs_v2)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v2 *verbs);
+ void (*hook_api_api_set_verbs_v3)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v3 *verbs);
+ void (*hook_api_api_add_verb)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb, const char *info, int glob);
+ void (*hook_api_api_del_verb)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb);
+ void (*hook_api_api_set_on_event)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result);
+ void (*hook_api_api_set_on_init)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result);
+ void (*hook_api_api_seal)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export);
+ void (*hook_api_event_handler_add)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern);
+ void (*hook_api_event_handler_del)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern);
+ void (*hook_api_class_provide)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name);
+ void (*hook_api_class_require)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name);
+ void (*hook_api_delete_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result);
+ void (*hook_api_on_event_handler_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern);
+ void (*hook_api_on_event_handler_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern);
+};
-extern int afb_hook_flags_svc(const char *api);
-extern struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_hook_svc_itf *itf, void *closure);
-extern struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook);
-extern void afb_hook_unref_svc(struct afb_hook_svc *hook);
+extern void afb_hook_api_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object);
+extern int afb_hook_api_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result);
+extern struct sd_event *afb_hook_api_get_event_loop(const struct afb_export *export, struct sd_event *result);
+extern struct sd_bus *afb_hook_api_get_user_bus(const struct afb_export *export, struct sd_bus *result);
+extern struct sd_bus *afb_hook_api_get_system_bus(const struct afb_export *export, struct sd_bus *result);
+extern void afb_hook_api_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args);
+extern struct afb_event_x2 *afb_hook_api_event_make(const struct afb_export *export, const char *name, struct afb_event_x2 *result);
+extern int afb_hook_api_rootdir_get_fd(const struct afb_export *export, int result);
+extern int afb_hook_api_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result);
+extern int afb_hook_api_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result);
+extern void afb_hook_api_legacy_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq);
+extern void afb_hook_api_require_api(const struct afb_export *export, const char *name, int initialized);
+extern int afb_hook_api_require_api_result(const struct afb_export *export, const char *name, int initialized, int result);
+extern int afb_hook_api_add_alias(const struct afb_export *export, const char *api, const char *alias, int result);
+extern void afb_hook_api_start_before(const struct afb_export *export);
+extern int afb_hook_api_start_after(const struct afb_export *export, int status);
+extern void afb_hook_api_on_event_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object);
+extern void afb_hook_api_on_event_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object);
+extern void afb_hook_api_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args);
+extern void afb_hook_api_call_result(const struct afb_export *export, struct json_object *object, const char *error, const char *info);
+extern void afb_hook_api_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args);
+extern int afb_hook_api_callsync_result(const struct afb_export *export, int result, struct json_object *object, const char *error, const char *info);
+extern void afb_hook_api_new_api_before(const struct afb_export *export, const char *api, const char *info, int noconcurrency);
+extern int afb_hook_api_new_api_after(const struct afb_export *export, int result, const char *api);
+extern int afb_hook_api_api_set_verbs_v2(const struct afb_export *export, int result, const struct afb_verb_v2 *verbs);
+extern int afb_hook_api_api_set_verbs_v3(const struct afb_export *export, int result, const struct afb_verb_v3 *verbs);
+extern int afb_hook_api_api_add_verb(const struct afb_export *export, int result, const char *verb, const char *info, int glob);
+extern int afb_hook_api_api_del_verb(const struct afb_export *export, int result, const char *verb);
+extern int afb_hook_api_api_set_on_event(const struct afb_export *export, int result);
+extern int afb_hook_api_api_set_on_init(const struct afb_export *export, int result);
+extern void afb_hook_api_api_seal(const struct afb_export *export);
+extern int afb_hook_api_event_handler_add(const struct afb_export *export, int result, const char *pattern);
+extern int afb_hook_api_event_handler_del(const struct afb_export *export, int result, const char *pattern);
+extern int afb_hook_api_class_provide(const struct afb_export *export, int result, const char *name);
+extern int afb_hook_api_class_require(const struct afb_export *export, int result, const char *name);
+extern int afb_hook_api_delete_api(const struct afb_export *export, int result);
+extern void afb_hook_api_on_event_handler_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern);
+extern void afb_hook_api_on_event_handler_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern);
+
+extern int afb_hook_flags_api(const char *api);
+extern struct afb_hook_api *afb_hook_create_api(const char *api, int flags, struct afb_hook_api_itf *itf, void *closure);
+extern struct afb_hook_api *afb_hook_addref_api(struct afb_hook_api *hook);
+extern void afb_hook_unref_api(struct afb_hook_api *hook);
/*********************************************************
* section hooking evt (event interface)
@@ -384,3 +454,4 @@ extern struct afb_hook_global *afb_hook_create_global(int flags, struct afb_hook
extern struct afb_hook_global *afb_hook_addref_global(struct afb_hook_global *hook);
extern void afb_hook_unref_global(struct afb_hook_global *hook);
+
diff --git a/src/afb-hreq.c b/src/afb-hreq.c
index 012debbd..e5dcf642 100644
--- a/src/afb-hreq.c
+++ b/src/afb-hreq.c
@@ -73,15 +73,13 @@ struct hreq_data {
static struct json_object *req_json(struct afb_xreq *xreq);
static struct afb_arg req_get(struct afb_xreq *xreq, const char *name);
-static void req_fail(struct afb_xreq *xreq, const char *status, const char *info);
-static void req_success(struct afb_xreq *xreq, json_object *obj, const char *info);
+static void req_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info);
static void req_destroy(struct afb_xreq *xreq);
const struct afb_xreq_query_itf afb_hreq_xreq_query_itf = {
.json = req_json,
.get = req_get,
- .success = req_success,
- .fail = req_fail,
+ .reply = req_reply,
.unref = req_destroy
};
@@ -332,8 +330,8 @@ static void req_destroy(struct afb_xreq *xreq)
}
afb_context_disconnect(&hreq->xreq.context);
json_object_put(hreq->json);
- free((char*)hreq->xreq.request.api);
- free((char*)hreq->xreq.request.verb);
+ free((char*)hreq->xreq.request.called_api);
+ free((char*)hreq->xreq.request.called_verb);
afb_cred_unref(hreq->xreq.cred);
free(hreq);
}
@@ -900,39 +898,32 @@ static ssize_t send_json_cb(json_object *obj, uint64_t pos, char *buf, size_t ma
return len ? : (ssize_t)MHD_CONTENT_READER_END_OF_STREAM;
}
-static void req_reply(struct afb_hreq *hreq, unsigned retcode, const char *status, const char *info, json_object *resp)
+static void req_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
{
- struct json_object *reply;
+ struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq);
+ struct json_object *sub, *reply;
const char *reqid;
struct MHD_Response *response;
+ /* create the reply */
+ reply = afb_msg_json_reply(object, error, info, &xreq->context);
+
+ /* append the req id on need */
reqid = afb_hreq_get_argument(hreq, long_key_for_reqid);
if (reqid == NULL)
reqid = afb_hreq_get_argument(hreq, short_key_for_reqid);
-
- reply = afb_msg_json_reply(status, info, resp, &hreq->xreq.context, reqid);
+ if (reqid != NULL && json_object_object_get_ex(reply, "request", &sub))
+ json_object_object_add(sub, "reqid", json_object_new_string(reqid));
response = MHD_create_response_from_callback((uint64_t)strlen(json_object_to_json_string_ext(reply, JSON_C_TO_STRING_PLAIN)), SIZE_RESPONSE_BUFFER, (void*)send_json_cb, reply, (void*)json_object_put);
- afb_hreq_reply(hreq, retcode, response, NULL);
-}
-
-static void req_fail(struct afb_xreq *xreq, const char *status, const char *info)
-{
- struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq);
- req_reply(hreq, MHD_HTTP_OK, status, info, NULL);
-}
-
-static void req_success(struct afb_xreq *xreq, json_object *obj, const char *info)
-{
- struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq);
- req_reply(hreq, MHD_HTTP_OK, "success", info, obj);
+ afb_hreq_reply(hreq, MHD_HTTP_OK, response, NULL);
}
void afb_hreq_call(struct afb_hreq *hreq, struct afb_apiset *apiset, const char *api, size_t lenapi, const char *verb, size_t lenverb)
{
- hreq->xreq.request.api = strndup(api, lenapi);
- hreq->xreq.request.verb = strndup(verb, lenverb);
- if (hreq->xreq.request.api == NULL || hreq->xreq.request.verb == NULL) {
+ hreq->xreq.request.called_api = strndup(api, lenapi);
+ hreq->xreq.request.called_verb = strndup(verb, lenverb);
+ if (hreq->xreq.request.called_api == NULL || hreq->xreq.request.called_verb == NULL) {
ERROR("Out of memory");
afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR);
} else if (afb_hreq_init_context(hreq) < 0) {
diff --git a/src/afb-monitor.c b/src/afb-monitor.c
index 18ea606b..a50e2c65 100644
--- a/src/afb-monitor.c
+++ b/src/afb-monitor.c
@@ -21,12 +21,12 @@
#include <json-c/json.h>
-#define AFB_BINDING_VERSION 0
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
#include "afb-api.h"
#include "afb-apiset.h"
-#include "afb-api-so-v2.h"
+#include "afb-api-v3.h"
#include "afb-evt.h"
#include "afb-xreq.h"
#include "afb-trace.h"
@@ -36,13 +36,12 @@
#include "monitor-api.inc"
-extern struct afb_apiset *main_apiset;
+static struct afb_apiset *target_set;
-static struct afb_binding_data_v2 datav2;
-
-int afb_monitor_init()
+int afb_monitor_init(struct afb_apiset *declare_set, struct afb_apiset *call_set)
{
- return afb_api_so_v2_add_binding(&_afb_binding_v2_monitor, NULL, main_apiset, &datav2);
+ target_set = call_set;
+ return -!afb_api_v3_from_binding(&_afb_binding_monitor, declare_set, call_set);
}
/******************************************************************************
@@ -66,28 +65,28 @@ static int decode_verbosity(struct json_object *v)
int level = -1;
if (!wrap_json_unpack(v, "i", &level)) {
- level = level < Verbosity_Level_Error ? Verbosity_Level_Error : level > Verbosity_Level_Debug ? Verbosity_Level_Debug : level;
+ level = level < _VERBOSITY_(Log_Level_Error) ? _VERBOSITY_(Log_Level_Error) : level > _VERBOSITY_(Log_Level_Debug) ? _VERBOSITY_(Log_Level_Debug) : level;
} else if (!wrap_json_unpack(v, "s", &s)) {
switch(*s&~' ') {
case 'D':
if (!strcasecmp(s, _debug_))
- level = Verbosity_Level_Debug;
+ level = _VERBOSITY_(Log_Level_Debug);
break;
case 'I':
if (!strcasecmp(s, _info_))
- level = Verbosity_Level_Info;
+ level = _VERBOSITY_(Log_Level_Info);
break;
case 'N':
if (!strcasecmp(s, _notice_))
- level = Verbosity_Level_Notice;
+ level = _VERBOSITY_(Log_Level_Notice);
break;
case 'W':
if (!strcasecmp(s, _warning_))
- level = Verbosity_Level_Warning;
+ level = _VERBOSITY_(Log_Level_Warning);
break;
case 'E':
if (!strcasecmp(s, _error_))
- level = Verbosity_Level_Error;
+ level = _VERBOSITY_(Log_Level_Error);
break;
}
}
@@ -100,9 +99,10 @@ static int decode_verbosity(struct json_object *v)
* @param the name of the api to set
* @param closure the verbosity to set as an integer casted to a pointer
*/
-static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, void *closure)
+static void set_verbosity_to_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias)
{
- afb_apiset_set_verbosity(set, name, (int)(intptr_t)closure);
+ if (!isalias)
+ afb_apiset_set_logmask(set, name, (int)(intptr_t)closure);
}
/**
@@ -112,12 +112,13 @@ static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, vo
*/
static void set_verbosity_to(const char *name, int level)
{
+ int mask = verbosity_to_mask(level);
if (!name || !name[0])
- verbosity = level;
+ verbosity_set(level);
else if (name[0] == '*' && !name[1])
- afb_apiset_enum(main_apiset, 1, set_verbosity_to_all_cb, (void*)(intptr_t)level);
+ afb_apiset_enum(target_set, 1, set_verbosity_to_all_cb, (void*)(intptr_t)mask);
else
- afb_apiset_set_verbosity(main_apiset, name, level);
+ afb_apiset_set_logmask(target_set, name, mask);
}
/**
@@ -154,12 +155,12 @@ static void set_verbosity(struct json_object *spec)
*/
static struct json_object *encode_verbosity(int level)
{
- switch(level) {
- case Verbosity_Level_Error: return json_object_new_string(_error_);
- case Verbosity_Level_Warning: return json_object_new_string(_warning_);
- case Verbosity_Level_Notice: return json_object_new_string(_notice_);
- case Verbosity_Level_Info: return json_object_new_string(_info_);
- case Verbosity_Level_Debug: return json_object_new_string(_debug_);
+ switch(_DEVERBOSITY_(level)) {
+ case Log_Level_Error: return json_object_new_string(_error_);
+ case Log_Level_Warning: return json_object_new_string(_warning_);
+ case Log_Level_Notice: return json_object_new_string(_notice_);
+ case Log_Level_Info: return json_object_new_string(_info_);
+ case Log_Level_Debug: return json_object_new_string(_debug_);
default: return json_object_new_int(level);
}
}
@@ -170,12 +171,12 @@ static struct json_object *encode_verbosity(int level)
* @param the name of the api to set
* @param closure the json object to build
*/
-static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
+static void get_verbosity_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias)
{
struct json_object *resu = closure;
- int l = afb_apiset_get_verbosity(set, name);
- if (l >= 0)
- json_object_object_add(resu, name, encode_verbosity(l));
+ int m = afb_apiset_get_logmask(set, name);
+ if (m >= 0)
+ json_object_object_add(resu, name, encode_verbosity(verbosity_from_mask(m)));
}
/**
@@ -185,15 +186,15 @@ static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, vo
*/
static void get_verbosity_of(struct json_object *resu, const char *name)
{
- int l;
+ int m;
if (!name || !name[0])
- json_object_object_add(resu, "", encode_verbosity(verbosity));
+ json_object_object_add(resu, "", encode_verbosity(verbosity_get()));
else if (name[0] == '*' && !name[1])
- afb_apiset_enum(main_apiset, 1, get_verbosity_of_all_cb, resu);
+ afb_apiset_enum(target_set, 1, get_verbosity_of_all_cb, resu);
else {
- l = afb_apiset_get_verbosity(main_apiset, name);
- if (l >= 0)
- json_object_object_add(resu, name, encode_verbosity(l));
+ m = afb_apiset_get_logmask(target_set, name);
+ if (m >= 0)
+ json_object_object_add(resu, name, encode_verbosity(verbosity_from_mask(m)));
}
}
@@ -242,8 +243,8 @@ static void get_one_api(struct json_object *resu, const char *name, struct json_
{
struct json_object *o;
- o = afb_apiset_describe(main_apiset, name);
- if (o || afb_apiset_lookup(main_apiset, name, 1))
+ o = afb_apiset_describe(target_set, name);
+ if (o || afb_apiset_lookup(target_set, name, 1))
json_object_object_add(resu, name, o);
}
@@ -253,7 +254,7 @@ static void get_one_api(struct json_object *resu, const char *name, struct json_
* @param the name of the api to set
* @param closure the json object to build
*/
-static void get_apis_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
+static void get_apis_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias)
{
struct json_object *resu = closure;
get_one_api(resu, name, NULL);
@@ -285,7 +286,7 @@ static struct json_object *get_apis(struct json_object *spec)
} else if (json_object_is_type(spec, json_type_string)) {
get_one_api(resu, json_object_get_string(spec), NULL);
} else if (json_object_get_boolean(spec)) {
- afb_apiset_enum(main_apiset, 1, get_apis_of_all_cb, resu);
+ afb_apiset_enum(target_set, 1, get_apis_of_all_cb, resu);
}
return resu;
}
@@ -298,7 +299,7 @@ static const char _verbosity_[] = "verbosity";
static const char _apis_[] = "apis";
static const char _refresh_token_[] = "refresh-token";
-static void f_get(struct afb_req req)
+static void f_get(afb_req_t req)
{
struct json_object *r;
struct json_object *apis = NULL;
@@ -314,7 +315,7 @@ static void f_get(struct afb_req req)
afb_req_success(req, r, NULL);
}
-static void f_set(struct afb_req req)
+static void f_set(afb_req_t req)
{
struct json_object *verbosity = NULL;
@@ -325,9 +326,9 @@ static void f_set(struct afb_req req)
afb_req_success(req, NULL, NULL);
}
-static void *context_create()
+static void *context_create(void *closure)
{
- return afb_trace_create(_afb_binding_v2_monitor.api, NULL);
+ return afb_trace_create(_afb_binding_monitor.api, NULL);
}
static void context_destroy(void *pointer)
@@ -336,14 +337,14 @@ static void context_destroy(void *pointer)
afb_trace_unref(trace);
}
-static void f_trace(struct afb_req req)
+static void f_trace(afb_req_t req)
{
int rc;
struct json_object *add = NULL;
struct json_object *drop = NULL;
struct afb_trace *trace;
- trace = afb_req_context(req, context_create, context_destroy);
+ trace = afb_req_context(req, 0, context_create, context_destroy, NULL);
wrap_json_unpack(afb_req_json(req), "{s?o s?o}", "add", &add, "drop", &drop);
if (add) {
rc = afb_trace_add(req, add, trace);
@@ -357,15 +358,15 @@ static void f_trace(struct afb_req req)
}
afb_req_success(req, NULL, NULL);
end:
- afb_apiset_update_hooks(main_apiset, NULL);
+ afb_apiset_update_hooks(target_set, NULL);
afb_evt_update_hooks();
}
-static void f_session(struct afb_req req)
+static void f_session(afb_req_t req)
{
struct json_object *r = NULL;
int refresh = 0;
- struct afb_xreq *xreq = xreq_from_request(req.closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
/* check right to call it */
if (xreq->context.super) {
@@ -387,4 +388,3 @@ static void f_session(struct afb_req req)
afb_req_success(req, r, NULL);
}
-
diff --git a/src/afb-monitor.h b/src/afb-monitor.h
index 1f3c1446..407116d2 100644
--- a/src/afb-monitor.h
+++ b/src/afb-monitor.h
@@ -18,4 +18,6 @@
#pragma once
-extern int afb_monitor_init();
+struct afb_apiset;
+
+extern int afb_monitor_init(struct afb_apiset *declare_set, struct afb_apiset *call_set);
diff --git a/src/afb-msg-json.c b/src/afb-msg-json.c
index 7597f80f..ceeee1a4 100644
--- a/src/afb-msg-json.c
+++ b/src/afb-msg-json.c
@@ -22,7 +22,9 @@
#include "afb-msg-json.h"
#include "afb-context.h"
-struct json_object *afb_msg_json_reply(const char *status, const char *info, struct json_object *resp, struct afb_context *context, const char *reqid)
+static const char _success_[] = "success";
+
+struct json_object *afb_msg_json_reply(struct json_object *resp, const char *error, const char *info, struct afb_context *context)
{
json_object *msg, *request;
const char *token, *uuid;
@@ -37,14 +39,11 @@ struct json_object *afb_msg_json_reply(const char *status, const char *info, str
request = json_object_new_object();
json_object_object_add(msg, "request", request);
- json_object_object_add(request, "status", json_object_new_string(status));
+ json_object_object_add(request, "status", json_object_new_string(error ?: _success_));
if (info != NULL)
json_object_object_add(request, "info", json_object_new_string(info));
- if (reqid != NULL)
- json_object_object_add(request, "reqid", json_object_new_string(reqid));
-
if (context != NULL) {
token = afb_context_sent_token(context);
if (token != NULL)
@@ -58,16 +57,6 @@ struct json_object *afb_msg_json_reply(const char *status, const char *info, str
return msg;
}
-struct json_object *afb_msg_json_reply_ok(const char *info, struct json_object *resp, struct afb_context *context, const char *reqid)
-{
- return afb_msg_json_reply("success", info, resp, context, reqid);
-}
-
-struct json_object *afb_msg_json_reply_error(const char *status, const char *info, struct afb_context *context, const char *reqid)
-{
- return afb_msg_json_reply(status, info, NULL, context, reqid);
-}
-
struct json_object *afb_msg_json_event(const char *event, struct json_object *object)
{
json_object *msg;
@@ -88,7 +77,7 @@ struct json_object *afb_msg_json_event(const char *event, struct json_object *ob
struct json_object *afb_msg_json_internal_error()
{
- return afb_msg_json_reply_error("failed", "internal error", NULL, NULL);
+ return afb_msg_json_reply(NULL, "failed", "internal error", NULL);
}
diff --git a/src/afb-msg-json.h b/src/afb-msg-json.h
index e18ca0a9..ee3ed20c 100644
--- a/src/afb-msg-json.h
+++ b/src/afb-msg-json.h
@@ -21,9 +21,7 @@ struct json_object;
struct afb_context;
struct afb_arg;
-extern struct json_object *afb_msg_json_reply(const char *status, const char *info, struct json_object *resp, struct afb_context *context, const char *reqid);
-extern struct json_object *afb_msg_json_reply_ok(const char *info, struct json_object *resp, struct afb_context *context, const char *reqid);
-extern struct json_object *afb_msg_json_reply_error(const char *status, const char *info, struct afb_context *context, const char *reqid);
+extern struct json_object *afb_msg_json_reply(struct json_object *resp, const char *status, const char *info, struct afb_context *context);
extern struct json_object *afb_msg_json_event(const char *event, struct json_object *object);
diff --git a/src/afb-proto-ws.c b/src/afb-proto-ws.c
index e1993abe..f9313545 100644
--- a/src/afb-proto-ws.c
+++ b/src/afb-proto-ws.c
@@ -61,8 +61,6 @@ The server must reply to the previous actions by
The server can also within the context of a call
- - make a subcall
-
- subscribe or unsubscribe an event
For the purpose of handling events the server can:
@@ -75,42 +73,17 @@ For the purpose of handling events the server can:
/************** constants for protocol definition *************************/
#define CHAR_FOR_CALL 'C'
-#define CHAR_FOR_ANSWER_SUCCESS 'T'
-#define CHAR_FOR_ANSWER_FAIL 'F'
+#define CHAR_FOR_REPLY 'Y'
#define CHAR_FOR_EVT_BROADCAST '*'
#define CHAR_FOR_EVT_ADD '+'
#define CHAR_FOR_EVT_DEL '-'
#define CHAR_FOR_EVT_PUSH '!'
#define CHAR_FOR_EVT_SUBSCRIBE 'S'
#define CHAR_FOR_EVT_UNSUBSCRIBE 'U'
-#define CHAR_FOR_SUBCALL_CALL 'B'
-#define CHAR_FOR_SUBCALL_REPLY 'R'
#define CHAR_FOR_DESCRIBE 'D'
#define CHAR_FOR_DESCRIPTION 'd'
-/******************* handling subcalls *****************************/
-
-/**
- * Structure on server side for recording pending
- * subcalls.
- */
-struct server_subcall
-{
- struct server_subcall *next; /**< next subcall for the client */
- uint32_t subcallid; /**< the subcallid */
- void (*callback)(void*, int, struct json_object*); /**< callback on completion */
- void *closure; /**< closure of the callback */
-};
-
-/**
- * Structure for sending back replies on client side
- */
-struct afb_proto_ws_subcall
-{
- struct afb_proto_ws *protows; /**< proto descriptor */
- void *buffer;
- uint32_t subcallid; /**< subcallid for the reply */
-};
+/******************* handling calls *****************************/
/*
* structure for recording calls on client side
@@ -182,9 +155,6 @@ struct afb_proto_ws
/* emitted calls (client side) */
struct client_call *calls;
- /* pending subcalls (server side) */
- struct server_subcall *subcalls;
-
/* pending description (client side) */
struct client_describe *describes;
@@ -237,6 +207,7 @@ static char *readbuf_get(struct readbuf *rb, uint32_t length)
return before;
}
+__attribute__((unused))
static int readbuf_char(struct readbuf *rb, char *value)
{
if (rb->head >= rb->end)
@@ -256,16 +227,35 @@ static int readbuf_uint32(struct readbuf *rb, uint32_t *value)
return 1;
}
-static int readbuf_string(struct readbuf *rb, const char **value, size_t *length)
+static int _readbuf_string_(struct readbuf *rb, const char **value, size_t *length, int nulok)
{
uint32_t len;
- if (!readbuf_uint32(rb, &len) || !len)
+ if (!readbuf_uint32(rb, &len))
return 0;
+ if (!len) {
+ if (!nulok)
+ return 0;
+ *value = NULL;
+ if (length)
+ *length = 0;
+ return 1;
+ }
if (length)
*length = (size_t)(len - 1);
return (*value = readbuf_get(rb, len)) != NULL && rb->head[-1] == 0;
}
+
+static int readbuf_string(struct readbuf *rb, const char **value, size_t *length)
+{
+ return _readbuf_string_(rb, value, length, 0);
+}
+
+static int readbuf_nullstring(struct readbuf *rb, const char **value, size_t *length)
+{
+ return _readbuf_string_(rb, value, length, 1);
+}
+
static int readbuf_object(struct readbuf *rb, struct json_object **object)
{
const char *string;
@@ -326,6 +316,11 @@ static int writebuf_string(struct writebuf *wb, const char *value)
return writebuf_string_length(wb, value, strlen(value));
}
+static int writebuf_nullstring(struct writebuf *wb, const char *value)
+{
+ return value ? writebuf_string_length(wb, value, strlen(value)) : writebuf_uint32(wb, 0);
+}
+
static int writebuf_object(struct writebuf *wb, struct json_object *object)
{
const char *string = json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN);
@@ -349,15 +344,16 @@ void afb_proto_ws_call_unref(struct afb_proto_ws_call *call)
free(call);
}
-int afb_proto_ws_call_success(struct afb_proto_ws_call *call, struct json_object *obj, const char *info)
+int afb_proto_ws_call_reply(struct afb_proto_ws_call *call, struct json_object *obj, const char *error, const char *info)
{
int rc = -1;
struct writebuf wb = { .count = 0 };
struct afb_proto_ws *protows = call->protows;
- if (writebuf_char(&wb, CHAR_FOR_ANSWER_SUCCESS)
+ if (writebuf_char(&wb, CHAR_FOR_REPLY)
&& writebuf_uint32(&wb, call->callid)
- && writebuf_string(&wb, info ?: "")
+ && writebuf_nullstring(&wb, error)
+ && writebuf_nullstring(&wb, info)
&& writebuf_object(&wb, obj)) {
pthread_mutex_lock(&protows->mutex);
rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count);
@@ -371,73 +367,6 @@ success:
return rc;
}
-int afb_proto_ws_call_fail(struct afb_proto_ws_call *call, const char *status, const char *info)
-{
- int rc = -1;
- struct writebuf wb = { .count = 0 };
- struct afb_proto_ws *protows = call->protows;
-
- if (writebuf_char(&wb, CHAR_FOR_ANSWER_FAIL)
- && writebuf_uint32(&wb, call->callid)
- && writebuf_string(&wb, status)
- && writebuf_string(&wb, info ? : "")) {
- pthread_mutex_lock(&protows->mutex);
- rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count);
- pthread_mutex_unlock(&protows->mutex);
- if (rc >= 0) {
- rc = 0;
- goto success;
- }
- }
-success:
- return rc;
-}
-
-int afb_proto_ws_call_subcall(struct afb_proto_ws_call *call, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
-{
- int rc = -1;
- struct writebuf wb = { .count = 0 };
- struct server_subcall *sc, *osc;
- struct afb_proto_ws *protows = call->protows;
-
- sc = malloc(sizeof *sc);
- if (!sc)
- errno = ENOMEM;
- else {
- sc->callback = callback;
- sc->closure = cb_closure;
-
- pthread_mutex_lock(&protows->mutex);
- sc->subcallid = ptr2id(sc);
- do {
- sc->subcallid++;
- osc = protows->subcalls;
- while(osc && osc->subcallid != sc->subcallid)
- osc = osc->next;
- } while (osc);
- sc->next = protows->subcalls;
- protows->subcalls = sc;
- pthread_mutex_unlock(&protows->mutex);
-
- if (writebuf_char(&wb, CHAR_FOR_SUBCALL_CALL)
- && writebuf_uint32(&wb, sc->subcallid)
- && writebuf_uint32(&wb, call->callid)
- && writebuf_string(&wb, api)
- && writebuf_string(&wb, verb)
- && writebuf_object(&wb, args)) {
- pthread_mutex_lock(&protows->mutex);
- rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count);
- pthread_mutex_unlock(&protows->mutex);
- if (rc >= 0) {
- rc = 0;
- goto success;
- }
- }
- }
-success:
- return rc;
-}
-
int afb_proto_ws_call_subscribe(struct afb_proto_ws_call *call, const char *event_name, int event_id)
{
int rc = -1;
@@ -613,113 +542,23 @@ static void client_on_event_push(struct afb_proto_ws *protows, struct readbuf *r
protows->client_itf->on_event_push(protows->closure, event_name, (int)event_id, object);
}
-static void client_on_reply_success(struct afb_proto_ws *protows, struct readbuf *rb)
+static void client_on_reply(struct afb_proto_ws *protows, struct readbuf *rb)
{
struct client_call *call;
struct json_object *object;
- const char *info;
-
- if (!client_msg_call_get(protows, rb, &call))
- return;
-
- if (readbuf_string(rb, &info, NULL) && readbuf_object(rb, &object)) {
- protows->client_itf->on_reply_success(protows->closure, call->request, object, info);
- } else {
- protows->client_itf->on_reply_fail(protows->closure, call->request, "proto-error", "can't process success");
- }
- client_call_destroy(call);
-}
-
-static void client_on_reply_fail(struct afb_proto_ws *protows, struct readbuf *rb)
-{
- struct client_call *call;
- const char *info, *status;
+ const char *error, *info;
if (!client_msg_call_get(protows, rb, &call))
return;
-
- if (readbuf_string(rb, &status, NULL) && readbuf_string(rb, &info, NULL)) {
- protows->client_itf->on_reply_fail(protows->closure, call->request, status, info);
+ if (readbuf_nullstring(rb, &error, NULL) && readbuf_nullstring(rb, &info, NULL) && readbuf_object(rb, &object)) {
+ protows->client_itf->on_reply(protows->closure, call->request, object, error, info);
} else {
- protows->client_itf->on_reply_fail(protows->closure, call->request, "proto-error", "can't process fail");
+ protows->client_itf->on_reply(protows->closure, call->request, NULL, "proto-error", "can't process success");
}
client_call_destroy(call);
}
-/* send a subcall reply */
-static int client_send_subcall_reply(struct afb_proto_ws *protows, uint32_t subcallid, int status, json_object *object)
-{
- struct writebuf wb = { .count = 0 };
- char ie = status < 0;
- int rc;
-
- if (writebuf_char(&wb, CHAR_FOR_SUBCALL_REPLY)
- && writebuf_uint32(&wb, subcallid)
- && writebuf_char(&wb, ie)
- && writebuf_object(&wb, object)) {
- pthread_mutex_lock(&protows->mutex);
- rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count);
- pthread_mutex_unlock(&protows->mutex);
- if (rc >= 0)
- return 0;
- }
- return -1;
-}
-
-/* callback for subcall reply */
-int afb_proto_ws_subcall_reply(struct afb_proto_ws_subcall *subcall, int status, struct json_object *result)
-{
- int rc = client_send_subcall_reply(subcall->protows, subcall->subcallid, status, result);
- afb_proto_ws_unref(subcall->protows);
- free(subcall->buffer);
- free(subcall);
- return rc;
-}
-
-/* received a subcall request */
-static void client_on_subcall(struct afb_proto_ws *protows, struct readbuf *rb)
-{
- struct afb_proto_ws_subcall *subcall;
- struct client_call *call;
- const char *api, *verb;
- uint32_t subcallid;
- struct json_object *object;
-
- /* get the subcallid */
- if (!readbuf_uint32(rb, &subcallid))
- return;
-
- /* if not expected drop it */
- if (!protows->client_itf->on_subcall)
- goto error;
-
- /* retrieve the message data */
- if (!client_msg_call_get(protows, rb, &call))
- goto error;
-
- /* allocation of the subcall */
- subcall = malloc(sizeof *subcall);
- if (!subcall)
- goto error;
-
- /* make the call */
- if (readbuf_string(rb, &api, NULL)
- && readbuf_string(rb, &verb, NULL)
- && readbuf_object(rb, &object)) {
- afb_proto_ws_addref(protows);
- subcall->protows = protows;
- subcall->subcallid = subcallid;
- subcall->buffer = rb->base;
- rb->base = NULL;
- protows->client_itf->on_subcall(protows->closure, subcall, call->request, api, verb, object);
- return;
- }
- free(subcall);
-error:
- client_send_subcall_reply(protows, subcallid, 1, NULL);
-}
-
static void client_on_description(struct afb_proto_ws *protows, struct readbuf *rb)
{
uint32_t descid;
@@ -751,11 +590,8 @@ static void client_on_binary_job(int sig, void *closure)
if (!sig) {
switch (*binary->rb.head++) {
- case CHAR_FOR_ANSWER_SUCCESS: /* success */
- client_on_reply_success(binary->protows, &binary->rb);
- break;
- case CHAR_FOR_ANSWER_FAIL: /* fail */
- client_on_reply_fail(binary->protows, &binary->rb);
+ case CHAR_FOR_REPLY: /* reply */
+ client_on_reply(binary->protows, &binary->rb);
break;
case CHAR_FOR_EVT_BROADCAST: /* broadcast */
client_on_event_broadcast(binary->protows, &binary->rb);
@@ -775,9 +611,6 @@ static void client_on_binary_job(int sig, void *closure)
case CHAR_FOR_EVT_UNSUBSCRIBE: /* unsubscribe event for a request */
client_on_event_unsubscribe(binary->protows, &binary->rb);
break;
- case CHAR_FOR_SUBCALL_CALL: /* subcall */
- client_on_subcall(binary->protows, &binary->rb);
- break;
case CHAR_FOR_DESCRIPTION: /* description */
client_on_description(binary->protows, &binary->rb);
break;
@@ -819,7 +652,8 @@ int afb_proto_ws_client_call(
const char *verb,
struct json_object *args,
const char *sessionid,
- void *request
+ void *request,
+ const char *user_creds
)
{
int rc = -1;
@@ -849,7 +683,8 @@ int afb_proto_ws_client_call(
|| !writebuf_uint32(&wb, call->callid)
|| !writebuf_string(&wb, verb)
|| !writebuf_string(&wb, sessionid)
- || !writebuf_object(&wb, args)) {
+ || !writebuf_object(&wb, args)
+ || !writebuf_nullstring(&wb, user_creds)) {
errno = EINVAL;
goto clean;
}
@@ -929,7 +764,7 @@ error:
static void server_on_call(struct afb_proto_ws *protows, struct readbuf *rb)
{
struct afb_proto_ws_call *call;
- const char *uuid, *verb;
+ const char *uuid, *verb, *user_creds;
uint32_t callid;
size_t lenverb;
struct json_object *object;
@@ -940,7 +775,8 @@ static void server_on_call(struct afb_proto_ws *protows, struct readbuf *rb)
if (!readbuf_uint32(rb, &callid)
|| !readbuf_string(rb, &verb, &lenverb)
|| !readbuf_string(rb, &uuid, NULL)
- || !readbuf_object(rb, &object))
+ || !readbuf_object(rb, &object)
+ || !readbuf_nullstring(rb, &user_creds, NULL))
goto overflow;
/* create the request */
@@ -954,7 +790,7 @@ static void server_on_call(struct afb_proto_ws *protows, struct readbuf *rb)
call->buffer = rb->base;
rb->base = NULL; /* don't free the buffer */
- protows->server_itf->on_call(protows->closure, call, verb, object, uuid);
+ protows->server_itf->on_call(protows->closure, call, verb, object, uuid, user_creds);
return;
out_of_memory:
@@ -964,39 +800,6 @@ overflow:
afb_proto_ws_unref(protows);
}
-/* on subcall reply */
-static void server_on_subcall_reply(struct afb_proto_ws *protows, struct readbuf *rb)
-{
- char ie;
- uint32_t subcallid;
- struct json_object *object;
- struct server_subcall *sc, **psc;
-
- /* reads the call message data */
- if (!readbuf_uint32(rb, &subcallid)
- || !readbuf_char(rb, &ie)
- || !readbuf_object(rb, &object)) {
- /* TODO bad protocol */
- return;
- }
-
- /* search the subcall and unlink it */
- pthread_mutex_lock(&protows->mutex);
- psc = &protows->subcalls;
- while ((sc = *psc) && sc->subcallid != subcallid)
- psc = &sc->next;
- if (!sc) {
- pthread_mutex_unlock(&protows->mutex);
- json_object_put(object);
- /* TODO subcall not found */
- } else {
- *psc = sc->next;
- pthread_mutex_unlock(&protows->mutex);
- sc->callback(sc->closure, -(int)ie, object);
- free(sc);
- }
-}
-
static int server_send_description(struct afb_proto_ws *protows, uint32_t descid, struct json_object *descobj)
{
int rc;
@@ -1055,9 +858,6 @@ static void server_on_binary_job(int sig, void *closure)
case CHAR_FOR_CALL:
server_on_call(binary->protows, &binary->rb);
break;
- case CHAR_FOR_SUBCALL_REPLY:
- server_on_subcall_reply(binary->protows, &binary->rb);
- break;
case CHAR_FOR_DESCRIBE:
server_on_describe(binary->protows, &binary->rb);
break;
@@ -1139,17 +939,8 @@ int afb_proto_ws_server_event_broadcast(struct afb_proto_ws *protows, const char
static void on_hangup(void *closure)
{
struct afb_proto_ws *protows = closure;
- struct server_subcall *sc, *nsc;
struct client_describe *cd, *ncd;
- nsc = protows->subcalls;
- while (nsc) {
- sc= nsc;
- nsc = sc->next;
- sc->callback(sc->closure, 1, NULL);
- free(sc);
- }
-
ncd = protows->describes;
while (ncd) {
cd= ncd;
@@ -1202,7 +993,6 @@ static struct afb_proto_ws *afb_proto_ws_create(struct fdev *fdev, const struct
if (protows->ws != NULL) {
protows->fdev = fdev;
protows->refcount = 1;
- protows->subcalls = NULL;
protows->closure = closure;
protows->server_itf = itfs;
protows->client_itf = itfc;
diff --git a/src/afb-proto-ws.h b/src/afb-proto-ws.h
index d674af3d..342313e7 100644
--- a/src/afb-proto-ws.h
+++ b/src/afb-proto-ws.h
@@ -18,17 +18,21 @@
#pragma once
+/*
+ * Defined since version 3, the value AFB_PROTO_WS_VERSION can be used to
+ * track versions of afb-proto-ws.
+ */
+#define AFB_PROTO_WS_VERSION 3
+
struct fdev;
struct afb_proto_ws;
struct afb_proto_ws_call;
-struct afb_proto_ws_subcall;
struct afb_proto_ws_describe;
struct afb_proto_ws_client_itf
{
/* can't be NULL */
- void (*on_reply_success)(void *closure, void *request, struct json_object *result, const char *info);
- void (*on_reply_fail)(void *closure, void *request, const char *status, const char *info);
+ void (*on_reply)(void *closure, void *request, struct json_object *obj, const char *error, const char *info);
/* can be NULL */
void (*on_event_create)(void *closure, const char *event_name, int event_id);
@@ -37,13 +41,11 @@ struct afb_proto_ws_client_itf
void (*on_event_unsubscribe)(void *closure, void *request, const char *event_name, int event_id);
void (*on_event_push)(void *closure, const char *event_name, int event_id, struct json_object *data);
void (*on_event_broadcast)(void *closure, const char *event_name, struct json_object *data);
-
- void (*on_subcall)(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args);
};
struct afb_proto_ws_server_itf
{
- void (*on_call)(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid);
+ void (*on_call)(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid, const char *user_creds);
void (*on_describe)(void *closure, struct afb_proto_ws_describe *describe);
};
@@ -61,7 +63,7 @@ extern void afb_proto_ws_on_hangup(struct afb_proto_ws *protows, void (*on_hangu
-extern int afb_proto_ws_client_call(struct afb_proto_ws *protows, const char *verb, struct json_object *args, const char *sessionid, void *request);
+extern int afb_proto_ws_client_call(struct afb_proto_ws *protows, const char *verb, struct json_object *args, const char *sessionid, void *request, const char *user_creds);
extern int afb_proto_ws_client_describe(struct afb_proto_ws *protows, void (*callback)(void*, struct json_object*), void *closure);
extern int afb_proto_ws_server_event_create(struct afb_proto_ws *protows, const char *event_name, int event_id);
@@ -72,14 +74,9 @@ extern int afb_proto_ws_server_event_broadcast(struct afb_proto_ws *protows, con
extern void afb_proto_ws_call_addref(struct afb_proto_ws_call *call);
extern void afb_proto_ws_call_unref(struct afb_proto_ws_call *call);
-extern int afb_proto_ws_call_success(struct afb_proto_ws_call *call, struct json_object *obj, const char *info);
-extern int afb_proto_ws_call_fail(struct afb_proto_ws_call *call, const char *status, const char *info);
+extern int afb_proto_ws_call_reply(struct afb_proto_ws_call *call, struct json_object *obj, const char *error, const char *info);
-extern int afb_proto_ws_call_subcall(struct afb_proto_ws_call *call, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure);
extern int afb_proto_ws_call_subscribe(struct afb_proto_ws_call *call, const char *event_name, int event_id);
extern int afb_proto_ws_call_unsubscribe(struct afb_proto_ws_call *call, const char *event_name, int event_id);
-extern int afb_proto_ws_subcall_reply(struct afb_proto_ws_subcall *subcall, int status, struct json_object *result);
-
extern int afb_proto_ws_describe_put(struct afb_proto_ws_describe *describe, struct json_object *description);
-
diff --git a/src/afb-session.c b/src/afb-session.c
index 8c0f77b8..16fc69bb 100644
--- a/src/afb-session.c
+++ b/src/afb-session.c
@@ -27,11 +27,10 @@
#include <uuid/uuid.h>
#include <errno.h>
-#include <json-c/json.h>
-
#include "afb-session.h"
#include "afb-hook.h"
#include "verbose.h"
+#include "pearson.h"
#define SIZEUUID 37
#define HEADCOUNT 16
@@ -43,41 +42,45 @@
#define MAX_EXPIRATION (_MAXEXP_ >= 0 ? _MAXEXP_ : _MAXEXP2_)
#define NOW (time_now())
-/* structure for a cookie added to sessions */
+/**
+ * structure for a cookie added to sessions
+ */
struct cookie
{
- struct cookie *next; /* link to next cookie */
- const void *key; /* pointer key */
- void *value; /* value */
- void (*freecb)(void*); /* function to call when session is closed */
+ struct cookie *next; /**< link to next cookie */
+ const void *key; /**< pointer key */
+ void *value; /**< value */
+ void (*freecb)(void*); /**< function to call when session is closed */
};
-/*
+/**
* structure for session
*/
struct afb_session
{
- struct afb_session *next; /* link to the next */
- unsigned refcount; /* external reference count of the session */
- int timeout; /* timeout of the session */
- time_t expiration; /* expiration time of the token */
- pthread_mutex_t mutex; /* mutex of the session */
- struct cookie *cookies[COOKIECOUNT]; /* cookies of the session */
- uint8_t closed: 1; /* is the session closed ? */
- uint8_t autoclose: 1; /* close the session when unreferenced */
- uint8_t notinset: 1; /* session removed from the set of sessions */
- char uuid[SIZEUUID]; /* long term authentication of remote client */
- char token[SIZEUUID]; /* short term authentication of remote client */
+ struct afb_session *next; /**< link to the next */
+ unsigned refcount; /**< external reference count of the session */
+ int timeout; /**< timeout of the session */
+ time_t expiration; /**< expiration time of the token */
+ pthread_mutex_t mutex; /**< mutex of the session */
+ struct cookie *cookies[COOKIECOUNT]; /**< cookies of the session */
+ uint8_t closed: 1; /**< is the session closed ? */
+ uint8_t autoclose: 1; /**< close the session when unreferenced */
+ uint8_t notinset: 1; /**< session removed from the set of sessions */
+ char uuid[SIZEUUID]; /**< long term authentication of remote client */
+ char token[SIZEUUID]; /**< short term authentication of remote client */
};
-/* Session UUID are store in a simple array [for 10 sessions this should be enough] */
+/**
+ * structure for managing sessions
+ */
static struct {
- int count; /* current number of sessions */
- int max; /* maximum count of sessions */
- int timeout; /* common initial timeout */
- struct afb_session *heads[HEADCOUNT]; /* sessions */
- char initok[SIZEUUID]; /* common initial token */
- pthread_mutex_t mutex; /* declare a mutex to protect hash table */
+ int count; /**< current number of sessions */
+ int max; /**< maximum count of sessions */
+ int timeout; /**< common initial timeout */
+ struct afb_session *heads[HEADCOUNT]; /**< sessions */
+ char initok[SIZEUUID]; /**< common initial token */
+ pthread_mutex_t mutex; /**< declare a mutex to protect hash table */
} sessions = {
.count = 0,
.max = 10,
@@ -87,7 +90,9 @@ static struct {
.mutex = PTHREAD_MUTEX_INITIALIZER
};
-/* Get the actual raw time */
+/**
+ * Get the actual raw time
+ */
static inline time_t time_now()
{
struct timespec ts;
@@ -95,7 +100,9 @@ static inline time_t time_now()
return ts.tv_sec;
}
-/* generate a new fresh 'uuid' */
+/**
+ * generate a new fresh 'uuid'
+ */
static void new_uuid(char uuid[SIZEUUID])
{
uuid_t newuuid;
@@ -103,26 +110,6 @@ static void new_uuid(char uuid[SIZEUUID])
uuid_unparse_lower(newuuid, uuid);
}
-/*
- * Returns a tiny hash value for the 'text'.
- *
- * Tiny hash function inspired from pearson
- */
-static uint8_t pearson4(const char *text)
-{
- static uint8_t T[16] = {
- 4, 1, 6, 0, 9, 14, 11, 5,
- 2, 3, 12, 15, 10, 7, 8, 13
- };
- uint8_t r, c;
-
- for (r = 0; (c = (uint8_t)*text) ; text++) {
- r = T[r ^ (15 & c)];
- r = T[r ^ (c >> 4)];
- }
- return r; // % HEADCOUNT;
-}
-
/* lock the set of sessions for exclusive access */
static inline void sessionset_lock()
{
@@ -155,7 +142,7 @@ static struct afb_session *sessionset_search(const char *uuid, uint8_t hashidx)
static int sessionset_add(struct afb_session *session, uint8_t hashidx)
{
/* check availability */
- if (sessions.count >= sessions.max) {
+ if (sessions.max && sessions.count >= sessions.max) {
errno = EBUSY;
return -1;
}
@@ -321,7 +308,7 @@ static time_t sessionset_cleanup (int force)
* @param max_session_count maximum allowed session count in the same time
* @param timeout the initial default timeout of sessions
* @param initok the initial default token of sessions
- *
+ *
*/
int afb_session_init (int max_session_count, int timeout, const char *initok)
{
@@ -513,7 +500,7 @@ void afb_session_close (struct afb_session *session)
* Set the 'autoclose' flag of the 'session'
*
* A session whose autoclose flag is true will close as
- * soon as it is no more referenced.
+ * soon as it is no more referenced.
*
* @param session the session to set
* @param autoclose the value to set
@@ -694,8 +681,7 @@ void *afb_session_get_cookie(struct afb_session *session, const void *key)
* @param value the value to store at key
* @param freecb a function to use when the cookie value is to remove (or null)
*
- * @return the data staored for the key or NULL if the key isn't found
- *
+ * @return 0 in case of success or -1 in case of error
*/
int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*))
{
diff --git a/src/afb-stub-ws.c b/src/afb-stub-ws.c
index e725d5ad..68bc8c7c 100644
--- a/src/afb-stub-ws.c
+++ b/src/afb-stub-ws.c
@@ -34,7 +34,7 @@
#include <json-c/json.h>
-#include <afb/afb-event.h>
+#include <afb/afb-event-x2.h>
#include "afb-session.h"
#include "afb-cred.h"
@@ -52,29 +52,6 @@
struct afb_stub_ws;
-/******************* handling subcalls *****************************/
-
-/**
- * Structure on server side for recording pending
- * subcalls.
- */
-struct server_subcall
-{
- struct server_subcall *next; /**< next subcall for the client */
- uint32_t subcallid; /**< the subcallid */
- void (*callback)(void*, int, struct json_object*); /**< callback on completion */
- void *closure; /**< closure of the callback */
-};
-
-/**
- * Structure for sending back replies on client side
- */
-struct client_subcall
-{
- struct afb_stub_ws *stubws; /**< stub descriptor */
- uint32_t subcallid; /**< subcallid for the reply */
-};
-
/*
* structure for recording calls on client side
*/
@@ -100,7 +77,7 @@ struct server_req {
struct client_event
{
struct client_event *next;
- struct afb_eventid *eventid;
+ struct afb_event_x2 *event;
int id;
int refcount;
};
@@ -152,7 +129,7 @@ struct afb_stub_ws
/* event replica (client side) */
struct client_event *events;
- /* credentials (server side) */
+ /* credentials of the client (server side) */
struct afb_cred *cred;
/* sessions (server side) */
@@ -183,57 +160,37 @@ static void server_req_destroy_cb(struct afb_xreq *xreq)
free(wreq);
}
-static void server_req_success_cb(struct afb_xreq *xreq, struct json_object *obj, const char *info)
+static void server_req_reply_cb(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info)
{
int rc;
struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq);
- rc = afb_proto_ws_call_success(wreq->call, obj, info);
+ rc = afb_proto_ws_call_reply(wreq->call, obj, error, info);
if (rc < 0)
- ERROR("error while sending success");
+ ERROR("error while sending reply");
json_object_put(obj);
}
-static void server_req_fail_cb(struct afb_xreq *xreq, const char *status, const char *info)
+static int server_req_subscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event)
{
int rc;
struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq);
- rc = afb_proto_ws_call_fail(wreq->call, status, info);
- if (rc < 0)
- ERROR("error while sending fail");
-}
-
-static void server_req_subcall_cb(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
-{
- int rc;
- struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq);
-
- rc = afb_proto_ws_call_subcall(wreq->call, api, verb, args, callback, cb_closure);
- if (rc < 0)
- ERROR("error while sending subcall");
-}
-
-static int server_req_subscribe_cb(struct afb_xreq *xreq, struct afb_eventid *event)
-{
- int rc;
- struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq);
-
- rc = afb_evt_eventid_add_watch(wreq->stubws->listener, event);
+ rc = afb_evt_event_x2_add_watch(wreq->stubws->listener, event);
if (rc >= 0)
- rc = afb_proto_ws_call_subscribe(wreq->call, afb_evt_eventid_fullname(event), afb_evt_eventid_id(event));
+ rc = afb_proto_ws_call_subscribe(wreq->call, afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event));
if (rc < 0)
ERROR("error while subscribing event");
return rc;
}
-static int server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_eventid *event)
+static int server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event)
{
int rc, rc2;
struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq);
- rc = afb_proto_ws_call_unsubscribe(wreq->call, afb_evt_eventid_fullname(event), afb_evt_eventid_id(event));
- rc2 = afb_evt_eventid_remove_watch(wreq->stubws->listener, event);
+ rc = afb_proto_ws_call_unsubscribe(wreq->call, afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event));
+ rc2 = afb_evt_event_x2_remove_watch(wreq->stubws->listener, event);
if (rc >= 0 && rc2 < 0)
rc = rc2;
if (rc < 0)
@@ -242,10 +199,8 @@ static int server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_eventid *
}
static const struct afb_xreq_query_itf server_req_xreq_itf = {
- .success = server_req_success_cb,
- .fail = server_req_fail_cb,
+ .reply = server_req_reply_cb,
.unref = server_req_destroy_cb,
- .subcall = server_req_subcall_cb,
.subscribe = server_req_subscribe_cb,
.unsubscribe = server_req_unsubscribe_cb
};
@@ -258,7 +213,7 @@ static struct client_event *client_event_search(struct afb_stub_ws *stubws, uint
struct client_event *ev;
ev = stubws->events;
- while (ev != NULL && (ev->id != eventid || 0 != strcmp(afb_evt_eventid_fullname(ev->eventid), name)))
+ while (ev != NULL && (ev->id != eventid || 0 != strcmp(afb_evt_event_x2_fullname(ev->event), name)))
ev = ev->next;
return ev;
@@ -269,7 +224,13 @@ static void client_call_cb(void * closure, struct afb_xreq *xreq)
{
struct afb_stub_ws *stubws = closure;
- afb_proto_ws_client_call(stubws->proto, xreq->request.verb, afb_xreq_json(xreq), afb_session_uuid(xreq->context.session), xreq);
+ afb_proto_ws_client_call(
+ stubws->proto,
+ xreq->request.called_verb,
+ afb_xreq_json(xreq),
+ afb_session_uuid(xreq->context.session),
+ xreq,
+ xreq_on_behalf_cred_export(xreq));
afb_xreq_unhooked_addref(xreq);
}
@@ -339,19 +300,11 @@ static void server_event_broadcast(void *closure, const char *event, int eventid
/*****************************************************/
-static void on_reply_success(void *closure, void *request, struct json_object *result, const char *info)
-{
- struct afb_xreq *xreq = request;
-
- afb_xreq_success(xreq, result, *info ? info : NULL);
- afb_xreq_unhooked_unref(xreq);
-}
-
-static void on_reply_fail(void *closure, void *request, const char *status, const char *info)
+static void on_reply(void *closure, void *request, struct json_object *object, const char *error, const char *info)
{
struct afb_xreq *xreq = request;
- afb_xreq_fail(xreq, status, *info ? info : NULL);
+ afb_xreq_reply(xreq, object, error, info);
afb_xreq_unhooked_unref(xreq);
}
@@ -370,8 +323,8 @@ static void on_event_create(void *closure, const char *event_name, int event_id)
/* no conflict, try to add it */
ev = malloc(sizeof *ev);
if (ev != NULL) {
- ev->eventid = afb_evt_eventid_create(event_name);
- if (ev->eventid != NULL) {
+ ev->event = afb_evt_event_x2_create(event_name);
+ if (ev->event != NULL) {
ev->refcount = 1;
ev->id = event_id;
ev->next = stubws->events;
@@ -404,7 +357,7 @@ static void on_event_remove(void *closure, const char *event_name, int event_id)
*prv = ev->next;
/* destroys the event */
- afb_evt_eventid_unref(ev->eventid);
+ afb_evt_event_x2_unref(ev->event);
free(ev);
}
@@ -419,7 +372,7 @@ static void on_event_subscribe(void *closure, void *request, const char *event_n
if (ev == NULL)
return;
- if (afb_xreq_subscribe(xreq, ev->eventid) < 0)
+ if (afb_xreq_subscribe(xreq, ev->event) < 0)
ERROR("can't subscribe: %m");
}
@@ -434,7 +387,7 @@ static void on_event_unsubscribe(void *closure, void *request, const char *event
if (ev == NULL)
return;
- if (afb_xreq_unsubscribe(xreq, ev->eventid) < 0)
+ if (afb_xreq_unsubscribe(xreq, ev->event) < 0)
ERROR("can't unsubscribe: %m");
}
@@ -446,7 +399,7 @@ static void on_event_push(void *closure, const char *event_name, int event_id, s
/* check conflicts */
ev = client_event_search(stubws, event_id, event_name);
if (ev)
- afb_evt_eventid_push(ev->eventid, data);
+ afb_evt_event_x2_push(ev->event, data);
else
ERROR("unreadable push event");
}
@@ -456,19 +409,6 @@ static void on_event_broadcast(void *closure, const char *event_name, struct jso
afb_evt_broadcast(event_name, data);
}
-static void client_subcall_reply_cb(void *closure, int status, json_object *object, struct afb_request *request)
-{
- struct afb_proto_ws_subcall *subcall = closure;
- afb_proto_ws_subcall_reply(subcall, status, object);
-}
-
-static void on_subcall(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args)
-{
- struct afb_xreq *xreq = request;
-
- afb_xreq_subcall(xreq, api, verb, args, client_subcall_reply_cb, subcall);
-}
-
/*****************************************************/
static void record_session(struct afb_stub_ws *stubws, struct afb_session *session)
@@ -514,7 +454,7 @@ static void release_all_sessions(struct afb_stub_ws *stubws)
/*****************************************************/
-static void on_call(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid)
+static void on_call(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid, const char *user_creds)
{
struct afb_stub_ws *stubws = closure;
struct server_req *wreq;
@@ -539,9 +479,9 @@ static void on_call(void *closure, struct afb_proto_ws_call *call, const char *v
afb_session_set_autoclose(wreq->xreq.context.session, 1);
/* makes the call */
- wreq->xreq.cred = afb_cred_addref(stubws->cred);
- wreq->xreq.request.api = stubws->apiname;
- wreq->xreq.request.verb = verb;
+ wreq->xreq.cred = afb_cred_mixed_on_behalf_import(stubws->cred, sessionid, user_creds);
+ wreq->xreq.request.called_api = stubws->apiname;
+ wreq->xreq.request.called_verb = verb;
wreq->xreq.json = args;
afb_xreq_process(&wreq->xreq, stubws->apiset);
return;
@@ -551,7 +491,7 @@ unconnected:
out_of_memory:
json_object_put(args);
afb_stub_ws_unref(stubws);
- afb_proto_ws_call_fail(call, "internal-error", NULL);
+ afb_proto_ws_call_reply(call, NULL, "internal-error", NULL);
afb_proto_ws_call_unref(call);
}
@@ -601,15 +541,13 @@ static void on_describe(void *closure, struct afb_proto_ws_describe *describe)
static const struct afb_proto_ws_client_itf client_itf =
{
- .on_reply_success = on_reply_success,
- .on_reply_fail = on_reply_fail,
+ .on_reply = on_reply,
.on_event_create = on_event_create,
.on_event_remove = on_event_remove,
.on_event_subscribe = on_event_subscribe,
.on_event_unsubscribe = on_event_unsubscribe,
.on_event_push = on_event_push,
.on_event_broadcast = on_event_broadcast,
- .on_subcall = on_subcall
};
static const struct afb_proto_ws_server_itf server_itf =
@@ -642,7 +580,7 @@ static void drop_all_events(struct afb_stub_ws *stubws)
while (ev) {
nxt = ev->next;
- afb_evt_eventid_unref(ev->eventid);
+ afb_evt_event_x2_unref(ev->event);
free(ev);
ev = nxt;
}
@@ -738,9 +676,9 @@ const char *afb_stub_ws_name(struct afb_stub_ws *stubws)
return stubws->apiname;
}
-struct afb_api afb_stub_ws_client_api(struct afb_stub_ws *stubws)
+struct afb_api_item afb_stub_ws_client_api(struct afb_stub_ws *stubws)
{
- struct afb_api api;
+ struct afb_api_item api;
assert(!stubws->listener); /* check client */
api.closure = stubws;
diff --git a/src/afb-stub-ws.h b/src/afb-stub-ws.h
index aa643363..e14eac17 100644
--- a/src/afb-stub-ws.h
+++ b/src/afb-stub-ws.h
@@ -21,7 +21,7 @@
struct fdev;
struct afb_stub_ws;
struct afb_apiset;
-struct afb_api;
+struct afb_api_item;
extern struct afb_stub_ws *afb_stub_ws_create_client(struct fdev *fdev, const char *apiname, struct afb_apiset *apiset);
@@ -35,7 +35,7 @@ extern void afb_stub_ws_on_hangup(struct afb_stub_ws *stubws, void (*on_hangup)(
extern const char *afb_stub_ws_name(struct afb_stub_ws *stubws);
-extern struct afb_api afb_stub_ws_client_api(struct afb_stub_ws *stubws);
+extern struct afb_api_item afb_stub_ws_client_api(struct afb_stub_ws *stubws);
extern int afb_stub_ws_client_add(struct afb_stub_ws *stubws, struct afb_apiset *apiset);
diff --git a/src/afb-supervision.c b/src/afb-supervision.c
index f1024c3c..79a9d3fd 100644
--- a/src/afb-supervision.c
+++ b/src/afb-supervision.c
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#define _GNU_SOURCE
#define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
@@ -29,7 +28,9 @@
#include <sys/un.h>
#include <json-c/json.h>
-#include <afb/afb-binding-v2.h>
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
#include "afb-cred.h"
#include "afb-api.h"
@@ -252,7 +253,7 @@ int afb_supervision_init()
/* init the apiset */
rc = afb_apiset_add(supervision_apiset, supervision_apiname,
- (struct afb_api){ .itf = &supervision_api_itf, .closure = NULL});
+ (struct afb_api_item){ .itf = &supervision_api_itf, .closure = NULL});
if (rc < 0) {
ERROR("Can't create supervision's apiset: %m");
afb_apiset_unref(supervision_apiset);
@@ -298,14 +299,14 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq)
struct json_object *args, *drop, *add, *sub, *list;
const char *api, *verb, *uuid;
struct afb_session *session;
- const struct afb_api *xapi;
- struct afb_req req;
+ const struct afb_api_item *xapi;
+ afb_req_t req;
/* search the verb */
i = (int)(sizeof verbs / sizeof *verbs);
- while(--i >= 0 && strcasecmp(verbs[i], xreq->request.verb));
+ while(--i >= 0 && strcasecmp(verbs[i], xreq->request.called_verb));
if (i < 0) {
- afb_xreq_fail_unknown_verb(xreq);
+ afb_xreq_reply_unknown_verb(xreq);
return;
}
@@ -324,32 +325,32 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq)
if (wrap_json_unpack(args, "s", &uuid))
wrap_json_unpack(args, "{ss}", "uuid", &uuid);
if (!uuid)
- afb_xreq_fail(xreq, "invalid", NULL);
+ afb_xreq_reply(xreq, NULL, "invalid", NULL);
else {
session = afb_session_search(uuid);
if (!session)
- afb_xreq_fail(xreq, "not-found", NULL);
+ afb_xreq_reply(xreq, NULL, "not-found", NULL);
else {
afb_session_close(session);
afb_session_unref(session);
afb_session_purge();
- afb_xreq_success(xreq, NULL, NULL);
+ afb_xreq_reply(xreq, NULL, NULL, NULL);
}
}
break;
case Slist:
list = json_object_new_object();
afb_session_foreach(slist, list);
- afb_xreq_success(xreq, list, NULL);
+ afb_xreq_reply(xreq, list, NULL, NULL);
break;
case Config:
- afb_xreq_success(xreq, afb_config_json(main_config), NULL);
+ afb_xreq_reply(xreq, afb_config_json(main_config), NULL, NULL);
break;
case Trace:
if (!trace)
trace = afb_trace_create(supervisor_apiname, NULL /* not bound to any session */);
- req = xreq_to_req(xreq);
+ req = xreq_to_req_x2(xreq);
add = drop = NULL;
wrap_json_unpack(args, "{s?o s?o}", "add", &add, "drop", &drop);
if (add) {
@@ -367,16 +368,16 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq)
case Do:
sub = NULL;
if (wrap_json_unpack(args, "{ss ss s?o*}", "api", &api, "verb", &verb, "args", &sub))
- afb_xreq_fail(xreq, "error", "bad request");
+ afb_xreq_reply(xreq, NULL, "error", "bad request");
else {
xapi = afb_apiset_lookup_started(main_apiset, api, 1);
if (!xapi)
- afb_xreq_fail_unknown_api(xreq);
+ afb_xreq_reply_unknown_api(xreq);
else {
afb_cred_unref(xreq->cred);
xreq->cred = NULL;
- xreq->request.api = api;
- xreq->request.verb = verb;
+ xreq->request.called_api = api;
+ xreq->request.called_verb = verb;
xreq->json = json_object_get(sub);
xapi->itf->call(xapi->closure, xreq);
json_object_put(args);
@@ -384,11 +385,11 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq)
}
break;
case Wait:
- afb_req_success(req, NULL, NULL);
+ afb_xreq_reply(xreq, NULL, NULL, NULL);
afb_debug_wait("supervisor");
break;
case Break:
- afb_req_success(req, NULL, NULL);
+ afb_xreq_reply(xreq, NULL, NULL, NULL);
afb_debug_break("supervisor");
break;
}
diff --git a/src/afb-trace.c b/src/afb-trace.c
index 5404a5af..a603951c 100644
--- a/src/afb-trace.c
+++ b/src/afb-trace.c
@@ -28,7 +28,7 @@
#include <json-c/json.h>
-#define AFB_BINDING_VERSION 0
+#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
#include "afb-hook.h"
@@ -74,7 +74,7 @@ struct tag {
/* struct for events */
struct event {
struct event *next; /* link to the next event */
- struct afb_evtid *evtid; /* the event */
+ struct afb_evtid *evtid; /* the event */
};
/* struct for sessions */
@@ -95,13 +95,16 @@ struct hook {
/* types of hooks */
enum trace_type
{
- Trace_Type_Xreq, /* xreq hooks */
- Trace_Type_Ditf, /* export hooks */
- Trace_Type_Svc, /* export hooks */
- Trace_Type_Evt, /* evt hooks */
- Trace_Type_Session, /* session hooks */
- Trace_Type_Global, /* global hooks */
- Trace_Type_Count /* count of types of hooks */
+ Trace_Type_Xreq, /* xreq hooks */
+ Trace_Type_Api, /* api hooks */
+ Trace_Type_Evt, /* evt hooks */
+ Trace_Type_Session, /* session hooks */
+ Trace_Type_Global, /* global hooks */
+#if !defined(REMOVE_LEGACY_TRACE)
+ Trace_Legacy_Type_Ditf, /* export hooks */
+ Trace_Legacy_Type_Svc, /* export hooks */
+#endif
+ Trace_Type_Count, /* count of types of hooks */
};
/* client data */
@@ -168,8 +171,15 @@ static struct json_object *timestamp(const struct afb_hookid *hookid)
{
char ts[50];
- snprintf(ts, sizeof ts, "%llu.%06lu", (long long unsigned)hookid->time.tv_sec, (long unsigned)(hookid->time.tv_nsec / 1000));
+ snprintf(ts, sizeof ts, "%llu.%06lu",
+ (long long unsigned)hookid->time.tv_sec,
+ (long unsigned)((hookid->time.tv_nsec + 500) / 1000));
+
+ return json_object_new_double_s(0.0f, ts); /* the real value isn't used */
+#if 0
return json_object_new_string(ts);
+ return json_object_new_double_s(0f, ts); /* the real value isn't used */
+#endif
}
/* verbosity level name or NULL */
@@ -222,38 +232,35 @@ static struct flag xreq_flags[] = { /* must be sorted by names */
{ "begin", afb_hook_flag_req_begin },
{ "common", afb_hook_flags_req_common },
{ "context", afb_hook_flags_req_context },
- { "context_get", afb_hook_flag_req_context_get },
+ { "context_get", afb_hook_flag_req_legacy_context_get },
{ "context_make", afb_hook_flag_req_context_make },
- { "context_set", afb_hook_flag_req_context_set },
+ { "context_set", afb_hook_flag_req_legacy_context_set },
{ "end", afb_hook_flag_req_end },
{ "event", afb_hook_flags_req_event },
{ "extra", afb_hook_flags_req_extra },
- { "fail", afb_hook_flag_req_fail },
{ "get", afb_hook_flag_req_get },
{ "get_application_id", afb_hook_flag_req_get_application_id },
+ { "get_client_info", afb_hook_flag_req_get_client_info },
{ "get_uid", afb_hook_flag_req_get_uid },
{ "has_permission", afb_hook_flag_req_has_permission },
{ "json", afb_hook_flag_req_json },
{ "life", afb_hook_flags_req_life },
{ "ref", afb_hook_flags_req_ref },
- { "result", afb_hook_flags_req_result },
+ { "reply", afb_hook_flag_req_reply },
{ "security", afb_hook_flags_req_security },
{ "session", afb_hook_flags_req_session },
{ "session_close", afb_hook_flag_req_session_close },
{ "session_set_LOA", afb_hook_flag_req_session_set_LOA },
- { "store", afb_hook_flag_req_store },
+ { "store", afb_hook_flag_req_legacy_store },
{ "stores", afb_hook_flags_req_stores },
{ "subcall", afb_hook_flag_req_subcall },
- { "subcall_req", afb_hook_flag_req_subcall_req },
- { "subcall_req_result", afb_hook_flag_req_subcall_req_result },
{ "subcall_result", afb_hook_flag_req_subcall_result },
{ "subcalls", afb_hook_flags_req_subcalls },
{ "subcallsync", afb_hook_flag_req_subcallsync },
{ "subcallsync_result", afb_hook_flag_req_subcallsync_result },
{ "subscribe", afb_hook_flag_req_subscribe },
- { "success", afb_hook_flag_req_success },
{ "unref", afb_hook_flag_req_unref },
- { "unstore", afb_hook_flag_req_unstore },
+ { "unstore", afb_hook_flag_req_legacy_unstore },
{ "unsubscribe", afb_hook_flag_req_unsubscribe },
{ "vverbose", afb_hook_flag_req_vverbose },
};
@@ -285,8 +292,8 @@ static void hook_xreq(void *closure, const struct afb_hookid *hookid, const stru
va_start(ap, format);
emit(closure, hookid, "request", "{si ss ss ss so* ss*}", format, ap,
"index", xreq->hookindex,
- "api", xreq->request.api,
- "verb", xreq->request.verb,
+ "api", xreq->request.called_api,
+ "verb", xreq->request.called_verb,
"action", action,
"credentials", cred,
"session", session);
@@ -295,7 +302,8 @@ static void hook_xreq(void *closure, const struct afb_hookid *hookid, const stru
static void hook_xreq_begin(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
{
- hook_xreq(closure, hookid, xreq, "begin", NULL);
+ hook_xreq(closure, hookid, xreq, "begin", "{sO?}",
+ "json", afb_xreq_unhooked_json((struct afb_xreq*)xreq));
}
static void hook_xreq_end(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
@@ -318,17 +326,11 @@ static void hook_xreq_get(void *closure, const struct afb_hookid *hookid, const
"path", arg.path);
}
-static void hook_xreq_success(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
+static void hook_xreq_reply(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info)
{
- hook_xreq(closure, hookid, xreq, "success", "{sO? ss?}",
+ hook_xreq(closure, hookid, xreq, "reply", "{sO? ss? ss?}",
"result", obj,
- "info", info);
-}
-
-static void hook_xreq_fail(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info)
-{
- hook_xreq(closure, hookid, xreq, "fail", "{ss? ss?}",
- "status", status,
+ "error", error,
"info", info);
}
@@ -364,21 +366,21 @@ static void hook_xreq_session_set_LOA(void *closure, const struct afb_hookid *ho
"result", result);
}
-static void hook_xreq_subscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result)
+static void hook_xreq_subscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event, int result)
{
hook_xreq(closure, hookid, xreq, "subscribe", "{s{ss si} si}",
"event",
- "name", afb_evt_eventid_fullname(eventid),
- "id", afb_evt_eventid_id(eventid),
+ "name", afb_evt_event_x2_fullname(event),
+ "id", afb_evt_event_x2_id(event),
"result", result);
}
-static void hook_xreq_unsubscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result)
+static void hook_xreq_unsubscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event, int result)
{
hook_xreq(closure, hookid, xreq, "unsubscribe", "{s{ss? si} si}",
"event",
- "name", afb_evt_eventid_fullname(eventid),
- "id", afb_evt_eventid_id(eventid),
+ "name", afb_evt_event_x2_fullname(event),
+ "id", afb_evt_event_x2_id(event),
"result", result);
}
@@ -390,11 +392,12 @@ static void hook_xreq_subcall(void *closure, const struct afb_hookid *hookid, co
"args", args);
}
-static void hook_xreq_subcall_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
+static void hook_xreq_subcall_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
{
- hook_xreq(closure, hookid, xreq, "subcall_result", "{si sO?}",
- "status", status,
- "result", result);
+ hook_xreq(closure, hookid, xreq, "subcall_result", "{sO? ss? ss?}",
+ "object", object,
+ "error", error,
+ "info", info);
}
static void hook_xreq_subcallsync(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
@@ -405,11 +408,13 @@ static void hook_xreq_subcallsync(void *closure, const struct afb_hookid *hookid
"args", args);
}
-static void hook_xreq_subcallsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
+static void hook_xreq_subcallsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info)
{
- hook_xreq(closure, hookid, xreq, "subcallsync_result", "{si sO?}",
+ hook_xreq(closure, hookid, xreq, "subcallsync_result", "{si sO? ss? ss?}",
"status", status,
- "result", result);
+ "object", object,
+ "error", error,
+ "info", info);
}
static void hook_xreq_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
@@ -448,21 +453,6 @@ static void hook_xreq_unstore(void *closure, const struct afb_hookid *hookid, co
hook_xreq(closure, hookid, xreq, "unstore", NULL);
}
-static void hook_xreq_subcall_req(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
-{
- hook_xreq(closure, hookid, xreq, "subcall_req", "{ss? ss? sO?}",
- "api", api,
- "verb", verb,
- "args", args);
-}
-
-static void hook_xreq_subcall_req_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
-{
- hook_xreq(closure, hookid, xreq, "subcall_req_result", "{si sO?}",
- "status", status,
- "result", result);
-}
-
static void hook_xreq_has_permission(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result)
{
hook_xreq(closure, hookid, xreq, "has_permission", "{ss sb}",
@@ -497,15 +487,20 @@ static void hook_xreq_get_uid(void *closure, const struct afb_hookid *hookid, co
"result", result);
}
+static void hook_xreq_get_client_info(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *result)
+{
+ hook_xreq(closure, hookid, xreq, "get_client_info", "{so}",
+ "result", result);
+}
+
static struct afb_hook_xreq_itf hook_xreq_itf = {
.hook_xreq_begin = hook_xreq_begin,
.hook_xreq_end = hook_xreq_end,
.hook_xreq_json = hook_xreq_json,
.hook_xreq_get = hook_xreq_get,
- .hook_xreq_success = hook_xreq_success,
- .hook_xreq_fail = hook_xreq_fail,
- .hook_xreq_context_get = hook_xreq_context_get,
- .hook_xreq_context_set = hook_xreq_context_set,
+ .hook_xreq_reply = hook_xreq_reply,
+ .hook_xreq_legacy_context_get = hook_xreq_context_get,
+ .hook_xreq_legacy_context_set = hook_xreq_context_set,
.hook_xreq_addref = hook_xreq_addref,
.hook_xreq_unref = hook_xreq_unref,
.hook_xreq_session_close = hook_xreq_session_close,
@@ -517,85 +512,146 @@ static struct afb_hook_xreq_itf hook_xreq_itf = {
.hook_xreq_subcallsync = hook_xreq_subcallsync,
.hook_xreq_subcallsync_result = hook_xreq_subcallsync_result,
.hook_xreq_vverbose = hook_xreq_vverbose,
- .hook_xreq_store = hook_xreq_store,
- .hook_xreq_unstore = hook_xreq_unstore,
- .hook_xreq_subcall_req = hook_xreq_subcall_req,
- .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result,
+ .hook_xreq_legacy_store = hook_xreq_store,
+ .hook_xreq_legacy_unstore = hook_xreq_unstore,
.hook_xreq_has_permission = hook_xreq_has_permission,
.hook_xreq_get_application_id = hook_xreq_get_application_id,
.hook_xreq_context_make = hook_xreq_context_make,
.hook_xreq_get_uid = hook_xreq_get_uid,
+ .hook_xreq_get_client_info = hook_xreq_get_client_info,
};
/*******************************************************************************/
-/***** trace the daemon interface *****/
+/***** trace the api interface *****/
/*******************************************************************************/
-static struct flag ditf_flags[] = { /* must be sorted by names */
- { "all", afb_hook_flags_ditf_all },
- { "common", afb_hook_flags_ditf_common },
- { "event_broadcast_after", afb_hook_flag_ditf_event_broadcast_after },
- { "event_broadcast_before", afb_hook_flag_ditf_event_broadcast_before },
- { "event_make", afb_hook_flag_ditf_event_make },
- { "extra", afb_hook_flags_ditf_extra },
- { "get_event_loop", afb_hook_flag_ditf_get_event_loop },
- { "get_system_bus", afb_hook_flag_ditf_get_system_bus },
- { "get_user_bus", afb_hook_flag_ditf_get_user_bus },
- { "queue_job", afb_hook_flag_ditf_queue_job },
- { "require_api", afb_hook_flag_ditf_require_api },
- { "require_api_result", afb_hook_flag_ditf_require_api_result },
- { "rootdir_get_fd", afb_hook_flag_ditf_rootdir_get_fd },
- { "rootdir_open_locale", afb_hook_flag_ditf_rootdir_open_locale },
- { "unstore_req", afb_hook_flag_ditf_unstore_req },
- { "vverbose", afb_hook_flag_ditf_vverbose },
+#if !defined(REMOVE_LEGACY_TRACE)
+static struct flag legacy_ditf_flags[] = { /* must be sorted by names */
+ { "all", afb_hook_flags_api_ditf_all },
+ { "common", afb_hook_flags_api_ditf_common },
+ { "event_broadcast_after", afb_hook_flag_api_event_broadcast },
+ { "event_broadcast_before", afb_hook_flag_api_event_broadcast },
+ { "event_make", afb_hook_flag_api_event_make },
+ { "extra", afb_hook_flags_api_ditf_extra },
+ { "get_event_loop", afb_hook_flag_api_get_event_loop },
+ { "get_system_bus", afb_hook_flag_api_get_system_bus },
+ { "get_user_bus", afb_hook_flag_api_get_user_bus },
+ { "queue_job", afb_hook_flag_api_queue_job },
+ { "require_api", afb_hook_flag_api_require_api },
+ { "require_api_result", afb_hook_flag_api_require_api },
+ { "rootdir_get_fd", afb_hook_flag_api_rootdir_get_fd },
+ { "rootdir_open_locale", afb_hook_flag_api_rootdir_open_locale },
+ { "unstore_req", afb_hook_flag_api_legacy_unstore_req },
+ { "vverbose", afb_hook_flag_api_vverbose },
};
+static struct flag legacy_svc_flags[] = { /* must be sorted by names */
+ { "all", afb_hook_flags_api_svc_all },
+ { "call", afb_hook_flag_api_call },
+ { "call_result", afb_hook_flag_api_call },
+ { "callsync", afb_hook_flag_api_callsync },
+ { "callsync_result", afb_hook_flag_api_callsync },
+ { "on_event_after", afb_hook_flag_api_on_event },
+ { "on_event_before", afb_hook_flag_api_on_event },
+ { "start_after", afb_hook_flag_api_start },
+ { "start_before", afb_hook_flag_api_start },
+};
+
+/* get the export value for flag of 'name' */
+static int get_legacy_ditf_flag(const char *name)
+{
+ return get_flag(name, legacy_ditf_flags, (int)(sizeof legacy_ditf_flags / sizeof *legacy_ditf_flags));
+}
+
/* get the export value for flag of 'name' */
-static int get_ditf_flag(const char *name)
+static int get_legacy_svc_flag(const char *name)
{
- return get_flag(name, ditf_flags, (int)(sizeof ditf_flags / sizeof *ditf_flags));
+ return get_flag(name, legacy_svc_flags, (int)(sizeof legacy_svc_flags / sizeof *legacy_svc_flags));
}
+#endif
+
+static struct flag api_flags[] = { /* must be sorted by names */
+ { "add_alias", afb_hook_flag_api_add_alias },
+ { "all", afb_hook_flags_api_all },
+ { "api_add_verb", afb_hook_flag_api_api_add_verb },
+ { "api", afb_hook_flags_api_api },
+ { "api_del_verb", afb_hook_flag_api_api_del_verb },
+ { "api_seal", afb_hook_flag_api_api_seal },
+ { "api_set_on_event", afb_hook_flag_api_api_set_on_event },
+ { "api_set_on_init", afb_hook_flag_api_api_set_on_init },
+ { "api_set_verbs", afb_hook_flag_api_api_set_verbs },
+ { "call", afb_hook_flag_api_call },
+ { "callsync", afb_hook_flag_api_callsync },
+ { "class_provide", afb_hook_flag_api_class_provide },
+ { "class_require", afb_hook_flag_api_class_require },
+ { "common", afb_hook_flags_api_common },
+ { "delete_api", afb_hook_flag_api_delete_api },
+ { "event", afb_hook_flags_api_event },
+ { "event_broadcast", afb_hook_flag_api_event_broadcast },
+ { "event_handler_add", afb_hook_flag_api_event_handler_add },
+ { "event_handler_del", afb_hook_flag_api_event_handler_del },
+ { "event_make", afb_hook_flag_api_event_make },
+ { "extra", afb_hook_flags_api_extra },
+ { "get_event_loop", afb_hook_flag_api_get_event_loop },
+ { "get_system_bus", afb_hook_flag_api_get_system_bus },
+ { "get_user_bus", afb_hook_flag_api_get_user_bus },
+ { "legacy_unstore_req", afb_hook_flag_api_legacy_unstore_req },
+ { "new_api", afb_hook_flag_api_new_api },
+ { "on_event", afb_hook_flag_api_on_event },
+ { "on_event_handler", afb_hook_flag_api_on_event_handler },
+ { "queue_job", afb_hook_flag_api_queue_job },
+ { "require_api", afb_hook_flag_api_require_api },
+ { "rootdir_get_fd", afb_hook_flag_api_rootdir_get_fd },
+ { "rootdir_open_locale",afb_hook_flag_api_rootdir_open_locale },
+ { "start", afb_hook_flag_api_start },
+ { "vverbose", afb_hook_flag_api_vverbose },
+};
+/* get the export value for flag of 'name' */
+static int get_api_flag(const char *name)
+{
+ return get_flag(name, api_flags, (int)(sizeof api_flags / sizeof *api_flags));
+}
-static void hook_ditf(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...)
+static void hook_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...)
{
va_list ap;
va_start(ap, format);
- emit(closure, hookid, "daemon", "{ss ss}", format, ap,
+ emit(closure, hookid, "api", "{ss ss}", format, ap,
"api", afb_export_apiname(export),
"action", action);
va_end(ap);
}
-static void hook_ditf_event_broadcast_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object)
+static void hook_api_event_broadcast_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object)
{
- hook_ditf(closure, hookid, export, "event_broadcast_before", "{ss sO*}",
+ hook_api(closure, hookid, export, "event_broadcast_before", "{ss sO?}",
"name", name, "data", object);
}
-static void hook_ditf_event_broadcast_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result)
+static void hook_api_event_broadcast_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result)
{
- hook_ditf(closure, hookid, export, "event_broadcast_after", "{ss sO* si}",
+ hook_api(closure, hookid, export, "event_broadcast_after", "{ss sO? si}",
"name", name, "data", object, "result", result);
}
-static void hook_ditf_get_event_loop(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result)
+static void hook_api_get_event_loop(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result)
{
- hook_ditf(closure, hookid, export, "get_event_loop", NULL);
+ hook_api(closure, hookid, export, "get_event_loop", NULL);
}
-static void hook_ditf_get_user_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
+static void hook_api_get_user_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
{
- hook_ditf(closure, hookid, export, "get_user_bus", NULL);
+ hook_api(closure, hookid, export, "get_user_bus", NULL);
}
-static void hook_ditf_get_system_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
+static void hook_api_get_system_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
{
- hook_ditf(closure, hookid, export, "get_system_bus", NULL);
+ hook_api(closure, hookid, export, "get_system_bus", NULL);
}
-static void hook_ditf_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
+static void hook_api_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
{
struct json_object *pos;
int len;
@@ -612,7 +668,7 @@ static void hook_ditf_vverbose(void *closure, const struct afb_hookid *hookid, c
if (file)
wrap_json_pack(&pos, "{ss si ss*}", "file", file, "line", line, "function", function);
- hook_ditf(closure, hookid, export, "vverbose", "{si ss* ss? so*}",
+ hook_api(closure, hookid, export, "vverbose", "{si ss* ss? so*}",
"level", level,
"type", verbosity_level_name(level),
len < 0 ? "format" : "message", len < 0 ? fmt : msg,
@@ -621,13 +677,13 @@ static void hook_ditf_vverbose(void *closure, const struct afb_hookid *hookid, c
free(msg);
}
-static void hook_ditf_event_make(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_eventid *result)
+static void hook_api_event_make(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_event_x2 *result)
{
- hook_ditf(closure, hookid, export, "event_make", "{ss ss si}",
- "name", name, "event", afb_evt_eventid_fullname(result), "id", afb_evt_eventid_id(result));
+ hook_api(closure, hookid, export, "event_make", "{ss ss si}",
+ "name", name, "event", afb_evt_event_x2_fullname(result), "id", afb_evt_event_x2_id(result));
}
-static void hook_ditf_rootdir_get_fd(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
+static void hook_api_rootdir_get_fd(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
{
char path[PATH_MAX];
@@ -636,12 +692,12 @@ static void hook_ditf_rootdir_get_fd(void *closure, const struct afb_hookid *hoo
readlink(path, path, sizeof path);
}
- hook_ditf(closure, hookid, export, "rootdir_get_fd", "{ss}",
+ hook_api(closure, hookid, export, "rootdir_get_fd", "{ss}",
result < 0 ? "path" : "error",
result < 0 ? strerror(errno) : path);
}
-static void hook_ditf_rootdir_open_locale(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result)
+static void hook_api_rootdir_open_locale(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result)
{
char path[PATH_MAX];
@@ -650,7 +706,7 @@ static void hook_ditf_rootdir_open_locale(void *closure, const struct afb_hookid
readlink(path, path, sizeof path);
}
- hook_ditf(closure, hookid, export, "rootdir_open_locale", "{ss si ss* ss}",
+ hook_api(closure, hookid, export, "rootdir_open_locale", "{ss si ss* ss}",
"file", filename,
"flags", flags,
"locale", locale,
@@ -658,130 +714,187 @@ static void hook_ditf_rootdir_open_locale(void *closure, const struct afb_hookid
result < 0 ? strerror(errno) : path);
}
-static void hook_ditf_queue_job(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
+static void hook_api_queue_job(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
{
- hook_ditf(closure, hookid, export, "queue_job", "{ss}", "result", result);
+ hook_api(closure, hookid, export, "queue_job", "{ss}", "result", result);
}
-static void hook_ditf_unstore_req(void * closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq)
+static void hook_api_unstore_req(void * closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq)
{
- hook_ditf(closure, hookid, export, "unstore_req", NULL);
+ hook_api(closure, hookid, export, "unstore_req", NULL);
}
-static void hook_ditf_require_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized)
+static void hook_api_require_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized)
{
- hook_ditf(closure, hookid, export, "require_api", "{ss sb}", "name", name, "initialized", initialized);
+ hook_api(closure, hookid, export, "require_api", "{ss sb}", "name", name, "initialized", initialized);
}
-static void hook_ditf_require_api_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result)
+static void hook_api_require_api_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result)
{
- hook_ditf(closure, hookid, export, "require_api_result", "{ss sb si}", "name", name, "initialized", initialized, "result", result);
+ hook_api(closure, hookid, export, "require_api_result", "{ss sb si}", "name", name, "initialized", initialized, "result", result);
}
-static struct afb_hook_ditf_itf hook_ditf_itf = {
- .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before,
- .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after,
- .hook_ditf_get_event_loop = hook_ditf_get_event_loop,
- .hook_ditf_get_user_bus = hook_ditf_get_user_bus,
- .hook_ditf_get_system_bus = hook_ditf_get_system_bus,
- .hook_ditf_vverbose = hook_ditf_vverbose,
- .hook_ditf_event_make = hook_ditf_event_make,
- .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd,
- .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale,
- .hook_ditf_queue_job = hook_ditf_queue_job,
- .hook_ditf_unstore_req = hook_ditf_unstore_req,
- .hook_ditf_require_api = hook_ditf_require_api,
- .hook_ditf_require_api_result = hook_ditf_require_api_result
-};
+static void hook_api_add_alias_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *alias, int result)
+{
+ hook_api(closure, hookid, export, "add_alias", "{si ss? ss}", "status", result, "api", api, "alias", alias);
+}
-/*******************************************************************************/
-/***** trace the services *****/
-/*******************************************************************************/
+static void hook_api_start_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
+{
+ hook_api(closure, hookid, export, "start_before", NULL);
+}
-static struct flag svc_flags[] = { /* must be sorted by names */
- { "all", afb_hook_flags_svc_all },
- { "call", afb_hook_flag_svc_call },
- { "call_result", afb_hook_flag_svc_call_result },
- { "callsync", afb_hook_flag_svc_callsync },
- { "callsync_result", afb_hook_flag_svc_callsync_result },
- { "on_event_after", afb_hook_flag_svc_on_event_after },
- { "on_event_before", afb_hook_flag_svc_on_event_before },
- { "start_after", afb_hook_flag_svc_start_after },
- { "start_before", afb_hook_flag_svc_start_before },
-};
+static void hook_api_start_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status)
+{
+ hook_api(closure, hookid, export, "start_after", "{si}", "result", status);
+}
-/* get the export value for flag of 'name' */
-static int get_svc_flag(const char *name)
+static void hook_api_on_event_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object)
{
- return get_flag(name, svc_flags, (int)(sizeof svc_flags / sizeof *svc_flags));
+ hook_api(closure, hookid, export, "on_event_before", "{ss si sO*}",
+ "event", event, "id", evtid, "data", object);
}
-static void hook_svc(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...)
+static void hook_api_on_event_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object)
{
- va_list ap;
+ hook_api(closure, hookid, export, "on_event_after", "{ss si sO?}",
+ "event", event, "id", evtid, "data", object);
+}
- va_start(ap, format);
- emit(closure, hookid, "service", "{ss ss}", format, ap,
- "api", afb_export_apiname(export),
- "action", action);
- va_end(ap);
+static void hook_api_call(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
+{
+ hook_api(closure, hookid, export, "call", "{ss ss sO?}",
+ "api", api, "verb", verb, "args", args);
}
-static void hook_svc_start_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
+static void hook_api_call_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object, const char *error, const char *info)
{
- hook_svc(closure, hookid, export, "start_before", NULL);
+ hook_api(closure, hookid, export, "call_result", "{sO? ss? ss?}",
+ "object", object, "error", error, "info", info);
}
-static void hook_svc_start_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status)
+static void hook_api_callsync(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
{
- hook_svc(closure, hookid, export, "start_after", "{si}", "result", status);
+ hook_api(closure, hookid, export, "callsync", "{ss ss sO?}",
+ "api", api, "verb", verb, "args", args);
}
-static void hook_svc_on_event_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object)
+static void hook_api_callsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info)
{
- hook_svc(closure, hookid, export, "on_event_before", "{ss si sO*}",
- "event", event, "id", evtid, "data", object);
+ hook_api(closure, hookid, export, "callsync_result", "{si sO? ss? ss?}",
+ "status", status, "object", object, "error", error, "info", info);
}
-static void hook_svc_on_event_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object)
+static void hook_api_new_api_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *info, int noconcurrency)
{
- hook_svc(closure, hookid, export, "on_event_after", "{ss si sO*}",
- "event", event, "id", evtid, "data", object);
+ hook_api(closure, hookid, export, "new_api.before", "{ss ss? sb}",
+ "api", api, "info", info, "noconcurrency", noconcurrency);
}
-static void hook_svc_call(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
+static void hook_api_new_api_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *api)
{
- hook_svc(closure, hookid, export, "call", "{ss ss sO*}",
- "api", api, "verb", verb, "args", args);
+ hook_api(closure, hookid, export, "new_api.after", "{si ss}",
+ "status", result, "api", api);
}
-static void hook_svc_call_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result)
+static void hook_api_api_set_verbs_v2(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v2 *verbs)
{
- hook_svc(closure, hookid, export, "call_result", "{si sO*}",
- "status", status, "result", result);
+ hook_api(closure, hookid, export, "set_verbs_v2", "{si}", "status", result);
}
-static void hook_svc_callsync(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
+static void hook_api_api_set_verbs_v3(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v3 *verbs)
{
- hook_svc(closure, hookid, export, "callsync", "{ss ss sO*}",
- "api", api, "verb", verb, "args", args);
+ hook_api(closure, hookid, export, "set_verbs_v3", "{si}", "status", result);
+}
+
+
+static void hook_api_api_add_verb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb, const char *info, int glob)
+{
+ hook_api(closure, hookid, export, "add_verb", "{si ss ss? sb}", "status", result, "verb", verb, "info", info, "glob", glob);
+}
+
+static void hook_api_api_del_verb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb)
+{
+ hook_api(closure, hookid, export, "del_verb", "{si ss}", "status", result, "verb", verb);
+}
+
+static void hook_api_api_set_on_event(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
+{
+ hook_api(closure, hookid, export, "set_on_event", "{si}", "status", result);
}
-static void hook_svc_callsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result)
+static void hook_api_api_set_on_init(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
{
- hook_svc(closure, hookid, export, "callsync_result", "{si sO*}",
- "status", status, "result", result);
+ hook_api(closure, hookid, export, "set_on_init", "{si}", "status", result);
}
-static struct afb_hook_svc_itf hook_svc_itf = {
- .hook_svc_start_before = hook_svc_start_before,
- .hook_svc_start_after = hook_svc_start_after,
- .hook_svc_on_event_before = hook_svc_on_event_before,
- .hook_svc_on_event_after = hook_svc_on_event_after,
- .hook_svc_call = hook_svc_call,
- .hook_svc_call_result = hook_svc_call_result,
- .hook_svc_callsync = hook_svc_callsync,
- .hook_svc_callsync_result = hook_svc_callsync_result
+static void hook_api_api_seal(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
+{
+ hook_api(closure, hookid, export, "seal", NULL);
+}
+
+static void hook_api_event_handler_add(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern)
+{
+ hook_api(closure, hookid, export, "event_handler_add", "{si ss?}", "status", result, "pattern", pattern);
+}
+
+static void hook_api_event_handler_del(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern)
+{
+ hook_api(closure, hookid, export, "event_handler_del", "{si ss?}", "status", result, "pattern", pattern);
+}
+
+static void hook_api_class_provide(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name)
+{
+ hook_api(closure, hookid, export, "class_provide", "{si ss?}", "status", result, "name", name);
+}
+
+static void hook_api_class_require(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name)
+{
+ hook_api(closure, hookid, export, "class_require", "{si ss?}", "status", result, "name", name);
+}
+
+static void hook_api_delete_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
+{
+ hook_api(closure, hookid, export, "delete_api", "{si}", "status", result);
+}
+
+static struct afb_hook_api_itf hook_api_itf = {
+ .hook_api_event_broadcast_before = hook_api_event_broadcast_before,
+ .hook_api_event_broadcast_after = hook_api_event_broadcast_after,
+ .hook_api_get_event_loop = hook_api_get_event_loop,
+ .hook_api_get_user_bus = hook_api_get_user_bus,
+ .hook_api_get_system_bus = hook_api_get_system_bus,
+ .hook_api_vverbose = hook_api_vverbose,
+ .hook_api_event_make = hook_api_event_make,
+ .hook_api_rootdir_get_fd = hook_api_rootdir_get_fd,
+ .hook_api_rootdir_open_locale = hook_api_rootdir_open_locale,
+ .hook_api_queue_job = hook_api_queue_job,
+ .hook_api_legacy_unstore_req = hook_api_unstore_req,
+ .hook_api_require_api = hook_api_require_api,
+ .hook_api_require_api_result = hook_api_require_api_result,
+ .hook_api_add_alias = hook_api_add_alias_cb,
+ .hook_api_start_before = hook_api_start_before,
+ .hook_api_start_after = hook_api_start_after,
+ .hook_api_on_event_before = hook_api_on_event_before,
+ .hook_api_on_event_after = hook_api_on_event_after,
+ .hook_api_call = hook_api_call,
+ .hook_api_call_result = hook_api_call_result,
+ .hook_api_callsync = hook_api_callsync,
+ .hook_api_callsync_result = hook_api_callsync_result,
+ .hook_api_new_api_before = hook_api_new_api_before,
+ .hook_api_new_api_after = hook_api_new_api_after,
+ .hook_api_api_set_verbs_v2 = hook_api_api_set_verbs_v2,
+ .hook_api_api_set_verbs_v3 = hook_api_api_set_verbs_v3,
+ .hook_api_api_add_verb = hook_api_api_add_verb,
+ .hook_api_api_del_verb = hook_api_api_del_verb,
+ .hook_api_api_set_on_event = hook_api_api_set_on_event,
+ .hook_api_api_set_on_init = hook_api_api_set_on_init,
+ .hook_api_api_seal = hook_api_api_seal,
+ .hook_api_event_handler_add = hook_api_event_handler_add,
+ .hook_api_event_handler_del = hook_api_event_handler_del,
+ .hook_api_class_provide = hook_api_class_provide,
+ .hook_api_class_require = hook_api_class_require,
+ .hook_api_delete_api = hook_api_delete_api,
};
/*******************************************************************************/
@@ -1016,17 +1129,11 @@ abstracting[Trace_Type_Count] =
.unref = (void(*)(void*))afb_hook_unref_xreq,
.get_flag = get_xreq_flag
},
- [Trace_Type_Ditf] =
- {
- .name = "daemon",
- .unref = (void(*)(void*))afb_hook_unref_ditf,
- .get_flag = get_ditf_flag
- },
- [Trace_Type_Svc] =
+ [Trace_Type_Api] =
{
- .name = "service",
- .unref = (void(*)(void*))afb_hook_unref_svc,
- .get_flag = get_svc_flag
+ .name = "api",
+ .unref = (void(*)(void*))afb_hook_unref_api,
+ .get_flag = get_api_flag
},
[Trace_Type_Evt] =
{
@@ -1046,6 +1153,20 @@ abstracting[Trace_Type_Count] =
.unref = (void(*)(void*))afb_hook_unref_global,
.get_flag = get_global_flag
},
+#if !defined(REMOVE_LEGACY_TRACE)
+ [Trace_Legacy_Type_Ditf] =
+ {
+ .name = "daemon",
+ .unref = (void(*)(void*))afb_hook_unref_api,
+ .get_flag = get_legacy_ditf_flag
+ },
+ [Trace_Legacy_Type_Svc] =
+ {
+ .name = "service",
+ .unref = (void(*)(void*))afb_hook_unref_api,
+ .get_flag = get_legacy_svc_flag
+ },
+#endif
};
/*******************************************************************************/
@@ -1242,7 +1363,7 @@ static void trace_attach_hook(struct afb_trace *trace, struct hook *hook, enum t
struct context
{
struct afb_trace *trace;
- struct afb_req req;
+ afb_req_t req;
char *errors;
};
@@ -1252,13 +1373,12 @@ struct desc
const char *name;
const char *tag;
const char *uuid;
- const char *api;
- const char *verb;
+ const char *apiname;
+ const char *verbname;
const char *pattern;
int flags[Trace_Type_Count];
};
-
static void addhook(struct desc *desc, enum trace_type type)
{
struct hook *hook;
@@ -1299,15 +1419,12 @@ static void addhook(struct desc *desc, enum trace_type type)
return;
}
}
- hook->handler = afb_hook_create_xreq(desc->api, desc->verb, session,
+ hook->handler = afb_hook_create_xreq(desc->apiname, desc->verbname, session,
desc->flags[type], &hook_xreq_itf, hook);
afb_session_unref(session);
break;
- case Trace_Type_Ditf:
- hook->handler = afb_hook_create_ditf(desc->api, desc->flags[type], &hook_ditf_itf, hook);
- break;
- case Trace_Type_Svc:
- hook->handler = afb_hook_create_svc(desc->api, desc->flags[type], &hook_svc_itf, hook);
+ case Trace_Type_Api:
+ hook->handler = afb_hook_create_api(desc->apiname, desc->flags[type], &hook_api_itf, hook);
break;
case Trace_Type_Evt:
hook->handler = afb_hook_create_evt(desc->pattern, desc->flags[type], &hook_evt_itf, hook);
@@ -1328,7 +1445,7 @@ static void addhook(struct desc *desc, enum trace_type type)
}
/* attach and activate the hook */
- afb_req_subscribe(desc->context->req, afb_evt_event_from_evtid(hook->event->evtid));
+ afb_req_subscribe(desc->context->req, afb_evt_event_x2_from_evtid(hook->event->evtid));
trace_attach_hook(trace, hook, type);
}
@@ -1336,6 +1453,11 @@ static void addhooks(struct desc *desc)
{
int i;
+#if !defined(REMOVE_LEGACY_TRACE)
+ desc->flags[Trace_Type_Api] |= desc->flags[Trace_Legacy_Type_Ditf] | desc->flags[Trace_Legacy_Type_Svc];
+ desc->flags[Trace_Legacy_Type_Ditf] = desc->flags[Trace_Legacy_Type_Svc] = 0;
+#endif
+
for (i = 0 ; i < Trace_Type_Count ; i++) {
if (desc->flags[i])
addhook(desc, i);
@@ -1368,14 +1490,21 @@ static void add_xreq_flags(void *closure, struct json_object *object)
add_flags(closure, object, Trace_Type_Xreq);
}
-static void add_ditf_flags(void *closure, struct json_object *object)
+#if !defined(REMOVE_LEGACY_TRACE)
+static void legacy_add_ditf_flags(void *closure, struct json_object *object)
+{
+ add_flags(closure, object, Trace_Legacy_Type_Ditf);
+}
+
+static void legacy_add_svc_flags(void *closure, struct json_object *object)
{
- add_flags(closure, object, Trace_Type_Ditf);
+ add_flags(closure, object, Trace_Legacy_Type_Svc);
}
+#endif
-static void add_svc_flags(void *closure, struct json_object *object)
+static void add_api_flags(void *closure, struct json_object *object)
{
- add_flags(closure, object, Trace_Type_Svc);
+ add_flags(closure, object, Trace_Type_Api);
}
static void add_evt_flags(void *closure, struct json_object *object)
@@ -1398,21 +1527,30 @@ static void add(void *closure, struct json_object *object)
{
int rc;
struct desc desc;
- struct json_object *request, *event, *daemon, *service, *sub, *global, *session;
+ struct json_object *request, *event, *sub, *global, *session, *api;
+#if !defined(REMOVE_LEGACY_TRACE)
+ struct json_object *daemon, *service;
+#endif
memcpy (&desc, closure, sizeof desc);
- request = event = daemon = service = sub = global = session = NULL;
+ request = event = sub = global = session = api = NULL;
+#if !defined(REMOVE_LEGACY_TRACE)
+ daemon = service = NULL;
+#endif
- rc = wrap_json_unpack(object, "{s?s s?s s?s s?s s?s s?s s?o s?o s?o s?o s?o s?o}",
+ rc = wrap_json_unpack(object, "{s?s s?s s?s s?s s?s s?s s?o s?o s?o s?o s?o s?o s?o}",
"name", &desc.name,
"tag", &desc.tag,
- "api", &desc.api,
- "verb", &desc.verb,
+ "apiname", &desc.apiname,
+ "verbname", &desc.verbname,
"uuid", &desc.uuid,
"pattern", &desc.pattern,
+ "api", &api,
"request", &request,
+#if !defined(REMOVE_LEGACY_TRACE)
"daemon", &daemon,
"service", &service,
+#endif
"event", &event,
"session", &session,
"global", &global,
@@ -1420,11 +1558,11 @@ static void add(void *closure, struct json_object *object)
if (!rc) {
/* replace stars */
- if (desc.api && desc.api[0] == '*' && !desc.api[1])
- desc.api = NULL;
+ if (desc.apiname && desc.apiname[0] == '*' && !desc.apiname[1])
+ desc.apiname = NULL;
- if (desc.verb && desc.verb[0] == '*' && !desc.verb[1])
- desc.verb = NULL;
+ if (desc.verbname && desc.verbname[0] == '*' && !desc.verbname[1])
+ desc.verbname = NULL;
if (desc.uuid && desc.uuid[0] == '*' && !desc.uuid[1])
desc.uuid = NULL;
@@ -1433,11 +1571,16 @@ static void add(void *closure, struct json_object *object)
if (request)
wrap_json_optarray_for_all(request, add_xreq_flags, &desc);
+ if (api)
+ wrap_json_optarray_for_all(api, add_api_flags, &desc);
+
+#if !defined(REMOVE_LEGACY_TRACE)
if (daemon)
- wrap_json_optarray_for_all(daemon, add_ditf_flags, &desc);
+ wrap_json_optarray_for_all(daemon, legacy_add_ditf_flags, &desc);
if (service)
- wrap_json_optarray_for_all(service, add_svc_flags, &desc);
+ wrap_json_optarray_for_all(service, legacy_add_svc_flags, &desc);
+#endif
if (event)
wrap_json_optarray_for_all(event, add_evt_flags, &desc);
@@ -1562,7 +1705,7 @@ void afb_trace_unref(struct afb_trace *trace)
}
/* add traces */
-int afb_trace_add(struct afb_req req, struct json_object *args, struct afb_trace *trace)
+int afb_trace_add(afb_req_t req, struct json_object *args, struct afb_trace *trace)
{
struct context context;
struct desc desc;
@@ -1587,7 +1730,7 @@ int afb_trace_add(struct afb_req req, struct json_object *args, struct afb_trace
}
/* drop traces */
-extern int afb_trace_drop(struct afb_req req, struct json_object *args, struct afb_trace *trace)
+extern int afb_trace_drop(afb_req_t req, struct json_object *args, struct afb_trace *trace)
{
int rc;
struct context context;
diff --git a/src/afb-trace.h b/src/afb-trace.h
index 5056fb25..0371546f 100644
--- a/src/afb-trace.h
+++ b/src/afb-trace.h
@@ -25,7 +25,7 @@ extern struct afb_trace *afb_trace_create(const char *api, struct afb_session *b
extern void afb_trace_addref(struct afb_trace *trace);
extern void afb_trace_unref(struct afb_trace *trace);
-extern int afb_trace_add(struct afb_req req, struct json_object *args, struct afb_trace *trace);
-extern int afb_trace_drop(struct afb_req req, struct json_object *args, struct afb_trace *trace);
+extern int afb_trace_add(afb_req_t req, struct json_object *args, struct afb_trace *trace);
+extern int afb_trace_drop(afb_req_t req, struct json_object *args, struct afb_trace *trace);
diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c
index 315bee8e..95167b5f 100644
--- a/src/afb-ws-json1.c
+++ b/src/afb-ws-json1.c
@@ -49,7 +49,7 @@ static void aws_on_event(struct afb_ws_json1 *ws, const char *event, int eventid
/* predeclaration of wsreq callbacks */
static void wsreq_destroy(struct afb_xreq *xreq);
-static void wsreq_reply(struct afb_xreq *xreq, int status, json_object *obj);
+static void wsreq_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info);
/* declaration of websocket structure */
struct afb_ws_json1
@@ -194,8 +194,8 @@ static void aws_on_call(struct afb_ws_json1 *ws, const char *api, const char *ve
afb_wsj1_msg_addref(msg);
wsreq->msgj1 = msg;
wsreq->xreq.cred = afb_cred_addref(ws->cred);
- wsreq->xreq.request.api = api;
- wsreq->xreq.request.verb = verb;
+ wsreq->xreq.request.called_api = api;
+ wsreq->xreq.request.called_verb = verb;
wsreq->xreq.json = afb_wsj1_msg_object_j(wsreq->msgj1);
wsreq->aws = afb_ws_json1_addref(ws);
wsreq->xreq.listener = wsreq->aws->listener;
@@ -228,13 +228,17 @@ static void wsreq_destroy(struct afb_xreq *xreq)
free(wsreq);
}
-static void wsreq_reply(struct afb_xreq *xreq, int status, json_object *obj)
+static void wsreq_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
{
struct afb_wsreq *wsreq = CONTAINER_OF_XREQ(struct afb_wsreq, xreq);
int rc;
+ struct json_object *reply;
- rc = (status < 0 ? afb_wsj1_reply_error_j : afb_wsj1_reply_ok_j)(
- wsreq->msgj1, obj, afb_context_sent_token(&wsreq->xreq.context));
+ /* create the reply */
+ reply = afb_msg_json_reply(object, error, info, &xreq->context);
+
+ rc = (error ? afb_wsj1_reply_error_j : afb_wsj1_reply_ok_j)(
+ wsreq->msgj1, reply, afb_context_sent_token(&wsreq->xreq.context));
if (rc)
ERROR("Can't send reply: %m");
}
diff --git a/src/afb-xreq.c b/src/afb-xreq.c
index 582e9b72..8f246b3c 100644
--- a/src/afb-xreq.c
+++ b/src/afb-xreq.c
@@ -21,22 +21,26 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
+#include <stdarg.h>
#include <json-c/json.h>
+
#include <afb/afb-binding-v1.h>
#include <afb/afb-binding-v2.h>
-#include <afb/afb-request.h>
+#include <afb/afb-binding-v3.h>
+#include <afb/afb-req-x2.h>
+#include "afb-api.h"
+#include "afb-apiset.h"
+#include "afb-auth.h"
+#include "afb-calls.h"
#include "afb-context.h"
-#include "afb-xreq.h"
#include "afb-evt.h"
-#include "afb-msg-json.h"
#include "afb-cred.h"
#include "afb-hook.h"
-#include "afb-api.h"
-#include "afb-api-dyn.h"
-#include "afb-apiset.h"
-#include "afb-auth.h"
+#include "afb-msg-json.h"
+#include "afb-xreq.h"
+
#include "jobs.h"
#include "verbose.h"
@@ -45,7 +49,7 @@
static void xreq_finalize(struct afb_xreq *xreq)
{
if (!xreq->replied)
- afb_xreq_fail(xreq, "error", "no reply");
+ afb_xreq_reply(xreq, NULL, "error", "no reply");
if (xreq->hookflags)
afb_hook_xreq_end(xreq);
if (xreq->caller)
@@ -66,274 +70,22 @@ inline void afb_xreq_unhooked_unref(struct afb_xreq *xreq)
/******************************************************************************/
-struct subcall
-{
- struct afb_xreq xreq;
-
- void (*completion)(struct subcall*, int, struct json_object*);
-
- union {
- struct {
- struct jobloop *jobloop;
- struct json_object *result;
- int status;
- };
- struct {
- union {
- void (*callback)(void*, int, struct json_object*);
- void (*callback_req)(void*, int, struct json_object*, struct afb_req);
- void (*callback_request)(void*, int, struct json_object*, struct afb_request*);
- };
- void *closure;
- };
- };
-};
-
-static int subcall_subscribe_cb(struct afb_xreq *xreq, struct afb_eventid *eventid)
-{
- struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
-
- return afb_xreq_subscribe(subcall->xreq.caller, eventid);
-}
-
-static int subcall_unsubscribe_cb(struct afb_xreq *xreq, struct afb_eventid *eventid)
-{
- struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
-
- return afb_xreq_unsubscribe(subcall->xreq.caller, eventid);
-}
-
-static void subcall_reply_cb(struct afb_xreq *xreq, int status, struct json_object *result)
-{
- struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
-
- subcall->completion(subcall, status, result);
- json_object_put(result);
- afb_xreq_unhooked_unref(&subcall->xreq);
-}
-
-static void subcall_destroy_cb(struct afb_xreq *xreq)
-{
- struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
-
- json_object_put(subcall->xreq.json);
- afb_cred_unref(subcall->xreq.cred);
- free(subcall);
-}
-
-const struct afb_xreq_query_itf afb_xreq_subcall_itf = {
- .reply = subcall_reply_cb,
- .unref = subcall_destroy_cb,
- .subscribe = subcall_subscribe_cb,
- .unsubscribe = subcall_unsubscribe_cb
-};
-
-static struct subcall *subcall_alloc(
- struct afb_xreq *caller,
- const char *api,
- const char *verb,
- struct json_object *args
-)
-{
- struct subcall *subcall;
- size_t lenapi, lenverb;
- char *copy;
-
- lenapi = 1 + strlen(api);
- lenverb = 1 + strlen(verb);
- subcall = malloc(lenapi + lenverb + sizeof *subcall);
- if (!subcall)
- ERROR("out of memory");
- else {
- copy = (char*)&subcall[1];
- memcpy(copy, api, lenapi);
- api = copy;
- copy = &copy[lenapi];
- memcpy(copy, verb, lenverb);
- verb = copy;
-
- afb_xreq_init(&subcall->xreq, &afb_xreq_subcall_itf);
- afb_context_subinit(&subcall->xreq.context, &caller->context);
- subcall->xreq.cred = afb_cred_addref(caller->cred);
- subcall->xreq.json = args;
- subcall->xreq.request.api = api;
- subcall->xreq.request.verb = verb;
- subcall->xreq.caller = caller;
- afb_xreq_unhooked_addref(caller);
- }
- return subcall;
-}
-
-
-static void subcall_on_reply(struct subcall *subcall, int status, struct json_object *result)
-{
- subcall->callback(subcall->closure, status, result);
-}
-
-static void subcall_req_on_reply(struct subcall *subcall, int status, struct json_object *result)
-{
- subcall->callback_req(subcall->closure, status, result, xreq_to_req(subcall->xreq.caller));
-}
-
-static void subcall_request_on_reply(struct subcall *subcall, int status, struct json_object *result)
-{
- subcall->callback_request(subcall->closure, status, result, xreq_to_request(subcall->xreq.caller));
-}
-
-static void subcall_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result)
-{
- afb_hook_xreq_subcall_result(subcall->xreq.caller, status, result);
- subcall_on_reply(subcall, status, result);
-}
-
-static void subcall_req_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result)
-{
- afb_hook_xreq_subcall_req_result(subcall->xreq.caller, status, result);
- subcall_req_on_reply(subcall, status, result);
-}
-
-static void subcall_request_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result)
-{
- afb_hook_xreq_subcall_result(subcall->xreq.caller, status, result);
- subcall_request_on_reply(subcall, status, result);
-}
-
-static void subcall_reply_direct_cb(void *closure, int status, struct json_object *result)
+struct json_object *afb_xreq_unhooked_json(struct afb_xreq *xreq)
{
- struct afb_xreq *xreq = closure;
-
- if (xreq->replied) {
- ERROR("subcall replied more than one time!!");
- json_object_put(result);
- } else {
- xreq->replied = 1;
- subcall_reply_cb(xreq, status, result);
- }
-}
-
-static void subcall_process(struct subcall *subcall, void (*completion)(struct subcall*, int, struct json_object*))
-{
- subcall->completion = completion;
- if (subcall->xreq.caller->queryitf->subcall) {
- subcall->xreq.caller->queryitf->subcall(
- subcall->xreq.caller, subcall->xreq.request.api, subcall->xreq.request.verb,
- subcall->xreq.json, subcall_reply_direct_cb, &subcall->xreq);
- } else {
- afb_xreq_unhooked_addref(&subcall->xreq);
- afb_xreq_process(&subcall->xreq, subcall->xreq.caller->apiset);
- }
-}
-
-static void subcall(struct subcall *subcall, void (*callback)(void*, int, struct json_object*), void *cb_closure)
-{
- subcall->callback = callback;
- subcall->closure = cb_closure;
- subcall_process(subcall, subcall_on_reply);
-}
-
-static void subcall_req(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure)
-{
- subcall->callback_req = callback;
- subcall->closure = cb_closure;
- subcall_process(subcall, subcall_req_on_reply);
-}
-
-static void subcall_request(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure)
-{
- subcall->callback_request = callback;
- subcall->closure = cb_closure;
- subcall_process(subcall, subcall_request_on_reply);
-}
-
-static void subcall_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*), void *cb_closure)
-{
- subcall->callback = callback;
- subcall->closure = cb_closure;
- subcall_process(subcall, subcall_hooked_on_reply);
-}
-
-static void subcall_req_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure)
-{
- subcall->callback_req = callback;
- subcall->closure = cb_closure;
- subcall_process(subcall, subcall_req_hooked_on_reply);
-}
-
-static void subcall_request_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure)
-{
- subcall->callback_request = callback;
- subcall->closure = cb_closure;
- subcall_process(subcall, subcall_request_hooked_on_reply);
-}
-
-static void subcall_sync_leave(struct subcall *subcall)
-{
- struct jobloop *jobloop = __atomic_exchange_n(&subcall->jobloop, NULL, __ATOMIC_RELAXED);
- if (jobloop)
- jobs_leave(jobloop);
-}
-
-static void subcall_sync_reply(struct subcall *subcall, int status, struct json_object *result)
-{
- subcall->status = status;
- subcall->result = json_object_get(result);
- subcall_sync_leave(subcall);
-}
-
-static void subcall_sync_enter(int signum, void *closure, struct jobloop *jobloop)
-{
- struct subcall *subcall = closure;
-
- if (!signum) {
- subcall->jobloop = jobloop;
- subcall->result = NULL;
- subcall->status = 0;
- subcall_process(subcall, subcall_sync_reply);
- } else {
- subcall->status = -1;
- subcall_sync_leave(subcall);
- }
-}
-
-static int subcallsync(struct subcall *subcall, struct json_object **result)
-{
- int rc;
-
- afb_xreq_unhooked_addref(&subcall->xreq);
- rc = jobs_enter(NULL, 0, subcall_sync_enter, subcall);
- *result = subcall->result;
- if (rc < 0 || subcall->status < 0) {
- *result = *result ?: afb_msg_json_internal_error();
- rc = -1;
- }
- afb_xreq_unhooked_unref(&subcall->xreq);
- return rc;
-}
-
-/******************************************************************************/
-
-static void vinfo(void *first, void *second, const char *fmt, va_list args, void (*fun)(void*,void*,const char*))
-{
- char *info;
- if (fmt == NULL || vasprintf(&info, fmt, args) < 0)
- info = NULL;
- fun(first, second, info);
- free(info);
-}
-
-/******************************************************************************/
-
-static struct json_object *xreq_json_cb(struct afb_request *closure)
-{
- struct afb_xreq *xreq = xreq_from_request(closure);
if (!xreq->json && xreq->queryitf->json)
xreq->json = xreq->queryitf->json(xreq);
return xreq->json;
}
-static struct afb_arg xreq_get_cb(struct afb_request *closure, const char *name)
+static struct json_object *xreq_json_cb(struct afb_req_x2 *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ return afb_xreq_unhooked_json(xreq);
+}
+
+static struct afb_arg xreq_get_cb(struct afb_req_x2 *closure, const char *name)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
struct afb_arg arg;
struct json_object *object, *value;
@@ -353,409 +105,388 @@ static struct afb_arg xreq_get_cb(struct afb_request *closure, const char *name)
return arg;
}
-static void xreq_success_cb(struct afb_request *closure, struct json_object *obj, const char *info)
+static void xreq_reply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *info)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
if (xreq->replied) {
ERROR("reply called more than one time!!");
json_object_put(obj);
} else {
xreq->replied = 1;
- if (xreq->queryitf->success)
- xreq->queryitf->success(xreq, obj, info);
- else
- xreq->queryitf->reply(xreq, 0, afb_msg_json_reply_ok(info, obj, &xreq->context, NULL));
+ xreq->queryitf->reply(xreq, obj, error, info);
}
}
-static void xreq_fail_cb(struct afb_request *closure, const char *status, const char *info)
+static void xreq_vreply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *fmt, va_list args)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ char *info;
+ if (fmt == NULL || vasprintf(&info, fmt, args) < 0)
+ info = NULL;
+ xreq_reply_cb(closure, obj, error, info);
+ free(info);
+}
- if (xreq->replied) {
- ERROR("reply called more than one time!!");
- } else {
- xreq->replied = 1;
- if (xreq->queryitf->fail)
- xreq->queryitf->fail(xreq, status, info);
- else
- xreq->queryitf->reply(xreq, -1, afb_msg_json_reply_error(status, info, &xreq->context, NULL));
- }
+static void xreq_legacy_success_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *info)
+{
+ xreq_reply_cb(closure, obj, NULL, info);
}
-static void xreq_vsuccess_cb(struct afb_request *closure, struct json_object *obj, const char *fmt, va_list args)
+static void xreq_legacy_fail_cb(struct afb_req_x2 *closure, const char *status, const char *info)
{
- vinfo(closure, obj, fmt, args, (void*)xreq_success_cb);
+ xreq_reply_cb(closure, NULL, status, info);
}
-static void xreq_vfail_cb(struct afb_request *closure, const char *status, const char *fmt, va_list args)
+static void xreq_legacy_vsuccess_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *fmt, va_list args)
{
- vinfo(closure, (void*)status, fmt, args, (void*)xreq_fail_cb);
+ xreq_vreply_cb(closure, obj, NULL, fmt, args);
}
-static void *xreq_context_get_cb(struct afb_request *closure)
+static void xreq_legacy_vfail_cb(struct afb_req_x2 *closure, const char *status, const char *fmt, va_list args)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ xreq_vreply_cb(closure, NULL, status, fmt, args);
+}
+
+static void *xreq_legacy_context_get_cb(struct afb_req_x2 *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
return afb_context_get(&xreq->context);
}
-static void xreq_context_set_cb(struct afb_request *closure, void *value, void (*free_value)(void*))
+static void xreq_legacy_context_set_cb(struct afb_req_x2 *closure, void *value, void (*free_value)(void*))
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
afb_context_set(&xreq->context, value, free_value);
}
-static struct afb_request *xreq_addref_cb(struct afb_request *closure)
+static struct afb_req_x2 *xreq_addref_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
afb_xreq_unhooked_addref(xreq);
return closure;
}
-static void xreq_unref_cb(struct afb_request *closure)
+static void xreq_unref_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
afb_xreq_unhooked_unref(xreq);
}
-static void xreq_session_close_cb(struct afb_request *closure)
+static void xreq_session_close_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
afb_context_close(&xreq->context);
}
-static int xreq_session_set_LOA_cb(struct afb_request *closure, unsigned level)
+static int xreq_session_set_LOA_cb(struct afb_req_x2 *closure, unsigned level)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
return afb_context_change_loa(&xreq->context, level);
}
-static int xreq_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid);
-static int xreq_subscribe_cb(struct afb_request *closure, struct afb_event event)
+static int xreq_subscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event)
{
- return xreq_subscribe_eventid_cb(closure, afb_event_to_eventid(event));
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ return afb_xreq_subscribe(xreq, event);
}
-static int xreq_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid)
+static int xreq_legacy_subscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- return afb_xreq_subscribe(xreq, eventid);
+ return xreq_subscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event));
}
-int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid)
+int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event)
{
if (xreq->listener)
- return afb_evt_eventid_add_watch(xreq->listener, eventid);
+ return afb_evt_event_x2_add_watch(xreq->listener, event);
if (xreq->queryitf->subscribe)
- return xreq->queryitf->subscribe(xreq, eventid);
+ return xreq->queryitf->subscribe(xreq, event);
ERROR("no event listener, subscription impossible");
errno = EINVAL;
return -1;
}
-static int xreq_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid);
-static int xreq_unsubscribe_cb(struct afb_request *closure, struct afb_event event)
+static int xreq_unsubscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event)
{
- return xreq_unsubscribe_eventid_cb(closure, afb_event_to_eventid(event));
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ return afb_xreq_unsubscribe(xreq, event);
}
-static int xreq_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid)
+static int xreq_legacy_unsubscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- return afb_xreq_unsubscribe(xreq, eventid);
+ return xreq_unsubscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event));
}
-int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid)
+int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event)
{
if (xreq->listener)
- return afb_evt_eventid_remove_watch(xreq->listener, eventid);
+ return afb_evt_event_x2_remove_watch(xreq->listener, event);
if (xreq->queryitf->unsubscribe)
- return xreq->queryitf->unsubscribe(xreq, eventid);
+ return xreq->queryitf->unsubscribe(xreq, event);
ERROR("no event listener, unsubscription impossible");
errno = EINVAL;
return -1;
}
-static void xreq_subcall_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
+static void xreq_legacy_subcall_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- struct subcall *sc;
-
- sc = subcall_alloc(xreq, api, verb, args);
- if (sc == NULL) {
- if (callback)
- callback(cb_closure, 1, afb_msg_json_internal_error());
- json_object_put(args);
- } else {
- subcall(sc, callback, cb_closure);
- }
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ return afb_calls_legacy_subcall_v1(xreq, api, verb, args, callback, closure);
}
-static void xreq_subcall_req_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure)
+static void xreq_legacy_subcall_req_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x1), void *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- struct subcall *sc;
-
- sc = subcall_alloc(xreq, api, verb, args);
- if (sc == NULL) {
- if (callback)
- callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_req(xreq));
- json_object_put(args);
- } else {
- subcall_req(sc, callback, cb_closure);
- }
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ return afb_calls_legacy_subcall_v2(xreq, api, verb, args, callback, closure);
}
-static void xreq_subcall_request_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure)
+static void xreq_legacy_subcall_request_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2*), void *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- struct subcall *sc;
-
- sc = subcall_alloc(xreq, api, verb, args);
- if (sc == NULL) {
- if (callback)
- callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_request(xreq));
- json_object_put(args);
- } else {
- subcall_request(sc, callback, cb_closure);
- }
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ return afb_calls_legacy_subcall_v3(xreq, api, verb, args, callback, closure);
}
-static int xreq_subcallsync_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result)
+static int xreq_legacy_subcallsync_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, struct json_object **result)
{
- int rc;
- struct subcall *sc;
- struct afb_xreq *xreq = xreq_from_request(closure);
- struct json_object *resu;
-
- sc = subcall_alloc(xreq, api, verb, args);
- if (!sc) {
- rc = -1;
- resu = afb_msg_json_internal_error();
- json_object_put(args);
- } else {
- rc = subcallsync(sc, &resu);
- }
- if (result)
- *result = resu;
- else
- json_object_put(resu);
- return rc;
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ return afb_calls_legacy_subcall_sync(xreq, api, verb, args, result);
}
-static void xreq_vverbose_cb(struct afb_request *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
+static void xreq_vverbose_cb(struct afb_req_x2 *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
{
char *p;
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
if (!fmt || vasprintf(&p, fmt, args) < 0)
vverbose(level, file, line, func, fmt, args);
else {
- verbose(level, file, line, func, "[REQ/API %s] %s", xreq->request.api, p);
+ verbose(level, file, line, func, "[REQ/API %s] %s", xreq->request.called_api, p);
free(p);
}
}
-static struct afb_stored_req *xreq_store_cb(struct afb_request *closure)
+static struct afb_stored_req *xreq_legacy_store_cb(struct afb_req_x2 *closure)
{
xreq_addref_cb(closure);
return (struct afb_stored_req*)closure;
}
-static int xreq_has_permission_cb(struct afb_request *closure, const char *permission)
+static int xreq_has_permission_cb(struct afb_req_x2 *closure, const char *permission)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
return afb_auth_has_permission(xreq, permission);
}
-static char *xreq_get_application_id_cb(struct afb_request *closure)
+static char *xreq_get_application_id_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
return xreq->cred && xreq->cred->id ? strdup(xreq->cred->id) : NULL;
}
-static void *xreq_context_make_cb(struct afb_request *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure)
+static void *xreq_context_make_cb(struct afb_req_x2 *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
return afb_context_make(&xreq->context, replace, create_value, free_value, create_closure);
}
-static int xreq_get_uid_cb(struct afb_request *closure)
+static int xreq_get_uid_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
return xreq->cred && xreq->cred->id ? (int)xreq->cred->uid : -1;
}
+static struct json_object *xreq_get_client_info_cb(struct afb_req_x2 *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ struct json_object *r = json_object_new_object();
+ if (xreq->cred && xreq->cred->id) {
+ json_object_object_add(r, "uid", json_object_new_int(xreq->cred->uid));
+ json_object_object_add(r, "gid", json_object_new_int(xreq->cred->gid));
+ json_object_object_add(r, "pid", json_object_new_int(xreq->cred->pid));
+ json_object_object_add(r, "user", json_object_new_string(xreq->cred->user));
+ json_object_object_add(r, "label", json_object_new_string(xreq->cred->label));
+ json_object_object_add(r, "id", json_object_new_string(xreq->cred->id));
+ }
+ if (xreq->context.session) {
+ json_object_object_add(r, "uuid", json_object_new_string(afb_context_uuid(&xreq->context)));
+ json_object_object_add(r, "LOA", json_object_new_int(afb_context_get_loa(&xreq->context)));
+ }
+ return r;
+}
+
+static void xreq_subcall_cb(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
+ void *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ afb_calls_subcall(xreq, api, verb, args, flags, callback, closure);
+}
+
+static int xreq_subcallsync_cb(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct json_object **object,
+ char **error,
+ char **info)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ return afb_calls_subcall_sync(xreq, api, verb, args, flags, object, error, info);
+}
+
/******************************************************************************/
-static struct json_object *xreq_hooked_json_cb(struct afb_request *closure)
+static struct json_object *xreq_hooked_json_cb(struct afb_req_x2 *closure)
{
struct json_object *r = xreq_json_cb(closure);
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
return afb_hook_xreq_json(xreq, r);
}
-static struct afb_arg xreq_hooked_get_cb(struct afb_request *closure, const char *name)
+static struct afb_arg xreq_hooked_get_cb(struct afb_req_x2 *closure, const char *name)
{
struct afb_arg r = xreq_get_cb(closure, name);
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
return afb_hook_xreq_get(xreq, name, r);
}
-static void xreq_hooked_success_cb(struct afb_request *closure, struct json_object *obj, const char *info)
+static void xreq_hooked_reply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *info)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ afb_hook_xreq_reply(xreq, obj, error, info);
+ xreq_reply_cb(closure, obj, error, info);
+}
+
+static void xreq_hooked_vreply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *fmt, va_list args)
+{
+ char *info;
+ if (fmt == NULL || vasprintf(&info, fmt, args) < 0)
+ info = NULL;
+ xreq_hooked_reply_cb(closure, obj, error, info);
+ free(info);
+}
+
+static void xreq_hooked_legacy_success_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *info)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- afb_hook_xreq_success(xreq, obj, info);
- xreq_success_cb(closure, obj, info);
+ xreq_hooked_reply_cb(closure, obj, NULL, info);
}
-static void xreq_hooked_fail_cb(struct afb_request *closure, const char *status, const char *info)
+static void xreq_hooked_legacy_fail_cb(struct afb_req_x2 *closure, const char *status, const char *info)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- afb_hook_xreq_fail(xreq, status, info);
- xreq_fail_cb(closure, status, info);
+ xreq_hooked_reply_cb(closure, NULL, status, info);
}
-static void xreq_hooked_vsuccess_cb(struct afb_request *closure, struct json_object *obj, const char *fmt, va_list args)
+static void xreq_hooked_legacy_vsuccess_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *fmt, va_list args)
{
- vinfo(closure, obj, fmt, args, (void*)xreq_hooked_success_cb);
+ xreq_hooked_vreply_cb(closure, obj, NULL, fmt, args);
}
-static void xreq_hooked_vfail_cb(struct afb_request *closure, const char *status, const char *fmt, va_list args)
+static void xreq_hooked_legacy_vfail_cb(struct afb_req_x2 *closure, const char *status, const char *fmt, va_list args)
{
- vinfo(closure, (void*)status, fmt, args, (void*)xreq_hooked_fail_cb);
+ xreq_hooked_vreply_cb(closure, NULL, status, fmt, args);
}
-static void *xreq_hooked_context_get_cb(struct afb_request *closure)
+static void *xreq_hooked_legacy_context_get_cb(struct afb_req_x2 *closure)
{
- void *r = xreq_context_get_cb(closure);
- struct afb_xreq *xreq = xreq_from_request(closure);
- return afb_hook_xreq_context_get(xreq, r);
+ void *r = xreq_legacy_context_get_cb(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ return afb_hook_xreq_legacy_context_get(xreq, r);
}
-static void xreq_hooked_context_set_cb(struct afb_request *closure, void *value, void (*free_value)(void*))
+static void xreq_hooked_legacy_context_set_cb(struct afb_req_x2 *closure, void *value, void (*free_value)(void*))
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- afb_hook_xreq_context_set(xreq, value, free_value);
- xreq_context_set_cb(closure, value, free_value);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ afb_hook_xreq_legacy_context_set(xreq, value, free_value);
+ xreq_legacy_context_set_cb(closure, value, free_value);
}
-static struct afb_request *xreq_hooked_addref_cb(struct afb_request *closure)
+static struct afb_req_x2 *xreq_hooked_addref_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
afb_hook_xreq_addref(xreq);
return xreq_addref_cb(closure);
}
-static void xreq_hooked_unref_cb(struct afb_request *closure)
+static void xreq_hooked_unref_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
afb_hook_xreq_unref(xreq);
xreq_unref_cb(closure);
}
-static void xreq_hooked_session_close_cb(struct afb_request *closure)
+static void xreq_hooked_session_close_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
afb_hook_xreq_session_close(xreq);
xreq_session_close_cb(closure);
}
-static int xreq_hooked_session_set_LOA_cb(struct afb_request *closure, unsigned level)
+static int xreq_hooked_session_set_LOA_cb(struct afb_req_x2 *closure, unsigned level)
{
int r = xreq_session_set_LOA_cb(closure, level);
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
return afb_hook_xreq_session_set_LOA(xreq, level, r);
}
-static int xreq_hooked_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid);
-static int xreq_hooked_subscribe_cb(struct afb_request *closure, struct afb_event event)
+static int xreq_hooked_subscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event)
{
- return xreq_hooked_subscribe_eventid_cb(closure, afb_event_to_eventid(event));
+ int r = xreq_subscribe_event_x2_cb(closure, event);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ return afb_hook_xreq_subscribe(xreq, event, r);
}
-static int xreq_hooked_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid)
+static int xreq_hooked_legacy_subscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event)
{
- int r = xreq_subscribe_eventid_cb(closure, eventid);
- struct afb_xreq *xreq = xreq_from_request(closure);
- return afb_hook_xreq_subscribe(xreq, eventid, r);
+ return xreq_hooked_subscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event));
}
-static int xreq_hooked_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid);
-static int xreq_hooked_unsubscribe_cb(struct afb_request *closure, struct afb_event event)
+static int xreq_hooked_unsubscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event)
{
- return xreq_hooked_unsubscribe_eventid_cb(closure, afb_event_to_eventid(event));
+ int r = xreq_unsubscribe_event_x2_cb(closure, event);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ return afb_hook_xreq_unsubscribe(xreq, event, r);
}
-static int xreq_hooked_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid)
+static int xreq_hooked_legacy_unsubscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event)
{
- int r = xreq_unsubscribe_eventid_cb(closure, eventid);
- struct afb_xreq *xreq = xreq_from_request(closure);
- return afb_hook_xreq_unsubscribe(xreq, eventid, r);
+ return xreq_hooked_unsubscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event));
}
-static void xreq_hooked_subcall_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
+static void xreq_hooked_legacy_subcall_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- struct subcall *sc;
-
- afb_hook_xreq_subcall(xreq, api, verb, args);
- sc = subcall_alloc(xreq, api, verb, args);
- if (sc == NULL) {
- if (callback)
- callback(cb_closure, 1, afb_msg_json_internal_error());
- json_object_put(args);
- } else {
- subcall_hooked(sc, callback, cb_closure);
- }
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ afb_calls_legacy_hooked_subcall_v1(xreq, api, verb, args, callback, closure);
}
-static void xreq_hooked_subcall_req_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure)
+static void xreq_hooked_legacy_subcall_req_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x1), void *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- struct subcall *sc;
-
- afb_hook_xreq_subcall_req(xreq, api, verb, args);
- sc = subcall_alloc(xreq, api, verb, args);
- if (sc == NULL) {
- if (callback)
- callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_req(xreq));
- json_object_put(args);
- } else {
- subcall_req_hooked(sc, callback, cb_closure);
- }
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ afb_calls_legacy_hooked_subcall_v2(xreq, api, verb, args, callback, closure);
}
-static void xreq_hooked_subcall_request_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure)
+static void xreq_hooked_legacy_subcall_request_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- struct subcall *sc;
-
- afb_hook_xreq_subcall(xreq, api, verb, args);
- sc = subcall_alloc(xreq, api, verb, args);
- if (sc == NULL) {
- if (callback)
- callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_request(xreq));
- json_object_put(args);
- } else {
- subcall_request_hooked(sc, callback, cb_closure);
- }
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ afb_calls_legacy_hooked_subcall_v3(xreq, api, verb, args, callback, closure);
}
-static int xreq_hooked_subcallsync_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result)
+static int xreq_hooked_legacy_subcallsync_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, struct json_object **result)
{
- int r;
- struct afb_xreq *xreq = xreq_from_request(closure);
- afb_hook_xreq_subcallsync(xreq, api, verb, args);
- r = xreq_subcallsync_cb(closure, api, verb, args, result);
- return afb_hook_xreq_subcallsync_result(xreq, r, *result);
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ return afb_calls_legacy_hooked_subcall_sync(xreq, api, verb, args, result);
}
-static void xreq_hooked_vverbose_cb(struct afb_request *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
+static void xreq_hooked_vverbose_cb(struct afb_req_x2 *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
va_list ap;
va_copy(ap, args);
xreq_vverbose_cb(closure, level, file, line, func, fmt, args);
@@ -763,149 +494,178 @@ static void xreq_hooked_vverbose_cb(struct afb_request *closure, int level, cons
va_end(ap);
}
-static struct afb_stored_req *xreq_hooked_store_cb(struct afb_request *closure)
+static struct afb_stored_req *xreq_hooked_legacy_store_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
- struct afb_stored_req *r = xreq_store_cb(closure);
- afb_hook_xreq_store(xreq, r);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ struct afb_stored_req *r = xreq_legacy_store_cb(closure);
+ afb_hook_xreq_legacy_store(xreq, r);
return r;
}
-static int xreq_hooked_has_permission_cb(struct afb_request *closure, const char *permission)
+static int xreq_hooked_has_permission_cb(struct afb_req_x2 *closure, const char *permission)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
int r = xreq_has_permission_cb(closure, permission);
return afb_hook_xreq_has_permission(xreq, permission, r);
}
-static char *xreq_hooked_get_application_id_cb(struct afb_request *closure)
+static char *xreq_hooked_get_application_id_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
char *r = xreq_get_application_id_cb(closure);
return afb_hook_xreq_get_application_id(xreq, r);
}
-static void *xreq_hooked_context_make_cb(struct afb_request *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure)
+static void *xreq_hooked_context_make_cb(struct afb_req_x2 *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
void *result = xreq_context_make_cb(closure, replace, create_value, free_value, create_closure);
return afb_hook_xreq_context_make(xreq, replace, create_value, free_value, create_closure, result);
}
-static int xreq_hooked_get_uid_cb(struct afb_request *closure)
+static int xreq_hooked_get_uid_cb(struct afb_req_x2 *closure)
{
- struct afb_xreq *xreq = xreq_from_request(closure);
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
int r = xreq_get_uid_cb(closure);
return afb_hook_xreq_get_uid(xreq, r);
}
+static struct json_object *xreq_hooked_get_client_info_cb(struct afb_req_x2 *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ struct json_object *r = xreq_get_client_info_cb(closure);
+ return afb_hook_xreq_get_client_info(xreq, r);
+}
+
+static void xreq_hooked_subcall_cb(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
+ void *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ afb_calls_hooked_subcall(xreq, api, verb, args, flags, callback, closure);
+}
+
+static int xreq_hooked_subcallsync_cb(
+ struct afb_req_x2 *req,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ struct json_object **object,
+ char **error,
+ char **info)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(req);
+ return afb_calls_hooked_subcall_sync(xreq, api, verb, args, flags, object, error, info);
+}
+
/******************************************************************************/
-const struct afb_request_itf xreq_itf = {
+const struct afb_req_x2_itf xreq_itf = {
.json = xreq_json_cb,
.get = xreq_get_cb,
- .success = xreq_success_cb,
- .fail = xreq_fail_cb,
- .vsuccess = xreq_vsuccess_cb,
- .vfail = xreq_vfail_cb,
- .context_get = xreq_context_get_cb,
- .context_set = xreq_context_set_cb,
+ .legacy_success = xreq_legacy_success_cb,
+ .legacy_fail = xreq_legacy_fail_cb,
+ .legacy_vsuccess = xreq_legacy_vsuccess_cb,
+ .legacy_vfail = xreq_legacy_vfail_cb,
+ .legacy_context_get = xreq_legacy_context_get_cb,
+ .legacy_context_set = xreq_legacy_context_set_cb,
.addref = xreq_addref_cb,
.unref = xreq_unref_cb,
.session_close = xreq_session_close_cb,
.session_set_LOA = xreq_session_set_LOA_cb,
- .subscribe = xreq_subscribe_cb,
- .unsubscribe = xreq_unsubscribe_cb,
- .subcall = xreq_subcall_cb,
- .subcallsync = xreq_subcallsync_cb,
+ .legacy_subscribe_event_x1 = xreq_legacy_subscribe_event_x1_cb,
+ .legacy_unsubscribe_event_x1 = xreq_legacy_unsubscribe_event_x1_cb,
+ .legacy_subcall = xreq_legacy_subcall_cb,
+ .legacy_subcallsync = xreq_legacy_subcallsync_cb,
.vverbose = xreq_vverbose_cb,
- .store = xreq_store_cb,
- .subcall_req = xreq_subcall_req_cb,
+ .legacy_store_req = xreq_legacy_store_cb,
+ .legacy_subcall_req = xreq_legacy_subcall_req_cb,
.has_permission = xreq_has_permission_cb,
.get_application_id = xreq_get_application_id_cb,
.context_make = xreq_context_make_cb,
- .subscribe_eventid = xreq_subscribe_eventid_cb,
- .unsubscribe_eventid = xreq_unsubscribe_eventid_cb,
- .subcall_request = xreq_subcall_request_cb,
+ .subscribe_event_x2 = xreq_subscribe_event_x2_cb,
+ .unsubscribe_event_x2 = xreq_unsubscribe_event_x2_cb,
+ .legacy_subcall_request = xreq_legacy_subcall_request_cb,
.get_uid = xreq_get_uid_cb,
+ .reply = xreq_reply_cb,
+ .vreply = xreq_vreply_cb,
+ .get_client_info = xreq_get_client_info_cb,
+ .subcall = xreq_subcall_cb,
+ .subcallsync = xreq_subcallsync_cb,
};
-const struct afb_request_itf xreq_hooked_itf = {
+const struct afb_req_x2_itf xreq_hooked_itf = {
.json = xreq_hooked_json_cb,
.get = xreq_hooked_get_cb,
- .success = xreq_hooked_success_cb,
- .fail = xreq_hooked_fail_cb,
- .vsuccess = xreq_hooked_vsuccess_cb,
- .vfail = xreq_hooked_vfail_cb,
- .context_get = xreq_hooked_context_get_cb,
- .context_set = xreq_hooked_context_set_cb,
+ .legacy_success = xreq_hooked_legacy_success_cb,
+ .legacy_fail = xreq_hooked_legacy_fail_cb,
+ .legacy_vsuccess = xreq_hooked_legacy_vsuccess_cb,
+ .legacy_vfail = xreq_hooked_legacy_vfail_cb,
+ .legacy_context_get = xreq_hooked_legacy_context_get_cb,
+ .legacy_context_set = xreq_hooked_legacy_context_set_cb,
.addref = xreq_hooked_addref_cb,
.unref = xreq_hooked_unref_cb,
.session_close = xreq_hooked_session_close_cb,
.session_set_LOA = xreq_hooked_session_set_LOA_cb,
- .subscribe = xreq_hooked_subscribe_cb,
- .unsubscribe = xreq_hooked_unsubscribe_cb,
- .subcall = xreq_hooked_subcall_cb,
- .subcallsync = xreq_hooked_subcallsync_cb,
+ .legacy_subscribe_event_x1 = xreq_hooked_legacy_subscribe_event_x1_cb,
+ .legacy_unsubscribe_event_x1 = xreq_hooked_legacy_unsubscribe_event_x1_cb,
+ .legacy_subcall = xreq_hooked_legacy_subcall_cb,
+ .legacy_subcallsync = xreq_hooked_legacy_subcallsync_cb,
.vverbose = xreq_hooked_vverbose_cb,
- .store = xreq_hooked_store_cb,
- .subcall_req = xreq_hooked_subcall_req_cb,
+ .legacy_store_req = xreq_hooked_legacy_store_cb,
+ .legacy_subcall_req = xreq_hooked_legacy_subcall_req_cb,
.has_permission = xreq_hooked_has_permission_cb,
.get_application_id = xreq_hooked_get_application_id_cb,
.context_make = xreq_hooked_context_make_cb,
- .subscribe_eventid = xreq_hooked_subscribe_eventid_cb,
- .unsubscribe_eventid = xreq_hooked_unsubscribe_eventid_cb,
- .subcall_request = xreq_hooked_subcall_request_cb,
+ .subscribe_event_x2 = xreq_hooked_subscribe_event_x2_cb,
+ .unsubscribe_event_x2 = xreq_hooked_unsubscribe_event_x2_cb,
+ .legacy_subcall_request = xreq_hooked_legacy_subcall_request_cb,
.get_uid = xreq_hooked_get_uid_cb,
+ .reply = xreq_hooked_reply_cb,
+ .vreply = xreq_hooked_vreply_cb,
+ .get_client_info = xreq_hooked_get_client_info_cb,
+ .subcall = xreq_hooked_subcall_cb,
+ .subcallsync = xreq_hooked_subcallsync_cb,
};
/******************************************************************************/
-struct afb_req afb_xreq_unstore(struct afb_stored_req *sreq)
+struct afb_req_x1 afb_xreq_unstore(struct afb_stored_req *sreq)
{
struct afb_xreq *xreq = (struct afb_xreq *)sreq;
if (xreq->hookflags)
- afb_hook_xreq_unstore(xreq);
- return xreq_to_req(xreq);
+ afb_hook_xreq_legacy_unstore(xreq);
+ return xreq_to_req_x1(xreq);
}
struct json_object *afb_xreq_json(struct afb_xreq *xreq)
{
- return afb_request_json(xreq_to_request(xreq));
+ return afb_req_x2_json(xreq_to_req_x2(xreq));
}
-void afb_xreq_success(struct afb_xreq *xreq, struct json_object *obj, const char *info)
+void afb_xreq_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info)
{
- afb_request_success(xreq_to_request(xreq), obj, info);
+ afb_req_x2_reply(xreq_to_req_x2(xreq), obj, error, info);
}
-void afb_xreq_success_f(struct afb_xreq *xreq, struct json_object *obj, const char *info, ...)
+void afb_xreq_reply_f(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info, ...)
{
va_list args;
va_start(args, info);
- afb_request_success_v(xreq_to_request(xreq), obj, info, args);
+ afb_req_x2_reply_v(xreq_to_req_x2(xreq), obj, error, info, args);
va_end(args);
}
-void afb_xreq_fail(struct afb_xreq *xreq, const char *status, const char *info)
-{
- afb_request_fail(xreq_to_request(xreq), status, info);
-}
-
-void afb_xreq_fail_f(struct afb_xreq *xreq, const char *status, const char *info, ...)
-{
- va_list args;
-
- va_start(args, info);
- afb_request_fail_v(xreq_to_request(xreq), status, info, args);
- va_end(args);
-
-}
-
const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size)
{
- struct json_object *obj = xreq_json_cb(xreq_to_request(xreq));
+ struct json_object *obj = xreq_json_cb(xreq_to_req_x2(xreq));
const char *result = json_object_to_json_string(obj);
if (size != NULL)
*size = strlen(result);
@@ -914,69 +674,79 @@ const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size)
void afb_xreq_addref(struct afb_xreq *xreq)
{
- afb_request_addref(xreq_to_request(xreq));
+ afb_req_x2_addref(xreq_to_req_x2(xreq));
}
void afb_xreq_unref(struct afb_xreq *xreq)
{
- afb_request_unref(xreq_to_request(xreq));
+ afb_req_x2_unref(xreq_to_req_x2(xreq));
+}
+
+void afb_xreq_unhooked_legacy_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *cb_closure)
+{
+ xreq_legacy_subcall_request_cb(xreq_to_req_x2(xreq), api, verb, args, callback, cb_closure);
+}
+
+void afb_xreq_legacy_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *cb_closure)
+{
+ afb_req_x2_subcall_legacy(xreq_to_req_x2(xreq), api, verb, args, callback, cb_closure);
}
-void afb_xreq_unhooked_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure)
+void afb_xreq_unhooked_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags, void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *), void *closure)
{
- xreq_subcall_request_cb(xreq_to_request(xreq), api, verb, args, callback, cb_closure);
+ xreq_subcall_cb(xreq_to_req_x2(xreq), api, verb, args, flags, callback, closure);
}
-void afb_xreq_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure)
+void afb_xreq_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags, void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *), void *closure)
{
- afb_request_subcall(xreq_to_request(xreq), api, verb, args, callback, cb_closure);
+ afb_req_x2_subcall(xreq_to_req_x2(xreq), api, verb, args, flags, callback, closure);
}
-int afb_xreq_unhooked_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result)
+int afb_xreq_unhooked_legacy_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result)
{
- return xreq_subcallsync_cb(xreq_to_request(xreq), api, verb, args, result);
+ return xreq_legacy_subcallsync_cb(xreq_to_req_x2(xreq), api, verb, args, result);
}
-int afb_xreq_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result)
+int afb_xreq_legacy_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result)
{
- return afb_request_subcall_sync(xreq_to_request(xreq), api, verb, args, result);
+ return afb_req_x2_subcall_sync_legacy(xreq_to_req_x2(xreq), api, verb, args, result);
}
static int xreq_session_check_apply_v1(struct afb_xreq *xreq, int sessionflags)
{
int loa;
- if ((sessionflags & (AFB_SESSION_CLOSE_V1|AFB_SESSION_RENEW_V1|AFB_SESSION_CHECK_V1|AFB_SESSION_LOA_EQ_V1)) != 0) {
+ if ((sessionflags & (AFB_SESSION_CLOSE_X1|AFB_SESSION_RENEW_X1|AFB_SESSION_CHECK_X1|AFB_SESSION_LOA_EQ_X1)) != 0) {
if (!afb_context_check(&xreq->context)) {
afb_context_close(&xreq->context);
- afb_xreq_fail_f(xreq, "denied", "invalid token's identity");
+ afb_xreq_reply_f(xreq, NULL, "denied", "invalid token's identity");
errno = EINVAL;
return -1;
}
}
- if ((sessionflags & AFB_SESSION_LOA_GE_V1) != 0) {
- loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1;
+ if ((sessionflags & AFB_SESSION_LOA_GE_X1) != 0) {
+ loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1;
if (!afb_context_check_loa(&xreq->context, loa)) {
- afb_xreq_fail_f(xreq, "denied", "invalid LOA");
+ afb_xreq_reply_f(xreq, NULL, "denied", "invalid LOA");
errno = EPERM;
return -1;
}
}
- if ((sessionflags & AFB_SESSION_LOA_LE_V1) != 0) {
- loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1;
+ if ((sessionflags & AFB_SESSION_LOA_LE_X1) != 0) {
+ loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1;
if (afb_context_check_loa(&xreq->context, loa + 1)) {
- afb_xreq_fail_f(xreq, "denied", "invalid LOA");
+ afb_xreq_reply_f(xreq, NULL, "denied", "invalid LOA");
errno = EPERM;
return -1;
}
}
- if ((sessionflags & AFB_SESSION_RENEW_V1) != 0) {
+ if ((sessionflags & AFB_SESSION_RENEW_X1) != 0) {
afb_context_refresh(&xreq->context);
}
- if ((sessionflags & AFB_SESSION_CLOSE_V1) != 0) {
+ if ((sessionflags & AFB_SESSION_CLOSE_X1) != 0) {
afb_context_change_loa(&xreq->context, 0);
afb_context_close(&xreq->context);
}
@@ -991,29 +761,29 @@ static int xreq_session_check_apply_v2(struct afb_xreq *xreq, uint32_t sessionfl
if (sessionflags != 0) {
if (!afb_context_check(&xreq->context)) {
afb_context_close(&xreq->context);
- afb_xreq_fail_f(xreq, "denied", "invalid token's identity");
+ afb_xreq_reply_f(xreq, NULL, "denied", "invalid token's identity");
errno = EINVAL;
return -1;
}
}
- loa = (int)(sessionflags & AFB_SESSION_LOA_MASK_V2);
+ loa = (int)(sessionflags & AFB_SESSION_LOA_MASK_X2);
if (loa && !afb_context_check_loa(&xreq->context, loa)) {
- afb_xreq_fail_f(xreq, "denied", "invalid LOA");
+ afb_xreq_reply_f(xreq, NULL, "denied", "invalid LOA");
errno = EPERM;
return -1;
}
if (auth && !afb_auth_check(xreq, auth)) {
- afb_xreq_fail_f(xreq, "denied", "authorisation refused");
+ afb_xreq_reply_f(xreq, NULL, "denied", "authorisation refused");
errno = EPERM;
return -1;
}
- if ((sessionflags & AFB_SESSION_REFRESH_V2) != 0) {
+ if ((sessionflags & AFB_SESSION_REFRESH_X2) != 0) {
afb_context_refresh(&xreq->context);
}
- if ((sessionflags & AFB_SESSION_CLOSE_V2) != 0) {
+ if ((sessionflags & AFB_SESSION_CLOSE_X2) != 0) {
afb_context_close(&xreq->context);
}
@@ -1023,55 +793,55 @@ static int xreq_session_check_apply_v2(struct afb_xreq *xreq, uint32_t sessionfl
void afb_xreq_call_verb_v1(struct afb_xreq *xreq, const struct afb_verb_desc_v1 *verb)
{
if (!verb)
- afb_xreq_fail_unknown_verb(xreq);
+ afb_xreq_reply_unknown_verb(xreq);
else
if (!xreq_session_check_apply_v1(xreq, verb->session))
- verb->callback(xreq_to_req(xreq));
+ verb->callback(xreq_to_req_x1(xreq));
}
void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb)
{
if (!verb)
- afb_xreq_fail_unknown_verb(xreq);
+ afb_xreq_reply_unknown_verb(xreq);
else
if (!xreq_session_check_apply_v2(xreq, verb->session, verb->auth))
- verb->callback(xreq_to_req(xreq));
+ verb->callback(xreq_to_req_x1(xreq));
}
-void afb_xreq_call_verb_vdyn(struct afb_xreq *xreq, const struct afb_api_dyn_verb *verb)
+void afb_xreq_call_verb_v3(struct afb_xreq *xreq, const struct afb_verb_v3 *verb)
{
if (!verb)
- afb_xreq_fail_unknown_verb(xreq);
+ afb_xreq_reply_unknown_verb(xreq);
else
if (xreq_session_check_apply_v2(xreq, verb->session, verb->auth) >= 0)
- verb->callback(xreq_to_request(xreq));
+ verb->callback(xreq_to_req_x2(xreq));
}
void afb_xreq_init(struct afb_xreq *xreq, const struct afb_xreq_query_itf *queryitf)
{
memset(xreq, 0, sizeof *xreq);
- xreq->request.itf = &xreq_hooked_itf; /* hook by default */
+ xreq->request.itf = &xreq_itf; /* no hook by default */
xreq->refcount = 1;
xreq->queryitf = queryitf;
}
-void afb_xreq_fail_unknown_api(struct afb_xreq *xreq)
+void afb_xreq_reply_unknown_api(struct afb_xreq *xreq)
{
- afb_xreq_fail_f(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->request.api, xreq->request.verb);
+ afb_xreq_reply_f(xreq, NULL, "unknown-api", "api %s not found (for verb %s)", xreq->request.called_api, xreq->request.called_verb);
}
-void afb_xreq_fail_unknown_verb(struct afb_xreq *xreq)
+void afb_xreq_reply_unknown_verb(struct afb_xreq *xreq)
{
- afb_xreq_fail_f(xreq, "unknown-verb", "verb %s unknown within api %s", xreq->request.verb, xreq->request.api);
+ afb_xreq_reply_f(xreq, NULL, "unknown-verb", "verb %s unknown within api %s", xreq->request.called_verb, xreq->request.called_api);
}
static void init_hooking(struct afb_xreq *xreq)
{
afb_hook_init_xreq(xreq);
- if (xreq->hookflags)
+ if (xreq->hookflags) {
+ xreq->request.itf = &xreq_hooked_itf; /* unhook the interface */
afb_hook_xreq_begin(xreq);
- else
- xreq->request.itf = &xreq_itf; /* unhook the interface */
+ }
}
/**
@@ -1080,16 +850,16 @@ static void init_hooking(struct afb_xreq *xreq)
static void process_async(int signum, void *arg)
{
struct afb_xreq *xreq = arg;
- const struct afb_api *api;
+ const struct afb_api_item *api;
if (signum != 0) {
/* emit the error (assumes that hooking is initialised) */
- afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum);
+ afb_xreq_reply_f(xreq, NULL, "aborted", "signal %s(%d) caught", strsignal(signum), signum);
} else {
/* init hooking */
init_hooking(xreq);
- /* invoke api call method to process the reqiest */
- api = (const struct afb_api*)xreq->context.api_key;
+ /* invoke api call method to process the request */
+ api = (const struct afb_api_item*)xreq->context.api_key;
api->itf->call(api->closure, xreq);
}
/* release the request */
@@ -1111,7 +881,7 @@ static void early_failure(struct afb_xreq *xreq, const char *status, const char
/* send error */
va_start(args, info);
- afb_request_fail_v(xreq_to_request(xreq), status, info, args);
+ afb_req_x2_reply_v(xreq_to_req_x2(xreq), NULL, status, info, args);
va_end(args);
}
@@ -1121,17 +891,17 @@ static void early_failure(struct afb_xreq *xreq, const char *status, const char
*/
void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset)
{
- const struct afb_api *api;
+ const struct afb_api_item *api;
struct afb_xreq *caller;
/* lookup at the api */
xreq->apiset = apiset;
- api = afb_apiset_lookup_started(apiset, xreq->request.api, 1);
+ api = afb_apiset_lookup_started(apiset, xreq->request.called_api, 1);
if (!api) {
if (errno == ENOENT)
- early_failure(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->request.api, xreq->request.verb);
+ early_failure(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->request.called_api, xreq->request.called_verb);
else
- early_failure(xreq, "bad-api-state", "api %s not started correctly: %m", xreq->request.api);
+ early_failure(xreq, "bad-api-state", "api %s not started correctly: %m", xreq->request.called_api);
goto end;
}
xreq->context.api_key = api;
@@ -1140,10 +910,10 @@ void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset)
if (api->group) {
caller = xreq->caller;
while (caller) {
- if (((const struct afb_api *)caller->context.api_key)->group == api->group) {
+ if (((const struct afb_api_item*)caller->context.api_key)->group == api->group) {
/* noconcurrency lock detected */
- ERROR("self-lock detected in call stack for API %s", xreq->request.api);
- early_failure(xreq, "self-locked", "recursive self lock, API %s", xreq->request.api);
+ ERROR("self-lock detected in call stack for API %s", xreq->request.called_api);
+ early_failure(xreq, "self-locked", "recursive self lock, API %s", xreq->request.called_api);
goto end;
}
caller = caller->caller;
@@ -1162,3 +932,8 @@ end:
afb_xreq_unhooked_unref(xreq);
}
+const char *xreq_on_behalf_cred_export(struct afb_xreq *xreq)
+{
+ return xreq->caller ? afb_cred_export(xreq->cred) : NULL;
+}
+
diff --git a/src/afb-xreq.h b/src/afb-xreq.h
index ae1419fb..5c748d6f 100644
--- a/src/afb-xreq.h
+++ b/src/afb-xreq.h
@@ -17,8 +17,9 @@
#pragma once
-#include <afb/afb-request-itf.h>
-#include <afb/afb-req-itf.h>
+#include <stdarg.h>
+#include <afb/afb-req-x1-itf.h>
+#include <afb/afb-req-x2-itf.h>
#include "afb-context.h"
struct json_object;
@@ -26,29 +27,20 @@ struct afb_evt_listener;
struct afb_xreq;
struct afb_cred;
struct afb_apiset;
-struct afb_api_dyn_verb;
-struct afb_eventid;
+struct afb_event_x2;
struct afb_verb_desc_v1;
struct afb_verb_v2;
-struct afb_req;
+struct afb_verb_v3;
+struct afb_req_x1;
struct afb_stored_req;
struct afb_xreq_query_itf {
struct json_object *(*json)(struct afb_xreq *xreq);
struct afb_arg (*get)(struct afb_xreq *xreq, const char *name);
- void (*success)(struct afb_xreq *xreq, struct json_object *obj, const char *info);
- void (*fail)(struct afb_xreq *xreq, const char *status, const char *info);
- void (*reply)(struct afb_xreq *xreq, int status, struct json_object *obj);
+ void (*reply)(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info);
void (*unref)(struct afb_xreq *xreq);
- int (*subscribe)(struct afb_xreq *xreq, struct afb_eventid *eventid);
- int (*unsubscribe)(struct afb_xreq *xreq, struct afb_eventid *eventid);
- void (*subcall)(
- struct afb_xreq *xreq,
- const char *api,
- const char *verb,
- struct json_object *args,
- void (*callback)(void*, int, struct json_object*),
- void *cb_closure);
+ int (*subscribe)(struct afb_xreq *xreq, struct afb_event_x2 *event);
+ int (*unsubscribe)(struct afb_xreq *xreq, struct afb_event_x2 *event);
};
/**
@@ -56,7 +48,7 @@ struct afb_xreq_query_itf {
*/
struct afb_xreq
{
- struct afb_request request; /**< exported request */
+ struct afb_req_x2 request; /**< exported request */
struct afb_context context; /**< context of the request */
struct afb_apiset *apiset; /**< apiset of the xreq */
struct json_object *json; /**< the json object (or NULL) */
@@ -90,49 +82,65 @@ struct afb_xreq
#define CONTAINER_OF_XREQ(type,x) CONTAINER_OF(type,xreq,x)
/* req wrappers for xreq */
-extern struct afb_req afb_xreq_unstore(struct afb_stored_req *sreq);
+extern struct afb_req_x1 afb_xreq_unstore(struct afb_stored_req *sreq);
extern void afb_xreq_addref(struct afb_xreq *xreq);
extern void afb_xreq_unref(struct afb_xreq *xreq);
extern void afb_xreq_unhooked_addref(struct afb_xreq *xreq);
extern void afb_xreq_unhooked_unref(struct afb_xreq *xreq);
+extern struct json_object *afb_xreq_unhooked_json(struct afb_xreq *xreq);
extern struct json_object *afb_xreq_json(struct afb_xreq *xreq);
-extern void afb_xreq_success(struct afb_xreq *xreq, struct json_object *obj, const char *info);
-extern void afb_xreq_success_f(struct afb_xreq *xreq, struct json_object *obj, const char *info, ...);
+extern void afb_xreq_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info);
+extern void afb_xreq_reply_f(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info, ...);
-extern void afb_xreq_fail(struct afb_xreq *xreq, const char *status, const char *info);
-extern void afb_xreq_fail_f(struct afb_xreq *xreq, const char *status, const char *info, ...);
-extern void afb_xreq_fail_unknown_api(struct afb_xreq *xreq);
-extern void afb_xreq_fail_unknown_verb(struct afb_xreq *xreq);
+extern void afb_xreq_reply_unknown_api(struct afb_xreq *xreq);
+extern void afb_xreq_reply_unknown_verb(struct afb_xreq *xreq);
extern const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size);
-extern int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid);
-extern int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid);
+extern int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event);
+extern int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event);
-extern void afb_xreq_subcall(
+extern void afb_xreq_legacy_subcall(
struct afb_xreq *xreq,
const char *api,
const char *verb,
struct json_object *args,
- void (*callback)(void*, int, struct json_object*, struct afb_request *),
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *),
void *cb_closure);
-extern void afb_xreq_unhooked_subcall(
+extern void afb_xreq_unhooked_legacy_subcall(
struct afb_xreq *xreq,
const char *api,
const char *verb,
struct json_object *args,
- void (*callback)(void*, int, struct json_object*, struct afb_request *),
+ void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *),
void *cb_closure);
-extern int afb_xreq_unhooked_subcall_sync(
+extern void afb_xreq_subcall(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *),
+ void *closure);
+extern void afb_xreq_unhooked_subcall(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ int flags,
+ void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *),
+ void *closure);
+
+extern int afb_xreq_unhooked_legacy_subcall_sync(
struct afb_xreq *xreq,
const char *api,
const char *verb,
struct json_object *args,
struct json_object **result);
-extern int afb_xreq_subcall_sync(
+extern int afb_xreq_legacy_subcall_sync(
struct afb_xreq *xreq,
const char *api,
const char *verb,
@@ -146,23 +154,24 @@ extern void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset);
extern void afb_xreq_call_verb_v1(struct afb_xreq *xreq, const struct afb_verb_desc_v1 *verb);
extern void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb);
-extern void afb_xreq_call_verb_vdyn(struct afb_xreq *xreq, const struct afb_api_dyn_verb *verb);
+extern void afb_xreq_call_verb_v3(struct afb_xreq *xreq, const struct afb_verb_v3 *verb);
+
+extern const char *xreq_on_behalf_cred_export(struct afb_xreq *xreq);
/******************************************************************************/
-static inline struct afb_req xreq_to_req(struct afb_xreq *xreq)
+static inline struct afb_req_x1 xreq_to_req_x1(struct afb_xreq *xreq)
{
- return (struct afb_req){ .itf = xreq->request.itf, .closure = &xreq->request };
+ return (struct afb_req_x1){ .itf = xreq->request.itf, .closure = &xreq->request };
}
-static inline struct afb_request *xreq_to_request(struct afb_xreq *xreq)
+static inline struct afb_req_x2 *xreq_to_req_x2(struct afb_xreq *xreq)
{
return &xreq->request;
}
-static inline struct afb_xreq *xreq_from_request(struct afb_request *request)
+static inline struct afb_xreq *xreq_from_req_x2(struct afb_req_x2 *req)
{
- return CONTAINER_OF(struct afb_xreq, request, request);
+ return CONTAINER_OF(struct afb_xreq, request, req);
}
-
diff --git a/src/afs-config.c b/src/afs-config.c
index 78fee7dc..70a6d475 100644
--- a/src/afs-config.c
+++ b/src/afs-config.c
@@ -263,11 +263,11 @@ static void parse_arguments(int argc, char **argv, struct afs_config *config)
while ((optc = getopt_long(argc, argv, shortopts, gnuOptions, NULL)) != EOF) {
switch (optc) {
case SET_VERBOSE:
- verbosity++;
+ verbose_inc();
break;
case SET_QUIET:
- verbosity--;
+ verbose_dec();
break;
case SET_TCP_PORT:
@@ -441,7 +441,7 @@ struct afs_config *afs_config_parse_arguments(int argc, char **argv)
parse_environment(result);
parse_arguments(argc, argv, result);
fulfill_config(result);
- if (verbosity >= 3)
+ if (verbose_wants(Log_Level_Info))
afs_config_dump(result);
return result;
}
diff --git a/src/afs-supervision.h b/src/afs-supervision.h
index 2c76f249..25d1b4b1 100644
--- a/src/afs-supervision.h
+++ b/src/afs-supervision.h
@@ -45,5 +45,5 @@ struct afs_supervision_initiator
char extra[27]; /**< zero terminated extra computed here to be 64-37 */
};
-#define AFS_SUPERVISION_APINAME "$"
+#define AFS_SUPERVISION_APINAME "."
#define AFS_SUPERVISOR_APINAME "supervisor"
diff --git a/src/afs-supervisor.c b/src/afs-supervisor.c
index 285d82cb..6bd1fc62 100644
--- a/src/afs-supervisor.c
+++ b/src/afs-supervisor.c
@@ -28,13 +28,15 @@
#include <sys/un.h>
#include <json-c/json.h>
-#include <afb/afb-binding-v2.h>
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
#include "afb-cred.h"
#include "afb-stub-ws.h"
#include "afb-api.h"
#include "afb-xreq.h"
-#include "afb-api-so-v2.h"
+#include "afb-api-v3.h"
#include "afb-apiset.h"
#include "afb-fdev.h"
@@ -76,6 +78,10 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/* list of supervised daemons */
static struct supervised *superviseds;
+/* events */
+static afb_event_t event_add_pid;
+static afb_event_t event_del_pid;
+
/*************************************************************************************/
@@ -155,7 +161,7 @@ static int send_initiator(int fd, const char *command)
}
/*
- * checks whether the incomming supervised represented by its creds
+ * checks whether the incoming supervised represented by its creds
* is to be accepted or not.
* return 1 if yes or 0 otherwise.
*/
@@ -171,11 +177,15 @@ static void on_supervised_hangup(struct afb_stub_ws *stub)
ps = &superviseds;
while ((s = *ps) && s->stub != stub)
ps = &s->next;
- if (s) {
+ if (s)
*ps = s->next;
- afb_stub_ws_unref(stub);
- }
pthread_mutex_unlock(&mutex);
+ afb_stub_ws_unref(stub);
+ if (s) {
+ afb_event_push(event_del_pid, json_object_new_int((int)s->cred->pid));
+ afb_cred_unref(s->cred);
+ free(s);
+ }
}
/*
@@ -246,8 +256,10 @@ static void accept_supervision_link(int sock)
rc = send_initiator(fd, NULL);
if (!rc) {
rc = make_supervised(fd, cred);
- if (!rc)
+ if (!rc) {
+ afb_event_push(event_add_pid, json_object_new_int((int)cred->pid));
return;
+ }
}
}
afb_cred_unref(cred);
@@ -290,9 +302,27 @@ int afs_supervisor_discover()
/*************************************************************************************/
-static struct afb_binding_data_v2 datav2;
+static void f_subscribe(afb_req_t req)
+{
+ struct json_object *args = afb_req_json(req);
+ int revoke, ok;
+
+ revoke = json_object_is_type(args, json_type_boolean)
+ && !json_object_get_boolean(args);
-static void f_list(struct afb_req req)
+ ok = 1;
+ if (!revoke) {
+ ok = !afb_req_subscribe(req, event_add_pid)
+ && !afb_req_subscribe(req, event_del_pid);
+ }
+ if (revoke || !ok) {
+ afb_req_unsubscribe(req, event_add_pid);
+ afb_req_unsubscribe(req, event_del_pid);
+ }
+ afb_req_reply(req, NULL, ok ? NULL : "error", NULL);
+}
+
+static void f_list(afb_req_t req)
{
char pid[50];
struct json_object *resu, *item;
@@ -317,82 +347,82 @@ static void f_list(struct afb_req req)
afb_req_success(req, resu, NULL);
}
-static void f_discover(struct afb_req req)
+static void f_discover(afb_req_t req)
{
afs_supervisor_discover();
afb_req_success(req, NULL, NULL);
}
-static void propagate(struct afb_req req, const char *verb)
+static void propagate(afb_req_t req, const char *verb)
{
struct afb_xreq *xreq;
struct json_object *args, *item;
struct supervised *s;
- struct afb_api api;
+ struct afb_api_item api;
int p;
- xreq = xreq_from_request(req.closure);
+ xreq = xreq_from_req_x2(req);
args = afb_xreq_json(xreq);
if (!json_object_object_get_ex(args, "pid", &item)) {
- afb_xreq_fail(xreq, "no-pid", NULL);
+ afb_xreq_reply(xreq, NULL, "no-pid", NULL);
return;
}
errno = 0;
p = json_object_get_int(item);
if (!p && errno) {
- afb_xreq_fail(xreq, "bad-pid", NULL);
+ afb_xreq_reply(xreq, NULL, "bad-pid", NULL);
return;
}
s = supervised_of_pid((pid_t)p);
if (!s) {
- afb_req_fail(req, "unknown-pid", NULL);
+ afb_req_reply(req, NULL, "unknown-pid", NULL);
return;
}
json_object_object_del(args, "pid");
if (verb)
- xreq->request.verb = verb;
+ xreq->request.called_verb = verb;
api = afb_stub_ws_client_api(s->stub);
api.itf->call(api.closure, xreq);
}
-static void f_do(struct afb_req req)
+static void f_do(afb_req_t req)
{
propagate(req, NULL);
}
-static void f_config(struct afb_req req)
+static void f_config(afb_req_t req)
{
propagate(req, NULL);
}
-static void f_trace(struct afb_req req)
+static void f_trace(afb_req_t req)
{
propagate(req, NULL);
}
-static void f_sessions(struct afb_req req)
+static void f_sessions(afb_req_t req)
{
propagate(req, "slist");
}
-static void f_session_close(struct afb_req req)
+static void f_session_close(afb_req_t req)
{
propagate(req, "sclose");
}
-static void f_exit(struct afb_req req)
+static void f_exit(afb_req_t req)
{
propagate(req, NULL);
afb_req_success(req, NULL, NULL);
}
-static void f_debug_wait(struct afb_req req)
+static void f_debug_wait(afb_req_t req)
{
propagate(req, "wait");
afb_req_success(req, NULL, NULL);
}
-static void f_debug_break(struct afb_req req)
+static void f_debug_break(afb_req_t req)
{
propagate(req, "break");
afb_req_success(req, NULL, NULL);
@@ -403,10 +433,22 @@ static void f_debug_break(struct afb_req req)
/**
* initialize the supervisor
*/
-static int init_supervisor()
+static int init_supervisor(afb_api_t api)
{
int rc, fd;
+ event_add_pid = afb_api_make_event(api, "add-pid");
+ if (!afb_event_is_valid(event_add_pid)) {
+ ERROR("Can't create added event");
+ return -1;
+ }
+
+ event_del_pid = afb_api_make_event(api, "del-pid");
+ if (!afb_event_is_valid(event_del_pid)) {
+ ERROR("Can't create deleted event");
+ return -1;
+ }
+
/* create an empty set for superviseds */
empty_apiset = afb_apiset_create(supervision_apiname, 0);
if (!empty_apiset) {
@@ -448,93 +490,102 @@ static const struct afb_auth _afb_auths_v2_supervisor[] = {
}
};
-static const struct afb_verb_v2 _afb_verbs_v2_supervisor[] = {
+static const struct afb_verb_v3 _afb_verbs_supervisor[] = {
+ {
+ .verb = "subscribe",
+ .callback = f_subscribe,
+ .auth = &_afb_auths_v2_supervisor[0],
+ .info = NULL,
+ .session = AFB_SESSION_CHECK_X2
+ },
{
.verb = "list",
.callback = f_list,
.auth = &_afb_auths_v2_supervisor[0],
.info = NULL,
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK_X2
},
{
.verb = "config",
.callback = f_config,
.auth = &_afb_auths_v2_supervisor[0],
.info = NULL,
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK_X2
},
{
.verb = "do",
.callback = f_do,
.auth = &_afb_auths_v2_supervisor[0],
.info = NULL,
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK_X2
},
{
.verb = "trace",
.callback = f_trace,
.auth = &_afb_auths_v2_supervisor[0],
.info = NULL,
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK_X2
},
{
.verb = "sessions",
.callback = f_sessions,
.auth = &_afb_auths_v2_supervisor[0],
.info = NULL,
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK_X2
},
{
.verb = "session-close",
.callback = f_session_close,
.auth = &_afb_auths_v2_supervisor[0],
.info = NULL,
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK_X2
},
{
.verb = "exit",
.callback = f_exit,
.auth = &_afb_auths_v2_supervisor[0],
.info = NULL,
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK_X2
},
{
.verb = "debug-wait",
.callback = f_debug_wait,
.auth = &_afb_auths_v2_supervisor[0],
.info = NULL,
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK_X2
},
{
.verb = "debug-break",
.callback = f_debug_break,
.auth = &_afb_auths_v2_supervisor[0],
.info = NULL,
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK_X2
},
{
.verb = "discover",
.callback = f_discover,
.auth = &_afb_auths_v2_supervisor[0],
.info = NULL,
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK_X2
},
{ .verb = NULL }
};
-static const struct afb_binding_v2 _afb_binding_v2_supervisor = {
+static const struct afb_binding_v3 _afb_binding_supervisor = {
.api = supervisor_apiname,
.specification = NULL,
.info = NULL,
- .verbs = _afb_verbs_v2_supervisor,
+ .verbs = _afb_verbs_supervisor,
.preinit = NULL,
.init = init_supervisor,
.onevent = NULL,
.noconcurrency = 0
};
-int afs_supervisor_add(struct afb_apiset *apiset)
+int afs_supervisor_add(
+ struct afb_apiset *declare_set,
+ struct afb_apiset * call_set)
{
- return afb_api_so_v2_add_binding(&_afb_binding_v2_supervisor, NULL, apiset, &datav2);
+ return -!afb_api_v3_from_binding(&_afb_binding_supervisor, declare_set, call_set);
}
diff --git a/src/afs-supervisor.h b/src/afs-supervisor.h
index aeae6c72..08768ae7 100644
--- a/src/afs-supervisor.h
+++ b/src/afs-supervisor.h
@@ -19,5 +19,6 @@
extern int afs_supervisor_discover();
-extern int afs_supervisor_add(struct afb_apiset *apiset);
-
+extern int afs_supervisor_add(
+ struct afb_apiset *declare_set,
+ struct afb_apiset * call_set);
diff --git a/src/devtools/genskel.c b/src/devtools/genskel.c
index a0a78815..55dd3c15 100644
--- a/src/devtools/genskel.c
+++ b/src/devtools/genskel.c
@@ -62,6 +62,7 @@ struct path
/**
* root of the JSON being parsed
*/
+int version = 3;
struct json_object *root = NULL;
struct json_object *d_perms = NULL;
struct json_object *a_perms = NULL;
@@ -78,8 +79,8 @@ int noconc = -1;
int cpp = 0;
/**
- * Search for a reference of type "#/a/b/c" int the
- * parsed JSON object
+ * Search for a reference of type "#/a/b/c" in the
+ * parsed JSON object (root)
*/
struct json_object *search(const char *path)
{
@@ -170,6 +171,7 @@ struct json_object *expand_$ref(struct path path)
return path.object;
}
+/* create c name by replacing non alpha numeric characters with underscores */
char *cify(const char *str)
{
char *r = strdup(str);
@@ -182,6 +184,7 @@ char *cify(const char *str)
return r;
}
+/* format the specification as a C string */
char *make_info(const char *text, int split)
{
const char *a, *b;
@@ -260,11 +263,13 @@ char *make_info(const char *text, int split)
return desc;
}
+/* make the description of the object */
char *make_desc(struct json_object *o)
{
- return make_info(json_object_to_json_string_ext(root, 0), 1);
+ return make_info(json_object_to_json_string_ext(o, 0), 1);
}
+/* get the permission odescription if set */
struct json_object *permissions_of_verb(struct json_object *obj)
{
struct json_object *x, *y;
@@ -279,6 +284,7 @@ struct json_object *permissions_of_verb(struct json_object *obj)
return NULL;
}
+/* output the array of permissions */
void print_perms()
{
int i, n;
@@ -286,7 +292,7 @@ void print_perms()
n = a_perms ? json_object_array_length(a_perms) : 0;
if (n) {
- printf("static const struct afb_auth _afb_auths_v2_%s[] = {\n" , capi);
+ printf("static const struct afb_auth _afb_auths_%s[] = {\n" , capi);
i = 0;
while (i < n) {
printf(fmtstr, json_object_get_string(json_object_array_get_idx(a_perms, i)));
@@ -296,6 +302,10 @@ void print_perms()
}
}
+/*
+ * search in the global object 'd_perm' the computed representation
+ * of the permission described either by 'obj' or 'desc'
+ */
struct json_object *new_perm(struct json_object *obj, const char *desc)
{
const char *tag;
@@ -304,12 +314,15 @@ struct json_object *new_perm(struct json_object *obj, const char *desc)
tag = obj ? json_object_to_json_string_ext(obj, 0) : desc;
if (!json_object_object_get_ex(d_perms, tag, &y)) {
+
+ /* creates the d_perms dico and the a_perms array */
if (!d_perms) {
d_perms = json_object_new_object();
a_perms = json_object_new_array();
}
- asprintf(&b, "&_afb_auths_v2_%s[%d]", capi, json_object_array_length(a_perms));
+ /* creates the reference in the structure */
+ asprintf(&b, "&_afb_auths_%s[%d]", capi, json_object_array_length(a_perms));
x = json_object_new_string(desc);
y = json_object_new_string(b);
json_object_array_add(a_perms, x);
@@ -323,6 +336,7 @@ struct json_object *decl_perm(struct json_object *obj);
enum optype { And, Or };
+/* recursive declare and/or permissions */
struct json_object *decl_perm_a(enum optype op, struct json_object *obj)
{
int i, n;
@@ -354,16 +368,22 @@ struct json_object *decl_perm_a(enum optype op, struct json_object *obj)
return x;
}
+/* declare the permission for obj */
struct json_object *decl_perm(struct json_object *obj)
{
char *a;
+ const char *fmt;
struct json_object *x, *y;
if (json_object_object_get_ex(d_perms, json_object_to_json_string_ext(obj, 0), &x))
return x;
if (json_object_object_get_ex(obj, "permission", &x)) {
- asprintf(&a, cpp ? "afb::auth_permission(\"%s\")" : ".type = afb_auth_Permission, .text = \"%s\"", json_object_get_string(x));
+ if (cpp)
+ fmt = "afb::auth_permission(\"%s\")";
+ else
+ fmt = ".type = afb_auth_Permission, .text = \"%s\"";
+ asprintf(&a, fmt, json_object_get_string(x));
y = new_perm(obj, a);
free(a);
}
@@ -375,7 +395,11 @@ struct json_object *decl_perm(struct json_object *obj)
}
else if (json_object_object_get_ex(obj, "not", &x)) {
x = decl_perm(x);
- asprintf(&a, cpp ? "afb::auth_not(%s)" : ".type = afb_auth_Not, .first = %s", json_object_get_string(x));
+ if (cpp)
+ fmt = "afb::auth_not(%s)";
+ else
+ fmt = ".type = afb_auth_Not, .first = %s";
+ asprintf(&a, fmt, json_object_get_string(x));
y = new_perm(obj, a);
free(a);
}
@@ -477,7 +501,7 @@ void print_session(struct json_object *p)
s = p ? get_session(p) : 0;
c = 1;
if (s & SESSION_CHECK) {
- printf("%s", "|AFB_SESSION_CHECK_V2" + c);
+ printf("%s", "|AFB_SESSION_CHECK" + c);
c = 0;
}
if (s & SESSION_LOA_3 & ~SESSION_LOA_2)
@@ -489,19 +513,19 @@ void print_session(struct json_object *p)
else
l = 0;
if (l) {
- printf("%s%d_V2", "|AFB_SESSION_LOA_" + c, l);
+ printf("%s%d", "|AFB_SESSION_LOA_" + c, l);
c = 0;
}
if (s & SESSION_CLOSE) {
- printf("%s", "|AFB_SESSION_CLOSE_V2" + c);
+ printf("%s", "|AFB_SESSION_CLOSE" + c);
c = 0;
}
if (s & SESSION_RENEW) {
- printf("%s", "|AFB_SESSION_REFRESH_V2" + c);
+ printf("%s", "|AFB_SESSION_REFRESH" + c);
c = 0;
}
if (c)
- printf("AFB_SESSION_NONE_V2");
+ printf("AFB_SESSION_NONE");
}
void print_verb(const char *name)
@@ -513,7 +537,7 @@ void print_declare_verb(const char *name, struct json_object *obj)
{
printf("%s void ", scope);
print_verb(name);
- printf("(struct afb_req req);\n");
+ printf("(afb_req req);\n");
}
void print_struct_verb(const char *name, struct json_object *obj)
@@ -542,6 +566,12 @@ void print_struct_verb(const char *name, struct json_object *obj)
, info ? make_info(info, 0) : "NULL"
);
print_session(p);
+ if (version == 3)
+ printf(
+ ",\n"
+ " .vcbdata = NULL,\n"
+ " .glob = 0"
+ );
printf(
"\n"
" },\n"
@@ -646,7 +676,7 @@ void process(char *filename)
/* get the API name */
printf(
"\n"
- "static const char _afb_description_v2_%s[] =\n"
+ "static const char _afb_description_%s[] =\n"
"%s"
";\n"
"\n"
@@ -657,8 +687,8 @@ void process(char *filename)
enum_verbs(print_declare_verb);
printf(
"\n"
- "static const struct afb_verb_v2 _afb_verbs_v2_%s[] = {\n"
- , capi
+ "static const struct afb_verb_v%d _afb_verbs_%s[] = {\n"
+ , version, capi
);
enum_verbs(print_struct_verb);
printf(
@@ -667,25 +697,36 @@ void process(char *filename)
" .callback = NULL,\n"
" .auth = NULL,\n"
" .info = NULL,\n"
- " .session = 0\n"
+ " .session = 0"
+ );
+ if (version == 3)
+ printf(
+ ",\n"
+ " .vcbdata = NULL,\n"
+ " .glob = 0"
+ );
+ printf(
+ "\n"
" }\n"
"};\n"
);
printf(
"\n"
- "%sconst struct afb_binding_v2 %s%s = {\n"
+ "%sconst struct afb_binding_v%d %s%s = {\n"
" .api = \"%s\",\n"
- " .specification = _afb_description_v2_%s,\n"
+ " .specification = _afb_description_%s,\n"
" .info = %s,\n"
- " .verbs = _afb_verbs_v2_%s,\n"
+ " .verbs = _afb_verbs_%s,\n"
" .preinit = %s,\n"
" .init = %s,\n"
" .onevent = %s,\n"
+ "%s"
" .noconcurrency = %d\n"
"};\n"
"\n"
, priv ? "static " : ""
- , priv ? "_afb_binding_v2_" : "afbBindingV2"
+ , version
+ , priv ? "_afb_binding_" : version==3 ? "afbBindingV3" : "afbBindingV2"
, priv ? capi : ""
, api
, capi
@@ -694,6 +735,7 @@ void process(char *filename)
, preinit ?: "NULL"
, init ?: "NULL"
, onevent ?: "NULL"
+ , version==3 ? " .userdata = NULL,\n" : ""
, !!noconc
);
@@ -705,11 +747,25 @@ void process(char *filename)
/** process the list of files or stdin if none */
int main(int ac, char **av)
{
+ int r, w;
av++;
- if (*av && !(strcmp(*av, "-x") && strcmp(*av, "--cpp"))) {
- cpp = 1;
- av++;
+
+ r = w = 0;
+ while (av[r]) {
+ if (!(strcmp(av[r], "-x") && strcmp(av[r], "--cpp"))) {
+ cpp = 1;
+ r++;
+ } else if (!strcmp(av[r], "-2")) {
+ version = 2;
+ r++;
+ } else if (!strcmp(av[r], "-3")) {
+ version = 3;
+ r++;
+ } else {
+ av[w++] = av[r++];
+ }
}
+ av[w] = NULL;
if (!*av)
process("-");
else {
@@ -718,7 +774,3 @@ int main(int ac, char **av)
return 0;
}
-
-
-
-
diff --git a/src/devtools/monitor-api.json b/src/devtools/monitor-api.json
index 3c8867cd..ca4a9b37 100644
--- a/src/devtools/monitor-api.json
+++ b/src/devtools/monitor-api.json
@@ -172,11 +172,11 @@
"end",
"event",
"extra",
- "fail",
"get",
"json",
"life",
"ref",
+ "reply",
"result",
"session",
"session_close",
@@ -190,7 +190,6 @@
"subcallsync",
"subcallsync_result",
"subscribe",
- "success",
"unref",
"unstore",
"unsubscribe",
@@ -306,8 +305,8 @@
"paths": {
"/get": {
"description": "Get monitoring data.",
+ "x-permissions": { "session": "check" },
"get": {
- "x-permissions": { "session": "check" },
"parameters": [
{
"in": "query",
@@ -338,8 +337,8 @@
},
"/set": {
"description": "Set monitoring actions.",
+ "x-permissions": { "session": "check" },
"get": {
- "x-permissions": { "session": "check" },
"parameters": [
{
"in": "query",
@@ -364,8 +363,8 @@
},
"/trace": {
"description": "Set monitoring actions.",
+ "x-permissions": { "session": "check" },
"get": {
- "x-permissions": { "session": "check" },
"parameters": [
{
"in": "query",
@@ -396,8 +395,8 @@
},
"/session": {
"description": "describes the session.",
+ "x-permissions": { "session": "check" },
"get": {
- "x-permissions": { "session": "check" },
"parameters": [
{
"in": "query",
diff --git a/src/jobs-fake.c b/src/jobs-fake.c
index d3444e32..d3cd19e1 100644
--- a/src/jobs-fake.c
+++ b/src/jobs-fake.c
@@ -71,7 +71,7 @@ static int add_job(const void *group, int timeout, void (*callback)(int signum,
else
first = j;
last = j;
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&mutex);
return 0;
}
@@ -83,7 +83,7 @@ static void *thrrun(void *arg)
j = first;
if (j)
first = j->next;
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&mutex);
if (j) {
j->callback(0, j->closure);
free(j);
diff --git a/src/jobs.c b/src/jobs.c
index 5980305a..26fc0157 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -716,7 +716,7 @@ static int on_evloop_efd(sd_event_source *s, int fd, uint32_t revents, void *use
struct evloop *evloop = userdata;
read(evloop->efd, &x, sizeof x);
pthread_mutex_lock(&mutex);
- pthread_cond_broadcast(&evloop->cond);
+ pthread_cond_broadcast(&evloop->cond);
pthread_mutex_unlock(&mutex);
return 1;
}
diff --git a/src/afb-client-demo.c b/src/main-afb-client-demo.c
index 011de2b5..4e865879 100644
--- a/src/afb-client-demo.c
+++ b/src/main-afb-client-demo.c
@@ -41,15 +41,13 @@ static void on_wsj1_call(void *closure, const char *api, const char *verb, struc
static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg *msg);
static void on_pws_hangup(void *closure);
-static void on_pws_reply_success(void *closure, void *request, struct json_object *result, const char *info);
-static void on_pws_reply_fail(void *closure, void *request, const char *status, const char *info);
+static void on_pws_reply(void *closure, void *request, struct json_object *result, const char *error, const char *info);
static void on_pws_event_create(void *closure, const char *event_name, int event_id);
static void on_pws_event_remove(void *closure, const char *event_name, int event_id);
static void on_pws_event_subscribe(void *closure, void *request, const char *event_name, int event_id);
static void on_pws_event_unsubscribe(void *closure, void *request, const char *event_name, int event_id);
static void on_pws_event_push(void *closure, const char *event_name, int event_id, struct json_object *data);
static void on_pws_event_broadcast(void *closure, const char *event_name, struct json_object *data);
-static void on_pws_subcall(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args);
static int io_event_callback(sd_event_source *src, int fd, uint32_t revents, void *closure);
@@ -65,15 +63,13 @@ static struct afb_wsj1_itf wsj1_itf = {
/* the callback interface for pws */
static struct afb_proto_ws_client_itf pws_itf = {
- .on_reply_success = on_pws_reply_success,
- .on_reply_fail = on_pws_reply_fail,
+ .on_reply = on_pws_reply,
.on_event_create = on_pws_event_create,
.on_event_remove = on_pws_event_remove,
.on_event_subscribe = on_pws_event_subscribe,
.on_event_unsubscribe = on_pws_event_unsubscribe,
.on_event_push = on_pws_event_push,
.on_event_broadcast = on_pws_event_broadcast,
- .on_subcall = on_pws_subcall,
};
/* global variables */
@@ -96,18 +92,18 @@ static void usage(int status, char *arg0)
name = name ? name + 1 : arg0;
fprintf(status ? stderr : stdout, "usage: %s [-H [-r]] [-b] [-e] uri [api verb [data]]\n", name);
fprintf(status ? stderr : stdout, " %s -d [-H [-r]] [-b] [-e] uri [verb [data]]\n", name);
- fprintf(status ? stderr : stdout, "\n" \
- "allowed options\n" \
- " --break, -b Break connection just after event/call has been emitted.\n" \
- " --direct, -d Direct api\n" \
- " --echo, -e Echo inputs\n" \
- " --help, -h Display this help\n" \
- " --human, -H Display human readable JSON\n" \
- " --raw, -r Raw output (default)\n" \
- "Example:\n" \
- " %s --human 'localhost:1234/api?token=HELLO&uuid=magic' hello ping\n"
- "\n", name
- );
+ fprintf(status ? stderr : stdout, "\n"
+ "allowed options\n"
+ " --break, -b Break connection just after event/call has been emitted.\n"
+ " --direct, -d Direct api\n"
+ " --echo, -e Echo inputs\n"
+ " --help, -h Display this help\n"
+ " --human, -H Display human readable JSON\n"
+ " --raw, -r Raw output (default)\n"
+ "Example:\n"
+ " %s --human 'localhost:1234/api?token=HELLO&uuid=magic' hello ping\n"
+ "\n", name
+ );
exit(status);
}
@@ -233,7 +229,7 @@ static void on_wsj1_call(void *closure, const char *api, const char *verb, struc
{
int rc;
if (raw)
- printf("%s", afb_wsj1_msg_object_s(msg));
+ printf("%s\n", afb_wsj1_msg_object_s(msg));
if (human)
printf("ON-CALL %s/%s:\n%s\n", api, verb,
json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg),
@@ -248,7 +244,7 @@ static void on_wsj1_call(void *closure, const char *api, const char *verb, struc
static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
{
if (raw)
- printf("%s", afb_wsj1_msg_object_s(msg));
+ printf("%s\n", afb_wsj1_msg_object_s(msg));
if (human)
printf("ON-EVENT %s:\n%s\n", event,
json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg),
@@ -260,7 +256,7 @@ static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg
static void on_wsj1_reply(void *closure, struct afb_wsj1_msg *msg)
{
if (raw)
- printf("%s", afb_wsj1_msg_object_s(msg));
+ printf("%s\n", afb_wsj1_msg_object_s(msg));
if (human)
printf("ON-REPLY %s: %s\n%s\n", (char*)closure,
afb_wsj1_msg_is_reply_ok(msg) ? "OK" : "ERROR",
@@ -393,20 +389,25 @@ static int io_event_callback(sd_event_source *src, int fd, uint32_t revents, voi
return 1;
}
-static void on_pws_reply_success(void *closure, void *request, struct json_object *result, const char *info)
+static void on_pws_reply(void *closure, void *request, struct json_object *result, const char *error, const char *info)
{
- if (raw)
- printf("%s", json_object_to_json_string(result));
+ error = error ?: "success";
+ if (raw) {
+ /* TODO: transitionnal: fake the structured response */
+ struct json_object *x = json_object_new_object(), *y = json_object_new_object();
+ json_object_object_add(x, "jtype", json_object_new_string("afb-reply"));
+ json_object_object_add(x, "request", y);
+ json_object_object_add(y, "status", json_object_new_string(error));
+ if (info)
+ json_object_object_add(y, "info", json_object_new_string(info));
+ if (result)
+ json_object_object_add(x, "response", json_object_get(result));
+
+ printf("%s\n", json_object_to_json_string(x));
+ json_object_put(x);
+ }
if (human)
- printf("ON-REPLY-SUCCESS %s: %s\n%s\n", (char*)request, info?:"", json_object_to_json_string_ext(result, JSON_C_TO_STRING_PRETTY));
- fflush(stdout);
- free(request);
- dec_callcount();
-}
-
-static void on_pws_reply_fail(void *closure, void *request, const char *status, const char *info)
-{
- printf("ON-REPLY-FAIL %s: %s [%s]\n", (char*)request, status?:"?", info?:"");
+ printf("ON-REPLY %s: %s %s\n%s\n", (char*)request, error, info ?: "", json_object_to_json_string_ext(result, JSON_C_TO_STRING_PRETTY));
fflush(stdout);
free(request);
dec_callcount();
@@ -439,7 +440,7 @@ static void on_pws_event_unsubscribe(void *closure, void *request, const char *e
static void on_pws_event_push(void *closure, const char *event_name, int event_id, struct json_object *data)
{
if (raw)
- printf("%s", json_object_to_json_string(data));
+ printf("ON-EVENT-PUSH: [%d:%s]\n%s\n", event_id, event_name, json_object_to_json_string_ext(data, 0));
if (human)
printf("ON-EVENT-PUSH: [%d:%s]\n%s\n", event_id, event_name, json_object_to_json_string_ext(data, JSON_C_TO_STRING_PRETTY));
fflush(stdout);
@@ -448,22 +449,12 @@ static void on_pws_event_push(void *closure, const char *event_name, int event_i
static void on_pws_event_broadcast(void *closure, const char *event_name, struct json_object *data)
{
if (raw)
- printf("%s", json_object_to_json_string(data));
+ printf("ON-EVENT-BROADCAST: [%s]\n%s\n", event_name, json_object_to_json_string_ext(data, 0));
if (human)
printf("ON-EVENT-BROADCAST: [%s]\n%s\n", event_name, json_object_to_json_string_ext(data, JSON_C_TO_STRING_PRETTY));
fflush(stdout);
}
-static void on_pws_subcall(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args)
-{
- if (raw)
- printf("%s", json_object_to_json_string(args));
- if (human)
- printf("ON-SUBCALL %s: %s/%s\n%s\n", (char*)request, api, verb, json_object_to_json_string_ext(args, JSON_C_TO_STRING_PRETTY));
- afb_proto_ws_subcall_reply(subcall, 1, NULL);
- fflush(stdout);
-}
-
/* makes a call */
static void pws_call(const char *verb, const char *object)
{
@@ -488,7 +479,7 @@ static void pws_call(const char *verb, const char *object)
if (!o)
o = json_object_new_string(object);
}
- rc = afb_proto_ws_client_call(pws, verb, o, sessionid, key);
+ rc = afb_proto_ws_client_call(pws, verb, o, sessionid, key, NULL);
json_object_put(o);
if (rc < 0) {
fprintf(stderr, "calling %s(%s) failed: %m\n", verb, object?:"");
diff --git a/src/main.c b/src/main-afb-daemon.c
index 8c243f73..8b1a2b23 100644
--- a/src/main.c
+++ b/src/main-afb-daemon.c
@@ -39,6 +39,7 @@
#include "afb-config.h"
#include "afb-hswitch.h"
#include "afb-apiset.h"
+#include "afb-autoset.h"
#include "afb-api-so.h"
#if defined(WITH_DBUS_TRANSPARENCY)
# include "afb-api-dbus.h"
@@ -90,12 +91,13 @@ static struct afb_config_list *run_for_list(struct afb_config_list *list,
static int run_start(void *closure, char *value)
{
- int (*starter) (const char *value, struct afb_apiset *apiset) = closure;
- return starter(value, main_apiset) >= 0;
+ int (*starter) (const char *value, struct afb_apiset *declare_set, struct afb_apiset *call_set) = closure;
+ return starter(value, main_apiset, main_apiset) >= 0;
}
static void apiset_start_list(struct afb_config_list *list,
- int (*starter) (const char *value, struct afb_apiset *apiset), const char *message)
+ int (*starter) (const char *value, struct afb_apiset *declare_set, struct afb_apiset *call_set),
+ const char *message)
{
list = run_for_list(list, run_start, starter);
if (list) {
@@ -263,17 +265,17 @@ static struct afb_hsrv *start_http_server()
return NULL;
}
- if (!afb_hsrv_set_cache_timeout(hsrv, main_config->cacheTimeout)
+ if (!afb_hsrv_set_cache_timeout(hsrv, main_config->cache_timeout)
|| !init_http_server(hsrv)) {
ERROR("initialisation of httpd failed");
afb_hsrv_put(hsrv);
return NULL;
}
- NOTICE("Waiting port=%d rootdir=%s", main_config->httpdPort, main_config->rootdir);
- NOTICE("Browser URL= http://localhost:%d", main_config->httpdPort);
+ NOTICE("Waiting port=%d rootdir=%s", main_config->http_port, main_config->rootdir);
+ NOTICE("Browser URL= http://localhost:%d", main_config->http_port);
- rc = afb_hsrv_start(hsrv, (uint16_t) main_config->httpdPort, 15);
+ rc = afb_hsrv_start(hsrv, (uint16_t) main_config->http_port, 15);
if (!rc) {
ERROR("starting of httpd failed");
afb_hsrv_put(hsrv);
@@ -419,8 +421,8 @@ static int execute_command()
return 0;
/* compute the string for port */
- if (main_config->httpdPort)
- rc = snprintf(port, sizeof port, "%d", main_config->httpdPort);
+ if (main_config->http_port)
+ rc = snprintf(port, sizeof port, "%d", main_config->http_port);
else
rc = snprintf(port, sizeof port, "%cp", SUBST_CHAR);
if (rc < 0 || rc >= (int)(sizeof port)) {
@@ -455,14 +457,16 @@ struct startup_req
struct afb_session *session;
};
-static void startup_call_reply(struct afb_xreq *xreq, int status, struct json_object *obj)
+static void startup_call_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
{
struct startup_req *sreq = CONTAINER_OF_XREQ(struct startup_req, xreq);
- if (status >= 0)
- NOTICE("startup call %s returned %s", sreq->current->value, json_object_get_string(obj));
- else {
- ERROR("startup call %s ERROR! %s", sreq->current->value, json_object_get_string(obj));
+ info = info ?: "";
+ if (!error) {
+ NOTICE("startup call %s returned %s (%s)", sreq->current->value, json_object_get_string(object), info);
+ json_object_put(object);
+ } else {
+ ERROR("startup call %s ERROR! %s (%s)", sreq->current->value, error, info);
exit(1);
}
}
@@ -506,8 +510,8 @@ static void startup_call_current(struct startup_req *sreq)
sreq->xreq.context.validated = 1;
sreq->api = strndup(api, verb - api);
sreq->verb = strndup(verb + 1, json - verb - 1);
- sreq->xreq.request.api = sreq->api;
- sreq->xreq.request.verb = sreq->verb;
+ sreq->xreq.request.called_api = sreq->api;
+ sreq->xreq.request.called_verb = sreq->verb;
sreq->xreq.json = json_tokener_parse(json + 1);
if (sreq->api && sreq->verb && sreq->xreq.json) {
afb_xreq_process(&sreq->xreq, main_apiset);
@@ -560,16 +564,16 @@ static void start(int signum, void *arg)
}
/* configure the daemon */
- if (afb_session_init(main_config->nbSessionMax, main_config->cntxTimeout, main_config->token)) {
+ if (afb_session_init(main_config->max_session_count, main_config->session_timeout, main_config->token)) {
ERROR("initialisation of session manager failed");
goto error;
}
- main_apiset = afb_apiset_create("main", main_config->apiTimeout);
+ main_apiset = afb_apiset_create("main", main_config->api_timeout);
if (!main_apiset) {
ERROR("can't create main api set");
goto error;
}
- if (afb_monitor_init() < 0) {
+ if (afb_monitor_init(main_apiset, main_apiset) < 0) {
ERROR("failed to setup monitor");
goto error;
}
@@ -581,10 +585,8 @@ static void start(int signum, void *arg)
/* install hooks */
if (main_config->tracereq)
afb_hook_create_xreq(NULL, NULL, NULL, main_config->tracereq, NULL, NULL);
- if (main_config->traceditf)
- afb_hook_create_ditf(NULL, main_config->traceditf, NULL, NULL);
- if (main_config->tracesvc)
- afb_hook_create_svc(NULL, main_config->tracesvc, NULL, NULL);
+ if (main_config->traceapi)
+ afb_hook_create_api(NULL, main_config->traceapi, NULL, NULL);
if (main_config->traceevt)
afb_hook_create_evt(NULL, main_config->traceevt, NULL, NULL);
if (main_config->traceses)
@@ -599,6 +601,8 @@ static void start(int signum, void *arg)
apiset_start_list(main_config->ws_clients, afb_api_ws_add_client_weak, "the afb-websocket client");
apiset_start_list(main_config->ldpaths, afb_api_so_add_pathset_fails, "the binding path set");
apiset_start_list(main_config->weak_ldpaths, afb_api_so_add_pathset_nofails, "the weak binding path set");
+ apiset_start_list(main_config->auto_ws, afb_autoset_add_ws, "the automatic afb-websocket path set");
+ apiset_start_list(main_config->auto_link, afb_autoset_add_so, "the automatic link binding path set");
#if defined(WITH_DBUS_TRANSPARENCY)
apiset_start_list(main_config->dbus_servers, afb_api_dbus_add_server, "the afb-dbus service");
@@ -617,13 +621,13 @@ static void start(int signum, void *arg)
/* start the HTTP server */
afb_debug("start-http");
- if (!main_config->noHttpd) {
- if (main_config->httpdPort <= 0) {
+ if (!main_config->no_httpd) {
+ if (main_config->http_port <= 0) {
ERROR("no port is defined");
goto error;
}
- if (!afb_hreq_init_cookie(main_config->httpdPort, main_config->rootapi, main_config->cntxTimeout)) {
+ if (!afb_hreq_init_cookie(main_config->http_port, main_config->rootapi, main_config->session_timeout)) {
ERROR("initialisation of HTTP cookies failed");
goto error;
}
diff --git a/src/afs-main.c b/src/main-afs-supervisor.c
index 88e4757f..14f1c3b0 100644
--- a/src/afs-main.c
+++ b/src/main-afs-supervisor.c
@@ -144,7 +144,7 @@ static void start(int signum, void *arg)
}
/* init the main apiset */
- rc = afs_supervisor_add(main_apiset);
+ rc = afs_supervisor_add(main_apiset, main_apiset);
if (rc < 0) {
ERROR("Can't create supervision's apiset: %m");
goto error;
@@ -152,7 +152,7 @@ static void start(int signum, void *arg)
/* export the service if required */
if (main_config->ws_server) {
- rc = afb_api_ws_add_server(main_config->ws_server, main_apiset);
+ rc = afb_api_ws_add_server(main_config->ws_server, main_apiset, main_apiset);
if (rc < 0) {
ERROR("Can't export (ws-server) api %s: %m", main_config->ws_server);
goto error;
diff --git a/src/monitor-api.inc b/src/monitor-api.inc
index cbc1187f..e4dc2c92 100644
--- a/src/monitor-api.inc
+++ b/src/monitor-api.inc
@@ -1,5 +1,5 @@
-static const char _afb_description_v2_monitor[] =
+static const char _afb_description_monitor[] =
"{\"openapi\":\"3.0.0\",\"info\":{\"description\":\"monitoring of binding"
"s and internals\",\"title\":\"monitor\",\"version\":\"1.0\",\"x-binding-"
"c-generator\":{\"api\":\"monitor\",\"version\":2,\"prefix\":\"f_\",\"pos"
@@ -118,57 +118,68 @@ static const char _afb_description_v2_monitor[] =
"}}}}}}}}}"
;
-static void f_get(struct afb_req req);
-static void f_set(struct afb_req req);
-static void f_trace(struct afb_req req);
-static void f_session(struct afb_req req);
+static void f_get(afb_req_t req);
+static void f_set(afb_req_t req);
+static void f_trace(afb_req_t req);
+static void f_session(afb_req_t req);
-static const struct afb_verb_v2 _afb_verbs_v2_monitor[] = {
+static const struct afb_verb_v3 _afb_verbs_monitor[] = {
{
.verb = "get",
.callback = f_get,
.auth = NULL,
.info = "Get monitoring data.",
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK,
+ .vcbdata = NULL,
+ .glob = 0
},
{
.verb = "set",
.callback = f_set,
.auth = NULL,
.info = "Set monitoring actions.",
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK,
+ .vcbdata = NULL,
+ .glob = 0
},
{
.verb = "trace",
.callback = f_trace,
.auth = NULL,
.info = "Set monitoring actions.",
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK,
+ .vcbdata = NULL,
+ .glob = 0
},
{
.verb = "session",
.callback = f_session,
.auth = NULL,
.info = "describes the session.",
- .session = AFB_SESSION_CHECK_V2
+ .session = AFB_SESSION_CHECK,
+ .vcbdata = NULL,
+ .glob = 0
},
{
.verb = NULL,
.callback = NULL,
.auth = NULL,
.info = NULL,
- .session = 0
+ .session = 0,
+ .vcbdata = NULL,
+ .glob = 0
}
};
-static const struct afb_binding_v2 _afb_binding_v2_monitor = {
+static const struct afb_binding_v3 _afb_binding_monitor = {
.api = "monitor",
- .specification = _afb_description_v2_monitor,
+ .specification = _afb_description_monitor,
.info = "monitoring of bindings and internals",
- .verbs = _afb_verbs_v2_monitor,
+ .verbs = _afb_verbs_monitor,
.preinit = NULL,
.init = NULL,
.onevent = NULL,
+ .userdata = NULL,
.noconcurrency = 0
};
diff --git a/src/pearson.c b/src/pearson.c
new file mode 100644
index 00000000..a39c8952
--- /dev/null
+++ b/src/pearson.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+/*
+ * Returns a tiny hash value for the 'text'.
+ *
+ * Tiny hash function inspired from pearson
+ */
+uint8_t pearson4(const char *text)
+{
+ static uint8_t T[16] = {
+ 4, 1, 6, 0, 9, 14, 11, 5,
+ 2, 3, 12, 15, 10, 7, 8, 13
+ };
+ uint8_t r, c;
+
+ for (r = 0; (c = (uint8_t)*text) ; text++) {
+ r = T[r ^ (15 & c)];
+ r = T[r ^ (c >> 4)];
+ }
+ return r; // % HEADCOUNT;
+}
+
diff --git a/src/pearson.h b/src/pearson.h
new file mode 100644
index 00000000..2daa6546
--- /dev/null
+++ b/src/pearson.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+extern uint8_t pearson4(const char *text);
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index f63f27ae..f0349a68 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -22,6 +22,8 @@ if(check_FOUND)
INCLUDE_DIRECTORIES(${INCLUDE_DIRS} ${check_INCLUDE_DIRS})
SET(link_libraries ${link_libraries} ${check_LDFLAGS})
add_subdirectory(session)
+ add_subdirectory(apiset)
+ add_subdirectory(apiv3)
else(check_FOUND)
MESSAGE(WARNING "check not found! no test!")
endif(check_FOUND)
diff --git a/src/tests/apiset/CMakeLists.txt b/src/tests/apiset/CMakeLists.txt
new file mode 100644
index 00000000..180c80b8
--- /dev/null
+++ b/src/tests/apiset/CMakeLists.txt
@@ -0,0 +1,23 @@
+###########################################################################
+# Copyright (C) 2018 "IoT.bzh"
+#
+# author: José Bollo <jose.bollo@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+add_executable(test-apiset test-apiset.c)
+target_include_directories(test-apiset PRIVATE ../..)
+target_link_libraries(test-apiset afb-lib ${link_libraries})
+add_test(NAME apiset COMMAND test-apiset)
+
diff --git a/src/tests/apiset/test-apiset.c b/src/tests/apiset/test-apiset.c
new file mode 100644
index 00000000..bdc84137
--- /dev/null
+++ b/src/tests/apiset/test-apiset.c
@@ -0,0 +1,579 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
+#include <check.h>
+#if !defined(ck_assert_ptr_null)
+# define ck_assert_ptr_null(X) ck_assert_ptr_eq(X, NULL)
+# define ck_assert_ptr_nonnull(X) ck_assert_ptr_ne(X, NULL)
+#endif
+
+#include "afb-api.h"
+#include "afb-apiset.h"
+
+const char *names[] = {
+ "Sadie",
+ "Milford",
+ "Yvette",
+ "Carma",
+ "Cory",
+ "Clarence",
+ "Jeffery",
+ "Molly",
+ "Sheba",
+ "Tasha",
+ "Corey",
+ "Gerry",
+ NULL
+};
+
+const char *aliases[] = {
+ "Rich", "Molly",
+ "Alicia", "Carma",
+ "Drema", "YVETTE",
+ "Pablo", "Sheba",
+ "Wendell", "Sadie",
+ "Cathrine", "CarMa",
+ "Allen", "Corey",
+ "Tori", "Drema",
+ NULL
+};
+
+const char *extras[] = {
+ "Meta",
+ "Delia",
+ "Pearlie",
+ "Hank",
+ "Vena",
+ "Terrance",
+ "Gloria",
+ "Tobi",
+ "Mack",
+ "Rosalee",
+ NULL
+};
+
+struct afb_api_itf api_itf_null = {
+ .call = NULL,
+ .service_start = NULL,
+ .update_hooks = NULL,
+ .get_logmask = NULL,
+ .set_logmask = NULL,
+ .describe = NULL,
+ .unref = NULL
+};
+
+
+/*********************************************************************/
+/* check the initialisation */
+START_TEST (check_initialisation)
+{
+ const char name[] = "name";
+ const char noname[] = "";
+ int to = 3600;
+ int noto = -1;
+ struct afb_apiset *a, *b;
+
+ a = afb_apiset_create(NULL, noto);
+ ck_assert_ptr_nonnull(a);
+ ck_assert_str_eq(noname, afb_apiset_name(a));
+ ck_assert_int_eq(noto, afb_apiset_timeout_get(a));
+ afb_apiset_timeout_set(a, to);
+ ck_assert_int_eq(to, afb_apiset_timeout_get(a));
+ b = afb_apiset_addref(a);
+ ck_assert_ptr_eq(a, b);
+ afb_apiset_unref(b);
+ afb_apiset_unref(a);
+
+ a = afb_apiset_create(name, to);
+ ck_assert_ptr_nonnull(a);
+ ck_assert_str_eq(name, afb_apiset_name(a));
+ ck_assert_int_eq(to, afb_apiset_timeout_get(a));
+ afb_apiset_timeout_set(a, noto);
+ ck_assert_int_eq(noto, afb_apiset_timeout_get(a));
+ b = afb_apiset_addref(a);
+ ck_assert_ptr_eq(a, b);
+ afb_apiset_unref(b);
+ afb_apiset_unref(a);
+}
+END_TEST
+
+/*********************************************************************/
+/* check that NULL is a valid value for addref/unref */
+START_TEST (check_sanity)
+{
+ struct afb_apiset *a;
+
+ a = afb_apiset_addref(NULL);
+ ck_assert_ptr_null(a);
+ afb_apiset_unref(NULL);
+ ck_assert(1);
+}
+END_TEST
+
+/*********************************************************************/
+/* check creation and retrieval of apis */
+
+START_TEST (check_creation)
+{
+ int i, j, nn, na;
+ struct afb_apiset *a;
+ struct afb_api_item sa;
+ const char *x, *y, **set;
+ const struct afb_api_item *pa;
+
+ /* create a apiset */
+ a = afb_apiset_create(NULL, 0);
+ ck_assert_ptr_nonnull(a);
+
+ /* add apis */
+ for (i = 0 ; names[i] != NULL ; i++) {
+ sa.itf = &api_itf_null;
+ sa.closure = (void*)names[i];
+ sa.group = names[i];
+ ck_assert_int_eq(0, afb_apiset_add(a, names[i], sa));
+ pa = afb_apiset_lookup(a, names[i], 1);
+ ck_assert_ptr_nonnull(pa);
+ ck_assert_ptr_eq(sa.itf, pa->itf);
+ ck_assert_ptr_eq(sa.closure, pa->closure);
+ ck_assert_ptr_eq(sa.group, pa->group);
+ ck_assert_int_eq(0, afb_apiset_is_alias(a, names[i]));
+ ck_assert_str_eq(names[i], afb_apiset_unalias(a, names[i]));
+ ck_assert_int_eq(-1, afb_apiset_add(a, names[i], sa));
+ ck_assert_int_eq(errno, EEXIST);
+ }
+ nn = i;
+
+ /* add aliases */
+ for (i = 0 ; aliases[i] != NULL ; i += 2) {
+ ck_assert_int_eq(-1, afb_apiset_add_alias(a, extras[0], aliases[i]));
+ ck_assert_int_eq(errno, ENOENT);
+ ck_assert_int_eq(0, afb_apiset_add_alias(a, aliases[i + 1], aliases[i]));
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, aliases[i], 1));
+ ck_assert_int_eq(1, afb_apiset_is_alias(a, aliases[i]));
+ x = afb_apiset_unalias(a, aliases[i]);
+ y = afb_apiset_unalias(a, aliases[i + 1]);
+ ck_assert_int_eq(0, strcasecmp(x, y));
+ ck_assert_int_eq(-1, afb_apiset_add_alias(a, aliases[i + 1], aliases[i]));
+ ck_assert_int_eq(errno, EEXIST);
+ }
+ na = i / 2;
+
+ /* check extras */
+ for (i = 0 ; extras[i] != NULL ; i++) {
+ pa = afb_apiset_lookup(a, extras[i], 1);
+ ck_assert_ptr_null(pa);
+ ck_assert_int_eq(errno, ENOENT);
+ }
+
+ /* get the names */
+ set = afb_apiset_get_names(a, 0, 1);
+ ck_assert_ptr_nonnull(set);
+ for (i = 0 ; set[i] != NULL ; i++) {
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0));
+ ck_assert_int_eq(0, afb_apiset_is_alias(a, set[i]));
+ if (i)
+ ck_assert_int_gt(0, strcasecmp(set[i-1], set[i]));
+ }
+ ck_assert_int_eq(i, nn);
+ free(set);
+ set = afb_apiset_get_names(a, 0, 2);
+ ck_assert_ptr_nonnull(set);
+ for (i = 0 ; set[i] != NULL ; i++) {
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0));
+ ck_assert_int_eq(1, afb_apiset_is_alias(a, set[i]));
+ if (i)
+ ck_assert_int_gt(0, strcasecmp(set[i-1], set[i]));
+ }
+ ck_assert_int_eq(i, na);
+ free(set);
+ set = afb_apiset_get_names(a, 0, 3);
+ ck_assert_ptr_nonnull(set);
+ for (i = 0 ; set[i] != NULL ; i++) {
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0));
+ if (i)
+ ck_assert_int_gt(0, strcasecmp(set[i-1], set[i]));
+ }
+ ck_assert_int_eq(i, nn + na);
+
+ /* removes the apis to check deletion */
+ for (i = 0 ; i < nn + na ; i++) {
+ if (!set[i])
+ continue;
+
+ /* should be present */
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0));
+
+ /* deleting a non aliased api removes the aliases! */
+ if (!afb_apiset_is_alias(a, set[i])) {
+ for (j = i + 1 ; j < nn + na ; j++) {
+ if (!set[j])
+ continue;
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[j], 0));
+ if (afb_apiset_is_alias(a, set[j])
+ && afb_apiset_lookup(a, set[i], 0) == afb_apiset_lookup(a, set[j], 0)) {
+ ck_assert(set[j][0] > 0);
+ ((char*)set[j])[0] = (char)-set[j][0];
+ }
+ }
+ }
+
+ /* delete now */
+ ck_assert_int_eq(0, afb_apiset_del(a, set[i]));
+ ck_assert_ptr_null(afb_apiset_lookup(a, set[i], 0));
+
+ /* check other not removed except aliases */
+ for (j = i + 1 ; j < nn + na ; j++) {
+ if (!set[j])
+ continue;
+ if (set[j][0] > 0)
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[j], 0));
+ else {
+ ((char*)set[j])[0] = (char)-set[j][0];
+ ck_assert_ptr_null(afb_apiset_lookup(a, set[j], 0));
+ set[j] = NULL;
+ }
+ }
+ }
+ free(set);
+
+ afb_apiset_unref(a);
+}
+END_TEST
+
+/*********************************************************************/
+/* check onlack behaviour */
+
+int onlackcount;
+
+static void onlackcleanup(void *closure)
+{
+ int *count = closure;
+ ck_assert_ptr_eq(count, &onlackcount);
+ *count = 0;
+}
+static int onlack(void *closure, struct afb_apiset *a, const char *name)
+{
+ int *count = closure;
+ struct afb_api_item sa;
+
+ ck_assert_ptr_eq(count, &onlackcount);
+ (*count)++;
+
+ sa.itf = &api_itf_null;
+ sa.closure = (void*)name;
+ sa.group = name;
+
+ ck_assert_int_eq(0, afb_apiset_add(a, name, sa));
+ return 1;
+}
+
+START_TEST (check_onlack)
+{
+ int i;
+ struct afb_apiset *a;
+ struct afb_api_item sa;
+ const char *x, *y;
+ const struct afb_api_item *pa;
+
+ /* create a apiset */
+ a = afb_apiset_create(NULL, 0);
+ ck_assert_ptr_nonnull(a);
+
+ /* add apis */
+ for (i = 0 ; names[i] != NULL ; i++) {
+ sa.itf = &api_itf_null;
+ sa.closure = (void*)names[i];
+ sa.group = names[i];
+ ck_assert_int_eq(0, afb_apiset_add(a, names[i], sa));
+ pa = afb_apiset_lookup(a, names[i], 1);
+ ck_assert_ptr_nonnull(pa);
+ ck_assert_ptr_eq(sa.itf, pa->itf);
+ ck_assert_ptr_eq(sa.closure, pa->closure);
+ ck_assert_ptr_eq(sa.group, pa->group);
+ ck_assert_int_eq(0, afb_apiset_is_alias(a, names[i]));
+ ck_assert_str_eq(names[i], afb_apiset_unalias(a, names[i]));
+ ck_assert_int_eq(-1, afb_apiset_add(a, names[i], sa));
+ ck_assert_int_eq(errno, EEXIST);
+ }
+
+ /* add aliases */
+ for (i = 0 ; aliases[i] != NULL ; i += 2) {
+ ck_assert_int_eq(-1, afb_apiset_add_alias(a, extras[0], aliases[i]));
+ ck_assert_int_eq(errno, ENOENT);
+ ck_assert_int_eq(0, afb_apiset_add_alias(a, aliases[i + 1], aliases[i]));
+ ck_assert_ptr_nonnull(afb_apiset_lookup(a, aliases[i], 1));
+ ck_assert_int_eq(1, afb_apiset_is_alias(a, aliases[i]));
+ x = afb_apiset_unalias(a, aliases[i]);
+ y = afb_apiset_unalias(a, aliases[i + 1]);
+ ck_assert_int_eq(0, strcasecmp(x, y));
+ ck_assert_int_eq(-1, afb_apiset_add_alias(a, aliases[i + 1], aliases[i]));
+ ck_assert_int_eq(errno, EEXIST);
+ }
+
+ /* check extras */
+ for (i = 0 ; extras[i] != NULL ; i++) {
+ pa = afb_apiset_lookup(a, extras[i], 1);
+ ck_assert_ptr_null(pa);
+ ck_assert_int_eq(errno, ENOENT);
+ }
+
+ /* put the onlack feature */
+ afb_apiset_onlack_set(a, onlack, &onlackcount, onlackcleanup);
+
+ /* check extras */
+ onlackcount = 0;
+ for (i = 0 ; extras[i] != NULL ; i++) {
+ ck_assert_int_eq(onlackcount, i);
+ pa = afb_apiset_lookup(a, extras[i], 1);
+ ck_assert_int_eq(onlackcount, i + 1);
+ ck_assert_ptr_nonnull(pa);
+ ck_assert_ptr_eq(&api_itf_null, pa->itf);
+ ck_assert_ptr_eq(extras[i], pa->closure);
+ ck_assert_ptr_eq(extras[i], pa->group);
+ }
+
+ ck_assert_int_eq(onlackcount, i);
+ afb_apiset_unref(a);
+ ck_assert_int_eq(onlackcount, 0);
+}
+END_TEST
+
+/*********************************************************************/
+
+struct set_api {
+ const char *name;
+ int init;
+ int mask;
+} set_apis[] = {
+ { "Sadie", 0, 0 },
+ { "Milford", 0, 0 },
+ { "Yvette", 0, 0 },
+ { "Carma", 0, 0 },
+ { "Cory", 0, 0 },
+ { "Clarence", 0, 0 },
+ { "Jeffery", 0, 0 },
+ { "Molly", 0, 0 },
+ { "Sheba", 0, 0 },
+ { "Tasha", 0, 0 },
+ { "Corey", 0, 0 },
+ { "Gerry", 0, 0 },
+ { NULL, 0, 0 }
+};
+
+int set_count;
+struct set_api *set_last_api;
+
+void set_cb0(void *closure)
+{
+ set_last_api = closure;
+ set_count++;
+}
+
+void set_cb_setmask(void *closure, int mask)
+{
+ set_cb0(closure);
+ set_last_api->mask = mask;
+}
+
+int set_cb_getmask(void *closure)
+{
+ set_cb0(closure);
+ return set_last_api->mask;
+}
+
+int set_cb_start(void *closure, int share_session, int onneed)
+{
+ set_cb0(closure);
+ ck_assert_int_eq(0, set_last_api->init);
+ set_last_api->init = 1;
+ return 0;
+}
+
+struct afb_api_itf set_api_itf = {
+ .call = NULL,
+ .service_start = set_cb_start,
+ .update_hooks = set_cb0,
+ .get_logmask = set_cb_getmask,
+ .set_logmask = set_cb_setmask,
+ .describe = NULL,
+ .unref = set_cb0
+};
+
+START_TEST (check_settings)
+{
+ int i, nn, mask;
+ struct afb_apiset *a;
+ struct afb_api_item sa;
+
+ /* create a apiset */
+ a = afb_apiset_create(NULL, 0);
+ ck_assert_ptr_nonnull(a);
+
+ /* add apis */
+ for (i = 0 ; set_apis[i].name != NULL ; i++) {
+ sa.itf = &set_api_itf;
+ sa.closure = &set_apis[i];
+ sa.group = NULL;
+ ck_assert_int_eq(0, afb_apiset_add(a, set_apis[i].name, sa));
+ }
+ nn = i;
+
+ set_count = 0;
+ afb_apiset_start_all_services(a, 1);
+ ck_assert_int_eq(nn, set_count);
+
+ set_count = 0;
+ afb_apiset_update_hooks(a, NULL);
+ ck_assert_int_eq(nn, set_count);
+
+ for (mask = 1 ; !(mask >> 10) ; mask <<= 1) {
+ set_count = 0;
+ afb_apiset_set_logmask(a, NULL, mask);
+ ck_assert_int_eq(nn, set_count);
+ set_count = 0;
+ for (i = 0 ; set_apis[i].name != NULL ; i++) {
+ ck_assert_int_eq(mask, afb_apiset_get_logmask(a, set_apis[i].name));
+ ck_assert_ptr_eq(set_last_api, &set_apis[i]);
+ ck_assert_int_eq(i + 1, set_count);
+ }
+ }
+
+ set_count = 0;
+ afb_apiset_unref(a);
+ ck_assert_int_eq(nn, set_count);
+}
+END_TEST
+
+/*********************************************************************/
+
+struct clacl {
+ const char *name;
+ int count;
+} clacl[] = {
+ { "Sadie", 0 },
+ { "Milford", 0 },
+ { "Yvette", 0 },
+};
+
+struct clapi {
+ const char *name;
+ const char *provides;
+ const char *requires;
+ const char *apireq;
+ int init;
+ int expect;
+} clapi[] = {
+ { "Carma", "", "Sadie", "", 0, 9 },
+ { "Cory", "Milford", "", "Clarence", 0, 3 },
+ { "Clarence", "Milford", "", "Jeffery", 0, 2 },
+ { "Jeffery", "Milford", "", "", 0, 1 },
+ { "Molly", "Yvette", "", "Corey", 0, 6 },
+ { "Sheba", "Yvette", "Milford", "Molly", 0, 7 },
+ { "Tasha", "Sadie", "Yvette", "", 0, 8 },
+ { "Corey", "Sadie", "Milford", "Gerry", 0, 5 },
+ { "Gerry", "Sadie", "Milford", "", 0, 4 },
+ { NULL, NULL, NULL, NULL, 0, 0 }
+};
+
+int clorder;
+
+int clacb_start(void *closure, int share_session, int onneed)
+{
+ struct clapi *a = closure;
+ int i;
+
+ ck_assert_int_eq(0, a->init);
+
+ for (i = 0 ; clapi[i].name ; i++) {
+ if (a->requires && a->requires[0]
+ && clapi[i].provides && clapi[i].provides[0]
+ && !strcmp(a->requires, clapi[i].provides))
+ ck_assert_int_ne(0, clapi[i].init);
+ if (a->apireq && a->apireq[0]
+ && !strcmp(a->apireq, clapi[i].name))
+ ck_assert_int_ne(0, clapi[i].init);
+ }
+ a->init = ++clorder;
+ ck_assert_int_eq(a->init, a->expect);
+
+ return 0;
+}
+
+struct afb_api_itf clitf = {
+ .call = NULL,
+ .service_start = clacb_start,
+ .update_hooks = NULL,
+ .get_logmask = NULL,
+ .set_logmask = NULL,
+ .describe = NULL,
+ .unref = NULL
+};
+
+START_TEST (check_classes)
+{
+ int i;
+ struct afb_apiset *a;
+ struct afb_api_item sa;
+
+ /* create a apiset */
+ a = afb_apiset_create(NULL, 0);
+ ck_assert_ptr_nonnull(a);
+
+ /* add apis */
+ for (i = 0 ; clapi[i].name != NULL ; i++) {
+ sa.itf = &clitf;
+ sa.closure = &clapi[i];
+ sa.group = NULL;
+ ck_assert_int_eq(0, afb_apiset_add(a, clapi[i].name, sa));
+ }
+
+ /* add constraints */
+ for (i = 0 ; clapi[i].name != NULL ; i++) {
+ if (clapi[i].provides && clapi[i].provides[0])
+ ck_assert_int_eq(0, afb_apiset_provide_class(a, clapi[i].name, clapi[i].provides));
+ if (clapi[i].requires && clapi[i].requires[0])
+ ck_assert_int_eq(0, afb_apiset_require_class(a, clapi[i].name, clapi[i].requires));
+ if (clapi[i].apireq && clapi[i].apireq[0])
+ ck_assert_int_eq(0, afb_apiset_require(a, clapi[i].name, clapi[i].apireq));
+ }
+
+ /* start all */
+ ck_assert_int_eq(0, afb_apiset_start_all_services(a, 0));
+
+ afb_apiset_unref(a);
+}
+END_TEST
+
+/*********************************************************************/
+
+static Suite *suite;
+static TCase *tcase;
+
+void mksuite(const char *name) { suite = suite_create(name); }
+void addtcase(const char *name) { tcase = tcase_create(name); suite_add_tcase(suite, tcase); }
+void addtest(TFun fun) { tcase_add_test(tcase, fun); }
+int srun()
+{
+ int nerr;
+ SRunner *srunner = srunner_create(suite);
+ srunner_run_all(srunner, CK_NORMAL);
+ nerr = srunner_ntests_failed(srunner);
+ srunner_free(srunner);
+ return nerr;
+}
+
+int main(int ac, char **av)
+{
+ mksuite("apiset");
+ addtcase("apiset");
+ addtest(check_initialisation);
+ addtest(check_sanity);
+ addtest(check_creation);
+ addtest(check_onlack);
+ addtest(check_settings);
+ addtest(check_classes);
+ return !!srun();
+}
diff --git a/src/tests/apiv3/CMakeLists.txt b/src/tests/apiv3/CMakeLists.txt
new file mode 100644
index 00000000..dfc44619
--- /dev/null
+++ b/src/tests/apiv3/CMakeLists.txt
@@ -0,0 +1,24 @@
+###########################################################################
+# Copyright (C) 2018 "IoT.bzh"
+#
+# author: José Bollo <jose.bollo@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+add_executable(test-apiv3 test-apiv3.c)
+target_include_directories(test-apiv3 PRIVATE ../..)
+target_link_libraries(test-apiv3 afb-lib ${link_libraries})
+add_test(NAME apiv3 COMMAND test-apiv3)
+
+
diff --git a/src/tests/apiv3/test-apiv3.c b/src/tests/apiv3/test-apiv3.c
new file mode 100644
index 00000000..dec1af97
--- /dev/null
+++ b/src/tests/apiv3/test-apiv3.c
@@ -0,0 +1,198 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
+#include <check.h>
+
+#if !defined(ck_assert_ptr_null)
+# define ck_assert_ptr_null(X) ck_assert_ptr_eq(X, NULL)
+# define ck_assert_ptr_nonnull(X) ck_assert_ptr_ne(X, NULL)
+#endif
+
+#define AFB_BINDING_VERSION 0
+#include <afb/afb-binding.h>
+#include "afb-api.h"
+#include "afb-apiset.h"
+#include "afb-api-v3.h"
+
+struct inapis {
+ struct afb_binding_v3 desc;
+ struct afb_api_x3 *api;
+ int init;
+};
+
+struct inapis inapis[] = {
+ { .desc = {
+ .api = "ezra",
+ .provide_class = "e",
+ .require_class = "c",
+ .require_api = "armel"
+ }},
+ { .desc = {
+ .api = "clara",
+ .provide_class = "c",
+ .require_class = "a"
+ }},
+ { .desc = {
+ .api = "amelie",
+ .provide_class = "a",
+ .require_api = "albert armel"
+ }},
+ { .desc = {
+ .api = "chloe",
+ .provide_class = "c a"
+ }},
+ { .desc = {
+ .api = "albert",
+ .provide_class = "a"
+ }},
+ { .desc = {
+ .api = "armel",
+ .provide_class = "a",
+ .require_api = "albert"
+ }},
+ { .desc = { .api = NULL }}
+};
+
+int last_in_init;
+
+int in_init(struct afb_api_x3 *api)
+{
+ struct inapis *desc = api->userdata;
+
+ ck_assert_str_eq(api->apiname, desc->desc.api);
+ ck_assert_int_eq(desc->init, 0);
+
+ desc->init = ++last_in_init;
+ printf("init %d of %s\n", desc->init, api->apiname);
+ return 0;
+}
+
+int in_preinit(void *closure, struct afb_api_x3 *api)
+{
+ int rc;
+ struct inapis *desc = closure;
+
+ printf("default preinit of %s\n", api->apiname);
+
+ ck_assert_ptr_nonnull(api);
+ ck_assert_ptr_nonnull(desc);
+ ck_assert_ptr_nonnull(api->apiname);
+ ck_assert_ptr_null(api->userdata);
+ ck_assert_str_eq(api->apiname, desc->desc.api);
+ ck_assert_ptr_null(desc->api);
+ ck_assert_int_eq(desc->init, 0);
+
+ rc = afb_api_v3_set_binding_fields(&desc->desc, api);
+ ck_assert_int_eq(rc, 0);
+
+ api->userdata = desc;
+ desc->api = api;
+
+ if (desc->desc.preinit)
+ desc->desc.preinit(api);
+
+ if (!desc->desc.init) {
+ rc = afb_api_x3_on_init(api, in_init);
+ ck_assert_int_eq(rc, 0);
+ }
+
+ return 0;
+}
+
+int out_init(struct afb_api_x3 *api)
+{
+ return 0;
+}
+
+struct afb_apiset *apiset;
+char out_apiname[] = "out";
+struct afb_api_v3 *out_v3;
+struct afb_api_x3 *out_api;
+
+int out_preinit(void *closure, struct afb_api_x3 *api)
+{
+ int i;
+ int rc;
+ struct afb_api_x3 *napi;
+
+ ck_assert_ptr_nonnull(api);
+ ck_assert_ptr_eq(closure, out_apiname);
+ ck_assert_ptr_null(api->userdata);
+ ck_assert_str_eq(api->apiname, out_apiname);
+ out_api = api;
+
+ for (i = 0 ; inapis[i].desc.api ; i++) {
+ ck_assert_ptr_null(inapis[i].api);
+ napi = afb_api_x3_new_api(
+ api,
+ inapis[i].desc.api,
+ NULL,
+ 0,
+ in_preinit,
+ &inapis[i]);
+ ck_assert_ptr_nonnull(napi);
+ ck_assert_ptr_nonnull(inapis[i].api);
+ ck_assert_ptr_eq(inapis[i].api, napi);
+ }
+
+ rc = afb_api_x3_on_init(api, out_init);
+ ck_assert_int_eq(rc, 0);
+
+ return 0;
+}
+
+START_TEST (test)
+{
+ int rc;
+
+ apiset = afb_apiset_create("test-apiv3", 1);
+ ck_assert_ptr_nonnull(apiset);
+
+ out_v3 = afb_api_v3_create(
+ apiset,
+ apiset,
+ out_apiname,
+ NULL,
+ 0,
+ out_preinit,
+ out_apiname,
+ 0
+ );
+ ck_assert_ptr_nonnull(out_v3);
+ ck_assert_ptr_nonnull(out_api);
+
+ /* start all services */
+ rc = afb_apiset_start_all_services(apiset, 1);
+ ck_assert_int_eq(rc, 0);
+}
+END_TEST
+
+
+/*********************************************************************/
+
+static Suite *suite;
+static TCase *tcase;
+
+void mksuite(const char *name) { suite = suite_create(name); }
+void addtcase(const char *name) { tcase = tcase_create(name); suite_add_tcase(suite, tcase); }
+void addtest(TFun fun) { tcase_add_test(tcase, fun); }
+int srun()
+{
+ int nerr;
+ SRunner *srunner = srunner_create(suite);
+ srunner_run_all(srunner, CK_NORMAL);
+ nerr = srunner_ntests_failed(srunner);
+ srunner_free(srunner);
+ return nerr;
+}
+
+int main(int ac, char **av)
+{
+ mksuite("apiv3");
+ addtcase("apiv3");
+ addtest(test);
+ return !!srun();
+}
diff --git a/src/tests/session/test-session.c b/src/tests/session/test-session.c
index 58e57536..637b0a16 100644
--- a/src/tests/session/test-session.c
+++ b/src/tests/session/test-session.c
@@ -55,7 +55,7 @@ START_TEST (check_creation)
ck_assert(afb_session_uuid(s) != NULL);
ck_assert(afb_session_token(s) != NULL);
ck_assert(!afb_session_is_closed(s));
-
+
/* token is the initial one */
ck_assert_str_eq(afb_session_token(s), GOOD_UUID);
ck_assert(afb_session_check_token(s, GOOD_UUID));
diff --git a/src/verbose.c b/src/verbose.c
index 3e266a18..5fd1940c 100644
--- a/src/verbose.c
+++ b/src/verbose.c
@@ -21,14 +21,44 @@
#include "verbose.h"
-#if !defined(DEFAULT_VERBOSITY)
-# define DEFAULT_VERBOSITY Verbosity_Level_Warning
+#define MASKOF(x) (1 << (x))
+
+#if !defined(DEFAULT_LOGLEVEL)
+# define DEFAULT_LOGLEVEL Log_Level_Warning
+#endif
+
+#if !defined(DEFAULT_LOGMASK)
+# define DEFAULT_LOGMASK (MASKOF((DEFAULT_LOGLEVEL) + 1) - 1)
+#endif
+
+#if !defined(MINIMAL_LOGLEVEL)
+# define MINIMAL_LOGLEVEL Log_Level_Error
#endif
-int verbosity = 1;
+#if !defined(MINIMAL_LOGMASK)
+# define MINIMAL_LOGMASK (MASKOF((MINIMAL_LOGLEVEL) + 1) - 1)
+#endif
+
+static const char *names[] = {
+ "emergency",
+ "alert",
+ "critical",
+ "error",
+ "warning",
+ "notice",
+ "info",
+ "debug"
+};
+
+static const char asort[] = { 1, 2, 7, 0, 3, 6, 5, 4 };
+
+int logmask = DEFAULT_LOGMASK | MINIMAL_LOGMASK;
+
void (*verbose_observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args);
-#define CROP_LOGLEVEL(x) ((x) < Log_Level_Emergency ? Log_Level_Emergency : (x) > Log_Level_Debug ? Log_Level_Debug : (x))
+#define CROP_LOGLEVEL(x) \
+ ((x) < Log_Level_Emergency ? Log_Level_Emergency \
+ : (x) > Log_Level_Debug ? Log_Level_Debug : (x))
#if defined(VERBOSE_WITH_SYSLOG)
@@ -41,7 +71,7 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun
if (file == NULL || vasprintf(&p, fmt, args) < 0)
vsyslog(loglevel, fmt, args);
else {
- syslog(CROP_LOGLEVEL(loglevel), "%s [%s:%d, function]", p, file, line, function);
+ syslog(CROP_LOGLEVEL(loglevel), "%s [%s:%d, %s]", p, file, line, function?:"?");
free(p);
}
}
@@ -115,14 +145,18 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun
int saverr, n, rc;
struct iovec iov[20];
+ /* save errno */
saverr = errno;
+ /* check if tty (2) or not (1) */
if (!tty)
tty = 1 + isatty(STDERR_FILENO);
+ /* prefix */
iov[0].iov_base = (void*)prefixes[CROP_LOGLEVEL(loglevel)] + (tty - 1 ? 4 : 0);
iov[0].iov_len = strlen(iov[0].iov_base);
+ /* " " */
iov[1].iov_base = (void*)&chars[2];
iov[1].iov_len = 2;
@@ -134,31 +168,40 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun
if (rc < 0)
rc = 0;
else if ((size_t)rc > sizeof buffer) {
+ /* if too long, ellipsis the end with ... */
rc = (int)sizeof buffer;
buffer[rc - 1] = buffer[rc - 2] = buffer[rc - 3] = '.';
}
iov[n++].iov_len = (size_t)rc;
}
if (file && (!fmt || tty == 1 || loglevel <= Log_Level_Warning)) {
+ /* "[" (!fmt) or " [" (fmt) */
iov[n].iov_base = (void*)&chars[3 + !fmt];
iov[n++].iov_len = 2 - !fmt;
+ /* file */
iov[n].iov_base = (void*)file;
iov[n++].iov_len = strlen(file);
+ /* ":" */
iov[n].iov_base = (void*)&chars[2];
iov[n++].iov_len = 1;
if (line) {
+ /* line number */
iov[n].iov_base = lino;
iov[n++].iov_len = snprintf(lino, sizeof lino, "%d", line);
} else {
+ /* "?" */
iov[n].iov_base = (void*)&chars[1];
iov[n++].iov_len = 1;
}
+ /* "," */
iov[n].iov_base = (void*)&chars[5];
iov[n++].iov_len = 1;
if (function) {
+ /* function name */
iov[n].iov_base = (void*)function;
iov[n++].iov_len = strlen(function);
} else {
+ /* "?" */
iov[n].iov_base = (void*)&chars[1];
iov[n++].iov_len = 1;
}
@@ -166,16 +209,20 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun
iov[n++].iov_len = 1;
}
if (n == 2) {
+ /* "?" */
iov[n].iov_base = (void*)&chars[1];
iov[n++].iov_len = 1;
}
+ /* "\n" */
iov[n].iov_base = (void*)&chars[0];
iov[n++].iov_len = 1;
+ /* emit the message */
pthread_mutex_lock(&mutex);
writev(STDERR_FILENO, iov, n);
pthread_mutex_unlock(&mutex);
+ /* restore errno */
errno = saverr;
}
@@ -187,15 +234,6 @@ void verbose_set_name(const char *name, int authority)
#endif
-void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vverbose(loglevel, file, line, function, fmt, ap);
- va_end(ap);
-}
-
void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
{
void (*observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) = verbose_observer;
@@ -211,3 +249,89 @@ void vverbose(int loglevel, const char *file, int line, const char *function, co
}
}
+void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vverbose(loglevel, file, line, function, fmt, ap);
+ va_end(ap);
+}
+
+void set_logmask(int lvl)
+{
+ logmask = lvl | MINIMAL_LOGMASK;
+}
+
+void verbose_add(int level)
+{
+ set_logmask(logmask | MASKOF(level));
+}
+
+void verbose_sub(int level)
+{
+ set_logmask(logmask & ~MASKOF(level));
+}
+
+void verbose_clear()
+{
+ set_logmask(0);
+}
+
+void verbose_dec()
+{
+ verbosity_set(verbosity_get() - 1);
+}
+
+void verbose_inc()
+{
+ verbosity_set(verbosity_get() + 1);
+}
+
+int verbosity_to_mask(int verbo)
+{
+ int x = verbo + Log_Level_Error;
+ int l = CROP_LOGLEVEL(x);
+ return (1 << (l + 1)) - 1;
+}
+
+int verbosity_from_mask(int mask)
+{
+ int v = 0;
+ while (mask > verbosity_to_mask(v))
+ v++;
+ return v;
+}
+
+void verbosity_set(int verbo)
+{
+ set_logmask(verbosity_to_mask(verbo));
+}
+
+int verbosity_get()
+{
+ return verbosity_from_mask(logmask);
+}
+
+int verbose_level_of_name(const char *name)
+{
+ int c, i, r, l = 0, u = sizeof names / sizeof * names;
+ while (l < u) {
+ i = (l + u) >> 1;
+ r = (int)asort[i];
+ c = strcasecmp(names[r], name);
+ if (!c)
+ return r;
+ if (c < 0)
+ l = i + 1;
+ else
+ u = i;
+ }
+ return -1;
+}
+
+const char *verbose_name_of_level(int level)
+{
+ return level == CROP_LOGLEVEL(level) ? names[level] : NULL;
+}
+
diff --git a/src/verbose.h b/src/verbose.h
index 5cbe2aa6..bd36f97e 100644
--- a/src/verbose.h
+++ b/src/verbose.h
@@ -32,7 +32,6 @@
3 : ERROR, WARNING, NOTICE, INFO
greater than 3 : ERROR, WARNING, NOTICE, INFO, DEBUG
-*/
extern int verbosity;
enum verbosity_levels
@@ -43,6 +42,7 @@ enum verbosity_levels
Verbosity_Level_Info = 3,
Verbosity_Level_Debug = 4
};
+*/
extern void verbose_set_name(const char *name, int authority);
@@ -58,7 +58,7 @@ extern void verbose_set_name(const char *name, int authority);
KERN_DEBUG 7 Debug-level messages
*/
-enum log_levels
+enum
{
Log_Level_Emergency = 0,
Log_Level_Alert = 1,
@@ -70,27 +70,53 @@ enum log_levels
Log_Level_Debug = 7
};
+extern int logmask;
+
extern void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
extern void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args);
#if defined(VERBOSE_NO_DATA)
-# define __VERBOSE__(lvl,...) do{if((lvl)<=Log_Level_Error) verbose(lvl, __FILE__, __LINE__, __func__, __VA_ARGS__)\
- else verbose(lvl, __FILE__, __LINE__, __func__, NULL);}while(0)
+# define __VERBOSE__(lvl,...) do{if((lvl)<=Log_Level_Error) verbose(lvl, __FILE__, __LINE__, NULL, __VA_ARGS__)\
+ else verbose(lvl, __FILE__, __LINE__, NULL, NULL);}while(0)
#elif defined(VERBOSE_NO_DETAILS)
# define __VERBOSE__(lvl,...) verbose(lvl, NULL, 0, NULL, __VA_ARGS__)
#else
# define __VERBOSE__(lvl,...) verbose(lvl, __FILE__, __LINE__, __func__, __VA_ARGS__)
#endif
-# define _VERBOSE_(vlvl,llvl,...) do{ if (verbosity >= vlvl) __VERBOSE__(llvl, __VA_ARGS__); } while(0)
+#define _LOGMASK_(lvl) ((lvl) < 0 ? -1 : (1 << (lvl)))
+#define _WANTLOG_(lvl) (logmask & _LOGMASK_(lvl))
+#define _VERBOSE_(lvl,...) do{ if (_WANTLOG_(lvl)) __VERBOSE__((lvl), __VA_ARGS__); } while(0)
-# define ERROR(...) _VERBOSE_(Verbosity_Level_Error, Log_Level_Error, __VA_ARGS__)
-# define WARNING(...) _VERBOSE_(Verbosity_Level_Warning, Log_Level_Warning, __VA_ARGS__)
-# define NOTICE(...) _VERBOSE_(Verbosity_Level_Notice, Log_Level_Notice, __VA_ARGS__)
-# define INFO(...) _VERBOSE_(Verbosity_Level_Info, Log_Level_Info, __VA_ARGS__)
-# define DEBUG(...) _VERBOSE_(Verbosity_Level_Debug, Log_Level_Debug, __VA_ARGS__)
+#define EMERGENCY(...) _VERBOSE_(Log_Level_Emergency, __VA_ARGS__)
+#define ALERT(...) _VERBOSE_(Log_Level_Alert, __VA_ARGS__)
+#define CRITICAL(...) _VERBOSE_(Log_Level_Critical, __VA_ARGS__)
+#define ERROR(...) _VERBOSE_(Log_Level_Error, __VA_ARGS__)
+#define WARNING(...) _VERBOSE_(Log_Level_Warning, __VA_ARGS__)
+#define NOTICE(...) _VERBOSE_(Log_Level_Notice, __VA_ARGS__)
+#define INFO(...) _VERBOSE_(Log_Level_Info, __VA_ARGS__)
+#define DEBUG(...) _VERBOSE_(Log_Level_Debug, __VA_ARGS__)
-# define LOGUSER(app) verbose_set_name(app,0)
-# define LOGAUTH(app) verbose_set_name(app,1)
+#define LOGUSER(app) verbose_set_name(app,0)
+#define LOGAUTH(app) verbose_set_name(app,1)
extern void (*verbose_observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args);
+
+static inline int verbose_wants(int lvl) { return _WANTLOG_(lvl); }
+
+extern void verbose_dec();
+extern void verbose_inc();
+extern void verbose_clear();
+extern void verbose_add(int level);
+extern void verbose_sub(int level);
+
+extern int verbose_level_of_name(const char *name);
+extern const char *verbose_name_of_level(int level);
+
+#define _DEVERBOSITY_(vlvl) ((vlvl) + Log_Level_Error)
+#define _VERBOSITY_(llvl) ((llvl) - Log_Level_Error)
+extern int verbosity_get();
+extern void verbosity_set(int verbo);
+extern int verbosity_from_mask(int mask);
+extern int verbosity_to_mask(int verbo);
+
diff --git a/src/wrap-json.c b/src/wrap-json.c
index b139e7ad..e757c369 100644
--- a/src/wrap-json.c
+++ b/src/wrap-json.c
@@ -17,6 +17,7 @@
*/
#include <string.h>
+#include <limits.h>
#include "wrap-json.h"
@@ -528,7 +529,7 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i
int64_t *pI = NULL;
size_t *pz = NULL;
uint8_t **py = NULL;
- struct { struct json_object *parent; const char *acc; size_t index; size_t count; char type; } stack[STACKCOUNT], *top;
+ struct { struct json_object *parent; const char *acc; int index; int count; char type; } stack[STACKCOUNT], *top;
struct json_object *obj;
struct json_object **po;
@@ -702,7 +703,7 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i
if (!ignore) {
if (!json_object_is_type(obj, json_type_array))
goto missfit;
- top->count = json_object_array_length(obj);
+ top->count = (int)json_object_array_length(obj);
}
xacc[0] = ']';
acc = unpack_accept_arr;
@@ -752,7 +753,7 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i
if (key && key >= unpack_accept_any) {
if (top->index >= top->count)
goto out_of_range;
- obj = json_object_array_get_idx(top->parent, (int)top->index++);
+ obj = json_object_array_get_idx(top->parent, top->index++);
}
}
break;
@@ -863,10 +864,10 @@ static void object_for_all(struct json_object *object, void (*callback)(void*,st
static void array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
{
- size_t n = json_object_array_length(object);
- size_t i = 0;
+ int n = (int)json_object_array_length(object);
+ int i = 0;
while(i < n)
- callback(closure, json_object_array_get_idx(object, (int)i++));
+ callback(closure, json_object_array_get_idx(object, i++));
}
void wrap_json_optarray_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
@@ -906,16 +907,362 @@ void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct
else if (!json_object_is_type(object, json_type_array))
callback(closure, object, NULL);
else {
- size_t n = json_object_array_length(object);
- size_t i = 0;
+ int n = (int)json_object_array_length(object);
+ int i = 0;
while(i < n)
- callback(closure, json_object_array_get_idx(object, (int)i++), NULL);
+ callback(closure, json_object_array_get_idx(object, i++), NULL);
}
}
+/**
+ * Clones the 'object' for the depth 'subdepth'. The object 'object' is
+ * duplicated and all its fields are cloned with the depth 'subdepth'.
+ *
+ * @param object the object to clone. MUST be an **object**.
+ * @param subdepth the depth to use when cloning the fields of the object.
+ *
+ * @return the cloned object.
+ */
+static struct json_object *clone_object(struct json_object *object, int subdepth)
+{
+ struct json_object *r = json_object_new_object();
+ struct json_object_iterator it = json_object_iter_begin(object);
+ struct json_object_iterator end = json_object_iter_end(object);
+ while (!json_object_iter_equal(&it, &end)) {
+ json_object_object_add(r,
+ json_object_iter_peek_name(&it),
+ wrap_json_clone_depth(json_object_iter_peek_value(&it), subdepth));
+ json_object_iter_next(&it);
+ }
+ return r;
+}
+
+/**
+ * Clones the 'array' for the depth 'subdepth'. The array 'array' is
+ * duplicated and all its fields are cloned with the depth 'subdepth'.
+ *
+ * @param array the array to clone. MUST be an **array**.
+ * @param subdepth the depth to use when cloning the items of the array.
+ *
+ * @return the cloned array.
+ */
+static struct json_object *clone_array(struct json_object *array, int subdepth)
+{
+ int n = json_object_array_length(array);
+ struct json_object *r = json_object_new_array();
+ while (n) {
+ n--;
+ json_object_array_put_idx(r, n,
+ wrap_json_clone_depth(json_object_array_get_idx(array, n), subdepth));
+ }
+ return r;
+}
+
+/**
+ * Clones any json 'item' for the depth 'depth'. The item is duplicated
+ * and if 'depth' is not zero, its contents is recursively cloned with
+ * the depth 'depth' - 1.
+ *
+ * Be aware that this implementation doesn't copies the primitive json
+ * items (numbers, nulls, booleans, strings) but instead increments their
+ * use count. This can cause issues with newer versions of libjson-c that
+ * now unfortunately allows to change their values.
+ *
+ * @param item the item to clone. Can be of any kind.
+ * @param depth the depth to use when cloning composites: object or arrays.
+ *
+ * @return the cloned array.
+ *
+ * @see wrap_json_clone
+ * @see wrap_json_clone_deep
+ */
+struct json_object *wrap_json_clone_depth(struct json_object *item, int depth)
+{
+ if (depth) {
+ switch (json_object_get_type(item)) {
+ case json_type_object:
+ return clone_object(item, depth - 1);
+ case json_type_array:
+ return clone_array(item, depth - 1);
+ default:
+ break;
+ }
+ }
+ return json_object_get(item);
+}
+
+/**
+ * Clones the 'object': returns a copy of it. But doen't clones
+ * the content. Synonym of wrap_json_clone_depth(object, 1).
+ *
+ * @param object the object to clone
+ *
+ * @return a copy of the object.
+ *
+ * @see wrap_json_clone_depth
+ * @see wrap_json_clone_deep
+ */
+struct json_object *wrap_json_clone(struct json_object *object)
+{
+ return wrap_json_clone_depth(object, 1);
+}
+
+/**
+ * Clones the 'object': returns a copy of it. Also clones all
+ * the content recursively. Synonym of wrap_json_clone_depth(object, INT_MAX).
+ *
+ * @param object the object to clone
+ *
+ * @return a copy of the object.
+ *
+ * @see wrap_json_clone_depth
+ * @see wrap_json_clone
+ */
+struct json_object *wrap_json_clone_deep(struct json_object *object)
+{
+ return wrap_json_clone_depth(object, INT_MAX);
+}
+
+/**
+ * Adds the items of the object 'added' to the object 'dest'.
+ *
+ * @param dest the object to complete this object is modified
+ * @added the object containing fields to add
+ *
+ * @return the destination object 'dest'
+ *
+ * @example wrap_json_object_add({"a":"a"},{"X":"X"}) -> {"a":"a","X":"X"}
+ */
+struct json_object *wrap_json_object_add(struct json_object *dest, struct json_object *added)
+{
+ struct json_object_iterator it, end;
+ if (json_object_is_type(dest, json_type_object) && json_object_is_type(added, json_type_object)) {
+ it = json_object_iter_begin(added);
+ end = json_object_iter_end(added);
+ while (!json_object_iter_equal(&it, &end)) {
+ json_object_object_add(dest,
+ json_object_iter_peek_name(&it),
+ json_object_get(json_object_iter_peek_value(&it)));
+ json_object_iter_next(&it);
+ }
+ }
+ return dest;
+}
+
+/**
+ * Sort the 'array' and returns it. Sorting is done accordingly to the
+ * order given by the function 'wrap_json_cmp'. If the paramater isn't
+ * an array, nothing is done and the parameter is returned unchanged.
+ *
+ * @param array the array to sort
+ *
+ * @returns the array sorted
+ */
+struct json_object *wrap_json_sort(struct json_object *array)
+{
+ if (json_object_is_type(array, json_type_array))
+ json_object_array_sort(array, (int(*)(const void*, const void*))wrap_json_cmp);
+
+ return array;
+}
+
+/**
+ * Returns a json array of the sorted keys of 'object' or null if 'object' has no keys.
+ *
+ * @param object the object whose keys are to be returned
+ *
+ * @return either NULL is 'object' isn't an object or a sorted array of the key's strings.
+ */
+struct json_object *wrap_json_keys(struct json_object *object)
+{
+ struct json_object *r;
+ struct json_object_iterator it, end;
+ if (!json_object_is_type(object, json_type_object))
+ r = NULL;
+ else {
+ r = json_object_new_array();
+ it = json_object_iter_begin(object);
+ end = json_object_iter_end(object);
+ while (!json_object_iter_equal(&it, &end)) {
+ json_object_array_add(r, json_object_new_string(json_object_iter_peek_name(&it)));
+ json_object_iter_next(&it);
+ }
+ wrap_json_sort(r);
+ }
+ return r;
+}
+
+/**
+ * Internal comparison of 'x' with 'y'
+ *
+ * @param x first object to compare
+ * @param y second object to compare
+ * @param inc boolean true if should test for inclusion of y in x
+ * @param sort boolean true if comparison used for sorting
+ *
+ * @return an integer indicating the computed result. Refer to
+ * the table below for meaning of the returned value.
+ *
+ * inc | sort | x < y | x == y | x > y | y in x
+ * ----+------+---------+----------+---------+---------
+ * 0 | 0 | != 0 | 0 | != 0 | > 0
+ * 0 | 1 | < 0 | 0 | > 0 | > 0
+ * 1 | 0 | != 0 | 0 | != 0 | 0
+ * 1 | 1 | < 0 | 0 | > 0 | 0
+ *
+ *
+ * if 'x' is found, respectively, to be less than, to match,
+ * or be greater than 'y'. This is valid when 'sort'
+ */
+static int jcmp(struct json_object *x, struct json_object *y, int inc, int sort)
+{
+ double dx, dy;
+ int64_t ix, iy;
+ const char *sx, *sy;
+ enum json_type tx, ty;
+ int r, nx, ny, i;
+ struct json_object_iterator it, end;
+ struct json_object *jx, *jy;
+
+ /* check equality of pointers */
+ if (x == y)
+ return 0;
+
+ /* get the types */
+ tx = json_object_get_type(x);
+ ty = json_object_get_type(y);
+ r = (int)tx - (int)ty;
+ if (r)
+ return r;
+
+ /* compare following the type */
+ switch (tx) {
+ default:
+ case json_type_null:
+ break;
+
+ case json_type_boolean:
+ r = (int)json_object_get_boolean(x)
+ - (int)json_object_get_boolean(y);
+ break;
+
+ case json_type_double:
+ dx = json_object_get_double(x);
+ dy = json_object_get_double(y);
+ r = dx < dy ? -1 : dx > dy;
+ break;
+
+ case json_type_int:
+ ix = json_object_get_int64(x);
+ iy = json_object_get_int64(y);
+ r = ix < iy ? -1 : ix > iy;
+ break;
+
+ case json_type_object:
+ it = json_object_iter_begin(y);
+ end = json_object_iter_end(y);
+ nx = json_object_object_length(x);
+ ny = json_object_object_length(y);
+ r = nx - ny;
+ if (r > 0 && inc)
+ r = 0;
+ while (!r && !json_object_iter_equal(&it, &end)) {
+ if (json_object_object_get_ex(x, json_object_iter_peek_name(&it), &jx)) {
+ jy = json_object_iter_peek_value(&it);
+ json_object_iter_next(&it);
+ r = jcmp(jx, jy, inc, sort);
+ } else if (sort) {
+ jx = wrap_json_keys(x);
+ jy = wrap_json_keys(y);
+ r = wrap_json_cmp(jx, jy);
+ json_object_put(jx);
+ json_object_put(jy);
+ } else
+ r = 1;
+ }
+ break;
+
+ case json_type_array:
+ nx = json_object_array_length(x);
+ ny = json_object_array_length(y);
+ r = nx - ny;
+ if (r > 0 && inc)
+ r = 0;
+ for (i = 0 ; !r && i < ny ; i++) {
+ jx = json_object_array_get_idx(x, i);
+ jy = json_object_array_get_idx(y, i);
+ r = jcmp(jx, jy, inc, sort);
+ }
+ break;
+
+ case json_type_string:
+ sx = json_object_get_string(x);
+ sy = json_object_get_string(y);
+ r = strcmp(sx, sy);
+ break;
+ }
+ return r;
+}
+
+/**
+ * Compares 'x' with 'y'
+ *
+ * @param x first object to compare
+ * @param y second object to compare
+ *
+ * @return an integer less than, equal to, or greater than zero
+ * if 'x' is found, respectively, to be less than, to match,
+ * or be greater than 'y'.
+ */
+int wrap_json_cmp(struct json_object *x, struct json_object *y)
+{
+ return jcmp(x, y, 0, 1);
+}
+
+/**
+ * Searchs wether 'x' equals 'y'
+ *
+ * @param x first object to compare
+ * @param y second object to compare
+ *
+ * @return an integer equal to zero when 'x' != 'y' or 1 when 'x' == 'y'.
+ */
+int wrap_json_equal(struct json_object *x, struct json_object *y)
+{
+ return !jcmp(x, y, 0, 0);
+}
+
+/**
+ * Searchs wether 'x' contains 'y'
+ *
+ * @param x first object to compare
+ * @param y second object to compare
+ *
+ * @return an integer equal to 1 when 'y' is a subset of 'x' or zero otherwise
+ */
+int wrap_json_contains(struct json_object *x, struct json_object *y)
+{
+ return !jcmp(x, y, 1, 0);
+}
+
#if defined(WRAP_JSON_TEST)
#include <stdio.h>
+void tclone(struct json_object *object)
+{
+ struct json_object *o;
+
+ o = wrap_json_clone(object);
+ if (!wrap_json_equal(object, o))
+ printf("ERROR in clone or equal: %s VERSUS %s\n", json_object_to_json_string(object), json_object_to_json_string(o));
+ json_object_put(o);
+
+ o = wrap_json_clone_deep(object);
+ if (!wrap_json_equal(object, o))
+ printf("ERROR in clone_deep or equal: %s VERSUS %s\n", json_object_to_json_string(object), json_object_to_json_string(o));
+ json_object_put(o);
+}
+
void p(const char *desc, ...)
{
int rc;
@@ -929,6 +1276,7 @@ void p(const char *desc, ...)
printf(" SUCCESS %s\n\n", json_object_to_json_string(result));
else
printf(" ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
+ tclone(result);
json_object_put(result);
}
@@ -945,7 +1293,7 @@ void u(const char *value, const char *desc, ...)
unsigned m, k;
int rc;
va_list args;
- struct json_object *obj, *o;
+ struct json_object *object, *o;
memset(xs, 0, sizeof xs);
memset(xi, 0, sizeof xi);
@@ -954,9 +1302,9 @@ void u(const char *value, const char *desc, ...)
memset(xo, 0, sizeof xo);
memset(xy, 0, sizeof xy);
memset(xz, 0, sizeof xz);
- obj = json_tokener_parse(value);
+ object = json_tokener_parse(value);
va_start(args, desc);
- rc = wrap_json_vunpack(obj, desc, args);
+ rc = wrap_json_vunpack(object, desc, args);
va_end(args);
if (rc)
printf(" ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
@@ -996,7 +1344,30 @@ void u(const char *value, const char *desc, ...)
va_end(args);
printf("\n\n");
}
- json_object_put(obj);
+ tclone(object);
+ json_object_put(object);
+}
+
+void c(const char *sx, const char *sy, int e, int c)
+{
+ int re, rc;
+ struct json_object *jx, *jy;
+
+ jx = json_tokener_parse(sx);
+ jy = json_tokener_parse(sy);
+
+ re = wrap_json_cmp(jx, jy);
+ rc = wrap_json_contains(jx, jy);
+
+ printf("compare(%s)(%s)\n", sx, sy);
+ printf(" -> %d / %d\n", re, rc);
+
+ if (!re != !!e)
+ printf(" ERROR should be %s\n", e ? "equal" : "different");
+ if (!rc != !c)
+ printf(" ERROR should %scontain\n", c ? "" : "not ");
+
+ printf("\n");
}
#define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0)
@@ -1145,6 +1516,41 @@ int main()
U("{\"foo\":\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"}", "{s?y}", "foo", &xy[0], &xz[0]);
U("{\"foo\":\"\"}", "{s?y}", "foo", &xy[0], &xz[0]);
U("{}", "{s?y}", "foo", &xy[0], &xz[0]);
+
+ c("null", "null", 1, 1);
+ c("true", "true", 1, 1);
+ c("false", "false", 1, 1);
+ c("1", "1", 1, 1);
+ c("1.0", "1.0", 1, 1);
+ c("\"\"", "\"\"", 1, 1);
+ c("\"hi\"", "\"hi\"", 1, 1);
+ c("{}", "{}", 1, 1);
+ c("{\"a\":true,\"b\":false}", "{\"b\":false,\"a\":true}", 1, 1);
+ c("[]", "[]", 1, 1);
+ c("[1,true,null]", "[1,true,null]", 1, 1);
+
+ c("null", "true", 0, 0);
+ c("null", "false", 0, 0);
+ c("0", "1", 0, 0);
+ c("1", "0", 0, 0);
+ c("0", "true", 0, 0);
+ c("0", "false", 0, 0);
+ c("0", "null", 0, 0);
+
+ c("\"hi\"", "\"hello\"", 0, 0);
+ c("\"hello\"", "\"hi\"", 0, 0);
+
+ c("{}", "null", 0, 0);
+ c("{}", "true", 0, 0);
+ c("{}", "1", 0, 0);
+ c("{}", "1.0", 0, 0);
+ c("{}", "[]", 0, 0);
+ c("{}", "\"x\"", 0, 0);
+
+ c("[1,true,null]", "[1,true]", 0, 1);
+ c("{\"a\":true,\"b\":false}", "{\"a\":true}", 0, 1);
+ c("{\"a\":true,\"b\":false}", "{\"a\":true,\"c\":false}", 0, 0);
+ c("{\"a\":true,\"c\":false}", "{\"a\":true,\"b\":false}", 0, 0);
return 0;
}
diff --git a/src/wrap-json.h b/src/wrap-json.h
index 56f99198..d75ebc43 100644
--- a/src/wrap-json.h
+++ b/src/wrap-json.h
@@ -18,6 +18,10 @@
#pragma once
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
#include <stdarg.h>
#include <json-c/json.h>
@@ -44,3 +48,18 @@ extern void wrap_json_object_for_all(struct json_object *object, void (*callback
extern void wrap_json_optobject_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure);
extern void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure);
+extern struct json_object *wrap_json_clone(struct json_object *object);
+extern struct json_object *wrap_json_clone_deep(struct json_object *object);
+extern struct json_object *wrap_json_clone_depth(struct json_object *object, int depth);
+
+extern struct json_object *wrap_json_object_add(struct json_object *dest, struct json_object *added);
+
+extern struct json_object *wrap_json_sort(struct json_object *array);
+extern struct json_object *wrap_json_keys(struct json_object *object);
+extern int wrap_json_cmp(struct json_object *x, struct json_object *y);
+extern int wrap_json_equal(struct json_object *x, struct json_object *y);
+extern int wrap_json_contains(struct json_object *x, struct json_object *y);
+
+#ifdef __cplusplus
+ }
+#endif
diff --git a/test/monitoring/monitor.js b/test/monitoring/monitor.js
index ec4821cc..1bdfcb43 100644
--- a/test/monitoring/monitor.js
+++ b/test/monitoring/monitor.js
@@ -454,12 +454,12 @@ function gottraceevent(obj) {
x.className = x.className + " " + type;
get(".time", x).textContent = data.time;
get(".tag", x).textContent = ({
- request: function(r) { return r.api + "/" + r.verb + " [" + r.index + "] " + r.action; },
+ request: function(r,d) { return r.api + "/" + r.verb + " [" + r.index + "] " + r.action + (r.action == 'reply' ? ' '+d.data.error : ''); },
service: function(r) { return r.api + "@" + r.action; },
daemon: function(r) { return r.api + ":" + r.action; },
event: function(r) { return r.name + "!" + r.action; },
global: function(r) { return "$" + r.action; },
- })[type](desc);
+ })[type](desc,data);
var tab = makeobj(desc, 4);
if ("data" in data)
makeobjitem(tab, 2, "data", data.data);
diff --git a/test/tic-tac-toe.html b/test/tic-tac-toe.html
new file mode 100644
index 00000000..d9ea664c
--- /dev/null
+++ b/test/tic-tac-toe.html
@@ -0,0 +1,87 @@
+<html>
+<head>
+ <title>tic tac toe</title>
+ <style>
+ td {
+ border: 1px solid black;
+ width: 3em;
+ height: 3em;
+ font-weight: bolder;
+ text-align: center;
+ align-content: center;
+ }
+ .button {
+ border: 1px solid black;
+ border-radius: 5px;
+ }
+ .button:hover {
+ border-width: 2px;
+ font-weight: bolder;
+ }
+ </style>
+ <script type="text/javascript" src="AFB.js"></script>
+ <script type="text/javascript">
+ var afb = new AFB("api", "HELLO");
+ var ws;
+
+ function $(x) { return document.getElementById(x); }
+
+
+ function replyok(obj) {
+ $("id").innerHTML = obj.response.boardid;
+ var i;
+ for (var i = 0 ; i < 9 ; i++)
+ $("cell-" + i).innerHTML = obj.response.board[i];
+ }
+ function replyerr(obj) {
+ }
+ function gotevent(obj) {
+ ws.call("tictactoe/board").then(replyok, replyerr);
+ }
+
+ function onopen() {
+ $("main").style.visibility = "visible";
+ $("connected").innerHTML = "Connected to WebSocket server";
+ ws.onevent("tictactoe/board", gotevent);
+ ws.call("tictactoe/new").then(gotevent, replyerr);
+ }
+ function onabort() {
+ $("main").style.visibility = "hidden";
+ $("connected").innerHTML = "Connected Closed";
+ }
+
+ function init() {
+ ws = new afb.ws(onopen, onabort);
+ }
+
+ </script>
+
+<body onload="init();">
+ <h1>Tic Tac Toe</h1>
+ <div id="connected">Not Connected</div>
+ <div id="main" style="visibility:hidden">
+ <div>board id <span id="id"></span></div>
+ <div>
+ <table>
+ <tr>
+ <td id="cell-0" onclick="javascript: ws.call('tictactoe/move',{'index':0})"> </td>
+ <td id="cell-1" onclick="javascript: ws.call('tictactoe/move',{'index':1})"> </td>
+ <td id="cell-2" onclick="javascript: ws.call('tictactoe/move',{'index':2})"> </td>
+ </tr>
+ <tr>
+ <td id="cell-3" onclick="javascript: ws.call('tictactoe/move',{'index':3})"> </td>
+ <td id="cell-4" onclick="javascript: ws.call('tictactoe/move',{'index':4})"> </td>
+ <td id="cell-5" onclick="javascript: ws.call('tictactoe/move',{'index':5})"> </td>
+ </tr>
+ <tr>
+ <td id="cell-6" onclick="javascript: ws.call('tictactoe/move',{'index':6})"> </td>
+ <td id="cell-7" onclick="javascript: ws.call('tictactoe/move',{'index':7})"> </td>
+ <td id="cell-8" onclick="javascript: ws.call('tictactoe/move',{'index':8})"> </td>
+ </tr>
+ </table>
+ </div>
+ <div><span class="button" id="play" onclick="javascript: ws.call('tictactoe/play')">play</span></div>
+ <div><span class="button" id="undo" onclick="javascript: ws.call('tictactoe/undo')">undo</span></div>
+ <div><span class="button" id="new" onclick="javascript: ws.call('tictactoe/new')">new</span></div>
+ </div>
+