api-v3: First draft 63/14363/3
authorJosé Bollo <jose.bollo@iot.bzh>
Mon, 9 Apr 2018 16:16:07 +0000 (18:16 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Fri, 15 Jun 2018 15:57:36 +0000 (17:57 +0200)
This commit introduces the bindings v3 API for bindings.

The documentation has still to be improved and will come
very soon.

Change-Id: I8f9007370e29f671fdfd1da87fff7372a17db7af
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
155 files changed:
.gitignore
CMakeLists.txt
README.md
bindings/intrinsics/afb-dbus-binding.c
bindings/samples/AuthLogin.c
bindings/samples/CMakeLists.txt
bindings/samples/DemoContext.c
bindings/samples/DemoPost.c
bindings/samples/HelloWorld.c
bindings/samples/ave.c
bindings/samples/hello3.c [new file with mode: 0644]
bindings/samples/hi3.c [new file with mode: 0644]
bindings/samples/tic-tac-toe.c
bindings/tutorial/tuto-1.c
bindings/tutorial/tuto-2.c
bindings/tutorial/tuto-3.cpp
book.json
docs/README.md
docs/REVISIONS.md [new file with mode: 0644]
docs/SUMMARY.md
docs/afb-binding-references.md
docs/afb-binding-writing.md
docs/afb-daemon-debugging.md
docs/afb-daemon-vocabulary.md
docs/afb-migration-to-binding-v3.md [new file with mode: 0644]
docs/afb-migration-v1-to-v2.md
docs/afb-overview.md
docs/annexes.md
docs/migration-to-binding-v3.sed [new file with mode: 0644]
doxyfile.binder [new file with mode: 0644]
doxyfile.binding [new file with mode: 0644]
include/afb/afb-api-x3-itf.h [new file with mode: 0644]
include/afb/afb-api-x3.h [new file with mode: 0644]
include/afb/afb-arg.h [new file with mode: 0644]
include/afb/afb-auth.h
include/afb/afb-binding-postdefs.h [new file with mode: 0644]
include/afb/afb-binding-predefs.h [new file with mode: 0644]
include/afb/afb-binding-v1.h
include/afb/afb-binding-v2.h
include/afb/afb-binding-v3.h [new file with mode: 0644]
include/afb/afb-binding-vdyn.h [deleted file]
include/afb/afb-binding.h
include/afb/afb-binding.hpp
include/afb/afb-daemon-itf-x1.h [new file with mode: 0644]
include/afb/afb-daemon-itf.h [deleted file]
include/afb/afb-daemon-v1.h
include/afb/afb-daemon-v2.h
include/afb/afb-dynapi-itf.h [deleted file]
include/afb/afb-dynapi-legacy.h [new file with mode: 0644]
include/afb/afb-dynapi.h [deleted file]
include/afb/afb-event-x1-itf.h [new file with mode: 0644]
include/afb/afb-event-x1.h [moved from include/afb/afb-event.h with 68% similarity]
include/afb/afb-event-x2-itf.h [moved from include/afb/afb-eventid-itf.h with 50% similarity]
include/afb/afb-event-x2.h [new file with mode: 0644]
include/afb/afb-eventid.h [deleted file]
include/afb/afb-req-v1.h
include/afb/afb-req-v2.h
include/afb/afb-req-x1-itf.h [moved from include/afb/afb-req-itf.h with 70% similarity]
include/afb/afb-req-x1.h [moved from include/afb/afb-req.h with 62% similarity]
include/afb/afb-req-x2-itf.h [new file with mode: 0644]
include/afb/afb-req-x2.h [new file with mode: 0644]
include/afb/afb-request-itf.h [deleted file]
include/afb/afb-request.h [deleted file]
include/afb/afb-service-itf-x1.h [moved from include/afb/afb-service-itf.h with 71% similarity]
include/afb/afb-service-v1.h
include/afb/afb-service-v2.h
include/afb/afb-session-v1.h [deleted file]
include/afb/afb-session-v2.h [deleted file]
include/afb/afb-session-x1.h [new file with mode: 0644]
include/afb/afb-session-x2.h [new file with mode: 0644]
include/afb/afb-verbosity.h
memo-supervisor.txt
memo-v3.txt [new file with mode: 0644]
mkdocs.yml
src/CMakeLists.txt
src/afb-api-dbus.c
src/afb-api-dbus.h
src/afb-api-dyn.c [deleted file]
src/afb-api-dyn.h [deleted file]
src/afb-api-so-v1.c
src/afb-api-so-v1.h
src/afb-api-so-v2.c
src/afb-api-so-v2.h
src/afb-api-so-v3.c [new file with mode: 0644]
src/afb-api-so-v3.h [new file with mode: 0644]
src/afb-api-so-vdyn.c
src/afb-api-so-vdyn.h
src/afb-api-so.c
src/afb-api-so.h
src/afb-api-v3.c [new file with mode: 0644]
src/afb-api-v3.h [new file with mode: 0644]
src/afb-api-ws.c
src/afb-api-ws.h
src/afb-api.c
src/afb-api.h
src/afb-apiset.c
src/afb-apiset.h
src/afb-auth.c
src/afb-autoset.c [new file with mode: 0644]
src/afb-autoset.h [new file with mode: 0644]
src/afb-calls.c [new file with mode: 0644]
src/afb-calls.h [new file with mode: 0644]
src/afb-config.c
src/afb-config.h
src/afb-context.c
src/afb-cred.c
src/afb-cred.h
src/afb-evt.c
src/afb-evt.h
src/afb-export.c
src/afb-export.h
src/afb-hook.c
src/afb-hook.h
src/afb-hreq.c
src/afb-monitor.c
src/afb-monitor.h
src/afb-msg-json.c
src/afb-msg-json.h
src/afb-proto-ws.c
src/afb-proto-ws.h
src/afb-session.c
src/afb-stub-ws.c
src/afb-stub-ws.h
src/afb-supervision.c
src/afb-trace.c
src/afb-trace.h
src/afb-ws-json1.c
src/afb-xreq.c
src/afb-xreq.h
src/afs-config.c
src/afs-supervision.h
src/afs-supervisor.c
src/afs-supervisor.h
src/devtools/genskel.c
src/devtools/monitor-api.json
src/jobs-fake.c
src/jobs.c
src/main-afb-client-demo.c [moved from src/afb-client-demo.c with 84% similarity]
src/main-afb-daemon.c [moved from src/main.c with 89% similarity]
src/main-afs-supervisor.c [moved from src/afs-main.c with 98% similarity]
src/monitor-api.inc
src/pearson.c [new file with mode: 0644]
src/pearson.h [new file with mode: 0644]
src/tests/CMakeLists.txt
src/tests/apiset/CMakeLists.txt [new file with mode: 0644]
src/tests/apiset/test-apiset.c [new file with mode: 0644]
src/tests/apiv3/CMakeLists.txt [new file with mode: 0644]
src/tests/apiv3/test-apiv3.c [new file with mode: 0644]
src/tests/session/test-session.c
src/verbose.c
src/verbose.h
src/wrap-json.c
src/wrap-json.h
test/monitoring/monitor.js
test/tic-tac-toe.html [new file with mode: 0644]

index 6ca8cc5..b65071c 100644 (file)
@@ -17,3 +17,5 @@ node_modules/
 _book/
 *.kdev4
 nbproject/*
+docs/binding
+docs/binder
index cda8190..2213f05 100644 (file)
@@ -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")
index e548bbb..e69966e 100644 (file)
--- a/README.md
+++ b/README.md
-### 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.
-
index a5b7d78..51474f6 100644 (file)
 #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
  */
@@ -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 */
-}
-
index a71f7d6..0f29dd0 100644 (file)
@@ -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 */
+};
index f596c33..d4e85e3 100644 (file)
@@ -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})
+
index bf35ab1..09f1764 100644 (file)
@@ -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 */
+};
index d92d502..3fd6f98 100644 (file)
 #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;
-};
index fef87d2..92d7c4d 100644 (file)
@@ -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,
index 5661e9a..ce01c6d 100644 (file)
@@ -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 (file)
index 0000000..ae70d1e
--- /dev/null
@@ -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 (file)
index 0000000..5202c46
--- /dev/null
@@ -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;
+}
+
index 6b7022b..2ee251c 100644 (file)
 #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
 };
 
 
index 433a4eb..1f58be6 100644 (file)
@@ -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
 };
index dc2d55a..1079708 100644 (file)
@@ -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,
index 7400b98..66f8e83 100644 (file)
@@ -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);
+
 
index 41e4cdd..e7127c4 100644 (file)
--- 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
                 }
             ]
-        }
+       }
     }
 }
index 94dc16a..503b854 100644 (file)
@@ -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 (file)
index 0000000..00787b0
--- /dev/null
@@ -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 ]                                  |
index 44b06f8..580660e 100644 (file)
@@ -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)
index 0e30ffe..4ff0f04 100644 (file)
@@ -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
index aad422c..69090e3 100644 (file)
@@ -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,
index dd5fd64..4cf62be 100644 (file)
@@ -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:
index 6c51f12..efe53d2 100644 (file)
@@ -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 (file)
index 0000000..8f1e678
--- /dev/null
@@ -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
+-------------------------------------------
+
index f318291..9a43454 100644 (file)
@@ -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:
 
index 0cff24c..2682d8d 100644 (file)
@@ -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.  
index 2304bfb..10952e0 100644 (file)
@@ -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 (file)
index 0000000..a668205
--- /dev/null
@@ -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 (file)
index 0000000..4aef9a1
--- /dev/null
@@ -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 (file)
index 0000000..7884159
--- /dev/null
@@ -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 (file)
index 0000000..38b2919
--- /dev/null
@@ -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 (file)
index 0000000..81323ef
--- /dev/null
@@ -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 (file)
index 0000000..de3fb9b
--- /dev/null
@@ -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 */
+};
+
index da4f8be..3ce7866 100644 (file)
 
 #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 (file)
index 0000000..93cd46e
--- /dev/null
@@ -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 (file)
index 0000000..f1765ed
--- /dev/null
@@ -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
+
index 9fb0ab8..3d5010d 100644 (file)
 
 #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
 
index 3aa61b2..1535f42 100644 (file)
 
 #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 (file)
index 0000000..ece3f1c
--- /dev/null
@@ -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 (file)
index 357a85f..0000000
+++ /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__)
-
-
index 3730599..085dc38 100644 (file)
 
 #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"
 
index ee15133..27715f3 100644 (file)
 
 #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 (file)
index 0000000..3ca12eb
--- /dev/null
@@ -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 (file)
index b8fa193..0000000
+++ /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 */
-};
-
index 5a78b15..d84517d 100644 (file)
 
 #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);
 }
index 4b8399c..f3c2c90 100644 (file)
 
 #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 (file)
index 979088d..0000000
+++ /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 (file)
index 0000000..ffa0d92
--- /dev/null
@@ -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 (file)
index 2a26915..0000000
+++ /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 (file)
index 0000000..afd033b
--- /dev/null
@@ -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' */
+};
+
similarity index 68%
rename from include/afb/afb-event.h
rename to include/afb/afb-event-x1.h
index 0876d8c..1fc7696 100644 (file)
 
 #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);
 }
similarity index 50%
rename from include/afb/afb-eventid-itf.h
rename to include/afb/afb-event-x2-itf.h
index 0af3658..ecc42c7 100644 (file)
 
 #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 (file)
index 0000000..f0a2787
--- /dev/null
@@ -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 (file)
index 69d82a7..0000000
+++ /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);
-}
-
index f1bcd47..40fb3b8 100644 (file)
 #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;
 }
index 34cbbda..f790190 100644 (file)
 
 #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);
 }
 
similarity index 70%
rename from include/afb/afb-req-itf.h
rename to include/afb/afb-req-x1-itf.h
index 2dd42d2..dce936d 100644 (file)
 
 #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' */
 };
 
similarity index 62%
rename from include/afb/afb-req.h
rename to include/afb/afb-req-x1.h
index 77153ef..cea17d0 100644 (file)
 
 #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 (file)
index 0000000..9de7a21
--- /dev/null
@@ -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 (file)
index 0000000..70ffab8
--- /dev/null
@@ -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 (file)
index 44066c6..0000000
+++ /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 (file)
index 8e909bb..0000000
+++ /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);
-}
-
similarity index 71%
rename from include/afb/afb-service-itf.h
rename to include/afb/afb-service-itf-x1.h
index dd79bdd..fcdd08e 100644 (file)
 
 #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;
 };
 
index 6a24ecb..a3265af 100644 (file)
 
 #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,
index df751bd..da59786 100644 (file)
 
 #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 (file)
index a606679..0000000
+++ /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 (file)
index 3f940ed..0000000
+++ /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 (file)
index 0000000..776cb8f
--- /dev/null
@@ -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 (file)
index 0000000..b4a24c7
--- /dev/null
@@ -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 */
+};
+
index 9f12205..dd34f84 100644 (file)
 #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;
+}
 
index ae1147a..f38c05d 100644 (file)
@@ -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 (file)
index 0000000..bf08230
--- /dev/null
@@ -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
+
+
index b2f24ac..b94263a 100644 (file)
@@ -1,4 +1,4 @@
-site_name: AGL Application Framework Binder
+site_name: AGL Framework Binder
 theme: readthedocs
 docs_dir: docs
 pages:
index c789fca..ed59ac0 100644 (file)
@@ -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}
index 98c2693..a1e15fd 100644 (file)
@@ -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);
index 90f20c1..1c47685 100644 (file)
@@ -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 (file)
index c2d6cdc..0000000
+++ /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 (file)
index 107d944..0000000
+++ /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);
-
index 985a113..7db686d 100644 (file)
@@ -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;
 }
index 42f18a1..ebe0095 100644 (file)
 
 #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);
index fb901f5..a13c00e 100644 (file)
 #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"
 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;
index 87cd80d..d53206d 100644 (file)
 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 (file)
index 0000000..415c13d
--- /dev/null
@@ -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 (file)
index 0000000..52ec22a
--- /dev/null
@@ -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);
index 300aa13..1734494 100644 (file)
 #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"
  */
 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;
 }
 
index 05d9623..d8a43f7 100644 (file)
@@ -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);
index 87916cb..3167ffa 100644 (file)
 #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);
 }
 
index d37f77c..e652746 100644 (file)
 
 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 (file)
index 0000000..8c755f9
--- /dev/null
@@ -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 (file)
index 0000000..33649f3
--- /dev/null
@@ -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);
+
index 190c2fd..c1ccd32 100644 (file)
@@ -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:
index 123efb7..812cff5 100644 (file)
 
 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);
 
 
index 54ee594..de603d3 100644 (file)
@@ -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;
 }
 
index 3f2e7f1..d03aaca 100644 (file)
@@ -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)
 
index 8d76bbf..af5a865 100644 (file)
@@ -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");
 
 #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,14 +100,132 @@ 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
@@ -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,21 +341,48 @@ 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
@@ -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);
+}
+
index 55068dd..fc8bc26 100644 (file)
 
 #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);
index 47a98d5..4a3c445 100644 (file)
@@ -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 (file)
index 0000000..102830c
--- /dev/null
@@ -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 (file)
index 0000000..50fdec1
--- /dev/null
@@ -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 (file)
index 0000000..73b89bf
--- /dev/null
@@ -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 (file)
index 0000000..15b71bf
--- /dev/null
@@ -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);
index 2a6f931..f3f48fd 100644 (file)
@@ -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
 #   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
 #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
 
 
 #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
 #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'
 #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
@@ -452,6 +500,53 @@ static char **make_exec(char **argv)
        return result;
 }
 
+/*---------------------------------------------------------
+ |   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)
index 89b1f78..30fd398 100644 (file)
@@ -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);
index 13733ce..6b3d6e9 100644 (file)
@@ -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)));
 }
-
-
index f09d444..b7b3175 100644 (file)
@@ -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
 
 #  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
+
index 7ee4723..614fa4b 100644 (file)
@@ -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);
 
index 6b94ce8..ed3e467 100644 (file)
@@ -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;
index c3999df..ceb1b1b 100644 (file)
@@ -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);
 
index 12adf08..fbf77f8 100644 (file)
@@ -20,6 +20,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <fnmatch.h>
+#include <ctype.h>
 
 #include <json-c/json.h>
 
 
 #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"
 #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);
+}
+
index 5acca20..c9046be 100644 (file)
@@ -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
 
index f5868b1..75e8a69 100644 (file)
@@ -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"
 #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
 };
 
 /******************************************************************************
index 52d8335..f315cc0 100644 (file)
@@ -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);
 
+
index 012debb..e5dcf64 100644 (file)
@@ -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) {
index 18ea606..a50e2c6 100644 (file)
 
 #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"
 
 #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);
 }
 
-
index 1f3c144..407116d 100644 (file)
@@ -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);
index 7597f80..ceeee1a 100644 (file)
@@ -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);
 }
 
 
index e18ca0a..ee3ed20 100644 (file)
@@ -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);
 
index e1993ab..f931354 100644 (file)
@@ -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;
index d674af3..342313e 100644 (file)
 
 #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);
-
index 8c0f77b..16fc69b 100644 (file)
 #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
 #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*))
 {
index e725d5a..68bc8c7 100644 (file)
@@ -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"
 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;
index aa64336..e14eac1 100644 (file)
@@ -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);
 
index f1024c3..79a9d3f 100644 (file)
@@ -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;
        }
index 5404a5a..a603951 100644 (file)
@@ -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;
index 5056fb2..0371546 100644 (file)
@@ -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);
 
 
index 315bee8..95167b5 100644 (file)
@@ -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");
 }
index 582e9b7..8f246b3 100644 (file)
 #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;
+}
+
index ae1419f..5c748d6 100644 (file)
@@ -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);
 }
 
-
index 78fee7d..70a6d47 100644 (file)
@@ -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;
 }
index 2c76f24..25d1b4b 100644 (file)
@@ -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"
index 285d82c..6bd1fc6 100644 (file)
 #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);
 }
 
index aeae6c7..08768ae 100644 (file)
@@ -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);
index a0a7881..55dd3c1 100644 (file)
@@ -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;
 }
 
-
-
-
-
index 3c8867c..ca4a9b3 100644 (file)
           "end",
           "event",
           "extra",
-          "fail",
           "get",
           "json",
           "life",
           "ref",
+         "reply",
           "result",
           "session",
           "session_close",
           "subcallsync",
           "subcallsync_result",
           "subscribe",
-          "success",
           "unref",
           "unstore",
           "unsubscribe",
   "paths": {
     "/get": {
       "description": "Get monitoring data.",
+      "x-permissions": { "session": "check" },
       "get": {
-        "x-permissions": { "session": "check" },
         "parameters": [
           {
             "in": "query",
     },
     "/set": {
       "description": "Set monitoring actions.",
+      "x-permissions": { "session": "check" },
       "get": {
-        "x-permissions": { "session": "check" },
         "parameters": [
           {
             "in": "query",
     },
     "/trace": {
       "description": "Set monitoring actions.",
+      "x-permissions": { "session": "check" },
       "get": {
-        "x-permissions": { "session": "check" },
         "parameters": [
           {
             "in": "query",
     },
     "/session": {
       "description": "describes the session.",
+      "x-permissions": { "session": "check" },
       "get": {
-        "x-permissions": { "session": "check" },
         "parameters": [
           {
             "in": "query",
index d3444e3..d3cd19e 100644 (file)
@@ -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);
index 5980305..26fc015 100644 (file)
@@ -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;
 }
similarity index 84%
rename from src/afb-client-demo.c
rename to src/main-afb-client-demo.c
index 011de2b..4e86587 100644 (file)
@@ -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?:"");
similarity index 89%
rename from src/main.c
rename to src/main-afb-daemon.c
index 8c243f7..8b1a2b2 100644 (file)
@@ -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;
                }
similarity index 98%
rename from src/afs-main.c
rename to src/main-afs-supervisor.c
index 88e4757..14f1c3b 100644 (file)
@@ -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;
index cbc1187..e4dc2c9 100644 (file)
@@ -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 (file)
index 0000000..a39c895
--- /dev/null
@@ -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 (file)
index 0000000..2daa654
--- /dev/null
@@ -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);
index f63f27a..f0349a6 100644 (file)
@@ -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 (file)
index 0000000..180c80b
--- /dev/null
@@ -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 (file)
index 0000000..bdc8413
--- /dev/null
@@ -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 (file)
index 0000000..dfc4461
--- /dev/null
@@ -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 (file)
index 0000000..dec1af9
--- /dev/null
@@ -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();
+}
index 58e5753..637b0a1 100644 (file)
@@ -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));
index 3e266a1..5fd1940 100644 (file)
 
 #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;
+}
+
index 5cbe2aa..bd36f97 100644 (file)
@@ -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);
+
index b139e7a..e757c36 100644 (file)
@@ -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;
 }
 
index 56f9919..d75ebc4 100644 (file)
 
 #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
index ec4821c..1bdfcb4 100644 (file)
@@ -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 (file)
index 0000000..d9ea664
--- /dev/null
@@ -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>
+