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/*
 _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_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")
 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
 
 ###########################################################################
 # 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(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")
 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);
  * 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");
 
  * 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:
 
 and the following tools:
+
  * gcc;
  * gcc;
- * make;
  * pkg-config;
  * pkg-config;
- * cmake >= 2.8.8.
+ * cmake >= 3.0
 
 To install all dependencies under Ubuntu (excepting libmicrohttpd), please type:
 
 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):
 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
 
 ### 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_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 --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
 ```
 $ 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
 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.
 ### 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>
 
 #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>
 
 #include <afb/afb-binding.h>
 
-/*
- * the interface to afb-daemon
- */
-const struct afb_binding_interface *afbitf;
-
 /*
  * union of possible dbus values
  */
 /*
  * union of possible dbus values
  */
@@ -497,7 +492,7 @@ error:
 /*
  * handle the reply
  */
 /*
  * 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;
 {
        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"
  *   }
  */
  *     "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;
 {
        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"))
        /* 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
        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);
 
        /* 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
  */
 /*
  * 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 */
   /* 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
  */
 };
 
 /*
  * 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 */
     .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>
 
 #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
 #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
 }
 
 // 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;
 
 {
     json_object *jresp;
 
@@ -56,7 +56,7 @@ static void clientContextConnect (struct afb_req request)
 }
 
 // Before entering here token will be check and renew
 }
 
 // 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;
 
 
     json_object *jresp;
 
 
@@ -68,7 +68,7 @@ static void clientContextRefresh (struct afb_req request) {
 
 
 // Session token will we verified before entering here
 
 
 // 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));
 
     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
 
 
 // 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
     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
     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;
 
     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}
 };
 
   {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})
 
 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>
 
 #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 {
 #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
 // 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));
 
 {
     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
 // 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);
 
 {
     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
 // 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);
 
 {
     MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request);
 
@@ -95,75 +95,44 @@ static void myClose (struct afb_req request)
 }
 
 // Set the LOA
 }
 
 // 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);
 }
 
        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
 {
     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}
 };
 
   {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>
 
 #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
 #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);
 {
     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
 }
 
 // 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;
 {
     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
 }
 
 // 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)
 {
    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
 }
 
 // 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
 {
     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
 {
     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");
 }
 {
     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
 
 // 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>
 
 
 #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;
 #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 event
 {
        struct event *next;
-       struct afb_event event;
+       afb_event_t event;
        char tag[1];
 };
 
        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);
 
        /* 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;
 
        /* link */
        e->next = events;
@@ -88,14 +88,14 @@ static int event_add(const char *tag, const char *name)
        return 0;
 }
 
        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;
 }
 
 {
        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);
 {
        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
 }
 
 // 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 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");
 }
 
 {
        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");
 }
 
 {
        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");
 }
 
 {
        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));
 {
        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/
 
 
 // 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();
     json_object *jresp, *embed;
 
     jresp = json_object_new_object();
@@ -169,38 +169,12 @@ static void pingJson (afb_req request) {
     ping(request, jresp, "pingJson");
 }
 
     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");
 {
        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
        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");
 {
        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 {
        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 {
                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");
 {
        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);
 }
 
        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");
 
 {
        const char *tag = afb_req_value(request, "tag");
 
@@ -263,7 +237,7 @@ static void eventdel (afb_req request)
        pthread_mutex_unlock(&mutex);
 }
 
        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");
 
 {
        const char *tag = afb_req_value(request, "tag");
 
@@ -277,7 +251,7 @@ static void eventsub (afb_req request)
        pthread_mutex_unlock(&mutex);
 }
 
        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");
 
 {
        const char *tag = afb_req_value(request, "tag");
 
@@ -291,7 +265,7 @@ static void eventunsub (afb_req request)
        pthread_mutex_unlock(&mutex);
 }
 
        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");
 {
        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);
 }
 
        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
        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);
 }
 
        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");
 {
        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
        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");
 {
        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;
 {
        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);
 }
 
        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;
 {
        int code = 0;
        json_object *query = afb_req_json(request), *l;
@@ -387,7 +361,7 @@ static void exitnow (afb_req request)
        exit(code);
 }
 
        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");
 {
        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);
 }
 
        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))
 {
        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)");
 }
 
                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);
 }
 
 {
        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);
 }
 
 {
        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;
 }
 
        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;
 }
 
        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
 }
 
 // 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 },
   { .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="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="subcallsync", .callback=subcallsync },
   { .verb="eventadd",    .callback=eventadd },
   { .verb="eventdel",    .callback=eventdel },
@@ -479,7 +452,7 @@ static const afb_verb_v2 verbs[]= {
   { .verb=NULL}
 };
 
   { .verb=NULL}
 };
 
-const afb_binding_v2 afbBindingV2 = {
+const struct afb_binding_v3 afbBindingV3 = {
        .api = "hello",
        .specification = NULL,
        .verbs = verbs,
        .api = "hello",
        .specification = NULL,
        .verbs = verbs,
index 5661e9a..ce01c6d 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <json-c/json.h>
 
 
 #include <json-c/json.h>
 
+#define AFB_BINDING_WANT_DYNAPI
 #define AFB_BINDING_VERSION 0
 #include <afb/afb-binding.h>
 
 #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);
 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");
 }
 
        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");
        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);
                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
        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)
 }
 
 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 {
        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 {
                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) {
                        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);
                        afb_request_fail(request, "failed", "broadcast error");
                else
                        afb_request_success(request, NULL, NULL);
@@ -447,13 +448,13 @@ static const struct {
   { .verb=NULL}
 };
 
   { .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}
   { .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>
 
 #include <string.h>
 #include <json-c/json.h>
 
-#define AFB_BINDING_VERSION 2
+#define AFB_BINDING_VERSION 3
 #include <afb/afb-binding.h>
 
 #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
 
 /*
  * definition of a board
@@ -44,7 +41,7 @@ struct board
        int id;
        int level;
        char board[9];
        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.
  */
 /*
  * 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 */
 {
        /* 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->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->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;
 
        /* link */
        board->next = all_boards;
@@ -87,6 +86,12 @@ static struct board *get_new_board()
        return board;
 }
 
        return board;
 }
 
+static void *get_new_board_cb(void *closure)
+{
+       afb_req_t req = closure;
+       return get_new_board(req);
+}
+
 /*
  * Release a board
  */
 /*
  * 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 */
        /* 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)
                /* 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
 /*
  * 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])
 {
  */
 static char winner(const char b[9])
 {
-       int i;
        char c;
 
        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;
 }
 
        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)
 {
 /* 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 */
 }
 
 /* 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;
 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;
 }
                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)
 {
  */
 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 */
 
        /* 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 */
                return 0;
 
        /* switch to the opponent */
-       c = (char)('O' + 'X' - c);
+       c = (char)(ROUND + CROSS - c);
 
        /* inspect opponent moves */
 
        /* inspect opponent moves */
-       r = 1;
+       nc = wc = lc = 0;
        for (i = 0 ; i < 9 ; i++) {
        for (i = 0 ; i < 9 ; i++) {
-               if (b[i] == ' ') {
+               if (b[i] == SPACE) {
                        b[i] = c;
                        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)
 {
 }
 
 /* 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];
 
        char c;
        char b[9];
 
@@ -222,22 +255,24 @@ static int get_move(struct board *board)
 
        /* depth and more */
        memcpy(b, board->board, 9);
 
        /* depth and more */
        memcpy(b, board->board, 9);
+       f = smax = 0;
        c = color(board->moves);
        c = color(board->moves);
-       f = 0;
        for (index = 0 ; index < 9 ; index++) {
        for (index = 0 ; index < 9 ; index++) {
-               if (board->board[index] == ' ') {
+               if (board->board[index] == SPACE) {
                        board->board[index] = c;
                        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;
                                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)
 {
  */
 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
  */
 }
 
 /*
  * 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
  */
 }
 
 /*
  * start a new game
  */
-static void new(struct afb_req req)
+static void new(afb_req_t req)
 {
        struct board *board;
 
 {
        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 */
        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 */
        board->moves = 0;
 
        /* replies */
@@ -331,7 +350,7 @@ static void new(struct afb_req req)
 /*
  * get the board
  */
 /*
  * get the board
  */
-static void board(struct afb_req req)
+static void board(afb_req_t req)
 {
        struct board *board;
        struct json_object *description;
 {
        struct board *board;
        struct json_object *description;
@@ -350,7 +369,7 @@ static void board(struct afb_req req)
 /*
  * move a piece
  */
 /*
  * move a piece
  */
-static void move(struct afb_req req)
+static void move(afb_req_t req)
 {
        struct board *board;
        int i;
 {
        struct board *board;
        int i;
@@ -379,7 +398,7 @@ static void move(struct afb_req req)
        }
 
        /* checks validity of the move */
        }
 
        /* 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;
                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
  */
 /*
  * set the level
  */
-static void level(struct afb_req req)
+static void level(afb_req_t req)
 {
        struct board *board;
        int l;
 {
        struct board *board;
        int l;
@@ -434,7 +453,7 @@ static void level(struct afb_req req)
 /*
  * Join a board
  */
 /*
  * 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;
 {
        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) {
 
        /* 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 */
        }
 
        /* 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.
         */
         * 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) */
        /* 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;
        /* replies */
        afb_req_success(req, NULL, NULL);
        return;
@@ -486,7 +508,7 @@ bad_request:
 /*
  * Undo the last move
  */
 /*
  * Undo the last move
  */
-static void undo(struct afb_req req)
+static void undo(afb_req_t req)
 {
        struct board *board;
        int i;
 {
        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];
 
        /* undo the last move */
        i = board->history[--board->moves];
-       board->board[i] = ' ';
+       board->board[i] = SPACE;
 
        /* replies */
        afb_req_success(req, NULL, NULL);
 
        /* replies */
        afb_req_success(req, NULL, NULL);
@@ -516,7 +538,7 @@ static void undo(struct afb_req req)
 /*
  * computer plays
  */
 /*
  * computer plays
  */
-static void play(struct afb_req req)
+static void play(afb_req_t req)
 {
        struct board *board;
        int index;
 {
        struct board *board;
        int index;
@@ -543,27 +565,10 @@ static void play(struct afb_req req)
        changed(board, "play");
 }
 
        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
  */
 /*
  * 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 },
    { .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="level", .callback=level },
    { .verb="join",  .callback=join },
    { .verb="undo",  .callback=undo },
-   { .verb="wait",  .callback=wait },
    { .verb=NULL }
 };
 
 /*
  * description of the binding for afb-daemon
  */
    { .verb=NULL }
 };
 
 /*
  * description of the binding for afb-daemon
  */
-const afb_binding_v2 afbBindingV2 = {
+const afb_binding_t afbBindingV3 = {
        .api = "tictactoe",
        .specification = NULL,
        .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>
 
 #include <afb/afb-binding.h>
 
-void hello(afb_req req)
+void hello(afb_req_t req)
 {
        AFB_REQ_DEBUG(req, "hello world");
 {
        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 }
 };
 
        { .verb="hello", .callback=hello },
        { .verb=NULL }
 };
 
-const afb_binding_v2 afbBindingV2 = {
+const afb_binding_t afbBindingExport = {
        .api = "tuto-1",
        .verbs = verbs
 };
        .api = "tuto-1",
        .verbs = verbs
 };
index dc2d55a..1079708 100644 (file)
@@ -1,12 +1,12 @@
 #include <string.h>
 #include <json-c/json.h>
 
 #include <string.h>
 #include <json-c/json.h>
 
-#define AFB_BINDING_VERSION 2
+#define AFB_BINDING_VERSION 3
 #include <afb/afb-binding.h>
 
 #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;
 {
         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));
         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");
         } 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));
         } 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);
         } 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));
         }
 }
 
                 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;
 {
         json_object *args, *val;
         char *usr;
@@ -51,10 +51,10 @@ void action(afb_req req)
                         afb_req_unsubscribe(req, event_logout);
                 }
         }
                         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;
 
 {
         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_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;
 }
 
         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;
         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;
 }
 
         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 }
 };
 
         { .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,
         .api = "tuto-2",
         .specification = NULL,
         .verbs = verbs,
index 7400b98..66f8e83 100644 (file)
@@ -1,11 +1,12 @@
 #include <string.h>
 #include <json-c/json.h>
 
 #include <string.h>
 #include <json-c/json.h>
 
+#define AFB_BINDING_VERSION 3
 #include <afb/afb-binding>
 
 afb::event event_login, event_logout;
 
 #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;
 {
        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);
                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));
        }
 }
 
                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();
 {
        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)) {
        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));
 }
 
        req.success(json_object_get(args));
 }
 
-void logout(afb_req r)
+void logout(afb_req_t r)
 {
        char *usr;
        afb::req req(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);
        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();
 }
 
        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");
 {
        AFB_NOTICE("init");
        event_login = afb_daemon_make_event("login");
@@ -79,12 +86,13 @@ int init()
        return -1;
 }
 
        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()
 };
 
        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",
     "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",
 
     "gitbook": "3.2.2",
     "root": "docs",
@@ -89,6 +89,6 @@
                     "decode": true
                 }
             ]
                     "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
 
 # Summary
 
-* [Document revisions](README.md)
 * [Binder Overview](afb-introduction.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)
 * [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 events guide](afb-events-guide.md)
 * [Binder Application writing guide](afb-application-writing.md)
-* [Binder daemon vocabulary](afb-daemon-vocabulary.md)
 * [Annexes](annexes.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)
   * [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
 
 
 ## 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
 
 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
 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_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
 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
 {
 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
 ```
 
 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
 {
  */
 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
 };
 ```
 
 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
 /*
 
 ```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();
 
 /*
  */
 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();
 
 /*
  */
 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();
 ```
  */
 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.
  */
  *
  * 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
 ```
 
 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.
  */
  *
  * 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
 ```
 
 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.
  */
  *
  * 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.
 
 /*
  * 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.
  */
  *
  * 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
 /*
 
 ```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.
  */
  * 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.
 ```
 
 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'.
  */
 /*
  * 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
 ```
 
 ## 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.
  */
  *
  * 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.
 ```
 
 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.
  */
  * 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'.
 
 /*
  * 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
  */
  *
  * 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'.
 
 /*
  * 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
  */
  *
  * 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'.
  */
 
 /*
  * 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.
 ```
 
 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.
  */
  * 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
 
 /*
  * 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.
  */
  * 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'
 
 /*
  * 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.
  */
  * 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
 
 /*
  * 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.
  */
  *
  * 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.
  */
 
 /*
  * 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.
  */
 
 /*
  * 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.
 ```
 
 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.
  */
  * 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.
  */
 
 /*
  * 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'.
 
 /*
  * 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'.
  */
  * 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'
 
 /*
  * 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)
  */
  *
  * 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.
  */
 
 /*
  * 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'
 
 /*
  * 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.
  */
  * 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.
 ```
 
 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.
  */
  * 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.
  */
 
 /*
  * 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.
 
 /*
  * 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).
  */
  * 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'.
 
 /*
  * 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.
  */
  * 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
 ```
 
 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.
  */
  * 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.
  */
 
 /*
  * 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
 ```
 
 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(
  *  - '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,
                 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
  */
  *  - '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);
 }
 {
        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(
  *  - '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,
                 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
  */
  *      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
 ```
 
 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.
  */
  *
  * 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
 
 /*
  * 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
  */
  *
  * 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
 
 /*
  * 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.
  */
  *
  * 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
 ```
 
 ## 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**.
 
 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:
 
 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.  
 
 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 -->
 
 
 <!-- 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
 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
   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");
   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
   8 }
   9
- 10 const afb_verb_v2 verbs[] = {
+ 10 const afb_verb_t verbs[] = {
  11         { .verb="hello", .callback=hello },
  12         { .verb=NULL }
  13 };
  14
  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 };
  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)
 ```
 
 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 ''
 ```
 
 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
 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
 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>
 ```
 
   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
 
 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
 ```
 
 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***.
 
 
 ### 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
 
 ```C
- 10 const afb_verb_v2 verbs[] = {
+ 10 const afb_verb_t verbs[] = {
  11         { .verb="hello", .callback=hello },
  12         { .verb=NULL }
  13 };
  14
  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 };
 ```
 
  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 **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**).
 
 
 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
 ### 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");
   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 }
 ```
 
   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.
 
 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 -->
 
 
 <!-- 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>
 ```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>
       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;
      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));
      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");
      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));
      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);
      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 }
      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;
      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));
      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         }
      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 }
      55 }
-     56
-     57 void logout(afb_req req)
+     56 
+     57 void logout(afb_req_t req)
      58 {
      59         char *usr;
      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);
      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 }
      67 }
-     68
-     69 int preinit()
+     68 
+     69 int preinit(afb_api_t api)
      70 {
      70 {
-     71         AFB_NOTICE("preinit");
+     71         AFB_API_NOTICE(api, "preinit");
      72         return 0;
      73 }
      72         return 0;
      73 }
-     74
-     75 int init()
+     74 
+     75 int init(afb_api_t api)
      76 {
      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;
      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 }
      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 };
      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,
      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:
 
 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.
 
 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
 ## 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.  
 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
 
 
 ## 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:
 
 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.
 
 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
 - 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.  
 
 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
 
 # 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)
 * [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
 
 
 #pragma once
 
-/*
- * Enum for Session/Token/Assurance middleware.
+/**
+ * Enumeration  for authority (Session/Token/Assurance) definitions.
+ *
+ * @see afb_auth
  */
 enum afb_auth_type
 {
  */
 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
 {
 struct afb_auth
 {
+       /** type of entry @see afb_auth_type */
        enum afb_auth_type type;
        enum afb_auth_type type;
+       
        union {
        union {
+               /** text when @ref type == @ref afb_auth_Permission */
                const char *text;
                const char *text;
+               
+               /** level of assurancy when @ref type ==  @ref afb_auth_LOA */
                unsigned 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;
        };
                const struct afb_auth *first;
        };
+       
+       /** second child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And } */
        const struct afb_auth *next;
 };
 
        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
 
 
 #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-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;
 
 #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
  * 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);
 
  */
 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
  * 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.
  */
  * 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.
  * 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);
 
 
 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
 {
  * 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
 {
  * 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
  * The definition uses hashes.
  */
 enum  afb_binding_type_v1
@@ -113,94 +128,107 @@ enum  afb_binding_type_v1
        AFB_BINDING_VERSION_1 = 123456789
 };
 
        AFB_BINDING_VERSION_1 = 123456789
 };
 
-/*
- * Description of a binding
+/**
+ * @deprecated use bindings version 3
+ *
+ * Description of a binding version 1
  */
 struct afb_binding_v1
 {
  */
 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 {
        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
 {
  */
 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_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)
 
 /*
  * 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)
 
 
 #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
 
 
 #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
 
 
 #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
 
 
 #pragma once
 
-#include <stdint.h>
+/******************************************************************************/
 
 
+#include "afb-verbosity.h"
 #include "afb-auth.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-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
 {
  */
 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
 {
  * 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
 {
 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:
  *
  * 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_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
 #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)
 
 /*
  * 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)
 
 
 #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
 
 
 #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
 
 
 #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"
 
 #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
 
 
 #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 <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_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
 
 #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\
 \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\
   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\
 \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
 #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
 #  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
 
 # 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-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
 #endif
+#include "afb-binding-postdefs.h"
 
 
index ee15133..27715f3 100644 (file)
 
 #pragma once
 
 
 #pragma once
 
+#include <cstddef>
 #include <cstdlib>
 #include <cstdarg>
 #include <functional>
 
 /* ensure version */
 #ifndef AFB_BINDING_VERSION
 #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
 #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 */
 #endif
 
 /* get C definitions of bindings */
@@ -44,16 +45,11 @@ namespace afb {
 class arg;
 class event;
 class req;
 class arg;
 class event;
 class req;
-class stored_req;
 
 /*************************************************************************/
 /* declaration of functions                                              */
 /*************************************************************************/
 
 
 /*************************************************************************/
 /* 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);
 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 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();
 
 
 int verbosity();
 
@@ -80,9 +76,17 @@ bool wants_notices();
 bool wants_infos();
 bool wants_debugs();
 
 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);
 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);
 
 
 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
 {
 /* events */
 class event
 {
-       struct afb_event event_;
+       afb_event_t event_;
 public:
 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);
 
        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;
 
        operator bool() const;
        bool is_valid() const;
@@ -139,30 +144,16 @@ public:
 /* req(uest) */
 class req
 {
 /* 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;
 
 public:
        req() = delete;
-       req(const struct afb_req &r);
+       req(afb_req_t r);
        req(const req &other);
        req &operator=(const req &other);
 
        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;
 
        operator bool() const;
        bool is_valid() const;
@@ -175,22 +166,20 @@ public:
 
        json_object *json() const;
 
 
        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 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;
 
 
        template < class T > T *context() const;
 
-       void context_clear() const;
-
        void addref() const;
 
        void unref() const;
        void addref() const;
 
        void unref() const;
@@ -199,19 +188,22 @@ public:
 
        bool session_set_LOA(unsigned level) const;
 
 
        bool session_set_LOA(unsigned level) const;
 
-       stored store() const;
-
        bool subscribe(const event &event) const;
 
        bool unsubscribe(const event &event) 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;
 
 
        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;
        char *get_application_id() const;
 
        int get_uid() const;
+
+       json_object *get_client_info() const;
 };
 
 /*************************************************************************/
 };
 
 /*************************************************************************/
@@ -250,18 +244,23 @@ public:
 /*************************************************************************/
 
 /* events */
 /*************************************************************************/
 
 /* 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::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 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(); }
 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 */
 
 
 /* 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::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)); }
 
 
 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 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);
 {
        va_list args;
        va_start(args, info);
-       afb_req_success_v(req_, obj, info, args);
+       replyv(obj, error, info, args);
        va_end(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);
 {
        va_list args;
        va_start(args, info);
-       afb_req_fail_v(req_, status, info, args);
+       successv(obj, info, args);
        va_end(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
 {
 
 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)));
        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 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 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);
        afb_req_subcall_req(req_, api, verb, args, callback, closure);
+#endif
 }
 
 template <class T>
 }
 
 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
 {
 }
 
 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
 {
 }
 
 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);
 }
 
 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
 {
        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
 {
 }
 
 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
 {
 }
 
 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)
 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)
 
 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)
 
 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()
 
 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)
 
 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)
 
 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)
 
 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()
 
 inline bool wants_errors()
-       { return afb_verbose_error(); }
+       { return AFB_SYSLOG_MASK_WANT_ERROR(logmask()); }
 
 inline bool wants_warnings()
 
 inline bool wants_warnings()
-       { return afb_verbose_warning(); }
+       { return AFB_SYSLOG_MASK_WANT_WARNING(logmask()); }
 
 inline bool wants_notices()
 
 inline bool wants_notices()
-       { return afb_verbose_notice(); }
+       { return AFB_SYSLOG_MASK_WANT_NOTICE(logmask()); }
 
 inline bool wants_infos()
 
 inline bool wants_infos()
-       { return afb_verbose_info(); }
+       { return AFB_SYSLOG_MASK_WANT_INFO(logmask()); }
 
 inline bool wants_debugs()
 
 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);
 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));
 }
 {
        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)
 {
 
 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);
 }
 
        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;
        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;
 }
 
        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;
 }
 
        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;
        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;
        r.init = init;
        r.onevent = onevent;
        r.noconcurrency = noconcurrency ? 1 : 0;
+#if AFB_BINDING_VERSION >= 3
+       r.userdata = userdata;
+#endif
        return r;
 };
 
        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
 
 
 #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.
  */
  * 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);
 }
 
 {
        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.
  */
  * 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);
 }
 
 {
        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.
  */
  * 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);
 }
 
 {
        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.
  * 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.
  */
  *
  * 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);
 }
 
 {
        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.
  *
  * 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.
  */
  *
  * 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);
 }
 
 {
        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'.
  *
  * 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
  */
  *      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);
 {
        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);
 }
 
        va_end(args);
 }
 
-/*
+/**
+ * @deprecated use bindings version 3
+ *
  * Send a message described by 'fmt' and following parameters
  * to the journal for the verbosity 'level'.
  *
  * 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
  */
  *      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);
 {
        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);
 }
 
        va_end(args);
 }
 
-/*
+/**
+ * @deprecated use bindings version 3
+ *
  * Get the root directory file descriptor. This file descriptor can
  * be used with functions 'openat', 'fstatat', ...
  * 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);
 }
 
 {
        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.
  * using the 'locale' definition (example: "jp,en-US") that can be NULL.
+ *
  * Returns the file descriptor or -1 in case of error.
  */
  * 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);
 }
 
 {
        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')
  * 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.
  */
  *
  * 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);
 }
 
 {
        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.
  * 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.
  */
  * 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);
 }
 
 {
        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.
  * Calling this function is only allowed within preinit.
+ *
  * Returns 0 in case of success or -1 in case of error.
  */
  * 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(
 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,
        const char *api,
        const char *info,
        int noconcurrency,
-       int (*preinit)(void*, struct afb_dynapi *),
+       int (*preinit)(void*, struct afb_api_x3 *),
        void *closure)
 {
        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
 
 
 #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()
  * 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);
 }
 
        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()
  * 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);
 }
 
        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()
  * 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);
 }
 
        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.
  *
  * 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);
 }
 
        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.
  */
  * 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);
 }
 
 {
        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'.
  *
  * 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);
 }
 
        va_end(args);
 }
 
-/*
+/**
+ * @deprecated use bindings version 3
+ *
  * Get the root directory file descriptor. This file descriptor can
  * be used with functions 'openat', 'fstatat', ...
  * 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);
 }
 
  */
 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.
  * 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)
  * 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);
 }
 
        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')
  * 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);
 }
 
        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.
  */
  * 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);
 }
 
 {
        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.
  * 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)
  * 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);
 }
 
        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.
  * Calling this function is only allowed within preinit.
+ *
  * Returns 0 in case of success or -1 in case of error.
  */
  * 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,
 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)
 {
        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
 
 
 #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.
  */
  * 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;
 }
 
 {
        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.
  */
  * 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;
 }
 
 {
        return !!event.itf;
 }
 
-/*
+/**
+ * @deprecated use bindings version 3
+ *
  * Broadcasts widely the 'event' with the data 'object'.
  * 'object' can be NULL.
  *
  * 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.
  */
  *
  * 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);
 }
 
 {
        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.
  *
  * 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.
  */
  *
  * 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 */
 {
        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'.
  */
  * 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);
 }
 
 {
        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.
  */
  * 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);
 }
 
 {
        event.itf->unref(event.closure);
 }
 
-/*
+/**
+ * @deprecated use bindings version 3
+ *
  * Increases the count of reference to 'event'
  */
  * 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);
 }
 {
        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
 
 
 #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.
  */
  * Don't use this structure directly.
  */
-struct afb_eventid_itf
+struct afb_event_x2_itf
 {
        /* CAUTION: respect the order, add at the end */
 
 {
        /* 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>
 #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).
  */
  * 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;
        if (result) {
                *result = req;
-               afb_req_addref(req);
+               afb_req_x1_addref(req);
        }
        return result;
 }
 
        }
        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.
  */
  * 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;
 }
        free(req);
        return result;
 }
index 34cbbda..f790190 100644 (file)
 
 #pragma once
 
 
 #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).
  */
  * 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
 
 
 #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
 
 
 #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.
  */
  * 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;
 }
 
 {
        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.
  */
  * 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;
 }
 
 {
        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.
  * 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.
  */
  * 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);
 }
 
 {
        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
  */
  * 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
  */
  * 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'.
  */
  * 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);
 }
 
 {
        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
  * 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.
  */
  *
  * 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.
  */
  * 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);
 {
        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);
 }
 
        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.
  */
  * 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.
  */
  * 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.
  */
  * 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'.
  */
  * 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);
 }
 
 {
        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'.
  * 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.
  */
  * 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);
 }
 
 {
        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)
  */
  * 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.
  */
  * 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);
 }
 
 {
        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.
  */
  * 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);
 }
 
 {
        req.itf->unref(req.closure);
 }
 
-/*
+/**
+ * @deprecated use bindings version 3
+ *
  * Closes the session associated with 'req'
  * and delete all associated contexts.
  */
  * 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);
 }
 
 {
        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.
  */
  * 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.
  */
  * 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.
  */
  * 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
  * 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
  */
  *  - '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
  * 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
  */
  *  - '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.
  * 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.
  */
  *  - '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'.
  *
  * 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
  */
  *      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);
 {
        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);
 }
 
        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.
  */
  * 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);
 }
 
 {
        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'.
  *
  * 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
  */
  *
  * 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);
 }
 
 {
        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.
  */
  * 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);
 }
 
 {
        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
 
 
 #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.
  */
  * 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 */
 
 {
        /* 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);
 
                     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);
 };
 
                         struct json_object **result);
 };
 
-/*
+/**
+ * @deprecated use bindings version 3
+ *
  * Object that encapsulate accesses to service items
  */
  * 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
 
 
 #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'.
  *
  * 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(
  * @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,
        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.
  *
  * 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(
  * @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,
        const char *api,
        const char *verb,
        struct json_object *args,
index df751bd..da59786 100644 (file)
 
 #pragma once
 
 
 #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'.
  *
  * 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.
  *
  * 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_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:
 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)
 
 # 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.c
-       afb-api-dyn.c
        afb-api-so.c
        afb-api-so.c
-       afb-api-so-v1.c
        afb-api-so-v2.c
        afb-api-so-v2.c
+       afb-api-so-v3.c
        afb-api-so-vdyn.c
        afb-api-so-vdyn.c
+       afb-api-v3.c
        afb-api-ws.c
        afb-apiset.c
        afb-auth.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
        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
        fdev-systemd.c
        jobs.c
        locale-root.c
+       pearson.c
        process-name.c
        sig-monitor.c
        subpath.c
        process-name.c
        sig-monitor.c
        subpath.c
@@ -74,15 +77,26 @@ ADD_LIBRARY(afb-lib STATIC
        wrap-json.c
 )
 
        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)
 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()
 
 ENDIF()
 
+ADD_LIBRARY(afb-lib STATIC ${AFB_LIB_SOURCES})
+
 ###########################################
 # build and install afb-daemon
 ###########################################
 ###########################################
 # 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}
 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)
 # 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}
        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
 ###########################################
 ###########################################
 # 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}
 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 <systemd/sd-bus.h>
 #include <json-c/json.h>
 
-#include <afb/afb-event.h>
+#include <afb/afb-event-x2.h>
 
 #include "afb-systemd.h"
 
 
 #include "afb-systemd.h"
 
@@ -76,9 +76,6 @@ struct api_dbus
        };
 };
 
        };
 };
 
-#define RETOK   1
-#define RETERR  2
-
 /******************* common part **********************************/
 
 /*
 /******************* 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++;
                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;
        }
                errno = EINVAL;
                goto error2;
        }
@@ -226,7 +223,7 @@ struct dbus_memo {
 struct dbus_event
 {
        struct dbus_event *next;
 struct dbus_event
 {
        struct dbus_event *next;
-       struct afb_eventid *eventid;
+       struct afb_event_x2 *event;
        int id;
        int refcount;
 };
        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;
 {
        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 */
 
        /* 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 */
        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 */
        } 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;
        }
        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;
        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) {
 
        /* 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;
                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;
 
        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),
                        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;
 
        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;
 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);
        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;
        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;
                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) {
        /* 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;
                        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 */
        *prv = ev->next;
 
        /* destroys the event */
-       afb_evt_eventid_unref(ev->eventid);
+       afb_evt_event_x2_unref(ev->event);
        free(ev);
 }
 
        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);
 
        /* 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 */
 }
 
 /* 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 */
        }
 
        /* 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");
 }
        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 */
        }
 
        /* 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");
 }
        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 */
 };
 
 /* 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;
 {
        int rc;
        struct api_dbus *api;
-       struct afb_api afb_api;
+       struct afb_api_item afb_api;
        char *match;
 
        /* create the dbus client 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;
        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;
                goto error2;
 
        return 0;
@@ -816,77 +803,51 @@ static struct json_object *dbus_req_json(struct afb_xreq *xreq)
        return dreq->json;
 }
 
        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;
        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");
 }
 
        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 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;
 
 {
        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);
        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;
 }
 
        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);
 {
        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;
 }
 
        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,
 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,
        .unref = dbus_req_destroy,
        .subscribe = dbus_req_subscribe,
        .unsubscribe = dbus_req_unsubscribe,
-       .subcall = dbus_req_subcall
 };
 
 /******************* server part **********************************/
 };
 
 /******************* 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;
        int rc;
        const char *method;
        const char *uuid;
+       const char *creds;
        struct dbus_req *dreq;
        struct api_dbus *api = userdata;
        uint32_t flags;
        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 */
                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;
        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;
 
        /* 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")) {
        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->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;
 
        afb_xreq_process(&dreq->xreq, api->server.apiset);
        return 1;
 
@@ -1012,7 +975,7 @@ error:
 }
 
 /* create the service */
 }
 
 /* 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;
 {
        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);
        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);
        return 0;
 error3:
        sd_bus_release_name(api->sdbus, api->name);
index 90f20c1..1c47685 100644 (file)
@@ -20,8 +20,8 @@
 
 struct afb_req_itf;
 
 
 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 <string.h>
 #include <dlfcn.h>
 #include <assert.h>
+#include <stdarg.h>
 
 #include <json-c/json.h>
 
 #include <json-c/json.h>
-
 #include <afb/afb-binding-v1.h>
 
 #include "afb-api.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";
 
 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;
 
 {
        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;
 }
 
        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;
 {
        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);
 }
 
        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;
 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));
 }
 
        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;
 {
        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);
 
        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, "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);
 
        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);
        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;
                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");
                        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");
                        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");
                        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);
 
                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;
 }
 
        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);
        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);
        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;
        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);
        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;
        }
                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 */
                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;
        }
                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;
        }
                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;
        }
                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;
        }
                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 */
                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;
        }
                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:
        return 1;
 
 error:
-       afb_export_destroy(export);
-       free(desc);
+       afb_export_unref(export);
 
        return -1;
 }
 
        return -1;
 }
index 42f18a1..ebe0095 100644 (file)
 
 #pragma once
 
 
 #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 <string.h>
 #include <dlfcn.h>
 #include <assert.h>
+#include <stdarg.h>
 
 
-#include <afb/afb-binding-v2.h>
 #include <json-c/json.h>
 #include <json-c/json.h>
+#include <afb/afb-binding-v2.h>
 
 #include "afb-api.h"
 #include "afb-api-so-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";
 
 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;
 
 {
        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;
 }
 
        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;
 
        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);
 }
 
        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;
 
 {
        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);
        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, "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);
 
        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);
        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;
 }
 
        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;
 {
        int rc;
-       struct api_so_v2 *desc;
-       struct afb_api afb_api;
        struct afb_export *export;
 
        /* basic checks */
        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 */
        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;
        }
                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) {
        /* 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;
                }
        }
 
                        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:
        return 1;
 
 error:
-       afb_export_destroy(export);
-       free(desc);
+       afb_export_unref(export);
 
        return -1;
 }
 
 
        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;
 {
        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;
        }
                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;
        }
                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;
        }
 
        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;
 
  error:
        return -1;
index 87cd80d..d53206d 100644 (file)
 struct afb_apiset;
 struct afb_binding_v2;
 struct afb_binding_data_v2;
 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>
 
 #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"
 #include "afb-api-so-vdyn.h"
 #include "afb-export.h"
 #include "verbose.h"
  */
 static const char afb_api_so_vdyn_entry[] = "afbBindingVdyn";
 
  */
 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);
        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);
 
 
        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) {
        if (!export) {
-               ERROR("can't create export for %s", path);
+               INFO("binding [%s] creation failed", path);
                return -1;
        }
 
                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;
 
 
 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 <sys/stat.h>
 
 #include "afb-api-so.h"
-#include "afb-api-so-v1.h"
 #include "afb-api-so-v2.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"
 
 #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;
 struct safe_dlopen
 {
        const char *path;
@@ -59,8 +65,9 @@ static void *safe_dlopen(const char *filename, int flags)
        return sd.handle;
 }
 
        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;
 
        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 */
        }
 
        /* 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;
        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 (rc)
                return 0; /* yes version 2 */
 
+#if defined(WITH_LEGACY_BINDING_VDYN)
        /* try the version dyn */
        /* 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 */
        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 */
        /* 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 */
        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 */
 
        /* 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);
 
 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;
 {
        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.
 
 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
 
 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"
 
    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
 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 */
 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);
 #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);
                } 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);
                }
                if (rc < 0 && failstops) {
                        closedir(dir);
@@ -220,7 +248,7 @@ See https://sourceware.org/bugzilla/show_bug.cgi?id=22101
        return 0;
 }
 
        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];
 {
        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);
        }
 
        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;
 {
        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))
        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"))
        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;
 }
 
        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;
 {
        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;
                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;
        }
 }
 
                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;
 
 
 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-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"
 #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];
        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;
        }
                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;
 {
        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;
 
        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 (!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;
        }
                ERROR("can't add the client to the apiset for service %s", apiws->path);
                goto error3;
        }
@@ -253,14 +254,14 @@ error:
        return -!!strong;
 }
 
        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)
 }
 
 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 */
 }
 
 /* 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;
 {
        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 */
                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;
        }
                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;
 
        if (rc < 0)
                goto error2;
 
-       apiws->apiset = afb_apiset_addref(apiset);
+       apiws->apiset = afb_apiset_addref(call_set);
        return 0;
 
 error2:
        return 0;
 
 error2:
index 123efb7..812cff5 100644 (file)
 
 struct afb_apiset;
 
 
 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
  */
  * 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;
 
 {
        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);
                }
                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);
 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);
        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 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;
 };
 
 {
        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"
 /*
  * 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");
  * 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 */
 
 
 #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
 {
 /**
  * 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 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 */
        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 */
 };
 
        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
 /**
  * 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;
 {
        int i, c, up, lo;
        struct api_desc *a;
+       struct api_alias *aliases;
 
        /* dichotomic search of the api */
        /* initial slice */
        lo = 0;
 
        /* 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;
                /* 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 */
                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;
        }
                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)
 {
  */
 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);
        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);
        }
 }
                free(set);
        }
 }
@@ -128,21 +341,48 @@ struct afb_apiset *afb_apiset_create(const char *name, int timeout)
 {
        struct afb_apiset *set;
 
 {
        struct afb_apiset *set;
 
-       set = malloc((name ? strlen(name) : 0) + sizeof *set);
+       set = calloc(1, (name ? strlen(name) : 0) + sizeof *set);
        if (set) {
        if (set) {
-               set->apis = malloc(INCR * sizeof *set->apis);
-               set->count = 0;
                set->timeout = timeout;
                set->refcount = 1;
                set->timeout = timeout;
                set->refcount = 1;
-               set->subset = NULL;
                if (name)
                        strcpy(set->name, name);
                if (name)
                        strcpy(set->name, name);
-               else
-                       set->name[0] = 0;
        }
        return set;
 }
 
        }
        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
 /**
  * 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);
 }
 
        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
 /**
  * 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
  */
  *   - 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;
 
        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;
        }
 
                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;
        }
                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;
 
 
        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;
 }
 
 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
 /**
  * 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)
 {
  */
 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 */
 
        /* 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 (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++;
                        }
                                i++;
                        }
+                       free(desc);
                        return 0;
                }
                if (c > 0)
                        break;
                        return 0;
                }
                if (c > 0)
                        break;
-               i++;
        }
        errno = ENOENT;
        return -1;
        }
        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)
 {
  */
 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
  */
  * @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;
 
 {
        struct api_desc *i;
 
@@ -322,6 +693,78 @@ const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name
        return NULL;
 }
 
        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
 /**
  * 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
  */
  *               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;
 
 {
        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);
        }
 
        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;
        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);
                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
  */
  * @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)
 {
        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;
 }
        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;
 
 {
        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;
        }
 
        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;
 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)
 {
  */
 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) {
 
        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 {
        } 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)
  */
  * @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) {
 
        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 {
        } 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
  * @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;
 
 {
        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) {
                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;
 
 {
        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;
 }
 
        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
 /**
  * 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.
  */
  * @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;
        size_t size;
-       char *dest;
        const char **names;
        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);
        names = malloc(size);
+
        if (!names)
                errno = ENOMEM;
        else {
        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;
 }
        }
        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
 /**
  * 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
  */
  * @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 afb_apiset *iset;
-       struct api_desc *i, *e;
+       struct api_desc *d;
+       struct api_alias *a;
 
        iset = set;
        while (iset) {
 
        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;
        }
 }
 
                }
                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
 
 
 #pragma once
 
-struct afb_api;
+struct afb_api_item;
 struct afb_apiset;
 struct json_object;
 
 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_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 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 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 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 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 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_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 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 <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"
 
 #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)
 {
 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;
 
 {
        struct json_object *result = NULL;
 
-       if (session & AFB_SESSION_CLOSE_V2)
+       if (session & AFB_SESSION_CLOSE_X2)
                result = addperm_key_valstr(result, "session", "close");
 
                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");
 
                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");
 
                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);
 
        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 <getopt.h>
 #include <limits.h>
 #include <unistd.h>
+#include <ctype.h>
 
 #include <json-c/json.h>
 
 
 #include <json-c/json.h>
 
@@ -30,8 +31,6 @@
 #include "afb-config.h"
 #include "afb-hook.h"
 
 #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
 #if !defined(BINDING_INSTALL_DIR)
 #error "you should define BINDING_INSTALL_DIR"
 #endif
 #   define HAS_DBUS 0
 #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 command line option
 #define SET_BACKGROUND     2
 #define SET_WEAK_LDPATH    16
 #define NO_LDPATH          17
 
 #define SET_WEAK_LDPATH    16
 #define NO_LDPATH          17
 
+#if defined(KEEP_LEGACY_MODE)
 #define SET_MODE           18
 #define SET_MODE           18
+#endif
 
 #if HAS_DBUS
 #   define DBUS_CLIENT        20
 #   define DBUS_SERVICE       21
 #endif
 
 
 #if HAS_DBUS
 #   define DBUS_CLIENT        20
 #   define DBUS_SERVICE       21
 #endif
 
-#define SO_BINDING         22
 
 #define SET_SESSIONMAX     23
 
 
 #define SET_SESSIONMAX     23
 
 
 #define SET_NO_HTTPD       28
 
 
 #define SET_NO_HTTPD       28
 
+#define AUTO_WS            'a'
+#define AUTO_LINK          'A'
+#define SO_BINDING         'b'
 #define ADD_CALL           'c'
 #define ADD_CALL           'c'
+#if !defined(REMOVE_LEGACY_TRACE)
 #define SET_TRACEDITF      'D'
 #define SET_TRACEDITF      'D'
+#endif
 #define SET_TRACEEVT       'E'
 #define SET_EXEC           'e'
 #define DISPLAY_HELP       'h'
 #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
 #if HAS_MONITORING
 #   define SET_MONITORING     'M'
 #endif
 #define SET_TCP_PORT       'p'
 #define SET_QUIET          'q'
 #define SET_RNDTOKEN       'r'
 #define SET_TCP_PORT       'p'
 #define SET_QUIET          'q'
 #define SET_RNDTOKEN       'r'
+#if !defined(REMOVE_LEGACY_TRACE)
 #define SET_TRACESVC       'S'
 #define SET_TRACESVC       'S'
+#endif
 #define SET_TRACESES       's'
 #define SET_TRACEREQ       'T'
 #define SET_AUTH_TOKEN     't'
 #define SET_TRACESES       's'
 #define SET_TRACEREQ       'T'
 #define SET_AUTH_TOKEN     't'
 #define SET_WORK_DIR       'w'
 
 const char shortopts[] =
 #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
 #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"},
 /* *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"},
 
        {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"},
 
        {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"},
        {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"},
 
 #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"},
 
        {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_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_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"},
 
 
        {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 }
 };
 
        { NULL, 0 }
 };
 
+#if !defined(REMOVE_LEGACY_TRACE)
 static struct enumdesc traceditf_desc[] = {
        { "no",     0 },
 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 },
        { NULL, 0 }
 };
 
 static struct enumdesc tracesvc_desc[] = {
        { "no",     0 },
-       { "all",    afb_hook_flags_svc_all },
+       { "all",    afb_hook_flags_api_svc_all },
        { NULL, 0 }
 };
        { NULL, 0 }
 };
+#endif
 
 static struct enumdesc traceevt_desc[] = {
        { "no",     0 },
 
 static struct enumdesc traceevt_desc[] = {
        { "no",     0 },
@@ -245,12 +280,25 @@ static struct enumdesc traceses_desc[] = {
        { NULL, 0 }
 };
 
        { 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 }
 };
 static struct enumdesc mode_desc[] = {
        { "local",  AFB_MODE_LOCAL },
        { "remote", AFB_MODE_REMOTE },
        { "global", AFB_MODE_GLOBAL },
        { NULL, 0 }
 };
+#endif
 
 /*----------------------------------------------------------
  | printversion
 
 /*----------------------------------------------------------
  | printversion
@@ -452,6 +500,53 @@ static char **make_exec(char **argv)
        return result;
 }
 
        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
  +--------------------------------------------------------- */
 /*---------------------------------------------------------
  |   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:
        while ((optc = getopt_long(argc, argv, shortopts, gnuOptions, NULL)) != EOF) {
                switch (optc) {
                case SET_VERBOSE:
-                       verbosity++;
+                       verbose_inc();
                        break;
 
                case SET_QUIET:
                        break;
 
                case SET_QUIET:
-                       verbosity--;
+                       verbose_dec();
+                       break;
+
+               case SET_LOG:
+                       set_log(argvalstr(optc));
                        break;
 
                case SET_TCP_PORT:
                        break;
 
                case SET_TCP_PORT:
-                       config->httpdPort = argvalintdec(optc, 1024, 32767);
+                       config->http_port = argvalintdec(optc, 1024, 32767);
                        break;
 
                case SET_APITIMEOUT:
                        break;
 
                case SET_APITIMEOUT:
-                       config->apiTimeout = argvalintdec(optc, 0, INT_MAX);
+                       config->api_timeout = argvalintdec(optc, 0, INT_MAX);
                        break;
 
                case SET_CNTXTIMEOUT:
                        break;
 
                case SET_CNTXTIMEOUT:
-                       config->cntxTimeout = argvalintdec(optc, 0, INT_MAX);
+                       config->session_timeout = argvalintdec(optc, 0, INT_MAX);
                        break;
 
                case SET_ROOT_DIR:
                        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:
                        break;
 
                case SET_CACHE_TIMEOUT:
-                       config->cacheTimeout = argvalintdec(optc, 0, INT_MAX);
+                       config->cache_timeout = argvalintdec(optc, 0, INT_MAX);
                        break;
 
                case SET_SESSIONMAX:
                        break;
 
                case SET_SESSIONMAX:
-                       config->nbSessionMax = argvalintdec(optc, 1, INT_MAX);
+                       config->max_session_count = argvalintdec(optc, 1, INT_MAX);
                        break;
 
                case SET_FORGROUND:
                        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;
 
                        config->name = argvalstr(optc);
                        break;
 
+#if defined(KEEP_LEGACY_MODE)
                case SET_MODE:
                        config->mode = argvalenum(optc, mode_desc);
                        break;
                case SET_MODE:
                        config->mode = argvalenum(optc, mode_desc);
                        break;
+#endif
 
 #if HAS_DBUS
                case DBUS_CLIENT:
 
 #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;
 
                        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;
 
                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;
                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;
                case SET_TRACESVC:
                        config->tracesvc = argvalenum(optc, tracesvc_desc);
                        break;
+#endif
 
                case SET_TRACEEVT:
                        config->traceevt = argvalenum(optc, traceevt_desc);
 
                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;
 
                        config->traceses = argvalenum(optc, traceses_desc);
                        break;
 
+               case SET_TRACEAPI:
+                       config->traceapi = argvalenum(optc, traceapi_desc);
+                       break;
+
                case SET_NO_HTTPD:
                        noarg(optc);
                case SET_NO_HTTPD:
                        noarg(optc);
-                       config->noHttpd = 1;
+                       config->no_httpd = 1;
                        break;
 
                case SET_EXEC:
                        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
 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
 
        // 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
 
        // 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
 
        // 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
 
        // 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)
 
        /* 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);
        }
                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)
 }
 
 void afb_config_dump(struct afb_config *config)
@@ -761,21 +880,26 @@ void afb_config_dump(struct afb_config *config)
 
        V(exec)
 
 
        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)
        E(mode,mode_desc)
+#endif
        E(tracereq,tracereq_desc)
        E(tracereq,tracereq_desc)
+#if !defined(REMOVE_LEGACY_TRACE)
        E(traceditf,traceditf_desc)
        E(tracesvc,tracesvc_desc)
        E(traceditf,traceditf_desc)
        E(tracesvc,tracesvc_desc)
+#endif
        E(traceevt,traceevt_desc)
        E(traceses,traceses_desc)
        E(traceevt,traceevt_desc)
        E(traceses,traceses_desc)
+       E(traceapi,traceapi_desc)
 
        B(no_ldpaths)
 
        B(no_ldpaths)
-       B(noHttpd)
+       B(no_httpd)
        B(background)
 #if HAS_MONITORING
        B(monitoring)
        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);
 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);
        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->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");
 }
 
        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);
        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;
 }
                afb_config_dump(result);
        return result;
 }
@@ -895,21 +1022,26 @@ struct json_object *afb_config_json(struct afb_config *config)
 
        V(exec)
 
 
        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)
        E(mode,mode_desc)
+#endif
        E(tracereq,tracereq_desc)
        E(tracereq,tracereq_desc)
+#if !defined(REMOVE_LEGACY_TRACE)
        E(traceditf,traceditf_desc)
        E(tracesvc,tracesvc_desc)
        E(traceditf,traceditf_desc)
        E(tracesvc,tracesvc_desc)
+#endif
        E(traceevt,traceevt_desc)
        E(traceses,traceses_desc)
        E(traceevt,traceevt_desc)
        E(traceses,traceses_desc)
+       E(traceapi,traceapi_desc)
 
        B(no_ldpaths)
 
        B(no_ldpaths)
-       B(noHttpd)
+       B(no_httpd)
        B(background)
 #if HAS_MONITORING
        B(monitoring)
        B(background)
 #if HAS_MONITORING
        B(monitoring)
index 89b1f78..30fd398 100644 (file)
@@ -22,22 +22,27 @@ struct json_object;
  * other definitions ---------------------------------------------------
  */
 
  * other definitions ---------------------------------------------------
  */
 
+/**
+ * list of configuration values
+ */
 struct afb_config_list {
        struct afb_config_list *next;
        char *value;
 };
 
 struct afb_config_list {
        struct afb_config_list *next;
        char *value;
 };
 
-// main config structure
+/**
+ * main config structure
+ */
 struct afb_config {
 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)
 
        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 *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 */
 
        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 */
 
        /* enums */
+#if defined(KEEP_LEGACY_MODE)
        int mode;               // mode of listening
        int mode;               // mode of listening
+#endif
        int tracereq;
        int tracereq;
+#if !defined(REMOVE_LEGACY_TRACE)
        int traceditf;
        int tracesvc;
        int traceditf;
        int tracesvc;
+#endif
        int traceevt;
        int traceses;
        int traceevt;
        int traceses;
+       int traceapi;
 
        /* booleans */
 
        /* 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)
 #if defined(WITH_MONITORING_OPTION)
-       unsigned monitoring: 1;         /* activates monitoring */
+       unsigned monitoring: 1;         /**< activates monitoring */
 #endif
 #endif
-       unsigned random_token: 1;       /* expects a random token */
 };
 
 extern struct afb_config *afb_config_parse_arguments(int argc, char **argv);
 };
 
 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 <assert.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <errno.h>
 
 #include "afb-session.h"
 #include "afb-context.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)
 {
 
 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)
 }
 
 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)));
 }
        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>
 #define _GNU_SOURCE
 
 #include <stdlib.h>
+#include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
@@ -26,6 +27,8 @@
 #include <sys/socket.h>
 
 #include "afb-cred.h"
 #include <sys/socket.h>
 
 #include "afb-cred.h"
+#include "verbose.h"
+
 
 #define MAX_LABEL_LENGTH  1024
 
 
 #define MAX_LABEL_LENGTH  1024
 
 #  define DEFAULT_PEERCRED_PID 0  /* no process */
 #endif
 
 #  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)
 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->uid = uid;
                cred->gid = gid;
                cred->pid = pid;
+               cred->exported = NULL;
                dest = (char*)(&cred[1]);
                cred->user = dest;
                while(i)
                dest = (char*)(&cred[1]);
                cred->user = dest;
                while(i)
@@ -175,3 +183,105 @@ struct afb_cred *afb_cred_current()
        return afb_cred_addref(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 *user;
        const char *label;
        const char *id;
+       const char *exported;
 };
 
 extern struct afb_cred *afb_cred_current();
 };
 
 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 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 <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"
 
 #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;
 
        /* 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;
 
        /* count of reference to the listener */
        int refcount;
@@ -63,7 +63,7 @@ struct afb_evt_listener {
 struct afb_evtid {
 
        /* interface */
 struct afb_evtid {
 
        /* interface */
-       struct afb_eventid eventid;
+       struct afb_event_x2 eventid;
 
        /* next event */
        struct afb_evtid *next;
 
        /* 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;
 
        /* 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;
 
        /* hooking */
        int hookflags;
@@ -109,7 +109,7 @@ struct afb_evt_watch {
 };
 
 /* the interface for events */
 };
 
 /* 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,
        .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 */
 };
 
 /* 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,
        .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 */
 };
 
 /* 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 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;
 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;
        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) {
        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;
        }
                }
                listener = listener->next;
        }
-       pthread_mutex_unlock(&listeners_mutex);
+       pthread_rwlock_unlock(&listeners_rwlock);
        json_object_put(obj);
        return result;
 }
        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;
        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;
        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;
        }
                }
                watch = watch->next_by_evtid;
        }
-       pthread_mutex_unlock(&evtid->mutex);
+       pthread_rwlock_unlock(&evtid->rwlock);
        json_object_put(obj);
        return result;
 }
        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 afb_evt_evtid_hooked_push(struct afb_evtid *evtid, struct json_object *obj)
 {
+
        int result;
 
        /* lease the object */
        int result;
 
        /* lease the object */
@@ -319,7 +321,7 @@ struct afb_evtid *afb_evt_evtid_create(const char *fullname)
                goto error;
 
        /* allocates the id */
                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;
        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;
        /* initialize the event */
        memcpy(evtid->fullname, fullname, len + 1);
        evtid->next = evtids;
+       evtid->refcount = 1;
        evtid->watchs = NULL;
        evtid->id = event_id_counter;
        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);
        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);
        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;
 
        /* 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! */
 
        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;
                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)
 
                /* 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;
                        /* 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);
                                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 */
                        }
 
                        /* free */
-                       pthread_mutex_destroy(&evtid->mutex);
+                       pthread_rwlock_destroy(&evtid->rwlock);
                        free(evtid);
                }
        }
                        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 */
        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) {
        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;
                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:
                listener->next = listeners;
                listeners = listener;
        }
  found:
-       pthread_mutex_unlock(&listeners_mutex);
+       pthread_rwlock_unlock(&listeners_rwlock);
        return listener;
 }
 
        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 */
        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;
                prv = &listeners;
                while (*prv != listener)
                        prv = &(*prv)->next;
                *prv = listener->next;
-               pthread_mutex_unlock(&listeners_mutex);
+               pthread_rwlock_unlock(&listeners_rwlock);
 
                /* remove the watchers */
 
                /* remove the watchers */
-               pthread_mutex_lock(&listener->mutex);
+               pthread_rwlock_wrlock(&listener->rwlock);
                while (listener->watchs != NULL) {
                        evtid = listener->watchs->evtid;
                while (listener->watchs != NULL) {
                        evtid = listener->watchs->evtid;
-                       pthread_mutex_lock(&evtid->mutex);
+                       pthread_rwlock_wrlock(&evtid->rwlock);
                        remove_watch(listener->watchs);
                        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 */
 
                /* free the listener */
-               pthread_mutex_destroy(&listener->mutex);
+               pthread_rwlock_destroy(&listener->rwlock);
                free(listener);
        }
 }
                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 */
        }
 
        /* 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)
        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) {
        /* 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;
        }
                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;
        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;
        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++;
 
 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;
 }
 
        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 */
        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) {
        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);
                        }
                                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;
        }
                        return 0;
                }
                watch = watch->next_by_listener;
        }
-       pthread_mutex_unlock(&listener->mutex);
+       pthread_rwlock_unlock(&listener->rwlock);
        errno = ENOENT;
        return -1;
 }
        errno = ENOENT;
        return -1;
 }
@@ -646,20 +649,20 @@ void afb_evt_update_hooks()
 {
        struct afb_evtid *evtid;
 
 {
        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);
        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;
 }
 
 {
        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;
 }
 {
        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.
  */
  * 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.
  */
 }
 
 /*
  * 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'
  */
 }
 
 /*
  * 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'
  */
        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;
 }
 
        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.
  */
  * 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) {
 
        /* 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.
  */
  * 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) {
 
        /* 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);
 }
 
        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;
 }
 
        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;
 }
 
        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
 {
        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);
 }
 
        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;
        if (evtid)
                afb_evt_evtid_addref(evtid);
        return eventid;
index c3999df..ceb1b1b 100644 (file)
@@ -17,8 +17,8 @@
 
 #pragma once
 
 
 #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;
 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 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 <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <fnmatch.h>
+#include <ctype.h>
 
 #include <json-c/json.h>
 
 
 #include <json-c/json.h>
 
 
 #include "afb-api.h"
 #include "afb-apiset.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-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-msg-json.h"
 #include "afb-session.h"
 #include "afb-xreq.h"
+#include "afb-calls.h"
 #include "jobs.h"
 #include "verbose.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
 {
 enum afb_api_version
 {
-       Api_Version_Dyn = 0,
+       Api_Version_None = 0,
+#if defined(WITH_LEGACY_BINDING_V1)
        Api_Version_1 = 1,
        Api_Version_1 = 1,
+#endif
        Api_Version_2 = 2,
        Api_Version_2 = 2,
+       Api_Version_3 = 3
 };
 
 };
 
+/*
+ * The states of exported APIs
+ */
 enum afb_api_state
 {
        Api_State_Pre_Init,
 enum afb_api_state
 {
        Api_State_Pre_Init,
@@ -59,13 +93,16 @@ enum afb_api_state
        Api_State_Run
 };
 
        Api_State_Run
 };
 
+/*
+ * structure of the exported API
+ */
 struct afb_export
 {
        /* keep it first */
 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;
 
        /* version of the api */
        unsigned version: 4;
@@ -73,124 +110,157 @@ struct afb_export
        /* current state */
        unsigned state: 4;
 
        /* current state */
        unsigned state: 4;
 
+       /* declared */
+       unsigned declared: 1;
+
+       /* unsealed */
+       unsigned unsealed: 1;
+
        /* hooking flags */
        int hookditf;
        int hooksvc;
 
        /* hooking flags */
        int hookditf;
        int hooksvc;
 
-       /* dynamic api */
-       struct afb_api_dyn *apidyn;
-
        /* session for service */
        struct afb_session *session;
 
        /* 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 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 {
        /* start function */
        union {
-               int (*v1)(struct afb_service);
+#if defined(WITH_LEGACY_BINDING_V1)
+               int (*v1)(struct afb_service_x1);
+#endif
                int (*v2)();
                int (*v2)();
-               int (*vdyn)(struct afb_dynapi *dynapi);
+               int (*v3)(struct afb_api_x3 *api);
        } init;
 
        /* event handling */
        } 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 {
 
        /* exported data */
        union {
+#if defined(WITH_LEGACY_BINDING_V1)
                struct afb_binding_interface_v1 v1;
                struct afb_binding_interface_v1 v1;
+#endif
                struct afb_binding_data_v2 *v2;
        } export;
                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
                                            F R O M     D I T F
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************/
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
 
 /**********************************************
 * normal flow
 **********************************************/
 
 /**********************************************
 * 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;
 {
        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 {
 
        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);
        }
 }
 
                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);
 }
 
 {
        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) {
 
        /* 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 */
                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;
 {
        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) {
 
        /* 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 */
                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);
        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);
 
        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);
 }
 
        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);
 }
 
 {
        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);
 }
 
 {
        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);
 }
 
 {
        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;
        }
                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;
 }
 
        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,
                const char *api,
                const char *info,
                int noconcurrency,
-               int (*preinit)(void*, struct afb_dynapi *),
+               int (*preinit)(void*, struct afb_api_x3 *),
                void *preinit_closure)
 {
                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
 **********************************************/
 }
 
 /**********************************************
 * 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);
        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);
 }
 
        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);
 }
 
 {
        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;
 }
 
        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;
 {
        int r;
-       struct afb_export *export = closure;
+       struct afb_export *export = from_api_x3(closure);
        json_object_get(object);
        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);
        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;
 }
 
        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();
        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();
        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();
        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();
        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);
        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);
        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;
 {
        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);
        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,
                const char *api,
                const char *info,
                int noconcurrency,
-               int (*preinit)(void*, struct afb_dynapi *),
+               int (*preinit)(void*, struct afb_api_x3 *),
                void *preinit_closure)
 {
                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
 **********************************************/
 /**********************************************
 * 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,
        .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,
        .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,
        .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,
        .require_api = require_api_cb,
-       .rename_api = rename_api_cb,
+       .add_alias = add_alias_cb,
        .new_api = api_new_api_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,
        .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,
        .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,
        .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,
        .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,
 };
 
        .new_api = hooked_api_new_api_cb,
 };
 
-/*************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
                                            F R O M     S V C
                                            F R O M     S V C
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************/
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
 
 /* the common session for services sharing their session */
 static struct afb_session *common_session;
 
 
 /* the common session for services sharing their session */
 static struct afb_session *common_session;
 
-/*************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
                                            F R O M     S V C
                                            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 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*),
                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,
                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)
 {
                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*),
                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,
                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)
 {
                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 */
 }
 
 /* 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 */
 };
 
 /* 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
                                            F R O M     D Y N A P I
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************
- *************************************************************************************************************/
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
 
 static int api_set_verbs_v2_cb(
 
 static int api_set_verbs_v2_cb(
-               struct afb_dynapi *dynapi,
+               struct afb_api_x3 *api,
                const struct afb_verb_v2 *verbs)
 {
                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;
        }
 
                return 0;
        }
 
@@ -829,115 +690,292 @@ static int api_set_verbs_v2_cb(
        return -1;
 }
 
        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(
 static int api_add_verb_cb(
-               struct afb_dynapi *dynapi,
+               struct afb_api_x3 *api,
                const char *verb,
                const char *info,
                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,
                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(
 }
 
 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(
 }
 
 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(
 }
 
 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(
 }
 
 static int hooked_api_set_verbs_v2_cb(
-               struct afb_dynapi *dynapi,
+               struct afb_api_x3 *api,
                const struct afb_verb_v2 *verbs)
 {
                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(
 }
 
 static int hooked_api_add_verb_cb(
-               struct afb_dynapi *dynapi,
+               struct afb_api_x3 *api,
                const char *verb,
                const char *info,
                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,
                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(
 }
 
 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(
 }
 
 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(
 }
 
 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,
 
 
        .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,
        .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,
 
        .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_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_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,
 
 
        .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,
        .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,
 
        .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_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_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
  */
 
 /*
  * 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 */
        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
                                            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;
 
 {
        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;
        }
                if (common_session == NULL)
                        return NULL;
        }
-       export = calloc(1, sizeof *export);
+       export = calloc(1, sizeof *export + strlen(apiname));
        if (!export)
                errno = ENOMEM;
        else {
        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->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;
 }
 
        }
        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)
 {
 void afb_export_destroy(struct afb_export *export)
 {
+       struct event_handler *handler;
+
        if (export) {
        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);
                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);
        }
 }
 
                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;
        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.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;
 }
        }
        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;
        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;
                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;
 }
 
        }
        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) {
        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;
 }
 
        }
        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)
 {
 }
 
 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) {
 
        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;
        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;
        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) {
 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;
 }
 
        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) {
 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:
        default:
-               ERROR("invalid version 12 for API %s", export->apiname);
+               ERROR("invalid version 12 for API %s", export->api.apiname);
                errno = EINVAL;
                return -1;
        }
 
                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) {
 {
        /* check version */
        switch (export->version) {
-       case Api_Version_Dyn: break;
+       case Api_Version_3: break;
        default:
        default:
-               ERROR("invalid version Dyn for API %s", export->apiname);
+               ERROR("invalid version Dyn for API %s", export->api.apiname);
                errno = EINVAL;
                return -1;
        }
 
                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) {
 {
        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;
        }
 
                errno = EINVAL;
                return -1;
        }
 
-       export->init.vdyn  = oninit;
+       export->init.v3  = oninit;
        return 0;
 }
 
        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*))
 {
 /*
  * 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) {
        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
                                            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;
 
 {
        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 */
                        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;
        }
 
                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) {
        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) {
                        return -1;
                }
        }
 
        /* set event handling */
        switch (export->version) {
+#if defined(WITH_LEGACY_BINDING_V1)
        case Api_Version_1:
        case Api_Version_1:
+#endif
        case Api_Version_2:
        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) {
                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 */
                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) {
        export->state = Api_State_Init;
        switch (export->version) {
+#if defined(WITH_LEGACY_BINDING_V1)
        case Api_Version_1:
        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;
                break;
+#endif
        case Api_Version_2:
                rc = export->init.v2 ? export->init.v2() : 0;
                break;
        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:
                break;
        default:
+               errno = EINVAL;
+               rc = -1;
                break;
        }
        export->state = Api_State_Run;
                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 */
        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;
        }
 
                return rc;
        }
 
@@ -1371,3 +1590,154 @@ done:
        return 0;
 }
 
        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_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_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 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 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 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 <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-context.h"
 #include "afb-hook.h"
 #include "afb-export.h"
 #include "afb-evt.h"
 #include "afb-api.h"
 #include "afb-export.h"
 #include "afb-evt.h"
 #include "afb-api.h"
+#include "afb-msg-json.h"
 #include "verbose.h"
 
 #include <fnmatch.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
 
 /**
  * Definition of a hook for xreq
@@ -60,24 +69,12 @@ struct afb_hook_xreq {
 /**
  * Definition of a hook for export
  */
 /**
  * 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 */
        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 */
 };
 
        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_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;
 
 /* 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);
 {
        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);
 }
 
        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");
 {
        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");
 }
 
 {
        _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));
 }
 
 {
        _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);
 }
 
 {
        _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);
 }
 
 {
        _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);
 }
 
 {
        _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()");
 }
 
 {
        _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()");
 }
 
 {
        _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()");
 }
 
 {
        _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);
 }
 
 {
        _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));
 }
 
 {
        _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));
 }
 
 {
        _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;
 {
        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)
        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 {
        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);
        }
 }
 
                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);
 }
 
 {
        _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()");
 }
 
 {
        _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);
 }
 
 {
        _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);
 }
 
 {
        _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);
 }
 
 {
        _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);
 }
 
 {
        _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 = {
 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
  *****************************************************************************/
 
 };
 
 /******************************************************************************
  * 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) { \
        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->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);
 
                } \
                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)
 {
 
 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;
 }
 
        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;
 }
 
        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)
 }
 
 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;
 }
 
        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;
 }
 
        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;
 }
 
        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);
 }
 
 {
        _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);
 }
 
 {
        _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;
 }
 
        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);
 }
 
        _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)
 }
 
 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;
 }
 
        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
  *****************************************************************************/
 /******************************************************************************
  * 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;
 
        /* 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;
 
        /* 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
  *****************************************************************************/
 
  * 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);
 {
        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);
 }
 
        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;
 {
        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)
        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 {
        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);
        }
 }
 
                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)
 {
        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);
        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)
 {
        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);
        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)
  *****************************************************************************/
 
 };
 
 /******************************************************************************
  * 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); \
        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) { \
        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);
 
                } \
                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;
 }
 
        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;
 }
 
        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;
 }
 
        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;
 }
 
        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;
 }
 
        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;
 }
 
        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;
 }
 
        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;
 }
 
        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;
 }
 
        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;
 }
 
        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;
 {
        int flags;
-       struct afb_hook_svc *hook;
+       struct afb_hook_api *hook;
 
        flags = 0;
 
        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;
 }
 
        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);
 
        /* 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;
        /* 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->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;
 }
 
        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++;
 {
        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;
 }
 
        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);
 
        if (hook) {
                pthread_rwlock_wrlock(&rwlock);
@@ -1217,7 +1251,7 @@ void afb_hook_unref_svc(struct afb_hook_svc *hook)
                        hook = NULL;
                else {
                        /* unlink */
                        hook = NULL;
                else {
                        /* unlink */
-                       prv = &list_of_svc_hooks;
+                       prv = &list_of_api_hooks;
                        while (*prv && *prv != hook)
                                prv = &(*prv)->next;
                        if(*prv)
                        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);
 }
 
        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");
 }
 
 {
        _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));
 }
 
 
 {
        _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);
 }
 
 {
        _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));
 }
 
 {
        _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);
 }
 
 {
        _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);
 }
 
 {
        _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");
 }
 
 {
        _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_(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 \
        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; \
                        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;
        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;
 }
 
        return flags;
 }
 
@@ -1458,43 +1490,43 @@ static void _hook_session_(struct afb_session *session, const char *format, ...)
        va_end(ap);
 }
 
        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));
 }
 
 {
        _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");
 }
 
 {
        _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");
 }
 
 {
        _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));
 }
 
 {
        _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");
 }
 
 {
        _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_(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 \
        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; \
                        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);
 }
 
        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;
 {
        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)
        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 {
        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 = {
                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_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;
 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 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;
 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_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
 #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_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)
 
 /* 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\
 #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_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)
 
 /* 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)
                                        |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 */
 
 /* 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\
                                        |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_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_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)(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)(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_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_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);
 };
 
 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_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 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_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 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)
 
 /*********************************************************
 * 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);
 
 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 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,
 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
 };
 
        .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);
        }
        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);
 }
        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;
 }
 
        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;
 
        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);
        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);
 
        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)
 {
 }
 
 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) {
                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>
 
 
 #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/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 "afb-evt.h"
 #include "afb-xreq.h"
 #include "afb-trace.h"
 
 #include "monitor-api.inc"
 
 
 #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)) {
        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_))
        } 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_))
                        break;
                case 'I':
                        if (!strcasecmp(s, _info_))
-                               level = Verbosity_Level_Info;
+                               level = _VERBOSITY_(Log_Level_Info);
                        break;
                case 'N':
                        if (!strcasecmp(s, _notice_))
                        break;
                case 'N':
                        if (!strcasecmp(s, _notice_))
-                               level = Verbosity_Level_Notice;
+                               level = _VERBOSITY_(Log_Level_Notice);
                        break;
                case 'W':
                        if (!strcasecmp(s, _warning_))
                        break;
                case 'W':
                        if (!strcasecmp(s, _warning_))
-                               level = Verbosity_Level_Warning;
+                               level = _VERBOSITY_(Log_Level_Warning);
                        break;
                case 'E':
                        if (!strcasecmp(s, _error_))
                        break;
                case 'E':
                        if (!strcasecmp(s, _error_))
-                               level = Verbosity_Level_Error;
+                               level = _VERBOSITY_(Log_Level_Error);
                        break;
                }
        }
                        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
  */
  * @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)
 {
  */
 static void set_verbosity_to(const char *name, int level)
 {
+       int mask = verbosity_to_mask(level);
        if (!name || !name[0])
        if (!name || !name[0])
-               verbosity = level;
+               verbosity_set(level);
        else if (name[0] == '*' && !name[1])
        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
        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)
 {
  */
 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);
        }
 }
        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
  */
  * @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;
 {
        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)
 {
  */
 static void get_verbosity_of(struct json_object *resu, const char *name)
 {
-       int l;
+       int m;
        if (!name || !name[0])
        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])
        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 {
        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;
 
 {
        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);
 }
 
                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
  */
  * @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);
 {
        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)) {
        } 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;
 }
        }
        return resu;
 }
@@ -298,7 +299,7 @@ static const char _verbosity_[] = "verbosity";
 static const char _apis_[] = "apis";
 static const char _refresh_token_[] = "refresh-token";
 
 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;
 {
        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);
 }
 
        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;
 
 {
        struct json_object *verbosity = NULL;
 
@@ -325,9 +326,9 @@ static void f_set(struct afb_req req)
        afb_req_success(req, NULL, NULL);
 }
 
        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)
 }
 
 static void context_destroy(void *pointer)
@@ -336,14 +337,14 @@ static void context_destroy(void *pointer)
        afb_trace_unref(trace);
 }
 
        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;
 
 {
        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);
        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_req_success(req, NULL, NULL);
 end:
-       afb_apiset_update_hooks(main_apiset, NULL);
+       afb_apiset_update_hooks(target_set, NULL);
        afb_evt_update_hooks();
 }
 
        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 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) {
 
        /* 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);
 }
 
        afb_req_success(req, r, NULL);
 }
 
-
index 1f3c144..407116d 100644 (file)
@@ -18,4 +18,6 @@
 
 #pragma once
 
 
 #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"
 
 #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;
 {
        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);
 
        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 (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)
        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;
 }
 
        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;
 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()
 {
 
 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;
 
 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);
 
 
 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
 
 
 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:
   - 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'
 /************** 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_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'
 
 #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
 
 /*
  * structure for recording calls on client side
@@ -182,9 +155,6 @@ struct afb_proto_ws
        /* emitted calls (client side) */
        struct client_call *calls;
 
        /* emitted calls (client side) */
        struct client_call *calls;
 
-       /* pending subcalls (server side) */
-       struct server_subcall *subcalls;
-
        /* pending description (client side) */
        struct client_describe *describes;
 
        /* pending description (client side) */
        struct client_describe *describes;
 
@@ -237,6 +207,7 @@ static char *readbuf_get(struct readbuf *rb, uint32_t length)
        return before;
 }
 
        return before;
 }
 
+__attribute__((unused))
 static int readbuf_char(struct readbuf *rb, char *value)
 {
        if (rb->head >= rb->end)
 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;
 }
 
        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;
 {
        uint32_t len;
-       if (!readbuf_uint32(rb, &len) || !len)
+       if (!readbuf_uint32(rb, &len))
                return 0;
                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;
 }
 
        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;
 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));
 }
 
        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);
 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);
 }
 
        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;
 
 {
        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_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);
         && 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;
 }
 
        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;
 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);
 }
 
                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;
 {
        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 (!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 {
        } 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);
 }
 
        }
        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;
 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++) {
 
        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);
                        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_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;
                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,
                const char *verb,
                struct json_object *args,
                const char *sessionid,
-               void *request
+               void *request,
+               const char *user_creds
 )
 {
        int rc = -1;
 )
 {
        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_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;
        }
                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;
 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;
        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)
        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 */
                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 */
 
        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:
        return;
 
 out_of_memory:
@@ -964,39 +800,6 @@ overflow:
        afb_proto_ws_unref(protows);
 }
 
        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;
 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_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;
                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;
 static void on_hangup(void *closure)
 {
        struct afb_proto_ws *protows = closure;
-       struct server_subcall *sc, *nsc;
        struct client_describe *cd, *ncd;
 
        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;
        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;
                if (protows->ws != NULL) {
                        protows->fdev = fdev;
                        protows->refcount = 1;
-                       protows->subcalls = NULL;
                        protows->closure = closure;
                        protows->server_itf = itfs;
                        protows->client_itf = itfc;
                        protows->closure = closure;
                        protows->server_itf = itfs;
                        protows->client_itf = itfc;
index d674af3..342313e 100644 (file)
 
 #pragma once
 
 
 #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 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 */
 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);
 
        /* 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_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
 {
 };
 
 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);
 };
 
        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);
 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 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_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);
 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 <uuid/uuid.h>
 #include <errno.h>
 
-#include <json-c/json.h>
-
 #include "afb-session.h"
 #include "afb-hook.h"
 #include "verbose.h"
 #include "afb-session.h"
 #include "afb-hook.h"
 #include "verbose.h"
+#include "pearson.h"
 
 #define SIZEUUID       37
 #define HEADCOUNT      16
 
 #define SIZEUUID       37
 #define HEADCOUNT      16
 #define MAX_EXPIRATION (_MAXEXP_ >= 0 ? _MAXEXP_ : _MAXEXP2_)
 #define NOW            (time_now())
 
 #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
 {
-       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
 {
  * 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 {
 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,
 } sessions = {
        .count = 0,
        .max = 10,
@@ -87,7 +90,9 @@ static struct {
        .mutex = PTHREAD_MUTEX_INITIALIZER
 };
 
        .mutex = PTHREAD_MUTEX_INITIALIZER
 };
 
-/* Get the actual raw time */
+/**
+ * Get the actual raw time
+ */
 static inline time_t time_now()
 {
        struct timespec ts;
 static inline time_t time_now()
 {
        struct timespec ts;
@@ -95,7 +100,9 @@ static inline time_t time_now()
        return ts.tv_sec;
 }
 
        return ts.tv_sec;
 }
 
-/* generate a new fresh 'uuid' */
+/**
+ * generate a new fresh 'uuid'
+ */
 static void new_uuid(char uuid[SIZEUUID])
 {
        uuid_t newuuid;
 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);
 }
 
        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()
 {
 /* 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 */
 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;
        }
                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
  * @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)
 {
  */
 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
  * 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
  *
  * @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)
  *
  * @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*))
 {
  */
 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 <json-c/json.h>
 
-#include <afb/afb-event.h>
+#include <afb/afb-event-x2.h>
 
 #include "afb-session.h"
 #include "afb-cred.h"
 
 #include "afb-session.h"
 #include "afb-cred.h"
 struct afb_stub_ws;
 
 
 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
  */
 /*
  * structure for recording calls on client side
  */
@@ -100,7 +77,7 @@ struct server_req {
 struct client_event
 {
        struct client_event *next;
 struct client_event
 {
        struct client_event *next;
-       struct afb_eventid *eventid;
+       struct afb_event_x2 *event;
        int id;
        int refcount;
 };
        int id;
        int refcount;
 };
@@ -152,7 +129,7 @@ struct afb_stub_ws
        /* event replica (client side) */
        struct client_event *events;
 
        /* event replica (client side) */
        struct client_event *events;
 
-       /* credentials (server side) */
+       /* credentials of the client (server side) */
        struct afb_cred *cred;
 
        /* sessions (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);
 }
 
        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);
 
 {
        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)
        if (rc < 0)
-               ERROR("error while sending success");
+               ERROR("error while sending reply");
        json_object_put(obj);
 }
 
        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);
 
 {
        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)
        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;
 }
 
        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);
 
 {
        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)
        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 = {
 }
 
 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,
        .unref = server_req_destroy_cb,
-       .subcall = server_req_subcall_cb,
        .subscribe = server_req_subscribe_cb,
        .unsubscribe = server_req_unsubscribe_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;
        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;
                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;
 
 {
        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);
 }
 
        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;
 
 {
        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);
 }
 
        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) {
        /* 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;
                        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 */
        *prv = ev->next;
 
        /* destroys the event */
-       afb_evt_eventid_unref(ev->eventid);
+       afb_evt_event_x2_unref(ev->event);
        free(ev);
 }
 
        free(ev);
 }
 
@@ -419,7 +372,7 @@ static void on_event_subscribe(void *closure, void *request, const char *event_n
        if (ev == NULL)
                return;
 
        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");
 }
 
                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 (ev == NULL)
                return;
 
-       if (afb_xreq_unsubscribe(xreq, ev->eventid) < 0)
+       if (afb_xreq_unsubscribe(xreq, ev->event) < 0)
                ERROR("can't unsubscribe: %m");
 }
 
                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)
        /* 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");
 }
        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);
 }
 
        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)
 /*****************************************************/
 
 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;
 {
        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 */
                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;
        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);
 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);
 }
 
        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 =
 {
 
 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_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 =
 };
 
 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;
 
        while (ev) {
                nxt = ev->next;
-               afb_evt_eventid_unref(ev->eventid);
+               afb_evt_event_x2_unref(ev->event);
                free(ev);
                ev = nxt;
        }
                free(ev);
                ev = nxt;
        }
@@ -738,9 +676,9 @@ const char *afb_stub_ws_name(struct afb_stub_ws *stubws)
        return stubws->apiname;
 }
 
        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;
 
        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 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);
 
 
 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 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);
 
 
 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.
  */
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #define _GNU_SOURCE
 #define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
 
 #define _GNU_SOURCE
 #define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
 
@@ -29,7 +28,9 @@
 #include <sys/un.h>
 
 #include <json-c/json.h>
 #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"
 
 #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,
 
        /* 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);
        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;
        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);
 
        /* 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) {
        if (i < 0) {
-               afb_xreq_fail_unknown_verb(xreq);
+               afb_xreq_reply_unknown_verb(xreq);
                return;
        }
 
                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)
                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)
                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();
                        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);
                        }
                }
                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:
                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 */);
 
                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) {
                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))
        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)
                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;
                        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);
                                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:
                }
                break;
        case Wait:
-               afb_req_success(req, NULL, NULL);
+               afb_xreq_reply(xreq, NULL, NULL, NULL);
                afb_debug_wait("supervisor");
                break;
        case Break:
                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;
        }
                afb_debug_break("supervisor");
                break;
        }
index 5404a5a..a603951 100644 (file)
@@ -28,7 +28,7 @@
 
 #include <json-c/json.h>
 
 
 #include <json-c/json.h>
 
-#define AFB_BINDING_VERSION 0
+#define AFB_BINDING_VERSION 3
 #include <afb/afb-binding.h>
 
 #include "afb-hook.h"
 #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 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 */
 };
 
 /* struct for sessions */
@@ -95,13 +95,16 @@ struct hook {
 /* types of hooks */
 enum trace_type
 {
 /* 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 */
 };
 
 /* client data */
@@ -168,8 +171,15 @@ static struct json_object *timestamp(const struct afb_hookid *hookid)
 {
        char ts[50];
 
 {
        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_string(ts);
+       return json_object_new_double_s(0f, ts); /* the real value isn't used */
+#endif
 }
 
 /* verbosity level name or NULL */
 }
 
 /* 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 },
                { "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_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 },
                { "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",                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 },
                { "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 },
                { "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 },
                { "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 },
                { "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 },
                { "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 },
 };
                { "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,
        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);
                                        "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)
 {
 
 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)
 }
 
 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);
 }
 
                                                "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,
                                                "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);
 }
 
                                                "info", info);
 }
 
@@ -364,21 +366,21 @@ static void hook_xreq_session_set_LOA(void *closure, const struct afb_hookid *ho
                                        "result", result);
 }
 
                                        "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",
 {
        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);
 }
 
                                        "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",
 {
        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);
 }
 
                                        "result", result);
 }
 
@@ -390,11 +392,12 @@ static void hook_xreq_subcall(void *closure, const struct afb_hookid *hookid, co
                                        "args", args);
 }
 
                                        "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)
 }
 
 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);
 }
 
                                        "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,
                                        "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)
 }
 
 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);
 }
 
        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}",
 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);
 }
 
                                        "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,
 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,
        .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_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_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' */
 /* 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);
 {
        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);
 }
 
                                        "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);
 }
 
                        "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);
 }
 
                        "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;
 {
        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);
 
        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,
                                        "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);
 }
 
        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];
 
 {
        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);
        }
 
                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);
 }
 
                        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];
 
 {
        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);
        }
 
                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,
                        "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);
 }
 
                        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
        },
                .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] =
        {
        },
        [Trace_Type_Evt] =
        {
@@ -1046,6 +1153,20 @@ abstracting[Trace_Type_Count] =
                .unref =  (void(*)(void*))afb_hook_unref_global,
                .get_flag = get_global_flag
        },
                .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 context
 {
        struct afb_trace *trace;
-       struct afb_req req;
+       afb_req_t req;
        char *errors;
 };
 
        char *errors;
 };
 
@@ -1252,13 +1373,12 @@ struct desc
        const char *name;
        const char *tag;
        const char *uuid;
        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];
 };
 
        const char *pattern;
        int flags[Trace_Type_Count];
 };
 
-
 static void addhook(struct desc *desc, enum trace_type type)
 {
        struct hook *hook;
 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;
                        }
                }
                                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;
                                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);
                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 */
        }
 
        /* 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);
 }
 
        trace_attach_hook(trace, hook, type);
 }
 
@@ -1336,6 +1453,11 @@ static void addhooks(struct desc *desc)
 {
        int i;
 
 {
        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);
        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);
 }
 
        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)
 }
 
 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;
 {
        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);
 
        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,
                        "name", &desc.name,
                        "tag", &desc.tag,
-                       "api", &desc.api,
-                       "verb", &desc.verb,
+                       "apiname", &desc.apiname,
+                       "verbname", &desc.verbname,
                        "uuid", &desc.uuid,
                        "pattern", &desc.pattern,
                        "uuid", &desc.uuid,
                        "pattern", &desc.pattern,
+                       "api", &api,
                        "request", &request,
                        "request", &request,
+#if !defined(REMOVE_LEGACY_TRACE)
                        "daemon", &daemon,
                        "service", &service,
                        "daemon", &daemon,
                        "service", &service,
+#endif
                        "event", &event,
                        "session", &session,
                        "global", &global,
                        "event", &event,
                        "session", &session,
                        "global", &global,
@@ -1420,11 +1558,11 @@ static void add(void *closure, struct json_object *object)
 
        if (!rc) {
                /* replace stars */
 
        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;
 
                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 (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)
                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)
 
                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);
 
                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 */
 }
 
 /* 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;
 {
        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 */
 }
 
 /* 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;
 {
        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 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);
 
 /* 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
 
 /* 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);
        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;
        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);
 }
 
        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 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");
 }
        if (rc)
                ERROR("Can't send reply: %m");
 }
index 582e9b7..8f246b3 100644 (file)
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <stdarg.h>
 
 #include <json-c/json.h>
 
 #include <json-c/json.h>
+
 #include <afb/afb-binding-v1.h>
 #include <afb/afb-binding-v2.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-context.h"
-#include "afb-xreq.h"
 #include "afb-evt.h"
 #include "afb-evt.h"
-#include "afb-msg-json.h"
 #include "afb-cred.h"
 #include "afb-hook.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"
 
 #include "jobs.h"
 #include "verbose.h"
 
@@ -45,7 +49,7 @@
 static void xreq_finalize(struct afb_xreq *xreq)
 {
        if (!xreq->replied)
 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)
        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;
 }
 
        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;
 
        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;
 }
 
        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->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);
 }
 
        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);
 }
 
        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;
 }
 
        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);
 }
 
        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);
 }
 
        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);
 }
 
        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)
 {
        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)
        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;
 }
 
        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)
 {
        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)
        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;
 }
 
        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;
 {
        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 {
 
        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);
        }
 }
 
                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;
 }
 
 {
        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);
 }
 
        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;
 }
 
        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);
 }
 
        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;
 }
 
        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 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);
 }
 
        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_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);
 }
 
        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);
 }
 
        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);
 }
 
        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);
 }
 
        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);
 {
        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);
 }
 
        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);
        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);
 }
 
        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;
 }
 
        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);
 }
 
        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);
 }
 
        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);
 }
 
        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);
 }
 
        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,
        .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,
        .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,
        .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,
        .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,
        .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,
        .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,
        .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,
        .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,
        .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,
        .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)
 {
        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)
 {
 }
 
 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);
 {
        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);
 }
 
        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)
 {
 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);
        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)
 {
 
 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)
 {
 }
 
 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;
 
 }
 
 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);
                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;
                }
        }
 
                        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)) {
                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;
                }
        }
 
                        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)) {
                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;
                }
        }
 
                        errno = EPERM;
                        return -1;
                }
        }
 
-       if ((sessionflags & AFB_SESSION_RENEW_V1) != 0) {
+       if ((sessionflags & AFB_SESSION_RENEW_X1) != 0) {
                afb_context_refresh(&xreq->context);
        }
                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);
        }
                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);
        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;
                }
        }
 
                        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)) {
        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)) {
                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;
        }
 
                errno = EPERM;
                return -1;
        }
 
-       if ((sessionflags & AFB_SESSION_REFRESH_V2) != 0) {
+       if ((sessionflags & AFB_SESSION_REFRESH_X2) != 0) {
                afb_context_refresh(&xreq->context);
        }
                afb_context_refresh(&xreq->context);
        }
-       if ((sessionflags & AFB_SESSION_CLOSE_V2) != 0) {
+       if ((sessionflags & AFB_SESSION_CLOSE_X2) != 0) {
                afb_context_close(&xreq->context);
        }
 
                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)
 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))
        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)
 }
 
 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))
        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)
 {
        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)
        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);
 }
 
 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;
 }
 
        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);
 }
 
 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);
                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;
 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) */
 
        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);
        } 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 */
                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);
 
        /* 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);
 }
 
        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)
 {
  */
 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;
        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)
        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
                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;
                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 (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 */
                                /* 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;
                                goto end;
                        }
                        caller = caller->caller;
@@ -1162,3 +932,8 @@ end:
        afb_xreq_unhooked_unref(xreq);
 }
 
        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
 
 
 #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;
 #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_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_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);
 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);
        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_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) */
        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 */
 #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 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 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 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,
                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);
                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,
                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);
 
                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);
                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,
                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_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;
 }
 
 {
        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:
        while ((optc = getopt_long(argc, argv, shortopts, gnuOptions, NULL)) != EOF) {
                switch (optc) {
                case SET_VERBOSE:
-                       verbosity++;
+                       verbose_inc();
                        break;
 
                case SET_QUIET:
                        break;
 
                case SET_QUIET:
-                       verbosity--;
+                       verbose_dec();
                        break;
 
                case SET_TCP_PORT:
                        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);
        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;
 }
                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 */
 };
 
        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"
 #define AFS_SUPERVISOR_APINAME       "supervisor"
index 285d82c..6bd1fc6 100644 (file)
 #include <sys/un.h>
 
 #include <json-c/json.h>
 #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-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"
 
 #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;
 
 /* 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.
  */
  * 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;
        ps = &superviseds;
        while ((s = *ps) && s->stub != stub)
                ps = &s->next;
-       if (s) {
+       if (s)
                *ps = s->next;
                *ps = s->next;
-               afb_stub_ws_unref(stub);
-       }
        pthread_mutex_unlock(&mutex);
        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);
                        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;
                                        return;
+                               }
                        }
                }
                afb_cred_unref(cred);
                        }
                }
                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;
 {
        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);
 }
 
        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);
 }
 
 {
        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_xreq *xreq;
        struct json_object *args, *item;
        struct supervised *s;
-       struct afb_api api;
+       struct afb_api_item api;
        int p;
 
        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)) {
        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) {
                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) {
                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)
                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);
 }
 
        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);
 }
 
 {
        propagate(req, NULL);
 }
 
-static void f_config(struct afb_req req)
+static void f_config(afb_req_t req)
 {
        propagate(req, NULL);
 }
 
 {
        propagate(req, NULL);
 }
 
-static void f_trace(struct afb_req req)
+static void f_trace(afb_req_t req)
 {
        propagate(req, NULL);
 }
 
 {
        propagate(req, NULL);
 }
 
-static void f_sessions(struct afb_req req)
+static void f_sessions(afb_req_t req)
 {
        propagate(req, "slist");
 }
 
 {
        propagate(req, "slist");
 }
 
-static void f_session_close(struct afb_req req)
+static void f_session_close(afb_req_t req)
 {
        propagate(req, "sclose");
 }
 
 {
        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);
 }
 
 {
        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);
 }
 
 {
        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);
 {
        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
  */
 /**
  * initialize the supervisor
  */
-static int init_supervisor()
+static int init_supervisor(afb_api_t api)
 {
        int rc, fd;
 
 {
        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) {
        /* 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,
     {
         .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,
     },
     {
         .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,
     },
     {
         .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,
     },
     {
         .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,
     },
     {
         .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,
     },
     {
         .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,
     },
     {
         .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,
     },
     {
         .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,
     },
     {
         .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,
     },
     {
         .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 }
 };
 
     },
     { .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,
     .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
 };
 
     .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_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
  */
 /**
  * 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;
 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;
 
 /**
 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)
 {
  */
 struct json_object *search(const char *path)
 {
@@ -170,6 +171,7 @@ struct json_object *expand_$ref(struct path path)
        return path.object;
 }
 
        return path.object;
 }
 
+/* create c name by replacing non alpha numeric characters with underscores */
 char *cify(const char *str)
 {
        char *r = strdup(str);
 char *cify(const char *str)
 {
        char *r = strdup(str);
@@ -182,6 +184,7 @@ char *cify(const char *str)
        return r;
 }
 
        return r;
 }
 
+/* format the specification as a C string */
 char *make_info(const char *text, int split)
 {
        const char *a, *b;
 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;
 }
 
        return desc;
 }
 
+/* make the description of the object */
 char *make_desc(struct json_object *o)
 {
 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;
 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;
 }
 
        return NULL;
 }
 
+/* output the array of permissions */
 void print_perms()
 {
        int i, n;
 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) {
 
        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)));
                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;
 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)) {
 
        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();
                }
 
                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);
                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 };
 
 
 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;
 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;
 }
 
        return x;
 }
 
+/* declare the permission for obj */
 struct json_object *decl_perm(struct json_object *obj)
 {
        char *a;
 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)) {
        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);
        }
                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);
        }
        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);
        }
                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) {
        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)
                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) {
        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) {
                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) {
                c = 0;
        }
        if (s & SESSION_RENEW) {
-               printf("%s", "|AFB_SESSION_REFRESH_V2" + c);
+               printf("%s", "|AFB_SESSION_REFRESH" + c);
                c = 0;
        }
        if (c)
                c = 0;
        }
        if (c)
-               printf("AFB_SESSION_NONE_V2");
+               printf("AFB_SESSION_NONE");
 }
 
 void print_verb(const char *name)
 }
 
 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("%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)
 }
 
 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);
                , info ? make_info(info, 0) : "NULL"
        );
        print_session(p);
+       if (version == 3)
+               printf(
+                       ",\n"
+                       "        .vcbdata = NULL,\n"
+                       "        .glob = 0"
+               );
        printf(
                "\n"
                "    },\n"
        printf(
                "\n"
                "    },\n"
@@ -646,7 +676,7 @@ void process(char *filename)
        /* get the API name */
        printf(
                "\n"
        /* get the API name */
        printf(
                "\n"
-               "static const char _afb_description_v2_%s[] =\n"
+               "static const char _afb_description_%s[] =\n"
                "%s"
                ";\n"
                "\n"
                "%s"
                ";\n"
                "\n"
@@ -657,8 +687,8 @@ void process(char *filename)
        enum_verbs(print_declare_verb);
        printf(
                "\n"
        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(
        );
        enum_verbs(print_struct_verb);
        printf(
@@ -667,25 +697,36 @@ void process(char *filename)
                "        .callback = NULL,\n"
                "        .auth = NULL,\n"
                "        .info = NULL,\n"
                "        .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"
                "       }\n"
                "};\n"
        );
        printf(
                "\n"
-               "%sconst struct afb_binding_v2 %s%s = {\n"
+               "%sconst struct afb_binding_v%d %s%s = {\n"
                "    .api = \"%s\",\n"
                "    .api = \"%s\",\n"
-               "    .specification = _afb_description_v2_%s,\n"
+               "    .specification = _afb_description_%s,\n"
                "    .info = %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"
                "    .preinit = %s,\n"
                "    .init = %s,\n"
                "    .onevent = %s,\n"
+               "%s"
                "    .noconcurrency = %d\n"
                "};\n"
                "\n"
                , priv ? "static " : ""
                "    .noconcurrency = %d\n"
                "};\n"
                "\n"
                , priv ? "static " : ""
-               , priv ? "_afb_binding_v2_" : "afbBindingV2"
+               , version
+               , priv ? "_afb_binding_" : version==3 ? "afbBindingV3" : "afbBindingV2"
                , priv ? capi : ""
                , api
                , capi
                , priv ? capi : ""
                , api
                , capi
@@ -694,6 +735,7 @@ void process(char *filename)
                , preinit ?: "NULL"
                , init ?: "NULL"
                , onevent ?: "NULL"
                , preinit ?: "NULL"
                , init ?: "NULL"
                , onevent ?: "NULL"
+               , version==3 ? "    .userdata = NULL,\n" : ""
                , !!noconc
        );
 
                , !!noconc
        );
 
@@ -705,11 +747,25 @@ void process(char *filename)
 /** process the list of files or stdin if none */
 int main(int ac, char **av)
 {
 /** process the list of files or stdin if none */
 int main(int ac, char **av)
 {
+       int r, w;
        av++;
        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 {
        if (!*av)
                process("-");
        else {
@@ -718,7 +774,3 @@ int main(int ac, char **av)
        return 0;
 }
 
        return 0;
 }
 
-
-
-
-
index 3c8867c..ca4a9b3 100644 (file)
           "end",
           "event",
           "extra",
           "end",
           "event",
           "extra",
-          "fail",
           "get",
           "json",
           "life",
           "ref",
           "get",
           "json",
           "life",
           "ref",
+         "reply",
           "result",
           "session",
           "session_close",
           "result",
           "session",
           "session_close",
           "subcallsync",
           "subcallsync_result",
           "subscribe",
           "subcallsync",
           "subcallsync_result",
           "subscribe",
-          "success",
           "unref",
           "unstore",
           "unsubscribe",
           "unref",
           "unstore",
           "unsubscribe",
   "paths": {
     "/get": {
       "description": "Get monitoring data.",
   "paths": {
     "/get": {
       "description": "Get monitoring data.",
+      "x-permissions": { "session": "check" },
       "get": {
       "get": {
-        "x-permissions": { "session": "check" },
         "parameters": [
           {
             "in": "query",
         "parameters": [
           {
             "in": "query",
     },
     "/set": {
       "description": "Set monitoring actions.",
     },
     "/set": {
       "description": "Set monitoring actions.",
+      "x-permissions": { "session": "check" },
       "get": {
       "get": {
-        "x-permissions": { "session": "check" },
         "parameters": [
           {
             "in": "query",
         "parameters": [
           {
             "in": "query",
     },
     "/trace": {
       "description": "Set monitoring actions.",
     },
     "/trace": {
       "description": "Set monitoring actions.",
+      "x-permissions": { "session": "check" },
       "get": {
       "get": {
-        "x-permissions": { "session": "check" },
         "parameters": [
           {
             "in": "query",
         "parameters": [
           {
             "in": "query",
     },
     "/session": {
       "description": "describes the session.",
     },
     "/session": {
       "description": "describes the session.",
+      "x-permissions": { "session": "check" },
       "get": {
       "get": {
-        "x-permissions": { "session": "check" },
         "parameters": [
           {
             "in": "query",
         "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;
        else
                first = j;
        last = j;
-       pthread_mutex_unlock(&mutex);   
+       pthread_mutex_unlock(&mutex);
        return 0;
 }
 
        return 0;
 }
 
@@ -83,7 +83,7 @@ static void *thrrun(void *arg)
        j = first;
        if (j)
                first = j->next;
        j = first;
        if (j)
                first = j->next;
-       pthread_mutex_unlock(&mutex);   
+       pthread_mutex_unlock(&mutex);
        if (j) {
                j->callback(0, j->closure);
                free(j);
        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);
        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;
 }
        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_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_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);
 
 
 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 = {
 
 /* 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_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 */
 };
 
 /* 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);
        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);
 }
 
        exit(status);
 }
@@ -233,7 +229,7 @@ static void on_wsj1_call(void *closure, const char *api, const char *verb, struc
 {
        int rc;
        if (raw)
 {
        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),
        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)
 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),
        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)
 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",
        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;
 }
 
        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)
        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();
        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)
 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);
        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)
 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);
 }
 
        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)
 {
 /* 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);
        }
                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?:"");
        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-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"
 #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)
 {
 
 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,
 }
 
 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) {
 {
        list = run_for_list(list, run_start, starter);
        if (list) {
@@ -263,17 +265,17 @@ static struct afb_hsrv *start_http_server()
                return NULL;
        }
 
                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;
        }
 
            || !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);
        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 */
                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)) {
        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;
 };
 
        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);
 
 {
        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);
        }
 }
                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.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);
                        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 */
        }
 
        /* 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;
        }
                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 (!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;
        }
                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);
        /* 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)
        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->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");
 
 #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");
 
        /* 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;
                }
 
                        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;
                }
                        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 */
        }
 
        /* 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;
        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) {
 
        /* 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;
                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"
     "{\"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.",
     {
         .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.",
     },
     {
         .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.",
     },
     {
         .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.",
     },
     {
         .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,
     },
     {
         .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",
     .api = "monitor",
-    .specification = _afb_description_v2_monitor,
+    .specification = _afb_description_monitor,
     .info = "monitoring of bindings and internals",
     .info = "monitoring of bindings and internals",
-    .verbs = _afb_verbs_v2_monitor,
+    .verbs = _afb_verbs_monitor,
     .preinit = NULL,
     .init = NULL,
     .onevent = NULL,
     .preinit = NULL,
     .init = NULL,
     .onevent = NULL,
+    .userdata = NULL,
     .noconcurrency = 0
 };
 
     .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)
        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)
 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));
        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));
        /* 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"
 
 
 #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
 
 #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);
 
 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)
 
 
 #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 {
        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);
        }
 }
                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];
 
        int saverr, n, rc;
        struct iovec iov[20];
 
+       /* save errno */
        saverr = errno;
 
        saverr = errno;
 
+       /* check if tty (2) or not (1) */
        if (!tty)
                tty = 1 + isatty(STDERR_FILENO);
 
        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[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;
 
        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 (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)) {
                        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;
                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*)file;
                iov[n++].iov_len = strlen(file);
+               /* ":" */
                iov[n].iov_base = (void*)&chars[2];
                iov[n++].iov_len = 1;
                if (line) {
                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 = 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[1];
                        iov[n++].iov_len = 1;
                }
+               /* "," */
                iov[n].iov_base = (void*)&chars[5];
                iov[n++].iov_len = 1;
                if (function) {
                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*)function;
                        iov[n++].iov_len = strlen(function);
                } else {
+                       /* "?" */
                        iov[n].iov_base = (void*)&chars[1];
                        iov[n++].iov_len = 1;
                }
                        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_len = 1;
        }
        if (n == 2) {
+               /* "?" */
                iov[n].iov_base = (void*)&chars[1];
                iov[n++].iov_len = 1;
        }
                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;
 
        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);
 
        pthread_mutex_lock(&mutex);
        writev(STDERR_FILENO, iov, n);
        pthread_mutex_unlock(&mutex);
 
+       /* restore errno */
        errno = saverr;
 }
 
        errno = saverr;
 }
 
@@ -187,15 +234,6 @@ void verbose_set_name(const char *name, int authority)
 
 #endif
 
 
 #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;
 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
 
          3         : ERROR, WARNING, NOTICE, INFO
     greater than 3 : ERROR, WARNING, NOTICE, INFO, DEBUG
 
-*/
 extern int verbosity;
 
 enum verbosity_levels
 extern int verbosity;
 
 enum verbosity_levels
@@ -43,6 +42,7 @@ enum verbosity_levels
        Verbosity_Level_Info = 3,
        Verbosity_Level_Debug = 4
 };
        Verbosity_Level_Info = 3,
        Verbosity_Level_Debug = 4
 };
+*/
 
 extern void verbose_set_name(const char *name, int authority);
 
 
 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
 */
 
        KERN_DEBUG             7        Debug-level messages
 */
 
-enum log_levels
+enum
 {
        Log_Level_Emergency = 0,
        Log_Level_Alert = 1,
 {
        Log_Level_Emergency = 0,
        Log_Level_Alert = 1,
@@ -70,27 +70,53 @@ enum log_levels
        Log_Level_Debug = 7
 };
 
        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)
 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
 
 #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);
 
 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 <string.h>
+#include <limits.h>
 
 #include "wrap-json.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;
        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;
 
        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;
                                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;
                                }
                                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;
                                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;
                                }
                        }
                        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)
 {
 
 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)
        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)
 }
 
 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 {
        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)
                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>
 
 #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;
 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));
                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);
 }
 
        json_object_put(result);
 }
 
@@ -945,7 +1293,7 @@ void u(const char *value, const char *desc, ...)
        unsigned m, k;
        int rc;
        va_list args;
        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);
 
        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);
        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);
        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));
        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");
        }
                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)
 }
 
 #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]);
        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;
 }
 
        return 0;
 }
 
index 56f9919..d75ebc4 100644 (file)
 
 #pragma once
 
 
 #pragma once
 
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
 #include <stdarg.h>
 #include <json-c/json.h>
 
 #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 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 = ({
        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; },
                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);
        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>
+