diff options
155 files changed, 19209 insertions, 6811 deletions
@@ -17,3 +17,5 @@ node_modules/ _book/ *.kdev4 nbproject/* +docs/binding +docs/binder diff --git a/CMakeLists.txt b/CMakeLists.txt index cda81908..2213f05d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ PROJECT(afb-daemon C CXX) SET(PROJECT_NAME "AFB Daemon") SET(PROJECT_PRETTY_NAME "Application Framework Binder Daemon") SET(PROJECT_DESCRIPTION "Secured binder of API for clients of the Application framework") -SET(PROJECT_VERSION "5.99-FFRC0") +SET(PROJECT_VERSION "5.99-FFRC1") set(PROJECT_URL "https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=summary") SET(LIBAFBWSC_VERSION "1.1") @@ -37,10 +37,13 @@ INCLUDE(CTest) ########################################################################### # possible settings + set(AGL_DEVEL OFF CACHE BOOL "Activates developping features") set(INCLUDE_MONITORING OFF CACHE BOOL "Activates installation of monitoring") set(INCLUDE_SUPERVISOR OFF CACHE BOOL "Activates installation of supervisor") set(INCLUDE_DBUS_TRANSPARENCY OFF CACHE BOOL "Allows API transparency over DBUS") +set(INCLUDE_LEGACY_BINDING_V1 OFF CACHE BOOL "Includes the legacy Binding API version 1") +set(INCLUDE_LEGACY_BINDING_VDYN OFF CACHE BOOL "Includes the legacy Binding API version dynamic") set(AFS_SUPERVISION_SOCKET "@urn:AGL:afs:supervision:socket" CACHE STRING "Internal socket for supervision") set(AFS_SUPERVISOR_PORT 1619 CACHE STRING "Port of service for the supervisor") set(AFS_SUPERVISOR_TOKEN HELLO CACHE STRING "Secret token for the supervisor") @@ -1,93 +1,154 @@ -### Application Framework Binder -This is an undergoing work, publication is only intended for developers to review and provide feedback. +# AGL Framework Binder -### License -Apache 2 +This project provides the binder component of the the microservice architecture +of Automotive Grade Linux (AGL). + +This project is available there https://git.automotivelinux.org/src/app-framework-binder/ + +It can be cloned with **git clone https://git.automotivelinux.org/src/app-framework-binder**. + + +## License and copying + +This software is an open source software funded by LinuxFoundation and Renesas. + +This software is delivered under the terms of the open source license Apache 2. + +This license is available in the file LICENSE-2.0.txt or on the worl wide web at the +location https://opensource.org/licenses/Apache-2.0 + + +## Building + +### Requirements + +Building the AGL framework binder has been tested under + **Ubuntu**, **Debian** and **Fedora 26** with gcc 6 and 7. + +It requires the following libraries: -### Building -Building Application Framework Binder has been tested under **Ubuntu 16.04 LTS (Xenial Xerus)** or **Fedora 23**, and requires the following libraries: * libmagic ("libmagic-dev" under Ubuntu, "file-devel" under Fedora); - * libmicrohttpd >= 0.9.48 (fetch and build from "http://ftp.gnu.org/gnu/libmicrohttpd"); + * libmicrohttpd >= 0.9.55 (fetch and build from "http://ftp.gnu.org/gnu/libmicrohttpd"); * json-c ("libjson-c-dev/devel"); * uuid ("uuid-dev/libuuid-devel"); * openssl ("libssl-dev/openssl-devel"); * systemd >= 222 ("libsystemd-dev/systemd-devel"); -Optionally, for plugins : - * alsa ("libasound2-dev/alsa-devel"); - * pulseaudio ("libpulse-dev/libpulse-devel"); - * rtl-sdr >= 0.5.0 ("librtlsdr-dev", or fetch and build from "git://git.osmocom.org/rtl-sdr" under Fedora); - * GUPnP ("libglib2.0-dev libgupnp-av-1.0-dev/glib2-devel libgupnp-av-devel"); +The following library can be used for checking permissions: -Libmicrohttpd : - * version >= 0.9.54 + * cynara (https://github.com/Samsung/cynara) and the following tools: + * gcc; - * make; * pkg-config; - * cmake >= 2.8.8. + * cmake >= 3.0 To install all dependencies under Ubuntu (excepting libmicrohttpd), please type: -``` -$ apt-get install libmagic-dev libjson-c-dev uuid-dev libsystemd-dev libssl-dev libasound2-dev libpulse-dev librtlsdr-dev libglib2.0-dev libgupnp-av-1.0-dev gcc make pkg-config cmake -``` + + $ apt-get install libmagic-dev libjson-c-dev uuid-dev libsystemd-dev libssl-dev gcc make pkg-config cmake + or under Fedora (excepting libmicrohttpd and rtl-sdr): -``` -$ dnf install git passwd iproute openssh-server openssh-client openssh-server # Tools needed on top of Docker Minimal Fedora -$ dnf install file-devel gcc gdb make pkgconfig cmake # install gcc development tool chain + cmake -$ dnf install file-devel json-c-devel libuuid-devel systemd-devel openssl-devel -$ dnf install alsa-lib-devel pulseaudio-libs-devel glib2-devel gupnp-av-devel # optional but require to build audio plugin -``` - To build, move to your HOME directory and type: -``` -$ LIB_MH_VERSION=0.9.54 -$ export LIBMICRODEST=/opt/libmicrohttpd-${LIB_MH_VERSION} -$ wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-${LIB_MH_VERSION}.tar.gz -$ tar -xzf libmicrohttpd-${LIB_MH_VERSION}.tar.gz -$ cd libmicrohttpd-${LIB_MH_VERSION} -$ ./configure --prefix=${LIBMICRODEST} -$ make -$ sudo make install-strip - -$ AFB_DAEMON_DIR=$HOME/app-framework-binder -$ git clone https://gerrit.automotivelinux.org/gerrit/src/app-framework-binder ${AFB_DAEMON_DIR} -$ cd ${AFB_DAEMON_DIR} -$ mkdir -p build; cd build<br /> -$ export PKG_CONFIG_PATH=${LIBMICRODEST}/lib/pkgconfig -$ cmake ..<br /> -$ make; -$ sudo make install<br /> -``` + $ dnf install git passwd iproute openssh-server openssh-client + $ dnf install file-devel gcc gdb make pkgconfig cmake + $ dnf install json-c-devel libuuid-devel systemd-devel openssl-devel + +### Simple compilation + +The following commands will install the binder in your subdirectory +**$HOME/local** (instead of **/usr/local** the default when +*CMAKE_INSTALL_PREFIX* isn't set). + + $ git clone https://git.automotivelinux.org/src/app-framework-binder + $ cd app-framework-binder + $ mkdir build + $ cd build + $ cmake -DCMAKE_INSTALL_PREFIX=$HOME/local .. + $ make install + +### Advanced compilation + +You can tune options when calling cmake. Here are the known options with +their default values. + + $ git clone https://git.automotivelinux.org/src/app-framework-binder + $ cd app-framework-binder + $ mkdir build + $ cd build + $ cmake \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ + -DAGL_DEVEL=OFF \ + -DINCLUDE_MONITORING=OFF \ + -DINCLUDE_SUPERVISOR=OFF \ + -DINCLUDE_DBUS_TRANSPARENCY=OFF \ + -DINCLUDE_LEGACY_BINDING_V1=OFF \ + -DINCLUDE_LEGACY_BINDING_VDYN=OFF \ + -DAFS_SUPERVISOR_PORT=1619 \ + -DAFS_SUPERVISOR_TOKEN="HELLO" \ + -DAFS_SUPERVISION_SOCKET="@urn:AGL:afs:supervision:socket" \ + -DUNITDIR_SYSTEM=${CMAKE_INSTALL_LIBDIR}/systemd/system \ + .. + $ make install + +The configuration options are: + +| Variable | Type | Feature +|:----------------------------|:-------:|:------------------------------ +| AGL_DEVEL | BOOLEAN | Activates development features +| INCLUDE_MONITORING | BOOLEAN | Activates installation of monitoring +| INCLUDE_SUPERVISOR | BOOLEAN | Activates installation of supervisor +| INCLUDE_DBUS_TRANSPARENCY | BOOLEAN | Allows API transparency over DBUS +| INCLUDE_LEGACY_BINDING_V1 | BOOLEAN | Includes the legacy Binding API version 1 +| INCLUDE_LEGACY_BINDING_VDYN | BOOLEAN | Includes the legacy Binding API version dynamic +| AFS_SUPERVISOR_PORT | INTEGER | Port of service for the supervisor +| AFS_SUPERVISOR_TOKEN | STRING | Secret token for the supervisor +| AFS_SUPERVISION_SOCKET | STRING | Internal socket path for supervision (internal if starts with @) +| UNITDIR_SYSTEM | STRING | Path to systemd system unit files for installing supervisor + + + + +***** TO BE COMPLETED ***** + + + + + + + + + + + + +## Simple demo + -### Archive -``` -VERSION=2.0 -GIT_TAG=master -PKG_NAME=app-framework-binder -git archive --format=tar.gz --prefix=agl-${PKG_NAME}-${VERSION}/ ${GIT_TAG} -o agl-${PKG_NAME}_${VERSION}.orig.tar.gz -``` ### Testing/Debug + ``` $ ${AFB_DAEMON_DIR}/build/src/afb-daemon --help $ ${AFB_DAEMON_DIR}/build/src/afb-daemon --port=1234 --token='' --ldpaths=${AFB_DAEMON_DIR}/build --sessiondir=/tmp --rootdir=${AFB_DAEMON_DIR}/test ``` ### Starting + ``` $ afb-daemon --help $ afb-daemon --verbose --port=<port> --token='' --sessiondir=<working directory> --rootdir=<web directory (index.html)> ``` ### Example + ``` $ afb-daemon --verbose --port=1234 --token='' --sessiondir=/tmp --rootdir=/srv/www/htdocs --alias=icons:/usr/share/icons ``` ### Directories & Paths + Default behaviour is to locate ROOTDIR in $HOME/.AFB ### REST API @@ -136,4 +197,3 @@ Only use alias for external support static files. This should not be used for AP ### Ongoing work Javascript plugins. As of today, only C plugins are supported, but JS plugins are on the TODO list. - diff --git a/bindings/intrinsics/afb-dbus-binding.c b/bindings/intrinsics/afb-dbus-binding.c index a5b7d788..51474f6b 100644 --- a/bindings/intrinsics/afb-dbus-binding.c +++ b/bindings/intrinsics/afb-dbus-binding.c @@ -23,15 +23,10 @@ #include <systemd/sd-bus.h> #include <systemd/sd-bus-protocol.h> -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> /* - * the interface to afb-daemon - */ -const struct afb_binding_interface *afbitf; - -/* * union of possible dbus values */ union any { @@ -497,7 +492,7 @@ error: /* * handle the reply */ -static int on_rawcall_reply(sd_bus_message *msg, struct afb_req *req, sd_bus_error *ret_error) +static int on_rawcall_reply(sd_bus_message *msg, afb_req_t *req, sd_bus_error *ret_error) { struct json_object *obj = NULL; int rc; @@ -532,7 +527,7 @@ static int on_rawcall_reply(sd_bus_message *msg, struct afb_req *req, sd_bus_err * "arguments": "ARRAY of arguments" * } */ -static void rawcall(struct afb_req req) +static void rawcall(afb_req_t req) { struct json_object *obj; struct json_object *args; @@ -569,9 +564,9 @@ static void rawcall(struct afb_req req) /* get bus */ busname = strval(obj, "bus"); if (busname != NULL && !strcmp(busname, "system")) - bus = afb_daemon_get_system_bus(afbitf->daemon); + bus = afb_api_get_system_bus(req->api); else - bus = afb_daemon_get_user_bus(afbitf->daemon); + bus = afb_api_get_user_bus(req->api); /* creates the message */ rc = sd_bus_message_new_method_call(bus, &msg, destination, path, interface, member); @@ -601,32 +596,19 @@ cleanup: /* * array of the verbs exported to afb-daemon */ -static const struct afb_verb_desc_v1 binding_verbs[] = { +static const struct afb_verb_v3 binding_verbs[] = { /* VERB'S NAME SESSION MANAGEMENT FUNCTION TO CALL SHORT DESCRIPTION */ - { .name= "rawcall", .session= AFB_SESSION_NONE, .callback= rawcall, .info= "raw call to dbus method" }, - { .name= NULL } /* marker for end of the array */ + { .verb= "rawcall", .session= AFB_SESSION_NONE, .callback= rawcall, .info= "raw call to dbus method" }, + { .verb= NULL } /* marker for end of the array */ }; /* * description of the binding for afb-daemon */ -static const struct afb_binding binding_description = +const struct afb_binding_v3 afbBindingV3 = { - /* description conforms to VERSION 1 */ - .type= AFB_BINDING_VERSION_1, - .v1= { /* fills the v1 field of the union when AFB_BINDING_VERSION_1 */ - .prefix= "dbus", /* the API name (or binding name or prefix) */ - .info= "raw dbus binding", /* short description of of the binding */ + .api = "dbus", /* the API name (or binding name or prefix) */ + .info = "raw dbus binding", /* short description of of the binding */ .verbs = binding_verbs /* the array describing the verbs of the API */ - } }; -/* - * activation function for registering the binding called by afb-daemon - */ -const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf) -{ - afbitf = itf; /* records the interface for accessing afb-daemon */ - return &binding_description; /* returns the description of the binding */ -} - diff --git a/bindings/samples/AuthLogin.c b/bindings/samples/AuthLogin.c index a71f7d6e..0f29dd0d 100644 --- a/bindings/samples/AuthLogin.c +++ b/bindings/samples/AuthLogin.c @@ -19,7 +19,7 @@ #include <stdio.h> #include <json-c/json.h> -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> // Dummy sample of Client Application Context @@ -37,7 +37,7 @@ static void clientContextFree(void *context) { } // Request Creation of new context if it does not exist -static void clientContextConnect (struct afb_req request) +static void clientContextConnect (afb_req_t request) { json_object *jresp; @@ -56,7 +56,7 @@ static void clientContextConnect (struct afb_req request) } // Before entering here token will be check and renew -static void clientContextRefresh (struct afb_req request) { +static void clientContextRefresh (afb_req_t request) { json_object *jresp; @@ -68,7 +68,7 @@ static void clientContextRefresh (struct afb_req request) { // Session token will we verified before entering here -static void clientContextCheck (struct afb_req request) { +static void clientContextCheck (afb_req_t request) { json_object *jresp = json_object_new_object(); json_object_object_add(jresp, "isvalid", json_object_new_boolean (TRUE)); @@ -78,7 +78,7 @@ static void clientContextCheck (struct afb_req request) { // Close and Free context -static void clientContextLogout (struct afb_req request) { +static void clientContextLogout (afb_req_t request) { json_object *jresp; /* after this call token will be reset @@ -95,7 +95,7 @@ static void clientContextLogout (struct afb_req request) { afb_req_session_set_LOA(request, 0); } // Close and Free context -static void clientGetPing (struct afb_req request) { +static void clientGetPing (afb_req_t request) { static int count=0; json_object *jresp; @@ -106,25 +106,18 @@ static void clientGetPing (struct afb_req request) { } -static const struct afb_verb_desc_v1 verbs[]= { - {"ping" , AFB_SESSION_NONE , clientGetPing ,"Ping Rest Test Service"}, - {"connect" , AFB_SESSION_LOA_EQ_0 | AFB_SESSION_RENEW, clientContextConnect,"Connect/Login Client"}, - {"refresh" , AFB_SESSION_LOA_GE_1 | AFB_SESSION_RENEW, clientContextRefresh,"Refresh Client Authentication Token"}, - {"check" , AFB_SESSION_LOA_GE_1 , clientContextCheck ,"Check Client Authentication Token"}, - {"logout" , AFB_SESSION_LOA_GE_1 | AFB_SESSION_CLOSE, clientContextLogout ,"Logout Client and Free resources"}, +static const struct afb_verb_v3 verbs[]= { + {.verb="ping" , .session=AFB_SESSION_NONE , .callback=clientGetPing ,.info="Ping Rest Test Service"}, + {.verb="connect" , .session=AFB_SESSION_LOA_0 | AFB_SESSION_RENEW, .callback=clientContextConnect,.info="Connect/Login Client"}, + {.verb="refresh" , .session=AFB_SESSION_LOA_1 | AFB_SESSION_RENEW, .callback=clientContextRefresh,.info="Refresh Client Authentication Token"}, + {.verb="check" , .session=AFB_SESSION_LOA_1 , .callback=clientContextCheck ,.info="Check Client Authentication Token"}, + {.verb="logout" , .session=AFB_SESSION_LOA_1 | AFB_SESSION_CLOSE, .callback=clientContextLogout ,.info="Logout Client and Free resources"}, {NULL} }; -static const struct afb_binding plugin_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Application Framework Binder Authentication sample", - .prefix = "auth", - .verbs = verbs - } -}; - -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +const struct afb_binding_v3 afbBindingV3 = { - return &plugin_desc; -} + .api = "auth", /* the API name (or binding name or prefix) */ + .info = "Application Framework Binder Authentication sample", /* short description of of the binding */ + .verbs = verbs /* the array describing the verbs of the API */ +}; diff --git a/bindings/samples/CMakeLists.txt b/bindings/samples/CMakeLists.txt index f596c333..d4e85e30 100644 --- a/bindings/samples/CMakeLists.txt +++ b/bindings/samples/CMakeLists.txt @@ -91,3 +91,27 @@ TARGET_LINK_LIBRARIES(tic-tac-toe ${link_libraries}) INSTALL(TARGETS tic-tac-toe LIBRARY DESTINATION ${binding_install_dir}) +################################################## +# hi3 +################################################## +ADD_LIBRARY(hi3 MODULE hi3.c) +SET_TARGET_PROPERTIES(hi3 PROPERTIES + PREFIX "" + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" +) +TARGET_LINK_LIBRARIES(hi3 ${link_libraries}) +INSTALL(TARGETS hi3 + LIBRARY DESTINATION ${binding_install_dir}) + +################################################## +# hello3 +################################################## +ADD_LIBRARY(hello3 MODULE hello3.c) +SET_TARGET_PROPERTIES(hello3 PROPERTIES + PREFIX "" + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" +) +TARGET_LINK_LIBRARIES(hello3 ${link_libraries}) +INSTALL(TARGETS hello3 + LIBRARY DESTINATION ${binding_install_dir}) + diff --git a/bindings/samples/DemoContext.c b/bindings/samples/DemoContext.c index bf35ab17..09f1764e 100644 --- a/bindings/samples/DemoContext.c +++ b/bindings/samples/DemoContext.c @@ -19,7 +19,7 @@ #include <stdio.h> #include <json-c/json.h> -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> typedef struct { @@ -48,7 +48,7 @@ typedef struct { // This function is call at session open time. Any client trying to // call it with an already open session will be denied. // Ex: http://localhost:1234/api/context/create?token=123456789 -static void myCreate (struct afb_req request) +static void myCreate (afb_req_t request) { MyClientContextT *ctx = malloc (sizeof (MyClientContextT)); @@ -64,7 +64,7 @@ static void myCreate (struct afb_req request) // session timeout a standard renew api is avaliable at /api/token/renew this API // can be called automatically with <token-renew> HTML5 widget. // ex: http://localhost:1234/api/context/action?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx -static void myAction (struct afb_req request) +static void myAction (afb_req_t request) { MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request); @@ -81,7 +81,7 @@ static void myAction (struct afb_req request) // created a context [request->context != NULL] every plugins will be notified // that they should free context resources. // ex: http://localhost:1234/api/context/close?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx -static void myClose (struct afb_req request) +static void myClose (afb_req_t request) { MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request); @@ -95,75 +95,44 @@ static void myClose (struct afb_req request) } // Set the LOA -static void setLOA(struct afb_req request, unsigned loa) +static void setLOA(afb_req_t request, unsigned loa) { - if (afb_req_session_set_LOA(request, loa)) + if (afb_req_session_set_LOA(request, loa) >= 0) afb_req_success_f(request, NULL, "loa set to %u", loa); else afb_req_fail_f(request, "failed", "can't set loa to %u", loa); } -static void clientSetLOA0(struct afb_req request) +static void clientSetLOA(afb_req_t request) { - setLOA(request, 0); + setLOA(request, (unsigned)(intptr_t)request->vcbdata); } -static void clientSetLOA1(struct afb_req request) -{ - setLOA(request, 1); -} - -static void clientSetLOA2(struct afb_req request) -{ - setLOA(request, 2); -} - -static void clientSetLOA3(struct afb_req request) -{ - setLOA(request, 3); -} - -static void clientCheckLOA(struct afb_req request) +static void clientCheckLOA(afb_req_t request) { afb_req_success(request, NULL, "LOA checked and okay"); } // NOTE: this sample does not use session to keep test a basic as possible // in real application most APIs should be protected with AFB_SESSION_CHECK -static const struct afb_verb_desc_v1 verbs[]= { - {"create", AFB_SESSION_CREATE, myCreate , "Create a new session"}, - {"action", AFB_SESSION_CHECK , myAction , "Use Session Context"}, - {"close" , AFB_SESSION_CLOSE , myClose , "Free Context"}, - {"set_loa_0", AFB_SESSION_RENEW, clientSetLOA0 ,"Set level of assurance to 0"}, - {"set_loa_1", AFB_SESSION_RENEW, clientSetLOA1 ,"Set level of assurance to 1"}, - {"set_loa_2", AFB_SESSION_RENEW, clientSetLOA2 ,"Set level of assurance to 2"}, - {"set_loa_3", AFB_SESSION_RENEW, clientSetLOA3 ,"Set level of assurance to 3"}, - {"check_loa_ge_0", AFB_SESSION_LOA_GE_0, clientCheckLOA ,"Check whether level of assurance is greater or equal to 0"}, - {"check_loa_ge_1", AFB_SESSION_LOA_GE_1, clientCheckLOA ,"Check whether level of assurance is greater or equal to 1"}, - {"check_loa_ge_2", AFB_SESSION_LOA_GE_2, clientCheckLOA ,"Check whether level of assurance is greater or equal to 2"}, - {"check_loa_ge_3", AFB_SESSION_LOA_GE_3, clientCheckLOA ,"Check whether level of assurance is greater or equal to 3"}, - {"check_loa_le_0", AFB_SESSION_LOA_LE_0, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 0"}, - {"check_loa_le_1", AFB_SESSION_LOA_LE_1, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 1"}, - {"check_loa_le_2", AFB_SESSION_LOA_LE_2, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 2"}, - {"check_loa_le_3", AFB_SESSION_LOA_LE_3, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 3"}, - {"check_loa_eq_0", AFB_SESSION_LOA_EQ_0, clientCheckLOA ,"Check whether level of assurance is equal to 0"}, - {"check_loa_eq_1", AFB_SESSION_LOA_EQ_1, clientCheckLOA ,"Check whether level of assurance is equal to 1"}, - {"check_loa_eq_2", AFB_SESSION_LOA_EQ_2, clientCheckLOA ,"Check whether level of assurance is equal to 2"}, - {"check_loa_eq_3", AFB_SESSION_LOA_EQ_3, clientCheckLOA ,"Check whether level of assurance is equal to 3"}, +static const struct afb_verb_v3 verbs[]= { + {.verb="create", .session=AFB_SESSION_NONE, .callback=myCreate , .info="Create a new session"}, + {.verb="action", .session=AFB_SESSION_CHECK , .callback=myAction , .info="Use Session Context"}, + {.verb="close" , .session=AFB_SESSION_CLOSE , .callback=myClose , .info="Free Context"}, + {.verb="set_loa_0", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)0 ,.info="Set level of assurance to 0"}, + {.verb="set_loa_1", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)1 ,.info="Set level of assurance to 1"}, + {.verb="set_loa_2", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)2 ,.info="Set level of assurance to 2"}, + {.verb="set_loa_3", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)3 ,.info="Set level of assurance to 3"}, + {.verb="check_loa_ge_0", .session=AFB_SESSION_LOA_0, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)0 ,.info="Check whether level of assurance is greater or equal to 0"}, + {.verb="check_loa_ge_1", .session=AFB_SESSION_LOA_1, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)1 ,.info="Check whether level of assurance is greater or equal to 1"}, + {.verb="check_loa_ge_2", .session=AFB_SESSION_LOA_2, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)2 ,.info="Check whether level of assurance is greater or equal to 2"}, + {.verb="check_loa_ge_3", .session=AFB_SESSION_LOA_3, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)3 ,.info="Check whether level of assurance is greater or equal to 3"}, {NULL} }; -static const struct afb_binding plugin_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Sample of Client Context Usage", - .prefix = "context", - .verbs = verbs, - } -}; - -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +const struct afb_binding_v3 afbBindingV3 = { - return &plugin_desc; -} - + .api = "context", /* the API name (or binding name or prefix) */ + .info = "Sample of Client Context Usage", /* short description of of the binding */ + .verbs = verbs /* the array describing the verbs of the API */ +}; diff --git a/bindings/samples/DemoPost.c b/bindings/samples/DemoPost.c index d92d502f..3fd6f983 100644 --- a/bindings/samples/DemoPost.c +++ b/bindings/samples/DemoPost.c @@ -20,12 +20,12 @@ #include <string.h> #include <json-c/json.h> -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> // Sample Generic Ping Debug API -static void getPingTest(struct afb_req request) +static void getPingTest(afb_req_t request) { static int pingcount = 0; json_object *query = afb_req_json(request); @@ -34,7 +34,7 @@ static void getPingTest(struct afb_req request) } // With content-type=json data are directly avaliable in request->post->data -static void GetJsonByPost (struct afb_req request) +static void GetJsonByPost (afb_req_t request) { struct afb_arg arg; json_object* jresp; @@ -46,7 +46,7 @@ static void GetJsonByPost (struct afb_req request) } // Upload a file and execute a function when upload is done -static void Uploads (struct afb_req request, const char *destination) +static void Uploads (afb_req_t request, const char *destination) { struct afb_arg a = afb_req_get(request, "file"); if (a.value == NULL || *a.value == 0) @@ -56,20 +56,20 @@ static void Uploads (struct afb_req request, const char *destination) } // Upload a file and execute a function when upload is done -static void UploadAppli (struct afb_req request) +static void UploadAppli (afb_req_t request) { Uploads(request, "applications"); } // Simples Upload case just upload a file -static void UploadMusic (struct afb_req request) +static void UploadMusic (afb_req_t request) { Uploads(request, "musics"); } // PostForm callback is called multiple times (one or each key within form, or once per file buffer) // When file has been fully uploaded call is call with item==NULL -static void UploadImage (struct afb_req request) +static void UploadImage (afb_req_t request) { Uploads(request, "images"); } @@ -77,25 +77,18 @@ static void UploadImage (struct afb_req request) // NOTE: this sample does not use session to keep test a basic as possible // in real application upload-xxx should be protected with AFB_SESSION_CHECK -static const struct afb_verb_desc_v1 verbs[]= { - {"ping" , AFB_SESSION_NONE , getPingTest ,"Ping Rest Test Service"}, - {"upload-json" , AFB_SESSION_NONE , GetJsonByPost ,"Demo for Json Buffer on Post"}, - {"upload-image" , AFB_SESSION_NONE , UploadImage ,"Demo for file upload"}, - {"upload-music" , AFB_SESSION_NONE , UploadMusic ,"Demo for file upload"}, - {"upload-appli" , AFB_SESSION_NONE , UploadAppli ,"Demo for file upload"}, - {NULL} +static const struct afb_verb_v3 verbs[]= { + {.verb="ping" , .session=AFB_SESSION_NONE , .callback=getPingTest ,.info="Ping Rest Test Service"}, + {.verb="upload-json" , .session=AFB_SESSION_NONE , .callback=GetJsonByPost ,.info="Demo for Json Buffer on Post"}, + {.verb="upload-image" , .session=AFB_SESSION_NONE , .callback=UploadImage ,.info="Demo for file upload"}, + {.verb="upload-music" , .session=AFB_SESSION_NONE , .callback=UploadMusic ,.info="Demo for file upload"}, + {.verb="upload-appli" , .session=AFB_SESSION_NONE , .callback=UploadAppli ,.info="Demo for file upload"}, + {.verb=NULL} }; -static const struct afb_binding plugin_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Sample with Post Upload Files", - .prefix = "post", - .verbs = verbs - } +const struct afb_binding_v3 afbBindingV3 = { + .info = "Sample with Post Upload Files", + .api = "post", + .verbs = verbs }; -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) -{ - return &plugin_desc; -}; diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c index fef87d2d..92d7c4d2 100644 --- a/bindings/samples/HelloWorld.c +++ b/bindings/samples/HelloWorld.c @@ -21,7 +21,7 @@ #include <json-c/json.h> -#define AFB_BINDING_VERSION 2 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; @@ -29,7 +29,7 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; struct event { struct event *next; - struct afb_event event; + afb_event_t event; char tag[1]; }; @@ -80,7 +80,7 @@ static int event_add(const char *tag, const char *name) /* make the event */ e->event = afb_daemon_make_event(name); - if (!e->event.closure) { free(e); return -1; } + if (!e->event) { free(e); return -1; } /* link */ e->next = events; @@ -88,14 +88,14 @@ static int event_add(const char *tag, const char *name) return 0; } -static int event_subscribe(afb_req request, const char *tag) +static int event_subscribe(afb_req_t request, const char *tag) { struct event *e; e = event_get(tag); return e ? afb_req_subscribe(request, e->event) : -1; } -static int event_unsubscribe(afb_req request, const char *tag) +static int event_unsubscribe(afb_req_t request, const char *tag) { struct event *e; e = event_get(tag); @@ -117,34 +117,34 @@ static int event_broadcast(struct json_object *args, const char *tag) } // Sample Generic Ping Debug API -static void ping(afb_req request, json_object *jresp, const char *tag) +static void ping(afb_req_t request, json_object *jresp, const char *tag) { static int pingcount = 0; json_object *query = afb_req_json(request); afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query)); } -static void pingSample (afb_req request) +static void pingSample (afb_req_t request) { ping(request, json_object_new_string ("Some String"), "pingSample"); } -static void pingFail (afb_req request) +static void pingFail (afb_req_t request) { afb_req_fail(request, "failed", "Ping Binder Daemon fails"); } -static void pingNull (afb_req request) +static void pingNull (afb_req_t request) { ping(request, NULL, "pingNull"); } -static void pingBug (afb_req request) +static void pingBug (afb_req_t request) { - ping((afb_req){NULL,NULL}, NULL, "pingBug"); + ping(NULL, NULL, "pingBug"); } -static void pingEvent(afb_req request) +static void pingEvent(afb_req_t request) { json_object *query = afb_req_json(request); afb_daemon_broadcast_event("event", json_object_get(query)); @@ -153,7 +153,7 @@ static void pingEvent(afb_req request) // For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/ -static void pingJson (afb_req request) { +static void pingJson (afb_req_t request) { json_object *jresp, *embed; jresp = json_object_new_object(); @@ -169,38 +169,12 @@ static void pingJson (afb_req request) { ping(request, jresp, "pingJson"); } -static void subcallcb (void *prequest, int status, json_object *object) +static void subcallcb (void *closure, json_object *object, const char *error, const char *info, afb_req_t request) { - afb_req request = afb_req_unstore(prequest); - if (status < 0) - afb_req_fail(request, "failed", json_object_to_json_string(object)); - else - afb_req_success(request, json_object_get(object), NULL); - afb_req_unref(request); -} - -static void subcall (afb_req request) -{ - const char *api = afb_req_value(request, "api"); - const char *verb = afb_req_value(request, "verb"); - const char *args = afb_req_value(request, "args"); - json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; - - if (object == NULL) - afb_req_fail(request, "failed", "bad arguments"); - else - afb_req_subcall(request, api, verb, object, subcallcb, afb_req_store(request)); -} - -static void subcallreqcb (void *prequest, int status, json_object *object, afb_req request) -{ - if (status < 0) - afb_req_fail(request, "failed", json_object_to_json_string(object)); - else - afb_req_success(request, json_object_get(object), NULL); + afb_req_reply(request, json_object_get(object), error, info); } -static void subcallreq (afb_req request) +static void subcall (afb_req_t request) { const char *api = afb_req_value(request, "api"); const char *verb = afb_req_value(request, "verb"); @@ -210,10 +184,10 @@ static void subcallreq (afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); else - afb_req_subcall_req(request, api, verb, object, subcallreqcb, NULL); + afb_req_subcall(request, api, verb, object, afb_req_subcall_pass_events, subcallcb, NULL); } -static void subcallsync (afb_req request) +static void subcallsync (afb_req_t request) { int rc; const char *api = afb_req_value(request, "api"); @@ -224,7 +198,7 @@ static void subcallsync (afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); else { - rc = afb_req_subcall_sync(request, api, verb, object, &result); + rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result); if (rc >= 0) afb_req_success(request, result, NULL); else { @@ -234,7 +208,7 @@ static void subcallsync (afb_req request) } } -static void eventadd (afb_req request) +static void eventadd (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); const char *name = afb_req_value(request, "name"); @@ -249,7 +223,7 @@ static void eventadd (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventdel (afb_req request) +static void eventdel (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); @@ -263,7 +237,7 @@ static void eventdel (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventsub (afb_req request) +static void eventsub (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); @@ -277,7 +251,7 @@ static void eventsub (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventunsub (afb_req request) +static void eventunsub (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); @@ -291,7 +265,7 @@ static void eventunsub (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventpush (afb_req request) +static void eventpush (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); const char *data = afb_req_value(request, "data"); @@ -308,9 +282,9 @@ static void eventpush (afb_req request) json_object_put(object); } -static void callcb (void *prequest, int status, json_object *object) +static void callcb (void *prequest, int status, json_object *object, afb_api_t api) { - afb_req request = afb_req_unstore(prequest); + afb_req_t request = prequest; if (status < 0) afb_req_fail(request, "failed", json_object_to_json_string(object)); else @@ -318,7 +292,7 @@ static void callcb (void *prequest, int status, json_object *object) afb_req_unref(request); } -static void call (afb_req request) +static void call (afb_req_t request) { const char *api = afb_req_value(request, "api"); const char *verb = afb_req_value(request, "verb"); @@ -328,10 +302,10 @@ static void call (afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); else - afb_service_call(api, verb, object, callcb, afb_req_store(request)); + afb_service_call(api, verb, object, callcb, afb_req_addref(request)); } -static void callsync (afb_req request) +static void callsync (afb_req_t request) { int rc; const char *api = afb_req_value(request, "api"); @@ -352,7 +326,7 @@ static void callsync (afb_req request) } } -static void verbose (afb_req request) +static void verbose (afb_req_t request) { int level = 5; json_object *query = afb_req_json(request), *l; @@ -369,7 +343,7 @@ static void verbose (afb_req request) afb_req_success(request, NULL, NULL); } -static void exitnow (afb_req request) +static void exitnow (afb_req_t request) { int code = 0; json_object *query = afb_req_json(request), *l; @@ -387,7 +361,7 @@ static void exitnow (afb_req request) exit(code); } -static void broadcast(afb_req request) +static void broadcast(afb_req_t request) { const char *tag = afb_req_value(request, "tag"); const char *name = afb_req_value(request, "name"); @@ -412,7 +386,7 @@ static void broadcast(afb_req request) json_object_put(object); } -static void hasperm (afb_req request) +static void hasperm (afb_req_t request) { const char *perm = afb_req_value(request, "perm"); if (afb_req_has_permission(request, perm)) @@ -421,39 +395,39 @@ static void hasperm (afb_req request) afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)"); } -static void appid (afb_req request) +static void appid (afb_req_t request) { char *aid = afb_req_get_application_id(request); afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?"); free(aid); } -static void uid (afb_req request) +static void uid (afb_req_t request) { int uid = afb_req_get_uid(request); afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid); } -static int preinit() +static int preinit(afb_api_t api) { - AFB_NOTICE("hello binding comes to live"); + AFB_API_NOTICE(api, "hello binding comes to live"); return 0; } -static int init() +static int init(afb_api_t api) { - AFB_NOTICE("hello binding starting"); + AFB_API_NOTICE(api, "hello binding starting"); return 0; } -static void onevent(const char *event, struct json_object *object) +static void onevent(afb_api_t api, const char *event, struct json_object *object) { - AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object)); + AFB_API_NOTICE(api, "received event %s(%s)", event, json_object_to_json_string(object)); } // NOTE: this sample does not use session to keep test a basic as possible // in real application most APIs should be protected with AFB_SESSION_CHECK -static const afb_verb_v2 verbs[]= { +static const struct afb_verb_v3 verbs[]= { { .verb="ping", .callback=pingSample }, { .verb="pingfail", .callback=pingFail }, { .verb="pingnull", .callback=pingNull }, @@ -461,7 +435,6 @@ static const afb_verb_v2 verbs[]= { { .verb="pingJson", .callback=pingJson }, { .verb="pingevent", .callback=pingEvent }, { .verb="subcall", .callback=subcall }, - { .verb="subcallreq", .callback=subcallreq }, { .verb="subcallsync", .callback=subcallsync }, { .verb="eventadd", .callback=eventadd }, { .verb="eventdel", .callback=eventdel }, @@ -479,7 +452,7 @@ static const afb_verb_v2 verbs[]= { { .verb=NULL} }; -const afb_binding_v2 afbBindingV2 = { +const struct afb_binding_v3 afbBindingV3 = { .api = "hello", .specification = NULL, .verbs = verbs, diff --git a/bindings/samples/ave.c b/bindings/samples/ave.c index 5661e9a5..ce01c6dc 100644 --- a/bindings/samples/ave.c +++ b/bindings/samples/ave.c @@ -21,6 +21,7 @@ #include <json-c/json.h> +#define AFB_BINDING_WANT_DYNAPI #define AFB_BINDING_VERSION 0 #include <afb/afb-binding.h> @@ -147,7 +148,7 @@ static void pingBug (afb_request *request) static void pingEvent(afb_request *request) { json_object *query = afb_request_json(request); - afb_dynapi_broadcast_event(request->dynapi, "event", json_object_get(query)); + afb_dynapi_broadcast_event(request->api, "event", json_object_get(query)); ping(request, json_object_get(query), "event"); } @@ -219,7 +220,7 @@ static void eventadd (afb_request *request) pthread_mutex_lock(&mutex); if (tag == NULL || name == NULL) afb_request_fail(request, "failed", "bad arguments"); - else if (0 != event_add(request->dynapi, tag, name)) + else if (0 != event_add(request->api, tag, name)) afb_request_fail(request, "failed", "creation error"); else afb_request_success(request, NULL, NULL); @@ -305,7 +306,7 @@ static void call (afb_request *request) if (object == NULL) afb_request_fail(request, "failed", "bad arguments"); else - afb_dynapi_call(request->dynapi, api, verb, object, callcb, afb_request_addref(request)); + afb_dynapi_call(request->api, api, verb, object, callcb, afb_request_addref(request)); } static void callsync (afb_request *request) @@ -319,7 +320,7 @@ static void callsync (afb_request *request) if (object == NULL) afb_request_fail(request, "failed", "bad arguments"); else { - rc = afb_dynapi_call_sync(request->dynapi, api, verb, object, &result); + rc = afb_dynapi_call_sync(request->api, api, verb, object, &result); if (rc >= 0) afb_request_success(request, result, NULL); else { @@ -379,7 +380,7 @@ static void broadcast(afb_request *request) afb_request_success(request, NULL, NULL); pthread_mutex_unlock(&mutex); } else if (name != NULL) { - if (0 > afb_dynapi_broadcast_event(request->dynapi, name, object)) + if (0 > afb_dynapi_broadcast_event(request->api, name, object)) afb_request_fail(request, "failed", "broadcast error"); else afb_request_success(request, NULL, NULL); @@ -447,13 +448,13 @@ static const struct { { .verb=NULL} }; -static void pingoo(afb_req req) +static void pingoo(struct afb_req_x1 req) { - json_object *args = afb_req_json(req); - afb_req_success_f(req, json_object_get(args), "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args)); + json_object *args = afb_req_x1_json(req); + afb_req_x1_reply_f(req, json_object_get(args), NULL, "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args)); } -static const afb_verb_v2 verbsv2[]= { +static const struct afb_verb_v2 verbsv2[]= { { .verb="pingoo", .callback=pingoo }, { .verb="ping", .callback=pingoo }, { .verb=NULL} diff --git a/bindings/samples/hello3.c b/bindings/samples/hello3.c new file mode 100644 index 00000000..ae70d1e5 --- /dev/null +++ b/bindings/samples/hello3.c @@ -0,0 +1,486 @@ +/* + * Copyright (C) 2015-2018 "IoT.bzh" + * Author "Fulup Ar Foll" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <pthread.h> + +#include <json-c/json.h> + +#define AFB_BINDING_VERSION 3 +#include <afb/afb-binding.h> + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +struct event +{ + struct event *next; + afb_event_t event; + char tag[1]; +}; + +static struct event *events = 0; + +/* searchs the event of tag */ +static struct event *event_get(const char *tag) +{ + struct event *e = events; + while(e && strcmp(e->tag, tag)) + e = e->next; + return e; +} + +/* deletes the event of tag */ +static int event_del(const char *tag) +{ + struct event *e, **p; + + /* check exists */ + e = event_get(tag); + if (!e) return -1; + + /* unlink */ + p = &events; + while(*p != e) p = &(*p)->next; + *p = e->next; + + /* destroys */ + afb_event_unref(e->event); + free(e); + return 0; +} + +/* creates the event of tag */ +static int event_add(const char *tag, const char *name) +{ + struct event *e; + + /* check valid tag */ + e = event_get(tag); + if (e) return -1; + + /* creation */ + e = malloc(strlen(tag) + sizeof *e); + if (!e) return -1; + strcpy(e->tag, tag); + + /* make the event */ + e->event = afb_daemon_make_event(name); + if (!e->event) { free(e); return -1; } + + /* link */ + e->next = events; + events = e; + return 0; +} + +static int event_subscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_subscribe(request, e->event) : -1; +} + +static int event_unsubscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_unsubscribe(request, e->event) : -1; +} + +static int event_push(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_push(e->event, json_object_get(args)) : -1; +} + +static int event_broadcast(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1; +} + +// Sample Generic Ping Debug API +static void ping(afb_req_t request, json_object *jresp, const char *tag) +{ + static int pingcount = 0; + json_object *query = afb_req_json(request); + afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query)); +} + +static void pingSample (afb_req_t request) +{ + ping(request, json_object_new_string ("Some String"), "pingSample"); +} + +static void pingFail (afb_req_t request) +{ + afb_req_fail(request, "failed", "Ping Binder Daemon fails"); +} + +static void pingNull (afb_req_t request) +{ + ping(request, NULL, "pingNull"); +} + +static void pingBug (afb_req_t request) +{ + ping(NULL, NULL, "pingBug"); +} + +static void pingEvent(afb_req_t request) +{ + json_object *query = afb_req_json(request); + afb_daemon_broadcast_event("event", json_object_get(query)); + ping(request, json_object_get(query), "event"); +} + + +// For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/ +static void pingJson (afb_req_t request) { + json_object *jresp, *embed; + + jresp = json_object_new_object(); + json_object_object_add(jresp, "myString", json_object_new_string ("Some String")); + json_object_object_add(jresp, "myInt", json_object_new_int (1234)); + + embed = json_object_new_object(); + json_object_object_add(embed, "subObjString", json_object_new_string ("Some String")); + json_object_object_add(embed, "subObjInt", json_object_new_int (5678)); + + json_object_object_add(jresp,"eobj", embed); + + ping(request, jresp, "pingJson"); +} + +static void subcallcb (void *prequest, int status, json_object *object, afb_req_t request) +{ + if (status < 0) + afb_req_fail(request, "failed", json_object_to_json_string(object)); + else + afb_req_success(request, json_object_get(object), NULL); + afb_req_unref(request); +} + +static void subcall (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_req_subcall_legacy(request, api, verb, object, subcallcb, NULL); +} + +static void subcallreqcb (void *prequest, int status, json_object *object, afb_req_t request) +{ + if (status < 0) + afb_req_fail(request, "failed", json_object_to_json_string(object)); + else + afb_req_success(request, json_object_get(object), NULL); +} + +static void subcallreq (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_req_subcall_legacy(request, api, verb, object, subcallreqcb, NULL); +} + +static void subcallsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result); + if (rc >= 0) + afb_req_success(request, result, NULL); + else { + afb_req_fail(request, "failed", json_object_to_json_string(result)); + json_object_put(result); + } + } +} + +static void eventadd (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + + pthread_mutex_lock(&mutex); + if (tag == NULL || name == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_add(tag, name)) + afb_req_fail(request, "failed", "creation error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventdel (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_del(tag)) + afb_req_fail(request, "failed", "deletion error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_subscribe(request, tag)) + afb_req_fail(request, "failed", "subscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventunsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_unsubscribe(request, tag)) + afb_req_fail(request, "failed", "unsubscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventpush (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 > event_push(object, tag)) + afb_req_fail(request, "failed", "push error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + json_object_put(object); +} + +static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api) +{ + afb_req_t request = afb_req_unstore(prequest); + afb_req_reply(request, json_object_get(object), error, info); + afb_req_unref(request); +} + +static void call (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_api_call(request->api, api, verb, object, callcb, afb_req_store(request)); +} + +static void callsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_service_call_sync(api, verb, object, &result); + if (rc >= 0) + afb_req_success(request, result, NULL); + else { + afb_req_fail(request, "failed", json_object_to_json_string(result)); + json_object_put(result); + } + } +} + +static void verbose (afb_req_t request) +{ + int level = 5; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + level = json_object_get_int(query); + else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int)) + level = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"message",&l)) + l = query; + + AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l)); + afb_req_success(request, NULL, NULL); +} + +static void exitnow (afb_req_t request) +{ + int code = 0; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + code = json_object_get_int(query); + else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int)) + code = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"reason",&l)) + l = NULL; + + AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown"); + afb_req_success(request, NULL, NULL); + exit(code); +} + +static void broadcast(afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + if (tag != NULL) { + pthread_mutex_lock(&mutex); + if (0 > event_broadcast(object, tag)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + } else if (name != NULL) { + if (0 > afb_daemon_broadcast_event(name, object)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + } else { + afb_req_fail(request, "failed", "bad arguments"); + } + json_object_put(object); +} + +static void hasperm (afb_req_t request) +{ + const char *perm = afb_req_value(request, "perm"); + if (afb_req_has_permission(request, perm)) + afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)"); + else + afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)"); +} + +static void appid (afb_req_t request) +{ + char *aid = afb_req_get_application_id(request); + afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?"); + free(aid); +} + +static void uid (afb_req_t request) +{ + int uid = afb_req_get_uid(request); + afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid); +} + +static int preinit() +{ + AFB_NOTICE("hello binding comes to live"); + return 0; +} + +static int init() +{ + AFB_NOTICE("hello binding starting"); + return 0; +} + +static void onevent(afb_api_t api, const char *event, struct json_object *object) +{ + AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object)); +} + +// NOTE: this sample does not use session to keep test a basic as possible +// in real application most APIs should be protected with AFB_SESSION_CHECK +static const struct afb_verb_v3 verbs[]= { + { .verb="ping", .callback=pingSample }, + { .verb="pingfail", .callback=pingFail }, + { .verb="pingnull", .callback=pingNull }, + { .verb="pingbug", .callback=pingBug }, + { .verb="pingJson", .callback=pingJson }, + { .verb="pingevent", .callback=pingEvent }, + { .verb="subcall", .callback=subcall }, + { .verb="subcallreq", .callback=subcallreq }, + { .verb="subcallsync", .callback=subcallsync }, + { .verb="eventadd", .callback=eventadd }, + { .verb="eventdel", .callback=eventdel }, + { .verb="eventsub", .callback=eventsub }, + { .verb="eventunsub", .callback=eventunsub }, + { .verb="eventpush", .callback=eventpush }, + { .verb="call", .callback=call }, + { .verb="callsync", .callback=callsync }, + { .verb="verbose", .callback=verbose }, + { .verb="broadcast", .callback=broadcast }, + { .verb="hasperm", .callback=hasperm }, + { .verb="appid", .callback=appid }, + { .verb="uid", .callback=uid }, + { .verb="exit", .callback=exitnow }, + { .verb=NULL} +}; + +const struct afb_binding_v3 afbBindingV3 = { + .api = "hello3", + .specification = NULL, + .verbs = verbs, + .preinit = preinit, + .init = init, + .onevent = onevent +}; + diff --git a/bindings/samples/hi3.c b/bindings/samples/hi3.c new file mode 100644 index 00000000..5202c46a --- /dev/null +++ b/bindings/samples/hi3.c @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2015-2018 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <pthread.h> + +#include <json-c/json.h> + +#define AFB_BINDING_VERSION 3 +#include <afb/afb-binding.h> + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +struct event +{ + struct event *next; + afb_event_t event; + char tag[1]; +}; + +static struct event *events = 0; + +/* searchs the event of tag */ +static struct event *event_get(const char *tag) +{ + struct event *e = events; + while(e && strcmp(e->tag, tag)) + e = e->next; + return e; +} + +/* deletes the event of tag */ +static int event_del(const char *tag) +{ + struct event *e, **p; + + /* check exists */ + e = event_get(tag); + if (!e) return -1; + + /* unlink */ + p = &events; + while(*p != e) p = &(*p)->next; + *p = e->next; + + /* destroys */ + afb_event_unref(e->event); + free(e); + return 0; +} + +/* creates the event of tag */ +static int event_add(afb_api_t api, const char *tag, const char *name) +{ + struct event *e; + + /* check valid tag */ + e = event_get(tag); + if (e) return -1; + + /* creation */ + e = malloc(strlen(tag) + sizeof *e); + if (!e) return -1; + strcpy(e->tag, tag); + + /* make the event */ + e->event = afb_api_make_event(api, name); + if (!e->event) { free(e); return -1; } + + /* link */ + e->next = events; + events = e; + return 0; +} + +static int event_subscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_subscribe(request, e->event) : -1; +} + +static int event_unsubscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_unsubscribe(request, e->event) : -1; +} + +static int event_push(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_push(e->event, json_object_get(args)) : -1; +} + +static int event_broadcast(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1; +} + +// Sample Generic Ping Debug API +static void ping(afb_req_t request, json_object *jresp, const char *tag) +{ + static int pingcount = 0; + json_object *query = afb_req_json(request); + afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query)); +} + +static void pingSample (afb_req_t request) +{ + ping(request, json_object_new_string ("Some String"), "pingSample"); +} + +static void pingFail (afb_req_t request) +{ + afb_req_fail(request, "failed", "Ping Binder Daemon fails"); +} + +static void pingNull (afb_req_t request) +{ + ping(request, NULL, "pingNull"); +} + +static void pingBug (afb_req_t request) +{ + ping(NULL, NULL, "pingBug"); +} + +static void pingEvent(afb_req_t request) +{ + json_object *query = afb_req_json(request); + afb_api_broadcast_event(request->api, "event", json_object_get(query)); + ping(request, json_object_get(query), "event"); +} + + +// For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/ +static void pingJson (afb_req_t request) { + json_object *jresp, *embed; + + jresp = json_object_new_object(); + json_object_object_add(jresp, "myString", json_object_new_string ("Some String")); + json_object_object_add(jresp, "myInt", json_object_new_int (1234)); + + embed = json_object_new_object(); + json_object_object_add(embed, "subObjString", json_object_new_string ("Some String")); + json_object_object_add(embed, "subObjInt", json_object_new_int (5678)); + + json_object_object_add(jresp,"eobj", embed); + + ping(request, jresp, "pingJson"); +} + +static void subcallcb (void *closure, json_object *object, const char *error, const char *info, afb_req_t request) +{ + afb_req_reply(request, json_object_get(object), error, info); +} + +static void subcall (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_req_subcall(request, api, verb, object, afb_req_subcall_pass_events, subcallcb, NULL); +} + +static void subcallsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *oargs = api && verb && args ? json_tokener_parse(args) : NULL; + json_object *object; + char *error, *info; + + if (oargs == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_req_subcall_sync(request, api, verb, oargs, afb_req_subcall_pass_events, &object, &error, &info); + afb_req_reply_f(request, object, error, "rc=%d, info=%s", rc, info?:"NULL"); + free(error); + free(info); + } +} + +static void eventadd (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + + pthread_mutex_lock(&mutex); + if (tag == NULL || name == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_add(request->api, tag, name)) + afb_req_fail(request, "failed", "creation error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventdel (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_del(tag)) + afb_req_fail(request, "failed", "deletion error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_subscribe(request, tag)) + afb_req_fail(request, "failed", "subscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventunsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_unsubscribe(request, tag)) + afb_req_fail(request, "failed", "unsubscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventpush (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 > event_push(object, tag)) + afb_req_fail(request, "failed", "push error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + json_object_put(object); +} + +static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api) +{ + afb_req_t request = prequest; + afb_req_reply(request, json_object_get(object), error, info); + afb_req_unref(request); +} + +static void call (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_api_call(request->api, api, verb, object, callcb, afb_req_addref(request)); +} + +static void callsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *oargs = api && verb && args ? json_tokener_parse(args) : NULL; + json_object *object; + char *error, *info; + + if (oargs == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_api_call_sync(request->api, api, verb, oargs, &object, &error, &info); + afb_req_reply_f(request, object, error, "rc=%d, info=%s", rc, info); + free(error); + free(info); + } +} + +static void verbose (afb_req_t request) +{ + int level = 5; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + level = json_object_get_int(query); + else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int)) + level = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"message",&l)) + l = query; + + AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l)); + afb_req_success(request, NULL, NULL); +} + +static void exitnow (afb_req_t request) +{ + int code = 0; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + code = json_object_get_int(query); + else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int)) + code = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"reason",&l)) + l = NULL; + + AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown"); + afb_req_success(request, NULL, NULL); + exit(code); +} + +static void broadcast(afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + if (tag != NULL) { + pthread_mutex_lock(&mutex); + if (0 > event_broadcast(object, tag)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + } else if (name != NULL) { + if (0 > afb_api_broadcast_event(request->api, name, object)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + } else { + afb_req_fail(request, "failed", "bad arguments"); + } + json_object_put(object); +} + +static void hasperm (afb_req_t request) +{ + const char *perm = afb_req_value(request, "perm"); + if (afb_req_has_permission(request, perm)) + afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)"); + else + afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)"); +} + +static void appid (afb_req_t request) +{ + char *aid = afb_req_get_application_id(request); + afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?"); + free(aid); +} + +static int init(afb_api_t api) +{ + AFB_API_NOTICE(api, "dynamic binding AVE(%s) starting", (const char*)api->userdata); + return 0; +} + +static void onevent(afb_api_t api, const char *event, struct json_object *object) +{ + AFB_API_NOTICE(api, "received event %s(%s) by AVE(%s)", + event, json_object_to_json_string(object), + (const char*)afb_api_get_userdata(api)); +} + +// NOTE: this sample does not use session to keep test a basic as possible +// in real application most APIs should be protected with AFB_SESSION_CHECK +static const struct { + const char *verb; + void (*callback)(afb_req_t); } verbs[] = +{ + { .verb="ping", .callback=pingSample }, + { .verb="pingfail", .callback=pingFail }, + { .verb="pingnull", .callback=pingNull }, + { .verb="pingbug", .callback=pingBug }, + { .verb="pingJson", .callback=pingJson }, + { .verb="pingevent", .callback=pingEvent }, + { .verb="subcall", .callback=subcall }, + { .verb="subcallsync", .callback=subcallsync }, + { .verb="eventadd", .callback=eventadd }, + { .verb="eventdel", .callback=eventdel }, + { .verb="eventsub", .callback=eventsub }, + { .verb="eventunsub", .callback=eventunsub }, + { .verb="eventpush", .callback=eventpush }, + { .verb="call", .callback=call }, + { .verb="callsync", .callback=callsync }, + { .verb="verbose", .callback=verbose }, + { .verb="broadcast", .callback=broadcast }, + { .verb="hasperm", .callback=hasperm }, + { .verb="appid", .callback=appid }, + { .verb="exit", .callback=exitnow }, + { .verb=NULL} +}; + +static void pingoo(struct afb_req_x1 req) +{ + json_object *args = afb_req_x1_json(req); + afb_req_x1_reply_f(req, json_object_get(args), NULL, "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args)); +} + +static const struct afb_verb_v2 verbsv2[]= { + { .verb="pingoo", .callback=pingoo }, + { .verb="ping", .callback=pingoo }, + { .verb=NULL} +}; + +static const char *apis[] = { "ave3", "hi3", "salut3", NULL }; + +static int build_api(void *closure, afb_api_t api) +{ + int i, rc; + + afb_api_set_userdata(api, closure); + AFB_API_NOTICE(api, "dynamic binding AVE(%s) comes to live", (const char*)afb_api_get_userdata(api)); + afb_api_on_init(api, init); + afb_api_on_event(api, onevent); + + rc = afb_api_set_verbs_v2(api, verbsv2); + for (i = rc = 0; verbs[i].verb && rc >= 0 ; i++) { + rc = afb_api_add_verb(api, verbs[i].verb, NULL, verbs[i].callback, (void*)(intptr_t)i, NULL, 0, 0); + } + afb_api_seal(api); + return rc; +} + +int afbBindingV3entry(afb_api_t api) +{ + int i; + afb_api_t napi; + + for (i = 0; apis[i] ; i++) { + napi = afb_api_new_api(api, apis[i], NULL, 0, build_api, (void*)apis[i]); + if (!napi) + AFB_API_ERROR(api, "can't create API %s", apis[i]); + } + return 0; +} + diff --git a/bindings/samples/tic-tac-toe.c b/bindings/samples/tic-tac-toe.c index 6b7022b8..2ee251cb 100644 --- a/bindings/samples/tic-tac-toe.c +++ b/bindings/samples/tic-tac-toe.c @@ -20,17 +20,14 @@ #include <string.h> #include <json-c/json.h> -#define AFB_BINDING_VERSION 2 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> -/* - * definition of waiters - */ -struct waiter -{ - struct waiter *next; - struct afb_req req; -}; +static const char SPACE = ' '; +static const char CROSS = 'X'; +static const char ROUND = 'O'; +static const char NHERE = '+'; +static const int DEFLVL = 8; /* * definition of a board @@ -44,7 +41,7 @@ struct board int id; int level; char board[9]; - struct waiter *waiters; + afb_event_t event; }; /* @@ -67,19 +64,21 @@ static struct board *search_board(int id) /* * Creates a new board and returns it. */ -static struct board *get_new_board() +static struct board *get_new_board(afb_req_t req) { /* allocation */ struct board *board = calloc(1, sizeof *board); /* initialisation */ - memset(board->board, ' ', sizeof board->board); + memset(board->board, SPACE, sizeof board->board); board->use_count = 1; - board->level = 1; + board->level = DEFLVL; board->moves = 0; do { board->id = (rand() >> 2) % 1000; } while(board->id == 0 || search_board(board->id) != NULL); + board->event = afb_daemon_make_event("board"); + afb_req_subscribe(req, board->event); /* link */ board->next = all_boards; @@ -87,6 +86,12 @@ static struct board *get_new_board() return board; } +static void *get_new_board_cb(void *closure) +{ + afb_req_t req = closure; + return get_new_board(req); +} + /* * Release a board */ @@ -95,6 +100,7 @@ static void release_board(struct board *board) /* decrease the reference count ... */ if (--board->use_count == 0) { /* ... no more use */ + afb_event_unref(board->event); /* unlink from the list of boards */ struct board **prv = &all_boards; while (*prv != NULL && *prv != board) @@ -106,6 +112,24 @@ static void release_board(struct board *board) } } +static void release_board_cb(void *closure) +{ + struct board *board = closure; + return release_board(board); +} + +/* + * Checks who wins + * Returns zero if there is no winner + * Returns the char of the winner if a player won + */ +static char wins(const char b[9], int first, int incr) +{ + char c = b[first]; + + return c != SPACE && b[first + incr] == c && b[first + incr + incr] == c ? c : 0; +} + /* * Checks who wins * Returns zero if there is no winner @@ -113,31 +137,39 @@ static void release_board(struct board *board) */ static char winner(const char b[9]) { - int i; char c; - /* check diagonals */ - c = b[4]; - if (c != ' ') { - if (b[0] == c && b[8] == c) - return c; - if (b[2] == c && b[6] == c) - return c; - } + c = wins(b, 0, 1); + if (c) + return c; - /* check lines */ - for (i = 0 ; i <= 6 ; i += 3) { - c = b[i]; - if (c != ' ' && b[i+1] == c && b[i+2] == c) - return c; - } + c = wins(b, 3, 1); + if (c) + return c; - /* check columns */ - for (i = 0 ; i <= 2 ; i++) { - c = b[i]; - if (c != ' ' && b[i+3] == c && b[i+6] == c) - return c; - } + c = wins(b, 6, 1); + if (c) + return c; + + c = wins(b, 0, 3); + if (c) + return c; + + c = wins(b, 1, 3); + if (c) + return c; + + c = wins(b, 2, 3); + if (c) + return c; + + c = wins(b, 0, 4); + if (c) + return c; + + c = wins(b, 2, 2); + if (c) + return c; return 0; } @@ -145,7 +177,7 @@ static char winner(const char b[9]) /* get the color (X or 0) of the move of index 'move' */ static char color(int move) { - return (move & 1) == 0 ? 'X' : '0'; + return (move & 1) == 0 ? CROSS : ROUND; } /* adds the move to the board */ @@ -160,7 +192,7 @@ static void add_move(struct board *board, int index) static int get_random_move(char b[9]) { int index = rand() % 9; - while (b[index] != ' ') + while (b[index] != SPACE) index = (index + 1) % 9; return index; } @@ -174,40 +206,41 @@ static int get_random_move(char b[9]) */ static int score_position(char b[9], char c, int depth) { - int i, t, r; + int i, s, nc, wc, lc; /* check if winner */ if (winner(b) == c) return 1; /* when depth of analysis is reached return unknown case */ - if (--depth == 0) + if (--depth <= 0) return 0; /* switch to the opponent */ - c = (char)('O' + 'X' - c); + c = (char)(ROUND + CROSS - c); /* inspect opponent moves */ - r = 1; + nc = wc = lc = 0; for (i = 0 ; i < 9 ; i++) { - if (b[i] == ' ') { + if (b[i] == SPACE) { b[i] = c; - t = score_position(b, c, depth); - b[i] = ' '; - if (t > 0) - return -1; /* opponent will win */ - - if (t == 0) - r = 0; /* something not clear */ + s = score_position(b, c, depth); + b[i] = SPACE; + if (s > 0) + lc++; /* opponent's victory, inc loose count */ + else if (s < 0) + wc++; /* current's victory, inc win count */ + else + nc++; /* none wins, increment null count */ } } - return r; + return lc ? -lc : wc; } /* get one move: return the computed index of the move */ static int get_move(struct board *board) { - int index, depth, t, f; + int index, depth, f, s, smax, imax; char c; char b[9]; @@ -222,22 +255,24 @@ static int get_move(struct board *board) /* depth and more */ memcpy(b, board->board, 9); + f = smax = 0; c = color(board->moves); - f = 0; for (index = 0 ; index < 9 ; index++) { - if (board->board[index] == ' ') { + if (board->board[index] == SPACE) { board->board[index] = c; - t = score_position(board->board, c, depth); - board->board[index] = ' '; - if (t > 0) - return index; - if (t < 0) - b[index] = '+'; - else + s = score_position(board->board, c, depth); + board->board[index] = SPACE; + if (s < 0) + b[index] = NHERE; + else if (s <= smax) f = 1; + else { + smax = s; + imax = index; + } } } - return get_random_move(f ? b : board->board); + return smax ? imax : get_random_move(f ? b : board->board); } /* @@ -279,37 +314,21 @@ static struct json_object *describe(struct board *board) */ static void changed(struct board *board, const char *reason) { - struct waiter *waiter, *next; - struct json_object *description; - - /* get the description */ - description = describe(board); - - waiter = board->waiters; - board->waiters = NULL; - while (waiter != NULL) { - next = waiter->next; - afb_req_success(waiter->req, json_object_get(description), reason); - afb_req_unref(waiter->req); - free(waiter); - waiter = next; - } - - afb_daemon_broadcast_event(reason, description); + afb_event_push(board->event, json_object_new_string(reason)); } /* * retrieves the board of the request */ -static inline struct board *board_of_req(struct afb_req req) +static inline struct board *board_of_req(afb_req_t req) { - return afb_req_context(req, (void*)get_new_board, (void*)release_board); + return afb_req_context(req, 0, get_new_board_cb, release_board_cb, req); } /* * start a new game */ -static void new(struct afb_req req) +static void new(afb_req_t req) { struct board *board; @@ -318,7 +337,7 @@ static void new(struct afb_req req) AFB_INFO("method 'new' called for boardid %d", board->id); /* reset the game */ - memset(board->board, ' ', sizeof board->board); + memset(board->board, SPACE, sizeof board->board); board->moves = 0; /* replies */ @@ -331,7 +350,7 @@ static void new(struct afb_req req) /* * get the board */ -static void board(struct afb_req req) +static void board(afb_req_t req) { struct board *board; struct json_object *description; @@ -350,7 +369,7 @@ static void board(struct afb_req req) /* * move a piece */ -static void move(struct afb_req req) +static void move(afb_req_t req) { struct board *board; int i; @@ -379,7 +398,7 @@ static void move(struct afb_req req) } /* checks validity of the move */ - if (board->board[i] != ' ') { + if (board->board[i] != SPACE) { AFB_WARNING("can't move to %s: room occupied", index); afb_req_fail(req, "error", "occupied"); return; @@ -399,7 +418,7 @@ static void move(struct afb_req req) /* * set the level */ -static void level(struct afb_req req) +static void level(afb_req_t req) { struct board *board; int l; @@ -434,7 +453,7 @@ static void level(struct afb_req req) /* * Join a board */ -static void join(struct afb_req req) +static void join(afb_req_t req) { struct board *board, *new_board; const char *id; @@ -450,8 +469,8 @@ static void join(struct afb_req req) /* none is a special id for joining a new session */ if (strcmp(id, "none") == 0) { - new_board = get_new_board(); - goto success; + new_board = get_new_board(req); + goto setctx; } /* searchs the board to join */ @@ -466,13 +485,16 @@ static void join(struct afb_req req) * function 'release_board'. So the use_count MUST not * be incremented. */ - if (new_board != board) - new_board->use_count++; + if (new_board == board) + goto success; -success: + new_board->use_count++; +setctx: /* set the new board (and leaves the previous one) */ - afb_req_context_set(req, new_board, (void*)release_board); + afb_req_context(req, 1, NULL, release_board_cb, new_board); + afb_req_unsubscribe(req, board->event); +success: /* replies */ afb_req_success(req, NULL, NULL); return; @@ -486,7 +508,7 @@ bad_request: /* * Undo the last move */ -static void undo(struct afb_req req) +static void undo(afb_req_t req) { struct board *board; int i; @@ -504,7 +526,7 @@ static void undo(struct afb_req req) /* undo the last move */ i = board->history[--board->moves]; - board->board[i] = ' '; + board->board[i] = SPACE; /* replies */ afb_req_success(req, NULL, NULL); @@ -516,7 +538,7 @@ static void undo(struct afb_req req) /* * computer plays */ -static void play(struct afb_req req) +static void play(afb_req_t req) { struct board *board; int index; @@ -543,27 +565,10 @@ static void play(struct afb_req req) changed(board, "play"); } -static void wait(struct afb_req req) -{ - struct board *board; - struct waiter *waiter; - - /* retrieves the context for the session */ - board = board_of_req(req); - AFB_INFO("method 'wait' called for boardid %d", board->id); - - /* creates the waiter and enqueues it */ - waiter = calloc(1, sizeof *waiter); - waiter->req = req; - waiter->next = board->waiters; - afb_req_addref(req); - board->waiters = waiter; -} - /* * array of the verbs exported to afb-daemon */ -static const struct afb_verb_v2 verbs[] = { +static const afb_verb_t verbs[] = { { .verb="new", .callback=new }, { .verb="play", .callback=play }, { .verb="move", .callback=move }, @@ -571,17 +576,17 @@ static const struct afb_verb_v2 verbs[] = { { .verb="level", .callback=level }, { .verb="join", .callback=join }, { .verb="undo", .callback=undo }, - { .verb="wait", .callback=wait }, { .verb=NULL } }; /* * description of the binding for afb-daemon */ -const afb_binding_v2 afbBindingV2 = { +const afb_binding_t afbBindingV3 = { .api = "tictactoe", .specification = NULL, - .verbs = verbs + .verbs = verbs, + .noconcurrency = 1 }; diff --git a/bindings/tutorial/tuto-1.c b/bindings/tutorial/tuto-1.c index 433a4ebb..1f58be6c 100644 --- a/bindings/tutorial/tuto-1.c +++ b/bindings/tutorial/tuto-1.c @@ -1,18 +1,18 @@ -#define AFB_BINDING_VERSION 2 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> -void hello(afb_req req) +void hello(afb_req_t req) { AFB_REQ_DEBUG(req, "hello world"); - afb_req_success(req, NULL, "hello world"); + afb_req_reply(req, NULL, NULL, "hello world"); } -const afb_verb_v2 verbs[] = { +const afb_verb_t verbs[] = { { .verb="hello", .callback=hello }, { .verb=NULL } }; -const afb_binding_v2 afbBindingV2 = { +const afb_binding_t afbBindingExport = { .api = "tuto-1", .verbs = verbs }; diff --git a/bindings/tutorial/tuto-2.c b/bindings/tutorial/tuto-2.c index dc2d55ab..10797081 100644 --- a/bindings/tutorial/tuto-2.c +++ b/bindings/tutorial/tuto-2.c @@ -1,12 +1,12 @@ #include <string.h> #include <json-c/json.h> -#define AFB_BINDING_VERSION 2 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> -afb_event event_login, event_logout; +afb_event_t event_login, event_logout; -void login(afb_req req) +void login(afb_req_t req) { json_object *args, *user, *passwd; char *usr; @@ -15,24 +15,24 @@ void login(afb_req req) if (!json_object_object_get_ex(args, "user", &user) || !json_object_object_get_ex(args, "password", &passwd)) { AFB_REQ_ERROR(req, "login, bad request: %s", json_object_get_string(args)); - afb_req_fail(req, "bad-request", NULL); + afb_req_reply(req, NULL, "bad-request", NULL); } else if (afb_req_context_get(req)) { AFB_REQ_ERROR(req, "login, bad state, logout first"); - afb_req_fail(req, "bad-state", NULL); + afb_req_reply(req, NULL, "bad-state", NULL); } else if (strcmp(json_object_get_string(passwd), "please")) { AFB_REQ_ERROR(req, "login, unauthorized: %s", json_object_get_string(args)); - afb_req_fail(req, "unauthorized", NULL); + afb_req_reply(req, NULL, "unauthorized", NULL); } else { usr = strdup(json_object_get_string(user)); AFB_REQ_NOTICE(req, "login user: %s", usr); afb_req_session_set_LOA(req, 1); afb_req_context_set(req, usr, free); - afb_req_success(req, NULL, NULL); + afb_req_reply(req, NULL, NULL, NULL); afb_event_push(event_login, json_object_new_string(usr)); } } -void action(afb_req req) +void action(afb_req_t req) { json_object *args, *val; char *usr; @@ -51,10 +51,10 @@ void action(afb_req req) afb_req_unsubscribe(req, event_logout); } } - afb_req_success(req, json_object_get(args), NULL); + afb_req_reply(req, json_object_get(args), NULL, NULL); } -void logout(afb_req req) +void logout(afb_req_t req) { char *usr; @@ -63,34 +63,34 @@ void logout(afb_req req) afb_event_push(event_logout, json_object_new_string(usr)); afb_req_session_set_LOA(req, 0); afb_req_context_clear(req); - afb_req_success(req, NULL, NULL); + afb_req_reply(req, NULL, NULL, NULL); } -int preinit() +int preinit(afb_api_t api) { - AFB_NOTICE("preinit"); + AFB_API_NOTICE(api, "preinit"); return 0; } -int init() +int init(afb_api_t api) { - AFB_NOTICE("init"); - event_login = afb_daemon_make_event("login"); - event_logout = afb_daemon_make_event("logout"); + AFB_API_NOTICE(api, "init"); + event_login = afb_api_make_event(api, "login"); + event_logout = afb_api_make_event(api, "logout"); if (afb_event_is_valid(event_login) && afb_event_is_valid(event_logout)) return 0; - AFB_ERROR("Can't create events"); + AFB_API_ERROR(api, "Can't create events"); return -1; } -const afb_verb_v2 verbs[] = { +const afb_verb_t verbs[] = { { .verb="login", .callback=login }, { .verb="action", .callback=action, .session=AFB_SESSION_LOA_1 }, { .verb="logout", .callback=logout, .session=AFB_SESSION_LOA_1 }, { .verb=NULL } }; -const afb_binding_v2 afbBindingV2 = { +const afb_binding_t afbBindingExport = { .api = "tuto-2", .specification = NULL, .verbs = verbs, diff --git a/bindings/tutorial/tuto-3.cpp b/bindings/tutorial/tuto-3.cpp index 7400b986..66f8e83a 100644 --- a/bindings/tutorial/tuto-3.cpp +++ b/bindings/tutorial/tuto-3.cpp @@ -1,11 +1,12 @@ #include <string.h> #include <json-c/json.h> +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding> afb::event event_login, event_logout; -void login(afb_req r) +void login(afb_req_t r) { json_object *args, *user, *passwd; char *usr; @@ -26,20 +27,21 @@ void login(afb_req r) usr = strdup(json_object_get_string(user)); AFB_REQ_NOTICE(req, "login user: %s", usr); req.session_set_LOA(1); - req.context_set(usr, free); +// req.context(1, nullptr, free, usr); req.success(); event_login.push(json_object_new_string(usr)); } } -void action(afb_req r) +void action(afb_req_t r) { json_object *args, *val; char *usr; afb::req req(r); args = req.json(); - usr = (char*)req.context_get(); +// usr = (char*)req.context_get(); +usr = nullptr; AFB_REQ_NOTICE(req, "action for user %s: %s", usr, json_object_get_string(args)); if (json_object_object_get_ex(args, "subscribe", &val)) { if (json_object_get_boolean(val)) { @@ -55,20 +57,25 @@ void action(afb_req r) req.success(json_object_get(args)); } -void logout(afb_req r) +void logout(afb_req_t r) { char *usr; afb::req req(r); - usr = (char*)req.context_get(); +// usr = (char*)req.context_get(); +usr = nullptr; AFB_REQ_NOTICE(req, "login user %s out", usr); event_logout.push(json_object_new_string(usr)); req.session_set_LOA(0); - req.context_clear(); +// req.context_clear(); req.success(); } -int init() +int init( +#if AFB_BINDING_VERSION >= 3 + afb_api_t api +#endif +) { AFB_NOTICE("init"); event_login = afb_daemon_make_event("login"); @@ -79,12 +86,13 @@ int init() return -1; } -const afb_verb_v2 verbs[] = { +const afb_verb_t verbs[] = { afb::verb("login", login, "log in the system"), afb::verb("action", action, "perform an action", AFB_SESSION_LOA_1), afb::verb("logout", logout, "log out the system", AFB_SESSION_LOA_1), afb::verbend() }; -const afb_binding_v2 afbBindingV2 = afb::binding("tuto-3", verbs, "third tutorial: C++", init); +const afb_binding_t afbBindingExport = afb::binding("tuto-3", verbs, "third tutorial: C++", init); + @@ -6,7 +6,7 @@ "author": "IoT.Bzh Team", "website": "http://iot.bzh", "published": "February 2018", - "version": "5.99-FFRC0", + "version": "5.99-FFRC1", "gitbook": "3.2.2", "root": "docs", @@ -89,6 +89,6 @@ "decode": true } ] - } + } } } diff --git a/docs/README.md b/docs/README.md index 94dc16aa..503b8545 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,13 +1,19 @@ -Document revisions -================== - -| Date | Version | Designation | Author | -|--------------|------------|----------------------------------------------|-------------------------------------------------------| -| 23 May 2016 | 0.9 | Initial release | J. Bollo [ IoT.bzh ] <br/> M. Bachmann [ IoT.bzh ] | -| 30 May 2016 | 1.0 | Master document edition, final review | S. Desneux [ IoT.bzh ] <br/> F. Ar Foll [ IoT.bzh ] | -| 21 Sept 2016 | 2.0 | Updated with new sections (events,widgets) | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] | -| 12 Dec 2016 | 2.1 | Updated for CC Release | S. Desneux [ IoT.bzh ] | -| 14 Dec 2016 | 3.0 | Minor fixes, alignment with CC version | S. Desneux [ IoT.bzh ] | -| 20 Mar 2017 | 3.1 | Systemd integration | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] | -| 21 Jun 2017 | 4.0 | Update for AGL DD | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] | -| 21 Sep 2017 | 4.99-EERC1 | Update for AGL EE-RC1 | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] | + +# AGL Framework Binder + +This project provides the binder component of the the microservice architecture +of Automotive Grade Linux (AGL). + +This project is available there https://git.automotivelinux.org/src/app-framework-binder/ + +It can be cloned with **git clone https://git.automotivelinux.org/src/app-framework-binder**. + +## License and copying + +This software is an open source software funded by LinuxFoundation and Renesas. + +This software is delivered under the terms of the open source license Apache 2. + +This license is available in the file LICENSE-2.0.txt or on the worl wide web at the +location https://opensource.org/licenses/Apache-2.0 + diff --git a/docs/REVISIONS.md b/docs/REVISIONS.md new file mode 100644 index 00000000..00787b02 --- /dev/null +++ b/docs/REVISIONS.md @@ -0,0 +1,14 @@ +Document revisions +================== + +| Date | Version | Designation | Author | +|--------------|:----------:|----------------------------------------------|-------------------------------------------------------| +| 23 May 2016 | 0.9 | Initial release | J. Bollo [ IoT.bzh ] <br/> M. Bachmann [ IoT.bzh ] | +| 30 May 2016 | 1.0 | Master document edition, final review | S. Desneux [ IoT.bzh ] <br/> F. Ar Foll [ IoT.bzh ] | +| 21 Sept 2016 | 2.0 | Updated with new sections (events,widgets) | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] | +| 12 Dec 2016 | 2.1 | Updated for CC Release | S. Desneux [ IoT.bzh ] | +| 14 Dec 2016 | 3.0 | Minor fixes, alignment with CC version | S. Desneux [ IoT.bzh ] | +| 20 Mar 2017 | 3.1 | Systemd integration | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] | +| 21 Jun 2017 | 4.0 | Update for AGL DD | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] | +| 21 Sep 2017 | 4.99-EERC1 | Update for AGL EE-RC1 | J. Bollo [ IoT.bzh ] <br/> S. Desneux [ IoT.bzh ] | +| 14 Jun 2018 | 5.99-FFRC1 | Update for AGL FF-RC1 | J. Bollo [ IoT.bzh ] | diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 44b06f8d..580660ea 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,14 +1,15 @@ # Summary -* [Document revisions](README.md) * [Binder Overview](afb-introduction.md) +* [Binder daemon vocabulary](afb-daemon-vocabulary.md) * [How to write a binding ?](afb-binding-writing.md) * [Binding references](afb-binding-references.md) -* [Migration from v1 to v2](afb-migration-v1-to-v2.md) * [Binder events guide](afb-events-guide.md) * [Binder Application writing guide](afb-application-writing.md) -* [Binder daemon vocabulary](afb-daemon-vocabulary.md) * [Annexes](annexes.md) + * [Migration to binding v3](afb-migration-to-binding-v3.md) * [Installing the binder on a desktop](afb-desktop-package.md) * [Options of afb-daemon](afb-daemon-options.md) - * [Debugging afb-daemon](afb-daemon-debugging.md) + * [Debugging binder and bindings](afb-daemon-debugging.md) + * [(LEGACY) guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md) +* [Document revisions](REVISIONS.md) diff --git a/docs/afb-binding-references.md b/docs/afb-binding-references.md index 0e30ffe7..4ff0f042 100644 --- a/docs/afb-binding-references.md +++ b/docs/afb-binding-references.md @@ -2,47 +2,98 @@ ## Structure for declaring binding -### struct afb_binding_v2 +### afb_binding_t -The main structure, of type **afb_binding_v2**, for describing the binding -must be exported under the name **afbBindingV2**. +The main structure, of type **afb_binding_t**, for describing the binding +must be exported under the name **afbBindingExport**. This structure is defined as below. ```C -/* - * Description of the bindings of type version 2 +typedef struct afb_binding_v3 afb_binding_t; +``` + +Where: + +```C +/** + * Description of the bindings of type version 3 */ -struct afb_binding_v2 +struct afb_binding_v3 { - const char *api; /* api name for the binding */ - const char *specification; /* textual openAPIv3 specification of the binding */ - const char *info; /* some info about the api, can be NULL */ - const struct afb_verb_v2 *verbs; /* array of descriptions of verbs terminated by a NULL name */ - int (*preinit)(); /* callback at load of the binding */ - int (*init)(); /* callback for starting the service */ - void (*onevent)(const char *event, struct json_object *object); /* callback for handling events */ - unsigned noconcurrency: 1; /* avoids concurrent requests to verbs */ + /** api name for the binding, can't be NULL */ + const char *api; + + /** textual specification of the binding, can be NULL */ + const char *specification; + + /** some info about the api, can be NULL */ + const char *info; + + /** array of descriptions of verbs terminated by a NULL name, can be NULL */ + const struct afb_verb_v3 *verbs; + + /** callback at load of the binding */ + int (*preinit)(struct afb_api_x3 *api); + + /** callback for starting the service */ + int (*init)(struct afb_api_x3 *api); + + /** callback for handling events */ + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object); + + /** userdata for afb_api_x3 */ + void *userdata; + + /** space separated list of provided class(es) */ + const char *provide_class; + + /** space separated list of required class(es) */ + const char *require_class; + + /** space separated list of required API(es) */ + const char *require_api; + + /** avoids concurrent requests to verbs */ + unsigned noconcurrency: 1; }; ``` -### struct afb_verb_v2 +### struct afb_verb_t -Each verb is described with a structure of type **afb_verb_v2** +Each verb is described with a structure of type **afb_verb_t** defined below: ```C -/* - * Description of one verb of the API provided by the binding - * This enumeration is valid for bindings of type version 2 +typedef struct afb_verb_v3 afb_verb_t; +``` + +```C +/** + * Description of one verb as provided for binding API version 3 */ -struct afb_verb_v2 +struct afb_verb_v3 { - const char *verb; /* name of the verb */ - void (*callback)(struct afb_req req); /* callback function implementing the verb */ - const struct afb_auth *auth; /* required authorization */ - const char *info; /* some info about the verb, can be NULL */ - uint32_t session; /* authorization and session requirements of the verb */ + /** name of the verb, NULL only at end of the array */ + const char *verb; + + /** callback function implementing the verb */ + void (*callback)(afb_req_t_x2 *req); + + /** required authorization, can be NULL */ + const struct afb_auth *auth; + + /** some info about the verb, can be NULL */ + const char *info; + + /**< data for the verb callback */ + void *vcbdata; + + /** authorization and session requirements of the verb */ + uint16_t session; + + /** is the verb glob name */ + uint16_t glob: 1; }; ``` @@ -55,55 +106,91 @@ The **session** flags is one of the constant defined below: - AFB_SESSION_LOA_3 : Requires the LOA to be 3 or more - AFB_SESSION_CHECK : Requires the token to be set and valid - AFB_SESSION_REFRESH : Implies a token refresh -- AFB_SESSION_CLOSE : Implies cloing the session +- AFB_SESSION_CLOSE : Implies closing the session after request processed -The LOA (Level Of Assurance) is set, by binding, using the function **afb_req_session_set_LOA**. +The LOA (Level Of Assurance) is set, by binding api, using the function **afb_req_session_set_LOA**. -### struct afb_auth and enum afb_auth_type +The session can be closed, by binding api, using the function **afb_req_session_close**. -The structure **afb_auth** is used within verb description to +### afb_auth_t and afb_auth_type_t + +The structure **afb_auth_t** is used within verb description to set security requirements. The interpretation of the structure depends on the value of the field **type**. ```C +typedef struct afb_auth afb_auth_t; + +/** + * Definition of an authorization entry + */ struct afb_auth { - const enum afb_auth_type type; - union { - const char *text; - const unsigned loa; - const struct afb_auth *first; - }; - const struct afb_auth *next; + /** type of entry @see afb_auth_type */ + enum afb_auth_type type; + + union { + /** text when @ref type == @ref afb_auth_Permission */ + const char *text; + + /** level of assurancy when @ref type == @ref afb_auth_LOA */ + unsigned loa; + + /** first child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And, @ref afb_auth_Not } */ + const struct afb_auth *first; + }; + + /** second child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And } */ + const struct afb_auth *next; }; + ``` The possible values for **type** is defined here: ```C -/* - * Enum for Session/Token/Assurance middleware. +typedef enum afb_auth_type afb_auth_type_t; + +/** + * Enumeration for authority (Session/Token/Assurance) definitions. + * + * @see afb_auth */ enum afb_auth_type { - afb_auth_No = 0, /** never authorized, no data */ - afb_auth_Token, /** authorized if token valid, no data */ - afb_auth_LOA, /** authorized if LOA greater than data 'loa' */ - afb_auth_Permission, /** authorized if permission 'text' is granted */ - afb_auth_Or, /** authorized if 'first' or 'next' is authorized */ - afb_auth_And, /** authorized if 'first' and 'next' are authorized */ - afb_auth_Not, /** authorized if 'first' is not authorized */ - afb_auth_Yes /** always authorized, no data */ + /** never authorized, no data */ + afb_auth_No = 0, + + /** authorized if token valid, no data */ + afb_auth_Token, + + /** authorized if LOA greater than data 'loa' */ + afb_auth_LOA, + + /** authorized if permission 'text' is granted */ + afb_auth_Permission, + + /** authorized if 'first' or 'next' is authorized */ + afb_auth_Or, + + /** authorized if 'first' and 'next' are authorized */ + afb_auth_And, + + /** authorized if 'first' is not authorized */ + afb_auth_Not, + + /** always authorized, no data */ + afb_auth_Yes }; ``` Example: ```C -static const struct afb_auth _afb_auths_v2_monitor[] = { - { .type = afb_auth_Permission, .text = "urn:AGL:permission:monitor:public:set" }, - { .type = afb_auth_Permission, .text = "urn:AGL:permission:monitor:public:get" }, - { .type = afb_auth_Or, .first = &_afb_auths_v2_monitor[1], .next = &_afb_auths_v2_monitor[0] } +static const afb_auth_t myauth[] = { + { .type = afb_auth_Permission, .text = "urn:AGL:permission:me:public:set" }, + { .type = afb_auth_Permission, .text = "urn:AGL:permission:me:public:get" }, + { .type = afb_auth_Or, .first = &myauth[1], .next = &myauth[0] } }; ``` @@ -115,17 +202,18 @@ to **sd_bus** features. ```C /* - * Retrieves the common systemd's event loop of AFB + * Retrieves the common systemd's event loop of AFB + * */ struct sd_event *afb_daemon_get_event_loop(); /* - * Retrieves the common systemd's user/session d-bus of AFB + * Retrieves the common systemd's user/session d-bus of AFB if active */ struct sd_bus *afb_daemon_get_user_bus(); /* - * Retrieves the common systemd's system d-bus of AFB + * Retrieves the common systemd's system d-bus of AFB if active or NULL */ struct sd_bus *afb_daemon_get_system_bus(); ``` @@ -155,7 +243,7 @@ int afb_daemon_broadcast_event(const char *name, struct json_object *object); * * See afb_event_is_valid to check if there is an error. */ -struct afb_event afb_daemon_make_event(const char *name); +afb_event_t afb_daemon_make_event(const char *name); ``` The following function is used by logging macros and should normally @@ -319,7 +407,7 @@ It must be used when creating events. * * Returns 0 if not valid or 1 if valid. */ -int afb_event_is_valid(struct afb_event event); +int afb_event_is_valid(afb_event_t event); ``` The two following functions are used to broadcast or push @@ -336,7 +424,7 @@ event with its data. * * Returns the count of clients that received the event. */ -int afb_event_broadcast(struct afb_event event, struct json_object *object); +int afb_event_broadcast(afb_event_t event, struct json_object *object); /* * Pushes the 'event' with the data 'object' to its observers. @@ -348,18 +436,29 @@ int afb_event_broadcast(struct afb_event event, struct json_object *object); * * Returns the count of clients that received the event. */ -int afb_event_push(struct afb_event event, struct json_object *object); +int afb_event_push(afb_event_t event, struct json_object *object); +``` + +The following function remove one reference to the event. + +```C +/* + * Decrease the reference count of the event. + * After calling this function, the event + * MUST NOT BE USED ANYMORE. + */ +void afb_event_unref(afb_event_t event); ``` -The following function destiys the event. +The following function add one reference to the event. ```C /* - * Drops the data associated to the 'event' + * Decrease the reference count of the event. * After calling this function, the event * MUST NOT BE USED ANYMORE. */ -void afb_event_drop(struct afb_event event); +void afb_event_unref(afb_event_t event); ``` This function allows to retrieve the exact name of the event. @@ -368,7 +467,7 @@ This function allows to retrieve the exact name of the event. /* * Gets the name associated to the 'event'. */ -const char *afb_event_name(struct afb_event event); +const char *afb_event_name(afb_event_t event); ``` ## Functions of class afb_req @@ -381,7 +480,7 @@ This function checks the validity of the **req**. * * Returns 0 if not valid or 1 if valid. */ -int afb_req_is_valid(struct afb_req req); +int afb_req_is_valid(afb_req_t req); ``` The following functions retrieves parameters of the request. @@ -399,7 +498,7 @@ The following functions retrieves parameters of the request. * an HTTP POST of Content-Type "application/json". In that case, the * argument of name "" receives the value of the body of the HTTP request. */ -struct afb_arg afb_req_get(struct afb_req req, const char *name); +afb_arg_t afb_req_get(afb_req_t req, const char *name); /* * Gets from the request 'req' the string value of the argument of 'name'. @@ -408,7 +507,7 @@ struct afb_arg afb_req_get(struct afb_req req, const char *name); * * Shortcut for: afb_req_get(req, name).value */ -const char *afb_req_value(struct afb_req req, const char *name); +const char *afb_req_value(afb_req_t req, const char *name); /* * Gets from the request 'req' the path for file attached to the argument of 'name'. @@ -417,13 +516,13 @@ const char *afb_req_value(struct afb_req req, const char *name); * * Shortcut for: afb_req_get(req, name).path */ -const char *afb_req_path(struct afb_req req, const char *name); +const char *afb_req_path(afb_req_t req, const char *name); /* * Gets from the request 'req' the json object hashing the arguments. * The returned object must not be released using 'json_object_put'. */ -struct json_object *afb_req_json(struct afb_req req); +struct json_object *afb_req_json(afb_req_t req); ``` The following functions emit the reply to the request. @@ -439,7 +538,7 @@ The following functions emit the reply to the request. * Thus, in the case where 'obj' should remain available after * the function returns, the function 'json_object_get' shall be used. */ -void afb_req_success(struct afb_req req, struct json_object *obj, const char *info); +void afb_req_success(afb_req_t req, struct json_object *obj, const char *info); /* * Same as 'afb_req_success' but the 'info' is a formatting @@ -449,7 +548,7 @@ void afb_req_success(struct afb_req req, struct json_object *obj, const char *in * Thus, in the case where 'obj' should remain available after * the function returns, the function 'json_object_get' shall be used. */ -void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...); +void afb_req_success_f(afb_req_t req, struct json_object *obj, const char *info, ...); /* * Same as 'afb_req_success_f' but the arguments to the format 'info' @@ -459,30 +558,30 @@ void afb_req_success_f(struct afb_req req, struct json_object *obj, const char * * Thus, in the case where 'obj' should remain available after * the function returns, the function 'json_object_get' shall be used. */ -void afb_req_success_v(struct afb_req req, struct json_object *obj, const char *info, va_list args); +void afb_req_success_v(afb_req_t req, struct json_object *obj, const char *info, va_list args); /* * Sends a reply of kind failure to the request 'req'. * The status of the reply is set to 'status' and an - * informationnal comment 'info' (can also be NULL) can be added. + * informational comment 'info' (can also be NULL) can be added. * * Note that calling afb_req_fail("success", info) is equivalent * to call afb_req_success(NULL, info). Thus even if possible it * is strongly recommended to NEVER use "success" for status. */ -void afb_req_fail(struct afb_req req, const char *status, const char *info); +void afb_req_fail(afb_req_t req, const char *status, const char *info); /* * Same as 'afb_req_fail' but the 'info' is a formatting * string followed by arguments. */ -void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...); +void afb_req_fail_f(afb_req_t req, const char *status, const char *info, ...); /* * Same as 'afb_req_fail_f' but the arguments to the format 'info' * are given as a variable argument list instance. */ -void afb_req_fail_v(struct afb_req req, const char *status, const char *info, va_list args); +void afb_req_fail_v(afb_req_t req, const char *status, const char *info, va_list args); ``` The following functions handle the session data. @@ -492,14 +591,14 @@ The following functions handle the session data. * Gets the pointer stored by the binding for the session of 'req'. * When the binding has not yet recorded a pointer, NULL is returned. */ -void *afb_req_context_get(struct afb_req req); +void *afb_req_context_get(afb_req_t req); /* * Stores for the binding the pointer 'context' to the session of 'req'. * The function 'free_context' will be called when the session is closed * or if binding stores an other pointer. */ -void afb_req_context_set(struct afb_req req, void *context, void (*free_context)(void*)); +void afb_req_context_set(afb_req_t req, void *context, void (*free_context)(void*)); /* * Gets the pointer stored by the binding for the session of 'req'. @@ -508,7 +607,7 @@ void afb_req_context_set(struct afb_req req, void *context, void (*free_context) * the function 'create_context' and stores it with the freeing function * 'free_context'. */ -void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*)); +void *afb_req_context(afb_req_t req, void *(*create_context)(), void (*free_context)(void*)); /* * Frees the pointer stored by the binding for the session of 'req' @@ -516,13 +615,13 @@ void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free * * Shortcut for: afb_req_context_set(req, NULL, NULL) */ -void afb_req_context_clear(struct afb_req req); +void afb_req_context_clear(afb_req_t req); /* * Closes the session associated with 'req' * and delete all associated contexts. */ -void afb_req_session_close(struct afb_req req); +void afb_req_session_close(afb_req_t req); /* * Sets the level of assurance of the session of 'req' @@ -530,7 +629,7 @@ void afb_req_session_close(struct afb_req req); * security policies. * Returns 1 on success or 0 if failed. */ -int afb_req_session_set_LOA(struct afb_req req, unsigned level); +int afb_req_session_set_LOA(afb_req_t req, unsigned level); ``` The 4 following functions must be used for asynchronous handling requests. @@ -541,14 +640,14 @@ The 4 following functions must be used for asynchronous handling requests. * This function MUST be called by asynchronous implementations * of verbs if no reply was sent before returning. */ -void afb_req_addref(struct afb_req req); +void afb_req_addref(afb_req_t req); /* * Substracts one to the count of references of 'req'. * This function MUST be called by asynchronous implementations * of verbs after sending the asynchronous reply. */ -void afb_req_unref(struct afb_req req); +void afb_req_unref(afb_req_t req); /* * Stores 'req' on heap for asynchronous use. @@ -556,7 +655,7 @@ void afb_req_unref(struct afb_req req); * The count of reference to 'req' is incremented on success * (see afb_req_addref). */ -struct afb_stored_req *afb_req_store(struct afb_req req); +struct afb_stored_req *afb_req_store(afb_req_t req); /* * Retrieves the afb_req stored at 'sreq'. @@ -565,7 +664,7 @@ struct afb_stored_req *afb_req_store(struct afb_req req); * function 'afb_req_unref' should be called on the result * after that the asynchronous reply if sent. */ -struct afb_req afb_req_unstore(struct afb_stored_req *sreq); +afb_req_t afb_req_unstore(struct afb_stored_req *sreq); ``` The two following functions are used to associate client with events @@ -577,14 +676,14 @@ The two following functions are used to associate client with events * to the 'event'. * Returns 0 in case of successful subscription or -1 in case of error. */ -int afb_req_subscribe(struct afb_req req, struct afb_event event); +int afb_req_subscribe(afb_req_t req, afb_event_t event); /* * Revokes the subscription established to the 'event' for the client * link identified by 'req'. * Returns 0 in case of successful subscription or -1 in case of error. */ -int afb_req_unsubscribe(struct afb_req req, struct afb_event event); +int afb_req_unsubscribe(afb_req_t req, afb_event_t event); ``` The following functions must be used to make request in the name of the @@ -609,7 +708,7 @@ client (with its permissions). * - 'afb_req_subcall_sync' the synchronous version */ void afb_req_subcall( - struct afb_req req, + afb_req_t req, const char *api, const char *verb, struct json_object *args, @@ -634,7 +733,7 @@ void afb_req_subcall( * - 'afb_req_subcall' that doesn't keep request alive automatically. * - 'afb_req_subcall_sync' the synchronous version */ -static inline void afb_req_subcall_req(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req req), void *closure) +static inline void afb_req_subcall_req(afb_req_t req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, afb_req_t req), void *closure) { req.itf->subcall_req(req.closure, api, verb, args, callback, closure); } @@ -656,7 +755,7 @@ static inline void afb_req_subcall_req(struct afb_req req, const char *api, cons * - 'afb_req_subcall' that doesn't keep request alive automatically. */ int afb_req_subcall_sync( - struct afb_req req, + afb_req_t req, const char *api, const char *verb, struct json_object *args, @@ -691,7 +790,7 @@ Instead, you should use the macros: * INFO 6 Informational * DEBUG 7 Debug-level messages */ -void afb_req_verbose(struct afb_req req, int level, const char *file, int line, const char * func, const char *fmt, ...); +void afb_req_verbose(afb_req_t req, int level, const char *file, int line, const char * func, const char *fmt, ...); ``` The functions below allow a binding involved in the platform security @@ -705,7 +804,7 @@ application identity. * * Returns 1 if the permission is granted or 0 otherwise. */ -int afb_req_has_permission(struct afb_req req, const char *permission); +int afb_req_has_permission(afb_req_t req, const char *permission); /* * Get the application identifier of the client application for the @@ -716,7 +815,7 @@ int afb_req_has_permission(struct afb_req req, const char *permission); * * The returned value if not NULL must be freed by the caller */ -char *afb_req_get_application_id(struct afb_req req); +char *afb_req_get_application_id(afb_req_t req); /* * Get the user identifier (UID) of the client application for the @@ -724,7 +823,7 @@ char *afb_req_get_application_id(struct afb_req req); * * Returns -1 when the application can not be identified. */ -int afb_req_get_uid(struct afb_req req); +int afb_req_get_uid(afb_req_t req); ``` ## Logging macros diff --git a/docs/afb-binding-writing.md b/docs/afb-binding-writing.md index aad422c4..69090e3d 100644 --- a/docs/afb-binding-writing.md +++ b/docs/afb-binding-writing.md @@ -51,14 +51,21 @@ The binder makes no distinctions between upper case and lower case latin letters. So **API/VERB** matches **Api/Verb** or **api/verb**. -Actually it exists 2 ways of writing ***bindings***. +## Versions of the bindings + +Since introduction of the binder, the way how bindings are written +evolved a little. While changing, attention was made to ensure binary +compatibility between the different versions. + +Actually it exists 3 ways of writing ***bindings***. You can either write: -- a binding version 1 (not recommended); -- a binding version 2 (RECOMMENDED). +- a binding version 1 (not more supported); +- a binding version 2 (not recommended); +- a binding version 3 (RECOMMENDED). A ***binder*** loads and runs any of these version in any combination. -This document explain how to write bindings version 2. +This document explain how to write bindings version 3. <!-- pagebreak --> @@ -67,21 +74,21 @@ This document explain how to write bindings version 2. This is the code of the binding **tuto-1.c**: ```C - 1 #define AFB_BINDING_VERSION 2 + 1 #define AFB_BINDING_VERSION 3 2 #include <afb/afb-binding.h> 3 - 4 void hello(afb_req req) + 4 void hello(afb_req_t req) 5 { 6 AFB_REQ_DEBUG(req, "hello world"); - 7 afb_req_success(req, NULL, "hello world"); + 7 afb_req_reply(req, NULL, NULL, "hello world"); 8 } 9 - 10 const afb_verb_v2 verbs[] = { + 10 const afb_verb_t verbs[] = { 11 { .verb="hello", .callback=hello }, 12 { .verb=NULL } 13 }; 14 - 15 const afb_binding_v2 afbBindingV2 = { + 15 const afb_binding_t afbBindingExport = { 16 .api = "tuto-1", 17 .verbs = verbs 18 }; @@ -93,12 +100,18 @@ Compiling: gcc -fPIC -shared tuto-1.c -o tuto-1.so $(pkg-config --cflags-only-I afb-daemon) ``` +> Note: the variable environment variable PKG_CONFIG_PATH might be necessary +> tuned to get **pkg-config** working properly + Running: ```bash afb-daemon --binding tuto-1.so --port 3333 --token '' ``` +At this point, afb-daemon has started, it loaded the binding tuto-1.so and now +listen at localhost on the port 3333. + Testing using **curl**: ```bash @@ -133,18 +146,15 @@ This shows basic things: The lines 1 and 2 show how to get the include file **afb-binding.h**. ```C - 1 #define AFB_BINDING_VERSION 2 + 1 #define AFB_BINDING_VERSION 3 2 #include <afb/afb-binding.h> ``` -You must define the version of ***binding*** that you are using. -This is done line 1 where we define that this is the version 2. +You must define the version of ***binding*** that you are using. +This is done line 1 where we define that this is the version 3 (earlier +versions 1 and 2 are deprecated). -If you don't define it, a warning message is prompted by the compiler -and the version is switched to version 1. -This behaviour is temporarily and enables to continue to use previously written -***binding*** without change but it will change in some future when -***bindings*** V1 will become obsoletes. +If you don't define it, an error is reported and the compilation aborts. To include **afb-binding.h** successfully, the include search path should be set correctly if needed (not needed only if installed in @@ -156,81 +166,54 @@ Setting the include path is easy using **pkg-config**: pkg-config --cflags-only-I afb-daemon ``` -Note for **C++** developers: - -- The ***binder*** currently expose only **C** language **API**. - The file **afb/afb-binding.h** isn't **C++** ready. - -You should use the construct **extern "C"** as below: +> Note for **C++** developers: +> +> The ***binder*** currently expose a draft version of **C++** api. +> To get it include the file <**afb/afb-binding**> (without **.h**). -```C - #define AFB_BINDING_VERSION 2 - extern "C" { - #include <afb/afb-binding.h> - } -``` - -Future version of the ***binder*** will include a **C++** -interface. -Until it is available, please, use the above construct. ### Declaring the API of the binding Lines 10 to 18 show the declaration of the ***binding***. -The ***binder*** knows that this is a ***binding*** version 2 because -it finds the exported symbol **afbBindingV2** that is expected to be -a structure of type **afb_binding_v2**. +The ***binder*** knows that this is a ***binding*** because +it finds the exported symbol **afbBindingExport** that is expected to be +a structure of type **afb_binding_t**. ```C - 10 const afb_verb_v2 verbs[] = { + 10 const afb_verb_t verbs[] = { 11 { .verb="hello", .callback=hello }, 12 { .verb=NULL } 13 }; 14 - 15 const afb_binding_v2 afbBindingV2 = { + 15 const afb_binding_t afbBindingExport = { 16 .api = "tuto-1", 17 .verbs = verbs 18 }; ``` -The structure **afbBindingV2** actually tells that: +The structure **afbBindingExport** actually tells that: - the exported **API** name is **tuto-1** (line 16) - the array of verbs is the above defined one -The exported list of verb is specified by an array of structures, -each describing a verb, ended with a verb NULL (line 12). +The exported list of verb is specified by an array of structures of +type **afb_verb_t**, each describing a verb, ended with a verb NULL (line 12). The only defined verb here (line 11) is named **hello** (field **.verb**) and the function that handle the related request is **hello** (field **.callback**). -Note that you can explicitly mark the fact that these are -struct by typing the **struct** as below: - -```C - 10 const struct afb_verb_v2 verbs[] = { - 11 { .verb="hello", .callback=hello }, - 12 { .verb=NULL } - 13 }; - 14 - 15 const struct afb_binding_v2 afbBindingV2 = { - 16 .api = "tuto-1", - 17 .verbs = verbs - 18 }; -``` - ### Handling binder's requests As shown above this is by default the common include directory where the AGL stuff is installed. ```C - 4 void hello(afb_req req) + 4 void hello(afb_req_t req) 5 { 6 AFB_REQ_DEBUG(req, "hello world"); - 7 afb_req_success(req, NULL, "hello world"); + 7 afb_req_reply(req, NULL, NULL, "hello world"); 8 } ``` @@ -241,18 +224,15 @@ with the argument **req** that handles the client request. The callback has to treat synchronously or asynchronously the request and should at the end emit a reply for the request. -Here, the callback for **tuto-1/hello** replies a successful answer -(line 7) to the request **req**. -The second parameter (here NULL) is a json object that is sent to the client with the reply. -The third parameter is also sent with the reply and is a string -called info that can be used as some meta data. +At the line 7, the callback for **tuto-1/hello** replies to the request **req**. +Parameters of the reply are: -Here again, you can explicitly mark the fact that -**afb_req** is a structure by declaring **hello** as below: + 1. The first parameter is the replied request + 2. The second parameter is a json object (here NULL) + 3. The third parameter is the error string indication (here NULL: no error) + 4. The fourth parameter is an informative string (that can be NULL) that can be used to provide meta data. -```C - 4 void hello(struct afb_req req) -``` +The 3 last parameters are sent back to the client as the reply content. <!-- pagebreak --> @@ -268,43 +248,43 @@ This is the code of the binding **tuto-2.c**: ```C 1 #include <string.h> 2 #include <json-c/json.h> - 3 - 4 #define AFB_BINDING_VERSION 2 + 3 + 4 #define AFB_BINDING_VERSION 3 5 #include <afb/afb-binding.h> - 6 - 7 afb_event event_login, event_logout; - 8 - 9 void login(afb_req req) + 6 + 7 afb_event_t event_login, event_logout; + 8 + 9 void login(afb_req_t req) 10 { 11 json_object *args, *user, *passwd; 12 char *usr; - 13 + 13 14 args = afb_req_json(req); 15 if (!json_object_object_get_ex(args, "user", &user) 16 || !json_object_object_get_ex(args, "password", &passwd)) { 17 AFB_REQ_ERROR(req, "login, bad request: %s", json_object_get_string(args)); - 18 afb_req_fail(req, "bad-request", NULL); + 18 afb_req_reply(req, NULL, "bad-request", NULL); 19 } else if (afb_req_context_get(req)) { 20 AFB_REQ_ERROR(req, "login, bad state, logout first"); - 21 afb_req_fail(req, "bad-state", NULL); + 21 afb_req_reply(req, NULL, "bad-state", NULL); 22 } else if (strcmp(json_object_get_string(passwd), "please")) { 23 AFB_REQ_ERROR(req, "login, unauthorized: %s", json_object_get_string(args)); - 24 afb_req_fail(req, "unauthorized", NULL); + 24 afb_req_reply(req, NULL, "unauthorized", NULL); 25 } else { 26 usr = strdup(json_object_get_string(user)); 27 AFB_REQ_NOTICE(req, "login user: %s", usr); 28 afb_req_session_set_LOA(req, 1); 29 afb_req_context_set(req, usr, free); - 30 afb_req_success(req, NULL, NULL); + 30 afb_req_reply(req, NULL, NULL, NULL); 31 afb_event_push(event_login, json_object_new_string(usr)); 32 } 33 } - 34 - 35 void action(afb_req req) + 34 + 35 void action(afb_req_t req) 36 { 37 json_object *args, *val; 38 char *usr; - 39 + 39 40 args = afb_req_json(req); 41 usr = afb_req_context_get(req); 42 AFB_REQ_NOTICE(req, "action for user %s: %s", usr, json_object_get_string(args)); @@ -319,46 +299,46 @@ This is the code of the binding **tuto-2.c**: 51 afb_req_unsubscribe(req, event_logout); 52 } 53 } - 54 afb_req_success(req, json_object_get(args), NULL); + 54 afb_req_reply(req, json_object_get(args), NULL, NULL); 55 } - 56 - 57 void logout(afb_req req) + 56 + 57 void logout(afb_req_t req) 58 { 59 char *usr; - 60 + 60 61 usr = afb_req_context_get(req); 62 AFB_REQ_NOTICE(req, "login user %s out", usr); 63 afb_event_push(event_logout, json_object_new_string(usr)); 64 afb_req_session_set_LOA(req, 0); 65 afb_req_context_clear(req); - 66 afb_req_success(req, NULL, NULL); + 66 afb_req_reply(req, NULL, NULL, NULL); 67 } - 68 - 69 int preinit() + 68 + 69 int preinit(afb_api_t api) 70 { - 71 AFB_NOTICE("preinit"); + 71 AFB_API_NOTICE(api, "preinit"); 72 return 0; 73 } - 74 - 75 int init() + 74 + 75 int init(afb_api_t api) 76 { - 77 AFB_NOTICE("init"); - 78 event_login = afb_daemon_make_event("login"); - 79 event_logout = afb_daemon_make_event("logout"); + 77 AFB_API_NOTICE(api, "init"); + 78 event_login = afb_api_make_event(api, "login"); + 79 event_logout = afb_api_make_event(api, "logout"); 80 if (afb_event_is_valid(event_login) && afb_event_is_valid(event_logout)) 81 return 0; - 82 AFB_ERROR("Can't create events"); + 82 AFB_API_ERROR(api, "Can't create events"); 83 return -1; 84 } - 85 - 86 const afb_verb_v2 verbs[] = { + 85 + 86 const afb_verb_t verbs[] = { 87 { .verb="login", .callback=login }, 88 { .verb="action", .callback=action, .session=AFB_SESSION_LOA_1 }, 89 { .verb="logout", .callback=logout, .session=AFB_SESSION_LOA_1 }, 90 { .verb=NULL } 91 }; - 92 - 93 const afb_binding_v2 afbBindingV2 = { + 92 + 93 const afb_binding_t afbBindingExport = { 94 .api = "tuto-2", 95 .specification = NULL, 96 .verbs = verbs, diff --git a/docs/afb-daemon-debugging.md b/docs/afb-daemon-debugging.md index dd5fd64b..4cf62bea 100644 --- a/docs/afb-daemon-debugging.md +++ b/docs/afb-daemon-debugging.md @@ -1,4 +1,4 @@ -# Debugging afb-daemon and its bindings +# Debugging binder and bindings When compiled with the symbol AGL_DEVEL defined, the ***binder*** understand the 2 configuration variables: diff --git a/docs/afb-daemon-vocabulary.md b/docs/afb-daemon-vocabulary.md index 6c51f124..efe53d20 100644 --- a/docs/afb-daemon-vocabulary.md +++ b/docs/afb-daemon-vocabulary.md @@ -24,10 +24,6 @@ assurance that the services can expect from the session. The exact definition of the meaning of these levels and how to use it remains to be achieved. -## Plugin - -Old name for binding, see binding. - ## Request A request is an invocation by a client to a binding method using a message @@ -51,7 +47,7 @@ It can serve many client. Each one attached to one session. The framework establishes connection between the services and the clients. -Using DBus currently but other protocols are considered. +Using sockets currently but other protocols are considered. ## Session diff --git a/docs/afb-migration-to-binding-v3.md b/docs/afb-migration-to-binding-v3.md new file mode 100644 index 00000000..8f1e678c --- /dev/null +++ b/docs/afb-migration-to-binding-v3.md @@ -0,0 +1,110 @@ +Migration to binding V3 +======================= + +The ***binding*** interface evolved from version 1 to version 2 +for the following reasons: + +- integration of the security requirements within the bindings +- simplification of the API (after developer feedbacks) +- removal of obscure features, cleanup + +The ***binder*** can run ***bindings*** v1, v2 and/or v3 in any combination. +Thus moving from v1 or v2 to v3 is not enforced at this time. But ... + +In the face to face meeting of Karlsruhe it was decided to remove support +of bindings v1 and to deprecate the use of bindings v2. + +So at the end, **IT IS HIGHLY NEEDED TO SWITCH TO VERSION 3** + +This guide covers the migration of bindings from version 2 to version 3. + +The migration from version 1 is not treated here because bindings version 1 +are very old and probably does not exist anymore. If needed you can refer +to the old [guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md). + + +Differences between version 2 and version 3 +------------------------------------------- + +### in v3 all is api + +The version 3 introduce the concept of "API" that gather what was called before +the daemon and the service. This is the new concept that predates the 2 others. + +The concept of API is intended to allow the definition of multiple APIs +by a same "binding" (a dynamically loaded library). + +Because there is potentially several "API", the functions that were without +context in bindings version 2 need now to tell what API is consumer. + +To be compatible with version 2, the bindings v3 still have a default hidden +context: the default API named **afbBindingV3root**. + +To summarize, the functions of class **daemon** and **service** use the default +hidden API. + +It is encouraged to avoid use of functions of class **daemon** and **service**. +You should replace these implicit calls to explicit **api** calls that +reference **afbBindingV3root**. + +Same thing for the logging macros: **AFB_ERROR**, **AFB_WARNING**, +**AFB_NOTICE**, **AFB_INFO**, **AFB_DEBUG** that becomes respectively +**AFB_API_ERROR**, **AFB_API_WARNING**, **AFB_API_NOTICE**, **AFB_API_INFO**, +**AFB_API_DEBUG**. + +Example of 2 equivalent writes: + +```C + AFB_NOTICE("send stress event"); + afb_daemon_broadcast_event(stressed_event, NULL); +``` + +or + +```C + AFB_API_NOTICE(afbBindingV3root, "send stress event"); + afb_api_broadcast_event(afbBindingV3root, stressed_event, NULL); +``` + +### the reply mechanism predates success and fail + +### subcall has more power + +Task list for the migration +--------------------------- + +This task list is: + +1. Use the automatic migration procedure described below +2. Adapt the init and preinit functions +3. Consider to change to use the new reply +4. Consider to change to use the new (sub)call + +The remaining chapters explain these task with more details. + +Automatic migration! +-------------------- + +A tiny **sed** script is intended to perform a first pass on the code that +you want to upgrade. It can be down using **curl** and applied using **sed** +as below. + +```bash +BASE=https://git.automotivelinux.org/src/app-framework-binder/tree +SED=migration-to-binding-v3.sed +curl -o $SED $BASE/docs/$SED +sed -i -f $SED file1 file2 file3... +``` + +This automatic action does most of the boring job nut not all the job. +The remaining of this guide explains the missing part. + +Adapt the init and preinit functions +------------------------------------ + +Consider to change to use the new reply +--------------------------------------- + +Consider to change to use the new (sub)call +------------------------------------------- + diff --git a/docs/afb-migration-v1-to-v2.md b/docs/afb-migration-v1-to-v2.md index f3182918..9a43454e 100644 --- a/docs/afb-migration-v1-to-v2.md +++ b/docs/afb-migration-v1-to-v2.md @@ -1,6 +1,11 @@ -Migration from binding V1 to binding V2 +[LEGACY] Migration from binding V1 to binding V2 ======================================= +> LEGACY!!! IT IS NOT EXPECTED THAT YOU STILL NEED THIS GUIDE. +> +> THIS GUIDE WILL BE REMOVED IN A NEAR FUTURE + + The ***binding*** interface evolved from version 1 to version 2 for the following reasons: diff --git a/docs/afb-overview.md b/docs/afb-overview.md index 0cff24cc..2682d8d1 100644 --- a/docs/afb-overview.md +++ b/docs/afb-overview.md @@ -6,14 +6,14 @@ the services that it needs. It provides a fast way to securely offer APIs to applications written in any language and running almost anywhere. -- The ***binder*** is developed for AGL. +- The ***binder*** is developed for AGL (Automotive Grade Linux) but it is not bound to AGL. - The ***binder*** is the usual name. - The binary is named **afb-daemon**. - The name **afb-daemon** stands for ***Application Framework Binder Daemon***. The word *daemon*, here, denote the fact that the ***binder*** makes witchcraft to -connect applications to their expected services. -(note: that usually the term of daemon denotes background process but not here). +connect applications to their expected services. (note: that usually the term of +daemon denotes background process but not here). Each ***binder*** **afb-daemon** is in charge to bind one instance of an application or service to the rest of the system, applications and services. diff --git a/docs/annexes.md b/docs/annexes.md index 2304bfb0..10952e0f 100644 --- a/docs/annexes.md +++ b/docs/annexes.md @@ -1,4 +1,7 @@ # Annexes +* [Migration to binding v3](afb-migration-to-binding-v3.md) +* [Options of afb-daemon](afb-daemon-options.md) * [Installing the binder on a desktop](afb-desktop-package.md) -* [Options of afb-daemon](afb-daemon-options.md)
\ No newline at end of file +* [Debugging afb-daemon](afb-daemon-debugging.md) +* [(LEGACY) guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md). diff --git a/docs/migration-to-binding-v3.sed b/docs/migration-to-binding-v3.sed new file mode 100644 index 00000000..a6682051 --- /dev/null +++ b/docs/migration-to-binding-v3.sed @@ -0,0 +1,68 @@ +####################################################################################### +# Script sed for migrating from AFB_BINDING_VERSION 2 to AFB_BINDING_VERSION 3 +# See http://docs.automotivelinux.org/docs/apis_services/en/dev/reference/af-binder/afb-migration-to-ibinding-v3.html +####################################################################################### +# update the version +# ------------------ +s:\(\<AFB_BINDING_VERSION[[:blank:]]\{1,\}\)2\>:\13: + +# update common types +# ------------------- +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_req\>:afb_req_t:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_event\>:afb_event_t:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_verb_v2\>:afb_verb_t:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_binding_v2\>:afb_binding_t:g + +# update common names +# ------------------- +s:\<afbBindingV2\>:afbBindingExport:g + +# very special +# ------------ +s:( *afb_req_t *) *{ *NULL *, *NULL *}:NULL:g + +# special dynapi +# -------------- +s:\(\<AFB_BINDING_VERSION[[:blank:]]\{1,\}\)0\>:\13: +/^[[:blank:]]*# *define *\<AFB_BINDING_WANT_DYNAPI\>/d +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_dynapi\>\([[:blank:]]*\)\*:afb_api_t\2:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_request\>\([[:blank:]]*\)\*:afb_req_t\2:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_eventid\>\([[:blank:]]*\)\*:afb_event_t\2:g +s:\<afb_request_:afb_req_:g +s:\<afb_dynapi_:afb_api_:g +s:\<afb_eventid_:afb_event_:g +s:\<AFB_DYNAPI_:AFB_API_:g +s:\<AFB_REQUEST_:AFB_REQ_:g +s:\<afbBindingVdyn\>:afbBindingV3entry:g +s:\<dynapi\>:api:g +s:\<eventid\>:event:g +s:\<afb_api_make_eventid\>:afb_api_make_event:g +s:\<afb_api_new_api\>:-!&:g +s:\<afb_api_sub_verb\>:afb_api_del_verb:g + +# udate legacy calls +# ------------------ +s:\<afb_req_subcall\(_req\)\>:afb_req_subcall_legacy:g +s:\<afb_req_subcall_sync\>:afb_req_subcall_sync_legacy:g +s:\<afb_api_call\>:afb_api_call_legacy:g +s:\<afb_api_call_sync\>:afb_api_call_sync_legacy:g +s:\<afb_req_store\>:afb_req_addref:g +s:\<afb_req_unstore\> *( *\(.*\) *):\1:g +s:\<afb_daemon_\([a-z_0-9]* *(\):afb_api_\1afbBindingV3root,:g +s:\<afb_daemon_\([a-z_0-9]* *(\):afb_api_\1afbBindingV3root,:g +s:\<afb_service_call_\([a-z_0-9]*\)\( *(\):afb_api_\1_legacy\2afbBindingV3root,:g +s:\<afb_service_\([a-z_0-9]* *(\):afb_api_\1afbBindingV3root,:g +s:\<AFB_\(\(ERROR\|WARNING\|NOTICE\|INFO\|DEBUG\)\> *(\):AFB_API_\1afbBindingV3root,:g + +# special app-controller +# ---------------------- +s:\<_\(AFB_SYSLOG_LEVEL_[A-Z]*\)_\>:\1:g + +# UNSAFES (uncomment it if optimistic) +# -------------- +#s:\<afb_req_fail\(_[fv]\)\{0,1\}\>\( *([^,]*\):afb_req_reply\1\2, NULL:g +#s:\<afb_req_success\(_[fv]\)\{0,1\}\>\( *([^,]*,[^,]*\):afb_req_reply\1\2, NULL:g +# +#s:\<afb_api_add_verb\>[^)]*:&, 0:g ;# dynapi +#s:\<afb_api_del_verb\>[^)]*:&, NULL:g ;# dynapi +####################################################################################### diff --git a/doxyfile.binder b/doxyfile.binder new file mode 100644 index 00000000..4aef9a15 --- /dev/null +++ b/doxyfile.binder @@ -0,0 +1,2435 @@ +# Doxyfile 1.8.13 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "AGL micro-service binder" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./docs/binder + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = YES + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = YES + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = NO + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ./include \ + ./src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = *.c \ + *.cxx \ + *.cpp \ + *.h \ + *.hxx \ + *.hpp \ + *.md + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = bindings/tutorial + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = NO + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 30 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 150 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 150 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: https://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: https://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = ../app-framework-binder/include + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = __attribute__(x)= \ + AFB_BINDING_VERSION=3 + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/doxyfile.binding b/doxyfile.binding new file mode 100644 index 00000000..78841591 --- /dev/null +++ b/doxyfile.binding @@ -0,0 +1,2434 @@ +# Doxyfile 1.8.13 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "AGL micro-service API for bindings" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./docs/binding + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = YES + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = YES + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = NO + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ./include + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = *.c \ + *.cxx \ + *.cpp \ + *.h \ + *.hxx \ + *.hpp \ + *.md + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = bindings/tutorial + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = NO + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 130 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 100 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: https://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: https://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = ../app-framework-binder/include + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = __attribute__(x)= \ + AFB_BINDING_VERSION=3 + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/include/afb/afb-api-x3-itf.h b/include/afb/afb-api-x3-itf.h new file mode 100644 index 00000000..38b29196 --- /dev/null +++ b/include/afb/afb-api-x3-itf.h @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/* declared here */ +struct afb_api_x3; +struct afb_api_x3_itf; + +/* referenced here */ +struct sd_event; +struct sd_bus; +struct afb_req_x2; +struct afb_event_x2; +struct afb_auth; +struct afb_verb_v2; +struct afb_verb_v3; + +/** + * Structure for the APIv3 + */ +struct afb_api_x3 +{ + /** + * Interface functions + * + * Don't use it directly, prefer helper functions. + */ + const struct afb_api_x3_itf *itf; + + /** + * The name of the api + * + * @see afb_api_x3_name + */ + const char *apiname; + + /** + * User defined data + * + * @see afb_api_x3_set_userdata + * @see afb_api_x3_get_userdata + */ + void *userdata; + + /** + * Current verbosity mask + * + * The bits tells what verbosity is required for the api. + * It is related to the syslog levels. + * + * EMERGENCY 0 System is unusable + * ALERT 1 Action must be taken immediately + * CRITICAL 2 Critical conditions + * ERROR 3 Error conditions + * WARNING 4 Warning conditions + * NOTICE 5 Normal but significant condition + * INFO 6 Informational + * DEBUG 7 Debug-level messages + */ + int logmask; +}; + +/** + * Definition of the function's interface for the APIv3 + */ +struct afb_api_x3_itf +{ + /* CAUTION: respect the order, add at the end */ + + /** sending log messages */ + void (*vverbose)( + struct afb_api_x3 *api, + int level, + const char *file, + int line, + const char * func, + const char *fmt, + va_list args); + + /** gets the common systemd's event loop */ + struct sd_event *(*get_event_loop)( + struct afb_api_x3 *api); + + /** gets the common systemd's user d-bus */ + struct sd_bus *(*get_user_bus)( + struct afb_api_x3 *api); + + /** gets the common systemd's system d-bus */ + struct sd_bus *(*get_system_bus)( + struct afb_api_x3 *api); + + /** get the file descriptor for the root directory */ + int (*rootdir_get_fd)( + struct afb_api_x3 *api); + + /** get a file using locale setting */ + int (*rootdir_open_locale)( + struct afb_api_x3 *api, + const char *filename, + int flags, + const char *locale); + + /** queue a job */ + int (*queue_job)( + struct afb_api_x3 *api, + void (*callback)(int signum, void *arg), + void *argument, + void *group, + int timeout); + + /** requires an api initialized or not */ + int (*require_api)( + struct afb_api_x3 *api, + const char *name, + int initialized); + + /** add an alias */ + int (*add_alias)( + struct afb_api_x3 *api, + const char *name, + const char *as_name); + + /** broadcasts event 'name' with 'object' */ + int (*event_broadcast)( + struct afb_api_x3 *api, + const char *name, + struct json_object *object); + + /** creates an event of 'name' */ + struct afb_event_x2 *(*event_make)( + struct afb_api_x3 *api, + const char *name); + + /** legacy asynchronous invocation */ + void (*legacy_call)( + struct afb_api_x3 *api, + const char *apiname, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *), + void *closure); + + /** legacy synchronous invocation */ + int (*legacy_call_sync)( + struct afb_api_x3 *api, + const char *apiname, + const char *verb, + struct json_object *args, + struct json_object **result); + + /** creation of a new api*/ + struct afb_api_x3 *(*api_new_api)( + struct afb_api_x3 *api, + const char *apiname, + const char *info, + int noconcurrency, + int (*preinit)(void*, struct afb_api_x3 *), + void *closure); + + /** set verbs of the api using v2 description */ + int (*api_set_verbs_v2)( + struct afb_api_x3 *api, + const struct afb_verb_v2 *verbs); + + /** add one verb to the api */ + int (*api_add_verb)( + struct afb_api_x3 *api, + const char *verb, + const char *info, + void (*callback)(struct afb_req_x2 *req), + void *vcbdata, + const struct afb_auth *auth, + uint32_t session, + int glob); + + /** delete one verb of the api */ + int (*api_del_verb)( + struct afb_api_x3 *api, + const char *verb, + void **vcbdata); + + /** set the api's callback for processing events */ + int (*api_set_on_event)( + struct afb_api_x3 *api, + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object)); + + /** set the api's callback for initialisation */ + int (*api_set_on_init)( + struct afb_api_x3 *api, + int (*oninit)(struct afb_api_x3 *api)); + + /** seal the api */ + void (*api_seal)( + struct afb_api_x3 *api); + + /** set verbs of the api using v3 description */ + int (*api_set_verbs_v3)( + struct afb_api_x3 *api, + const struct afb_verb_v3 *verbs); + + /** add an event handler for the api */ + int (*event_handler_add)( + struct afb_api_x3 *api, + const char *pattern, + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*), + void *closure); + + /** delete an event handler of the api */ + int (*event_handler_del)( + struct afb_api_x3 *api, + const char *pattern, + void **closure); + + /** asynchronous call for the api */ + void (*call)( + struct afb_api_x3 *api, + const char *apiname, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_api_x3 *), + void *closure); + + /** synchronous call for the api */ + int (*call_sync)( + struct afb_api_x3 *api, + const char *apiname, + const char *verb, + struct json_object *args, + struct json_object **result, + char **error, + char **info); + + /** indicate provided classes of the api */ + int (*class_provide)( + struct afb_api_x3 *api, + const char *name); + + /** indicate required classes of the api */ + int (*class_require)( + struct afb_api_x3 *api, + const char *name); + + /** delete the api */ + int (*delete_api)( + struct afb_api_x3 *api); +}; + diff --git a/include/afb/afb-api-x3.h b/include/afb/afb-api-x3.h new file mode 100644 index 00000000..81323ef5 --- /dev/null +++ b/include/afb/afb-api-x3.h @@ -0,0 +1,884 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "afb-verbosity.h" +#include "afb-api-x3-itf.h" + +/** + * Get the name of the 'api'. + * + * @param api the api whose name is to be returned + * + * @return the name of the api. + * + * The returned value must not be changed nor freed. + */ +static inline +const char *afb_api_x3_name(struct afb_api_x3 *api) +{ + return api->apiname; +} + +/** + * Get the "userdata" pointer of the 'api' + * + * @param api the api whose user's data is to be returned + * + * @return the user's data pointer of the api. + * + * @see afb_api_x3_set_userdata + */ +static inline +void *afb_api_x3_get_userdata(struct afb_api_x3 *api) +{ + return api->userdata; +} + +/** + * Set the "userdata" pointer of the 'api' to 'value' + * + * @param api the api whose user's data is to be set + * @param value the data to set + * + * @see afb_api_x3_get_userdata + */ +static inline +void afb_api_x3_set_userdata(struct afb_api_x3 *api, void *value) +{ + api->userdata = value; +} + +/** + * Is the log message of 'level (as defined for syslog) required for the api? + * + * @param api the api to check + * @param level the level to check as defined for syslog: + * + * EMERGENCY 0 System is unusable + * ALERT 1 Action must be taken immediately + * CRITICAL 2 Critical conditions + * ERROR 3 Error conditions + * WARNING 4 Warning conditions + * NOTICE 5 Normal but significant condition + * INFO 6 Informational + * DEBUG 7 Debug-level messages + * + * @return 0 if not required or a value not null if required + * + * @see syslog + */ +static inline +int afb_api_x3_wants_log_level(struct afb_api_x3 *api, int level) +{ + return AFB_SYSLOG_MASK_WANT(api->logmask, level); +} + +/** + * Send to the journal with the log 'level' a message described + * by 'fmt' applied to the va-list 'args'. + * + * 'file', 'line' and 'func' are indicators of position of the code in source files + * (see macros __FILE__, __LINE__ and __func__). + * + * 'level' is defined by syslog standard: + * + * EMERGENCY 0 System is unusable + * ALERT 1 Action must be taken immediately + * CRITICAL 2 Critical conditions + * ERROR 3 Error conditions + * WARNING 4 Warning conditions + * NOTICE 5 Normal but significant condition + * INFO 6 Informational + * DEBUG 7 Debug-level messages + * + * @param api the api that collects the logging message + * @param level the level of the message + * @param file the source file that logs the messages or NULL + * @param line the line in the source file that logs the message + * @param func the name of the function in the source file that logs + * @param fmt the format of the message as in printf + * @param args the arguments to the format string of the message as a va_list + * + * @see syslog + * @see printf + */ +static inline +void afb_api_x3_vverbose(struct afb_api_x3 *api, int level, const char *file, int line, const char *func, const char *fmt, va_list args) +{ + api->itf->vverbose(api, level, file, line, func, fmt, args); +} + +/** + * Send to the journal with the log 'level' a message described + * by 'fmt' and following parameters. + * + * 'file', 'line' and 'func' are indicators of position of the code in source files + * (see macros __FILE__, __LINE__ and __func__). + * + * 'level' is defined by syslog standard: + * EMERGENCY 0 System is unusable + * ALERT 1 Action must be taken immediately + * CRITICAL 2 Critical conditions + * ERROR 3 Error conditions + * WARNING 4 Warning conditions + * NOTICE 5 Normal but significant condition + * INFO 6 Informational + * DEBUG 7 Debug-level messages + * + * @param api the api that collects the logging message + * @param level the level of the message + * @param file the source file that logs the messages or NULL + * @param line the line in the source file that logs the message + * @param func the name of the function in the source file that logs + * @param fmt the format of the message as in printf + * @param ... the arguments to the format string of the message + * + * @see syslog + * @see printf + */ +__attribute__((format(printf, 6, 7))) +static inline +void afb_api_x3_verbose( + struct afb_api_x3 *api, + int level, + const char *file, + int line, + const char *func, + const char *fmt, + ...) +{ + va_list args; + va_start(args, fmt); + api->itf->vverbose(api, level, file, line, func, fmt, args); + va_end(args); +} + +/** + * Retrieves the common systemd's event loop of AFB + * + * @param api the api that uses the event loop + * + * @return the systemd event loop if active, NULL otherwise + * + * @see afb_api_x3_get_user_bus + * @see afb_api_x3_get_system_bus + */ +static inline +struct sd_event *afb_api_x3_get_event_loop(struct afb_api_x3 *api) +{ + return api->itf->get_event_loop(api); +} + +/** + * Retrieves the common systemd's user/session d-bus of AFB + * + * @param api the api that uses the user dbus + * + * @return the systemd user connection to dbus if active, NULL otherwise + * + * @see afb_api_x3_get_event_loop + * @see afb_api_x3_get_system_bus + */ +static inline +struct sd_bus *afb_api_x3_get_user_bus(struct afb_api_x3 *api) +{ + return api->itf->get_user_bus(api); +} + +/** + * Retrieves the common systemd's system d-bus of AFB + * + * @param api the api that uses the system dbus + * + * @return the systemd system connection to dbus if active, NULL otherwise + * + * @see afb_api_x3_get_event_loop + * @see afb_api_x3_get_user_bus + */ + +static inline +struct sd_bus *afb_api_x3_get_system_bus(struct afb_api_x3 *api) +{ + return api->itf->get_system_bus(api); +} + +/** + * Get the root directory file descriptor. This file descriptor can + * be used with functions 'openat', 'fstatat', ... + * + * CAUTION, manipulate this this descriptor with care, in particular, don't close + * it. + * + * This can be used to get the path of the root directory using: + * + * ```C + * char buffer[MAX_PATH]; + * int dirfd = afb_api_x3_rootdir_get_fd(api); + * snprintf(buffer, sizeof buffer, "/proc/self/fd/%d", dirfd); + * readlink(buffer, buffer, sizeof buffer); + * ``` + * + * But note that within AGL this is the value given by the environment variable + * AFM_APP_INSTALL_DIR. + * + * @param api the api that uses the directory file descriptor + * + * @return the file descriptor of the root directory. + * + * @see afb_api_x3_rootdir_open_locale + */ +static inline +int afb_api_x3_rootdir_get_fd(struct afb_api_x3 *api) +{ + return api->itf->rootdir_get_fd(api); +} + +/** + * Opens 'filename' within the root directory with 'flags' (see function openat) + * using the 'locale' definition (example: "jp,en-US") that can be NULL. + * + * The filename must be relative to the root of the bindings. + * + * The opening mode must be for read or write but not for O_CREAT. + * + * The definition of locales and of how files are searched can be checked + * here: https://www.w3.org/TR/widgets/#folder-based-localization + * and https://tools.ietf.org/html/rfc7231#section-5.3.5 + * + * @param api the api that queries the file + * @param filename the relative path to the file to open + * @param flags the flags for opening as for C function 'open' + * @param locale string indicating how to search content, can be NULL + * + * @return the file descriptor or -1 in case of error and errno is set with the + * error indication. + * + * @see open + * @see afb_api_x3_rootdir_get_fd + */ +static inline +int afb_api_x3_rootdir_open_locale(struct afb_api_x3 *api, const char *filename, int flags, const char *locale) +{ + return api->itf->rootdir_open_locale(api, filename, flags, locale); +} + +/** + * Queue the job defined by 'callback' and 'argument' for being executed asynchronously + * in this thread (later) or in an other thread. + * + * If 'group' is not NULL, the jobs queued with a same value (as the pointer value 'group') + * are executed in sequence in the order of there submission. + * + * If 'timeout' is not 0, it represent the maximum execution time for the job in seconds. + * At first, the job is called with 0 as signum and the given argument. + * + * The job is executed with the monitoring of its time and some signals like SIGSEGV and + * SIGFPE. When a such signal is catched, the job is terminated and reexecuted but with + * signum being the signal number (SIGALRM when timeout expired). + * + * When executed, the callback function receives 2 arguments: + * + * - int signum: the signal catched if any or zero at the beginning + * - void *arg: the parameter 'argument' + * + * A typical implmentation of the job callback is: + * + * ```C + * void my_job_cb(int signum, void *arg) + * { + * struct myarg_t *myarg = arg; + * if (signum) + * AFB_API_ERROR(myarg->api, "job interupted with signal %s", strsignal(signum)); + * else + * really_do_my_job(myarg); + * } + * ``` + * + * @param api the api that queue the job + * @param callback the job as a callback function + * @param argument the argument to pass to the queued job + * @param group the group of the job, NULL if no group + * @param timeout the timeout of execution of the job + * + * @return 0 in case of success or -1 in case of error with errno set appropriately. + */ +static inline +int afb_api_x3_queue_job(struct afb_api_x3 *api, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) +{ + return api->itf->queue_job(api, callback, argument, group, timeout); +} + +/** + * Tells that it requires the API of "name" to exist + * and if 'initialized' is not null to be initialized. + * Calling this function is only allowed within init. + * + * A single request allows to require multiple apis. + * + * @param api the api that requires the other api by its name + * @param name a space separated list of the names of the required api + * @param initialized if zero, the api is just required to exist. If not zero, + * the api is required to exist and to be initialized. + * + * @return 0 in case of success or -1 in case of error with errno set appropriately. + */ +static inline +int afb_api_x3_require_api(struct afb_api_x3 *api, const char *name, int initialized) +{ + return api->itf->require_api(api, name, initialized); +} + +/** + * Create an aliased name 'as_name' for the api 'name'. + * Calling this function is only allowed within preinit. + * + * @param api the api that requires the aliasing + * @param name the api to alias + * @param as_name the aliased name of the aliased api + * + * @return 0 in case of success or -1 in case of error with errno set appropriately. + */ +static inline +int afb_api_x3_add_alias(struct afb_api_x3 *api, const char *name, const char *as_name) +{ + return api->itf->add_alias(api, name, as_name); +} + +/** + * Broadcasts widely the event of 'name' with the data 'object'. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * Calling this function is only forbidden during preinit. + * + * The event sent as the name API/name where API is the name of the + * api. + * + * @param api the api that broadcast the event + * @param name the event name suffix + * @param object the object that comes with the event + * + * @return the count of clients that received the event. + */ +static inline +int afb_api_x3_broadcast_event(struct afb_api_x3 *api, const char *name, struct json_object *object) +{ + return api->itf->event_broadcast(api, name, object); +} + +/** + * Creates an event of 'name' and returns it. + * + * Calling this function is only forbidden during preinit. + * + * See afb_event_is_valid to check if there is an error. + * + * The event created as the name API/name where API is the name of the + * api. + * + * @param api the api that creates the event + * @param name the event name suffix + * + * @return the created event. Use the function afb_event_is_valid to check + * whether the event is valid (created) or not (error as reported by errno). + * + * @see afb_event_is_valid + */ +static inline +struct afb_event_x2 *afb_api_x3_make_event_x2(struct afb_api_x3 *api, const char *name) +{ + return api->itf->event_make(api, name); +} + +/** + * @deprecated try to use @ref afb_api_x3_call instead + * + * * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. + * The result of the call is delivered to the 'callback' function with the 'callback_closure'. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * The 'callback' receives 3 arguments: + * 1. 'closure' the user defined closure pointer 'closure', + * 2. 'status' a status being 0 on success or negative when an error occurred, + * 2. 'result' the resulting data as a JSON object. + * + * @param api The api + * @param apiname The api name of the method to call + * @param verb The verb name of the method to call + * @param args The arguments to pass to the method + * @param callback The to call on completion + * @param closure The closure to pass to the callback + * + * @see also 'afb_api_call' + * @see also 'afb_api_call_sync' + * @see also 'afb_api_call_sync_legacy' + * @see also 'afb_req_subcall' + * @see also 'afb_req_subcall_sync' + */ +static inline +void afb_api_x3_call_legacy( + struct afb_api_x3 *api, + const char *apiname, + const char *verb, + struct json_object *args, + void (*callback)(void *closure, int status, struct json_object *result, struct afb_api_x3 *api), + void *closure) +{ + api->itf->legacy_call(api, apiname, verb, args, callback, closure); +} + +/** + * @deprecated try to use @ref afb_api_x3_call_sync instead + * + * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. + * 'result' will receive the response. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param api The api + * @param apiname The api name of the method to call + * @param verb The verb name of the method to call + * @param args The arguments to pass to the method + * @param result Where to store the result - should call json_object_put on it - + * + * @returns 0 in case of success or a negative value in case of error. + * + * @see also 'afb_api_call' + * @see also 'afb_api_call_sync' + * @see also 'afb_api_call_legacy' + * @see also 'afb_req_subcall' + * @see also 'afb_req_subcall_sync' + */ +static inline +int afb_api_x3_call_sync_legacy( + struct afb_api_x3 *api, + const char *apiname, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + return api->itf->legacy_call_sync(api, apiname, verb, args, result); +} + +/** + * Creates a new api of name 'apiname' briefly described by 'info' (that can + * be NULL). + * + * When the pre-initialization function is given, it is a function that + * receives 2 parameters: + * + * - the closure as given in the call + * - the created api that can be initialised + * + * This pre-initialization function must return a negative value to abort + * the creation of the api. Otherwise, it returns a non-negative value to + * continue. + * + * @param api the api that creates the other one + * @param apiname the name of the new api + * @param info the brief description of the new api (can be NULL) + * @param noconcurrency zero or not zero whether the new api is reentrant or not + * @param preinit the pre-initialization function if any (can be NULL) + * @param closure the closure for the pre-initialization \ref preinit + * + * @return 0 in case of success or -1 on failure with errno set + * + * @see afb_api_x3_delete_api + */ +static inline +struct afb_api_x3 *afb_api_x3_new_api( + struct afb_api_x3 *api, + const char *apiname, + const char *info, + int noconcurrency, + int (*preinit)(void*, struct afb_api_x3 *), + void *closure) +{ + return api->itf->api_new_api(api, apiname, info, noconcurrency, preinit, closure); +} + +/** + * @deprecated use @ref afb_api_x3_set_verbs_v3 instead + * + * Set the verbs of the 'api' using description of verbs of the api v2 + * + * @param api the api that will get the verbs + * @param verbs the array of verbs to add terminated with an item with name=NULL + * + * @return 0 in case of success or -1 on failure with errno set + * + * @see afb_verb_v2 + * @see afb_api_x3_add_verb + * @see afb_api_x3_set_verbs_v3 + */ +static inline +int afb_api_x3_set_verbs_v2( + struct afb_api_x3 *api, + const struct afb_verb_v2 *verbs) +{ + return api->itf->api_set_verbs_v2(api, verbs); +} + +/** + * Add one verb to the dynamic set of the api + * + * @param api the api to change + * @param verb name of the verb + * @param info brief description of the verb, can be NULL + * @param callback callback function implementing the verb + * @param vcbdata data for the verb callback, available through req + * @param auth required authorization, can be NULL + * @param session authorization and session requirements of the verb + * @param glob is the verb glob name + * + * @return 0 in case of success or -1 on failure with errno set + * + * @see afb_verb_v3 + * @see afb_api_x3_del_verb + * @see afb_api_x3_set_verbs_v3 + * @see fnmatch for matching names using glob + */ +static inline +int afb_api_x3_add_verb( + struct afb_api_x3 *api, + const char *verb, + const char *info, + void (*callback)(struct afb_req_x2 *req), + void *vcbdata, + const struct afb_auth *auth, + uint32_t session, + int glob) +{ + return api->itf->api_add_verb(api, verb, info, callback, vcbdata, auth, session, glob); +} + +/** + * Delete one verb from the dynamic set of the api + * + * @param api the api to change + * @param verb name of the verb to delete + * @param vcbdata if not NULL will receive the vcbdata of the deleted verb + * + * @return 0 in case of success or -1 on failure with errno set + * + * @see afb_api_x3_add_verb + */ +static inline +int afb_api_x3_del_verb( + struct afb_api_x3 *api, + const char *verb, + void **vcbdata) +{ + return api->itf->api_del_verb(api, verb, vcbdata); +} + +/** + * Set the callback 'onevent' to process events in the name of the 'api'. + * + * This setting can be done statically using the global variable + * @ref afbBindingV3. + * + * This function replace any previously global event callback set. + * + * When an event is received, the callback 'onevent' is called with 3 parameters + * + * - the api that recorded the event handler + * - the full name of the event + * - the companion JSON object of the event + * + * @param api the api that wants to process events + * @param onevent the callback function that will process events (can be NULL + * to remove event callback) + * + * @return 0 in case of success or -1 on failure with errno set + * + * @see afbBindingV3 + * @see afb_binding_v3 + * @see afb_api_x3_event_handler_add + * @see afb_api_x3_event_handler_del + */ +static inline +int afb_api_x3_on_event( + struct afb_api_x3 *api, + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object)) +{ + return api->itf->api_set_on_event(api, onevent); +} + +/** + * Set the callback 'oninit' to process initialization of the 'api'. + * + * This setting can be done statically using the global variable + * @ref afbBindingV3 + * + * This function replace any previously initialization callback set. + * + * This function is only valid during the pre-initialization stage. + * + * The callback initialization function will receive one argument: the api + * to initialize. + * + * @param api the api that wants to process events + * @param oninit the callback function that initialize the api + * + * @return 0 in case of success or -1 on failure with errno set + * + * @see afbBindingV3 + * @see afb_binding_v3 + */ +static inline +int afb_api_x3_on_init( + struct afb_api_x3 *api, + int (*oninit)(struct afb_api_x3 *api)) +{ + return api->itf->api_set_on_init(api, oninit); +} + +/** + * Seal the api. After a call to this function the api can not be modified + * anymore. + * + * @param api the api to be sealed + */ +static inline +void afb_api_x3_seal( + struct afb_api_x3 *api) +{ + api->itf->api_seal(api); +} + +/** + * Set the verbs of the 'api' using description of verbs of the api v2 + * + * @param api the api that will get the verbs + * @param verbs the array of verbs to add terminated with an item with name=NULL + * + * @return 0 in case of success or -1 on failure with errno set + * + * @see afb_verb_v3 + * @see afb_api_x3_add_verb + * @see afb_api_x3_del_verb + */ +static inline +int afb_api_x3_set_verbs_v3( + struct afb_api_x3 *api, + const struct afb_verb_v3 *verbs) +{ + return api->itf->api_set_verbs_v3(api, verbs); +} + +/** + * Add a specific event handler for the api + * + * The handler callback is called when an event matching the given pattern + * is received (it is received if broadcasted or after subscription through + * a call or a subcall). + * + * The handler callback receive 4 arguments: + * + * - the closure given here + * - the event full name + * - the companion JSON object of the event + * - the api that subscribed the event + * + * @param api the api that creates the handler + * @param pattern the global pattern of the event to handle + * @param callback the handler callback function + * @param closure the closure of the handler + * + * @return 0 in case of success or -1 on failure with errno set + * + * @see afb_api_x3_on_event + * @see afb_api_x3_event_handler_del + */ +static inline +int afb_api_x3_event_handler_add( + struct afb_api_x3 *api, + const char *pattern, + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*), + void *closure) +{ + return api->itf->event_handler_add(api, pattern, callback, closure); +} + +/** + * Delete a specific event handler for the api + * + * @param api the api that the handler belongs to + * @param pattern the global pattern of the handler to remove + * @param closure if not NULL it will receive the closure set to the handler + * + * @return 0 in case of success or -1 on failure with errno set + * + * @see afb_api_x3_on_event + * @see afb_api_x3_event_handler_add + */ +static inline +int afb_api_x3_event_handler_del( + struct afb_api_x3 *api, + const char *pattern, + void **closure) +{ + return api->itf->event_handler_del(api, pattern, closure); +} + +/** + * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. + * The result of the call is delivered to the 'callback' function with the 'callback_closure'. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * The 'callback' receives 5 arguments: + * 1. 'closure' the user defined closure pointer 'closure', + * 2. 'object' a JSON object returned (can be NULL) + * 3. 'error' a string not NULL in case of error but NULL on success + * 4. 'info' a string handling some info (can be NULL) + * 5. 'api' the api + * + * @param api The api that makes the call + * @param apiname The api name of the method to call + * @param verb The verb name of the method to call + * @param args The arguments to pass to the method + * @param callback The to call on completion + * @param closure The closure to pass to the callback + * + * + * @see afb_req_subcall + * @see afb_req_subcall_sync + * @see afb_api_x3_call_sync + */ +static inline +void afb_api_x3_call( + struct afb_api_x3 *api, + const char *apiname, + const char *verb, + struct json_object *args, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_api_x3 *api), + void *closure) +{ + api->itf->call(api, apiname, verb, args, callback, closure); +} + +/** + * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. + * 'result' will receive the response. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param api The api that makes the call + * @param apiname The api name of the method to call + * @param verb The verb name of the method to call + * @param args The arguments to pass to the method + * @param object Where to store the returned object - should call json_object_put on it - can be NULL + * @param error Where to store the copied returned error - should call free on it - can be NULL + * @param info Where to store the copied returned info - should call free on it - can be NULL + * + * @returns 0 in case of success or a negative value in case of error. + * + * @see afb_req_subcall + * @see afb_req_subcall_sync + * @see afb_api_x3_call + */ +static inline +int afb_api_x3_call_sync( + struct afb_api_x3 *api, + const char *apiname, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info) +{ + return api->itf->call_sync(api, apiname, verb, args, object, error, info); +} + +/** + * Tells that the api provides a class of features. Classes are intended to + * allow ordering of initializations: apis that provides a given class are + * initialized before apis requiring it. + * + * This function is only valid during the pre-initialization stage. + * + * @param api the api that provides the classes + * @param name a space separated list of the names of the provided classes + * + * @returns 0 in case of success or a negative value in case of error. + * + * @see afb_api_x3_require_class + */ +static inline +int afb_api_x3_provide_class( + struct afb_api_x3 *api, + const char *name) +{ + return api->itf->class_provide(api, name); +} + +/** + * Tells that the api requires a set of class features. Classes are intended to + * allow ordering of initializations: apis that provides a given class are + * initialized before apis requiring it. + * + * This function is only valid during the pre-initialization stage. + * + * @param api the api that requires the classes + * @param name a space separated list of the names of the requireded classes + * + * @returns 0 in case of success or a negative value in case of error. + * + * @see afb_api_x3_provide_class + */ +static inline +int afb_api_x3_require_class( + struct afb_api_x3 *api, + const char *name) +{ + return api->itf->class_require(api, name); +} + +/** + * Delete the given api. + * + * It is of the responsibility of the caller to don't used the deleted api + * anymore after this function returned. + * + * @param api the api to delete + * + * @returns 0 in case of success or a negative value in case of error. + * + * @see afb_api_x3_new_api + */ +static inline +int afb_api_x3_delete_api( + struct afb_api_x3 *api) +{ + return api->itf->delete_api(api); +} diff --git a/include/afb/afb-arg.h b/include/afb/afb-arg.h new file mode 100644 index 00000000..de3fb9b5 --- /dev/null +++ b/include/afb/afb-arg.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/** + * Describes an argument (or parameter) of a request. + * + * @see afb_req_get + */ +struct afb_arg +{ + const char *name; /**< name of the argument or NULL if invalid */ + const char *value; /**< string representation of the value of the argument */ + /**< original filename of the argument if path != NULL */ + const char *path; /**< if not NULL, path of the received file for the argument */ + /**< when the request is finalized this file is removed */ +}; + diff --git a/include/afb/afb-auth.h b/include/afb/afb-auth.h index da4f8be8..3ce78666 100644 --- a/include/afb/afb-auth.h +++ b/include/afb/afb-auth.h @@ -17,29 +17,58 @@ #pragma once -/* - * Enum for Session/Token/Assurance middleware. +/** + * Enumeration for authority (Session/Token/Assurance) definitions. + * + * @see afb_auth */ enum afb_auth_type { - afb_auth_No = 0, /** never authorized, no data */ - afb_auth_Token, /** authorized if token valid, no data */ - afb_auth_LOA, /** authorized if LOA greater than data 'loa' */ - afb_auth_Permission, /** authorized if permission 'text' is granted */ - afb_auth_Or, /** authorized if 'first' or 'next' is authorized */ - afb_auth_And, /** authorized if 'first' and 'next' are authorized */ - afb_auth_Not, /** authorized if 'first' is not authorized */ - afb_auth_Yes /** always authorized, no data */ + /** never authorized, no data */ + afb_auth_No = 0, + + /** authorized if token valid, no data */ + afb_auth_Token, + + /** authorized if LOA greater than data 'loa' */ + afb_auth_LOA, + + /** authorized if permission 'text' is granted */ + afb_auth_Permission, + + /** authorized if 'first' or 'next' is authorized */ + afb_auth_Or, + + /** authorized if 'first' and 'next' are authorized */ + afb_auth_And, + + /** authorized if 'first' is not authorized */ + afb_auth_Not, + + /** always authorized, no data */ + afb_auth_Yes }; +/** + * Definition of an authorization entry + */ struct afb_auth { + /** type of entry @see afb_auth_type */ enum afb_auth_type type; + union { + /** text when @ref type == @ref afb_auth_Permission */ const char *text; + + /** level of assurancy when @ref type == @ref afb_auth_LOA */ unsigned loa; + + /** first child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And, @ref afb_auth_Not } */ const struct afb_auth *first; }; + + /** second child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And } */ const struct afb_auth *next; }; diff --git a/include/afb/afb-binding-postdefs.h b/include/afb/afb-binding-postdefs.h new file mode 100644 index 00000000..93cd46ef --- /dev/null +++ b/include/afb/afb-binding-postdefs.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +typedef enum afb_auth_type afb_auth_type_t; +typedef struct afb_auth afb_auth_t; +typedef struct afb_arg afb_arg_t; + +#if AFB_BINDING_VERSION == 1 + +typedef struct afb_verb_desc_v1 afb_verb_t; +typedef struct afb_binding_v1 afb_binding_t; +typedef struct afb_binding_interface_v1 afb_binding_interface_v1; + +typedef struct afb_daemon_x1 afb_daemon_t; +typedef struct afb_service_x1 afb_service_t; + +typedef struct afb_event_x1 afb_event_t; +typedef struct afb_req_x1 afb_req_t; + +typedef struct afb_stored_req afb_stored_req_t; + +#ifndef __cplusplus +typedef struct afb_event_x1 afb_event; +typedef struct afb_req_x1 afb_req; +typedef struct afb_stored_req afb_stored_req; +#endif + +#endif + +#if AFB_BINDING_VERSION == 2 + +typedef struct afb_verb_v2 afb_verb_t; +typedef struct afb_binding_v2 afb_binding_t; + +typedef struct afb_daemon afb_daemon_t; +typedef struct afb_event afb_event_t; +typedef struct afb_req afb_req_t; +typedef struct afb_stored_req afb_stored_req_t; +typedef struct afb_service afb_service_t; + +#define afbBindingExport afbBindingV2 + +#ifndef __cplusplus +typedef struct afb_verb_v2 afb_verb_v2; +typedef struct afb_binding_v2 afb_binding_v2; +typedef struct afb_event_x1 afb_event; +typedef struct afb_req_x1 afb_req; +typedef struct afb_stored_req afb_stored_req; +#endif + +#endif + +#if AFB_BINDING_VERSION == 3 + +typedef struct afb_verb_v3 afb_verb_t; +typedef struct afb_binding_v3 afb_binding_t; + +typedef struct afb_event_x2 *afb_event_t; +typedef struct afb_req_x2 *afb_req_t; +typedef struct afb_api_x3 *afb_api_t; + +#define afbBindingExport afbBindingV3 + +/* compatibility with previous versions */ + +typedef struct afb_api_x3 *afb_daemon_t; +typedef struct afb_api_x3 *afb_service_t; + +#endif + + +#if defined(AFB_BINDING_WANT_DYNAPI) +typedef struct afb_dynapi *afb_dynapi_t; +typedef struct afb_request *afb_request_t; +typedef struct afb_eventid *afb_eventid_t; +#endif
\ No newline at end of file diff --git a/include/afb/afb-binding-predefs.h b/include/afb/afb-binding-predefs.h new file mode 100644 index 00000000..f1765edb --- /dev/null +++ b/include/afb/afb-binding-predefs.h @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/******************************************************************************/ + +#if AFB_BINDING_VERSION == 1 || AFB_BINDING_VERSION == 2 + +#define afb_req afb_req_x1 +#define afb_req_is_valid afb_req_x1_is_valid +#define afb_req_get afb_req_x1_get +#define afb_req_value afb_req_x1_value +#define afb_req_path afb_req_x1_path +#define afb_req_json afb_req_x1_json +#define afb_req_reply afb_req_x1_reply +#define afb_req_reply_f afb_req_x1_reply_f +#define afb_req_reply_v afb_req_x1_reply_v +#define afb_req_success(r,o,i) afb_req_x1_reply(r,o,0,i) +#define afb_req_success_f(r,o,...) afb_req_x1_reply_f(r,o,0,__VA_ARGS__) +#define afb_req_success_v(r,o,f,v) afb_req_x1_reply_v(r,o,0,f,v) +#define afb_req_fail(r,e,i) afb_req_x1_reply(r,0,e,i) +#define afb_req_fail_f(r,e,...) afb_req_x1_reply_f(r,0,e,__VA_ARGS__) +#define afb_req_fail_v(r,e,f,v) afb_req_x1_reply_v(r,0,e,f,v) +#define afb_req_context_get afb_req_x1_context_get +#define afb_req_context_set afb_req_x1_context_set +#define afb_req_context afb_req_x1_context +#define afb_req_context_make afb_req_x1_context_make +#define afb_req_context_clear afb_req_x1_context_clear +#define afb_req_addref afb_req_x1_addref +#define afb_req_unref afb_req_x1_unref +#define afb_req_session_close afb_req_x1_session_close +#define afb_req_session_set_LOA afb_req_x1_session_set_LOA +#define afb_req_subscribe afb_req_x1_subscribe +#define afb_req_unsubscribe afb_req_x1_unsubscribe +#define afb_req_subcall afb_req_x1_subcall +#define afb_req_subcall_req afb_req_x1_subcall_req +#define afb_req_subcall_sync afb_req_x1_subcall_sync +#define afb_req_verbose afb_req_x1_verbose +#define afb_req_has_permission afb_req_x1_has_permission +#define afb_req_get_application_id afb_req_x1_get_application_id +#define afb_req_get_uid afb_req_x1_get_uid +#define afb_req_get_client_info afb_req_x1_get_client_info + +#define afb_event afb_event_x1 +#define afb_event_to_event_x2 afb_event_x1_to_event_x2 +#define afb_event_is_valid afb_event_x1_is_valid +#define afb_event_broadcast afb_event_x1_broadcast +#define afb_event_push afb_event_x1_push +#define afb_event_drop afb_event_x1_unref +#define afb_event_name afb_event_x1_name +#define afb_event_unref afb_event_x1_unref +#define afb_event_addref afb_event_x1_addref + +#define afb_service afb_service_x1 +#define afb_daemon afb_daemon_x1 + +#define _AFB_SYSLOG_LEVEL_EMERGENCY_ AFB_SYSLOG_LEVEL_EMERGENCY +#define _AFB_SYSLOG_LEVEL_ALERT_ AFB_SYSLOG_LEVEL_ALERT +#define _AFB_SYSLOG_LEVEL_CRITICAL_ AFB_SYSLOG_LEVEL_CRITICAL +#define _AFB_SYSLOG_LEVEL_ERROR_ AFB_SYSLOG_LEVEL_ERROR +#define _AFB_SYSLOG_LEVEL_WARNING_ AFB_SYSLOG_LEVEL_WARNING +#define _AFB_SYSLOG_LEVEL_NOTICE_ AFB_SYSLOG_LEVEL_NOTICE +#define _AFB_SYSLOG_LEVEL_INFO_ AFB_SYSLOG_LEVEL_INFO +#define _AFB_SYSLOG_LEVEL_DEBUG_ AFB_SYSLOG_LEVEL_DEBUG + +#endif + +/******************************************************************************/ +#if AFB_BINDING_VERSION == 1 + +#define afb_req_store afb_req_x1_store_v1 +#define afb_req_unstore afb_req_x1_unstore_v1 + +#define afb_binding afb_binding_v1 +#define afb_binding_interface afb_binding_interface_v1 + +#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v1 +#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v1 +#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v1 +#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v1 +#define afb_daemon_make_event afb_daemon_make_event_v1 +#define afb_daemon_verbose afb_daemon_verbose_v1 +#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v1 +#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v1 +#define afb_daemon_queue_job afb_daemon_queue_job_v1 +#define afb_daemon_require_api afb_daemon_require_api_v1 +#define afb_daemon_rename_api afb_daemon_add_alias_v1 + +#define afb_service_call afb_service_call_v1 +#define afb_service_call_sync afb_service_call_sync_v1 + +# define AFB_ERROR AFB_ERROR_V1 +# define AFB_WARNING AFB_WARNING_V1 +# define AFB_NOTICE AFB_NOTICE_V1 +# define AFB_INFO AFB_INFO_V1 +# define AFB_DEBUG AFB_DEBUG_V1 + +# define AFB_REQ_ERROR AFB_REQ_ERROR_V1 +# define AFB_REQ_WARNING AFB_REQ_WARNING_V1 +# define AFB_REQ_NOTICE AFB_REQ_NOTICE_V1 +# define AFB_REQ_INFO AFB_REQ_INFO_V1 +# define AFB_REQ_DEBUG AFB_REQ_DEBUG_V1 + +#define AFB_REQ_VERBOSE AFB_REQ_VERBOSE_V1 + +# define AFB_SESSION_NONE AFB_SESSION_NONE_X1 +# define AFB_SESSION_CREATE AFB_SESSION_CREATE_X1 +# define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_X1 +# define AFB_SESSION_RENEW AFB_SESSION_RENEW_X1 +# define AFB_SESSION_CHECK AFB_SESSION_CHECK_X1 + +# define AFB_SESSION_LOA_GE AFB_SESSION_LOA_GE_X1 +# define AFB_SESSION_LOA_LE AFB_SESSION_LOA_LE_X1 +# define AFB_SESSION_LOA_EQ AFB_SESSION_LOA_EQ_X1 + +# define AFB_SESSION_LOA_SHIFT AFB_SESSION_LOA_SHIFT_X1 +# define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_X1 + +# define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_X1 +# define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_X1 +# define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_X1 +# define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_X1 +# define AFB_SESSION_LOA_4 AFB_SESSION_LOA_4_X1 + +# define AFB_SESSION_LOA_LE_0 AFB_SESSION_LOA_LE_0_X1 +# define AFB_SESSION_LOA_LE_1 AFB_SESSION_LOA_LE_1_X1 +# define AFB_SESSION_LOA_LE_2 AFB_SESSION_LOA_LE_2_X1 +# define AFB_SESSION_LOA_LE_3 AFB_SESSION_LOA_LE_3_X1 + +# define AFB_SESSION_LOA_EQ_0 AFB_SESSION_LOA_EQ_0_X1 +# define AFB_SESSION_LOA_EQ_1 AFB_SESSION_LOA_EQ_1_X1 +# define AFB_SESSION_LOA_EQ_2 AFB_SESSION_LOA_EQ_2_X1 +# define AFB_SESSION_LOA_EQ_3 AFB_SESSION_LOA_EQ_3_X1 + +# define AFB_SESSION_LOA_GE_0 AFB_SESSION_LOA_GE_0_X1 +# define AFB_SESSION_LOA_GE_1 AFB_SESSION_LOA_GE_1_X1 +# define AFB_SESSION_LOA_GE_2 AFB_SESSION_LOA_GE_2_X1 +# define AFB_SESSION_LOA_GE_3 AFB_SESSION_LOA_GE_3_X1 + +#endif + +/******************************************************************************/ +#if AFB_BINDING_VERSION == 2 + +#define afb_req_store afb_req_x1_store_v2 +#define afb_req_unstore afb_daemon_unstore_req_v2 + +#define afb_binding afb_binding_v2 + +#define afb_get_verbosity afb_get_verbosity_v2 +#define afb_get_daemon afb_get_daemon_v2 +#define afb_get_service afb_get_service_v2 + +#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v2 +#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v2 +#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v2 +#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v2 +#define afb_daemon_make_event afb_daemon_make_event_v2 +#define afb_daemon_verbose afb_daemon_verbose_v2 +#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v2 +#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v2 +#define afb_daemon_queue_job afb_daemon_queue_job_v2 +#define afb_daemon_unstore_req afb_daemon_unstore_req_v2 +#define afb_daemon_require_api afb_daemon_require_api_v2 +#define afb_daemon_rename_api(x) afb_daemon_add_alias_v2(0,x) +#define afb_daemon_add_alias afb_daemon_add_alias_v2 + +#define afb_service_call afb_service_call_v2 +#define afb_service_call_sync afb_service_call_sync_v2 + +#define AFB_ERROR AFB_ERROR_V2 +#define AFB_WARNING AFB_WARNING_V2 +#define AFB_NOTICE AFB_NOTICE_V2 +#define AFB_INFO AFB_INFO_V2 +#define AFB_DEBUG AFB_DEBUG_V2 + +#define AFB_REQ_ERROR AFB_REQ_ERROR_V2 +#define AFB_REQ_WARNING AFB_REQ_WARNING_V2 +#define AFB_REQ_NOTICE AFB_REQ_NOTICE_V2 +#define AFB_REQ_INFO AFB_REQ_INFO_V2 +#define AFB_REQ_DEBUG AFB_REQ_DEBUG_V2 + +#define AFB_REQ_VERBOSE AFB_REQ_VERBOSE_V2 + +#endif + +/******************************************************************************/ +#if AFB_BINDING_VERSION == 2 || AFB_BINDING_VERSION == 3 + +#define AFB_SESSION_NONE AFB_SESSION_NONE_X2 +#define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_X2 +#define AFB_SESSION_RENEW AFB_SESSION_REFRESH_X2 +#define AFB_SESSION_REFRESH AFB_SESSION_REFRESH_X2 +#define AFB_SESSION_CHECK AFB_SESSION_CHECK_X2 + +#define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_X2 + +#define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_X2 +#define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_X2 +#define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_X2 +#define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_X2 + +#endif + +/******************************************************************************/ +#if AFB_BINDING_VERSION == 2 + +#define AFB_SESSION_NONE_V2 AFB_SESSION_NONE_X2 +#define AFB_SESSION_CLOSE_V2 AFB_SESSION_CLOSE_X2 +#define AFB_SESSION_RENEW_V2 AFB_SESSION_REFRESH_X2 +#define AFB_SESSION_REFRESH_V2 AFB_SESSION_REFRESH_X2 +#define AFB_SESSION_CHECK_V2 AFB_SESSION_CHECK_X2 + +#define AFB_SESSION_LOA_MASK_V2 AFB_SESSION_LOA_MASK_X2 + +#define AFB_SESSION_LOA_0_V2 AFB_SESSION_LOA_0_X2 +#define AFB_SESSION_LOA_1_V2 AFB_SESSION_LOA_1_X2 +#define AFB_SESSION_LOA_2_V2 AFB_SESSION_LOA_2_X2 +#define AFB_SESSION_LOA_3_V2 AFB_SESSION_LOA_3_X2 + +#endif + +/******************************************************************************/ +#if AFB_BINDING_VERSION == 3 + +#define afb_req_x2 afb_req + +#define afb_req_x2_is_valid afb_req_is_valid +#define afb_req_x2_get_api afb_req_get_api +#define afb_req_x2_get_vcbdata afb_req_get_vcbdata +#define afb_req_x2_get_called_api afb_req_get_called_api +#define afb_req_x2_get_called_verb afb_req_get_called_verb +#define afb_req_x2_wants_log_level afb_req_wants_log_level + +#define afb_req_x2_get afb_req_get +#define afb_req_x2_value afb_req_value +#define afb_req_x2_path afb_req_path +#define afb_req_x2_json afb_req_json +#define afb_req_x2_reply afb_req_reply +#define afb_req_x2_reply_f afb_req_reply_f +#define afb_req_x2_reply_v afb_req_reply_v +#define afb_req_success(r,o,i) afb_req_reply(r,o,0,i) +#define afb_req_success_f(r,o,...) afb_req_reply_f(r,o,0,__VA_ARGS__) +#define afb_req_success_v(r,o,f,v) afb_req_reply_v(r,o,0,f,v) +#define afb_req_fail(r,e,i) afb_req_reply(r,0,e,i) +#define afb_req_fail_f(r,e,...) afb_req_reply_f(r,0,e,__VA_ARGS__) +#define afb_req_fail_v(r,e,f,v) afb_req_reply_v(r,0,e,f,v) +#define afb_req_x2_context_get afb_req_context_get +#define afb_req_x2_context_set afb_req_context_set +#define afb_req_x2_context afb_req_context +#define afb_req_x2_context_make afb_req_context_make +#define afb_req_x2_context_clear afb_req_context_clear +#define afb_req_x2_addref afb_req_addref +#define afb_req_x2_unref afb_req_unref +#define afb_req_x2_session_close afb_req_session_close +#define afb_req_x2_session_set_LOA afb_req_session_set_LOA +#define afb_req_x2_subscribe afb_req_subscribe +#define afb_req_x2_unsubscribe afb_req_unsubscribe +#define afb_req_x2_subcall afb_req_subcall +#define afb_req_x2_subcall_legacy afb_req_subcall_legacy +#define afb_req_x2_subcall_req afb_req_subcall_req +#define afb_req_x2_subcall_sync_legacy afb_req_subcall_sync_legacy +#define afb_req_x2_subcall_sync afb_req_subcall_sync +#define afb_req_x2_verbose afb_req_verbose +#define afb_req_x2_has_permission afb_req_has_permission +#define afb_req_x2_get_application_id afb_req_get_application_id +#define afb_req_x2_get_uid afb_req_get_uid +#define afb_req_x2_get_client_info afb_req_get_client_info + +#define afb_req_x2_subcall_catch_events afb_req_subcall_catch_events +#define afb_req_x2_subcall_pass_events afb_req_subcall_pass_events +#define afb_req_x2_subcall_on_behalf afb_req_subcall_on_behalf + +#define afb_event_x2 afb_event +#define afb_event_x2_is_valid afb_event_is_valid +#define afb_event_x2_broadcast afb_event_broadcast +#define afb_event_x2_push afb_event_push +#define afb_event_x2_name afb_event_name +#define afb_event_x2_unref afb_event_unref +#define afb_event_x2_addref afb_event_addref + +#define afb_api_x3 afb_api + +#define afb_api_x3_name afb_api_name +#define afb_api_x3_get_userdata afb_api_get_userdata +#define afb_api_x3_set_userdata afb_api_set_userdata +#define afb_api_x3_wants_log_level afb_api_wants_log_level + +#define afb_api_x3_verbose afb_api_verbose +#define afb_api_x3_get_event_loop afb_api_get_event_loop +#define afb_api_x3_get_user_bus afb_api_get_user_bus +#define afb_api_x3_get_system_bus afb_api_get_system_bus +#define afb_api_x3_rootdir_get_fd afb_api_rootdir_get_fd +#define afb_api_x3_rootdir_open_locale afb_api_rootdir_open_locale +#define afb_api_x3_queue_job afb_api_queue_job +#define afb_api_x3_require_api afb_api_require_api +#define afb_api_x3_broadcast_event afb_api_broadcast_event +#define afb_api_x3_make_event_x2 afb_api_make_event +#define afb_api_x3_call afb_api_call +#define afb_api_x3_call_sync afb_api_call_sync +#define afb_api_x3_call_legacy afb_api_call_legacy +#define afb_api_x3_call_sync_legacy afb_api_call_sync_legacy +#define afb_api_x3_new_api afb_api_new_api +#define afb_api_x3_set_verbs_v2 afb_api_set_verbs_v2 +#define afb_api_x3_add_verb afb_api_add_verb +#define afb_api_x3_del_verb afb_api_del_verb +#define afb_api_x3_on_event afb_api_on_event +#define afb_api_x3_on_init afb_api_on_init +#define afb_api_x3_seal afb_api_seal +#define afb_api_x3_add_alias afb_api_add_alias + +#define AFB_API_ERROR AFB_API_ERROR_V3 +#define AFB_API_WARNING AFB_API_WARNING_V3 +#define AFB_API_NOTICE AFB_API_NOTICE_V3 +#define AFB_API_INFO AFB_API_INFO_V3 +#define AFB_API_DEBUG AFB_API_DEBUG_V3 + +#define AFB_REQ_ERROR AFB_REQ_ERROR_V3 +#define AFB_REQ_WARNING AFB_REQ_WARNING_V3 +#define AFB_REQ_NOTICE AFB_REQ_NOTICE_V3 +#define AFB_REQ_INFO AFB_REQ_INFO_V3 +#define AFB_REQ_DEBUG AFB_REQ_DEBUG_V3 + +#define AFB_REQ_VERBOSE AFB_REQ_VERBOSE_V3 + +#define afb_stored_req afb_req_x2 +#define afb_req_store(x) afb_req_x2_addref(x) +#define afb_req_unstore(x) (x) + +#define afb_get_verbosity afb_get_verbosity_v3 +#define afb_get_logmask afb_get_logmask_v3 +#define afb_get_daemon afb_get_root_api_v3 +#define afb_get_service afb_get_root_api_v3 + +#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v3 +#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v3 +#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v3 +#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v3 +#define afb_daemon_make_event afb_daemon_make_event_v3 +#define afb_daemon_verbose afb_daemon_verbose_v3 +#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v3 +#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v3 +#define afb_daemon_queue_job afb_daemon_queue_job_v3 +#define afb_daemon_require_api afb_daemon_require_api_v3 +#define afb_daemon_add_alias afb_daemon_add_alias_v3 + +# define afb_service_call afb_service_call_v3 +# define afb_service_call_sync afb_service_call_sync_v3 + +# define AFB_ERROR AFB_ERROR_V3 +# define AFB_WARNING AFB_WARNING_V3 +# define AFB_NOTICE AFB_NOTICE_V3 +# define AFB_INFO AFB_INFO_V3 +# define AFB_DEBUG AFB_DEBUG_V3 + +#endif + diff --git a/include/afb/afb-binding-v1.h b/include/afb/afb-binding-v1.h index 9fb0ab89..3d5010d0 100644 --- a/include/afb/afb-binding-v1.h +++ b/include/afb/afb-binding-v1.h @@ -17,22 +17,27 @@ #pragma once -struct json_object; +/******************************************************************************/ -#include "afb-req.h" -#include "afb-event.h" -#include "afb-service-itf.h" -#include "afb-daemon-itf.h" +#include "afb-verbosity.h" +#include "afb-req-x1.h" +#include "afb-event-x1.h" +#include "afb-service-itf-x1.h" +#include "afb-daemon-itf-x1.h" #include "afb-req-v1.h" -#include "afb-session-v1.h" +#include "afb-session-x1.h" #include "afb-service-v1.h" #include "afb-daemon-v1.h" struct afb_binding_v1; struct afb_binding_interface_v1; -/* +/******************************************************************************/ + +/** + * @deprecated use bindings version 3 + * * Function for registering the binding * * A binding V1 MUST have an exported function of name @@ -57,7 +62,9 @@ struct afb_binding_interface_v1; */ extern const struct afb_binding_v1 *afbBindingV1Register (const struct afb_binding_interface_v1 *interface); -/* +/** + * @deprecated use bindings version 3 + * * When a binding have an exported implementation of the * function 'afbBindingV1ServiceInit', defined below, * the framework calls it for initialising the service after @@ -69,9 +76,11 @@ extern const struct afb_binding_v1 *afbBindingV1Register (const struct afb_bindi * The function should return 0 in case of success or, else, should return * a negative value. */ -extern int afbBindingV1ServiceInit(struct afb_service service); +extern int afbBindingV1ServiceInit(struct afb_service_x1 service); -/* +/** + * @deprecated use bindings version 3 + * * When a binding have an implementation of the function 'afbBindingV1ServiceEvent', * defined below, the framework calls that function for any broadcasted event or for * events that the service subscribed to in its name. @@ -82,30 +91,36 @@ extern int afbBindingV1ServiceInit(struct afb_service service); extern void afbBindingV1ServiceEvent(const char *event, struct json_object *object); -/* +/** + * @deprecated use bindings version 3 + * * Description of one verb of the API provided by the binding * This enumeration is valid for bindings of type version 1 */ struct afb_verb_desc_v1 { - const char *name; /* name of the verb */ - enum afb_session_flags_v1 session; /* authorisation and session requirements of the verb */ - void (*callback)(struct afb_req req); /* callback function implementing the verb */ - const char *info; /* textual description of the verb */ + const char *name; /**< name of the verb */ + enum afb_session_flags_x1 session; /**< authorisation and session requirements of the verb */ + void (*callback)(struct afb_req_x1 req);/**< callback function implementing the verb */ + const char *info; /**< textual description of the verb */ }; -/* +/** + * @deprecated use bindings version 3 + * * Description of the bindings of type version 1 */ struct afb_binding_desc_v1 { - const char *info; /* textual information about the binding */ - const char *prefix; /* required prefix name for the binding */ - const struct afb_verb_desc_v1 *verbs; /* array of descriptions of verbs terminated by a NULL name */ + const char *info; /**< textual information about the binding */ + const char *prefix; /**< required prefix name for the binding */ + const struct afb_verb_desc_v1 *verbs; /**< array of descriptions of verbs terminated by a NULL name */ }; -/* - * Definition of the type+versions of the binding. +/** + * @deprecated use bindings version 3 + * + * Definition of the type+versions of the binding version 1. * The definition uses hashes. */ enum afb_binding_type_v1 @@ -113,94 +128,107 @@ enum afb_binding_type_v1 AFB_BINDING_VERSION_1 = 123456789 }; -/* - * Description of a binding +/** + * @deprecated use bindings version 3 + * + * Description of a binding version 1 */ struct afb_binding_v1 { - enum afb_binding_type_v1 type; /* type of the binding */ + enum afb_binding_type_v1 type; /**< type of the binding */ union { - struct afb_binding_desc_v1 v1; /* description of the binding of type 1 */ + struct afb_binding_desc_v1 v1; /**< description of the binding of type 1 */ }; }; -/* - * config mode +/** + * @deprecated use bindings version 3 + * + * config mode for bindings version 1 */ enum afb_mode_v1 { - AFB_MODE_LOCAL = 0, /* run locally */ - AFB_MODE_REMOTE, /* run remotely */ - AFB_MODE_GLOBAL /* run either remotely or locally (DONT USE! reserved for future) */ + AFB_MODE_LOCAL = 0, /**< run locally */ + AFB_MODE_REMOTE, /**< run remotely */ + AFB_MODE_GLOBAL /**< run either remotely or locally (DONT USE! reserved for future) */ }; -/* - * Interface between the daemon and the binding. +/** + * @deprecated use bindings version 3 + * + * Interface between the daemon and the binding version 1. */ struct afb_binding_interface_v1 { - struct afb_daemon daemon; /* access to the daemon facilies */ - int verbosity; /* level of verbosity */ - enum afb_mode_v1 mode; /* run mode (local or remote) */ + struct afb_daemon_x1 daemon; /**< access to the daemon facilies */ + int verbosity; /**< level of verbosity */ + enum afb_mode_v1 mode; /**< run mode (local or remote) */ }; +/******************************************************************************/ /* * Macros for logging messages */ #if defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DATA) -# define _AFB_LOGGING_V1_(itf,vlevel,llevel,...) \ - do{ \ - if(itf->verbosity>=vlevel) {\ - if (llevel <= AFB_VERBOSITY_LEVEL_ERROR) \ - afb_daemon_verbose2_v1(itf->daemon,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ - else \ - afb_daemon_verbose2_v1(itf->daemon,llevel,__FILE__,__LINE__,NULL,NULL); \ - } \ - }while(0) -# define _AFB_REQ_LOGGING_V1_(itf,vlevel,llevel,req,...) \ - do{ \ - if(itf->verbosity>=vlevel) \ - afb_req_verbose(req,llevel,__FILE__,__LINE__,NULL,NULL); \ - }while(0) +# define AFB_VERBOSE_V1(itf,level,...) \ + do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \ + afb_daemon_verbose2_v1(itf->daemon,level,__FILE__,__LINE__,NULL,__VA_ARGS__); \ + else afb_daemon_verbose2_v1(itf->daemon,level,__FILE__,__LINE__,NULL); } while(0) + +# define AFB_REQ_VERBOSE_V1(req,level,...) \ + do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \ + afb_req_x1_verbose(req,level,__FILE__,__LINE__,NULL,__VA_ARGS__); \ + else afb_req_x1_verbose(req,level,__FILE__,__LINE__,NULL); } while(0) #elif defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS) -# define _AFB_LOGGING_V1_(itf,vlevel,llevel,...) \ - do{ \ - if(itf->verbosity>=vlevel) \ - afb_daemon_verbose2_v1(itf->daemon,llevel,NULL,0,NULL,__VA_ARGS__); \ - }while(0) -# define _AFB_REQ_LOGGING_V1_(itf,vlevel,llevel,req,...) \ - do{ \ - if(itf->verbosity>=vlevel) \ - afb_req_verbose(req,llevel,NULL,0,NULL,__VA_ARGS__); \ - }while(0) +# define AFB_VERBOSE_V1(itf,level,...) \ + afb_daemon_verbose2_v1(itf->daemon,level,NULL,0,NULL,__VA_ARGS__) + +# define AFB_REQ_VERBOSE_V1(req,level,...) \ + afb_req_x1_verbose(req,level,NULL,0,NULL,__VA_ARGS__) #else -# define _AFB_LOGGING_V1_(itf,vlevel,llevel,...) \ - do{ \ - if(itf->verbosity>=vlevel) \ - afb_daemon_verbose2_v1(itf->daemon,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ - }while(0) -# define _AFB_REQ_LOGGING_V1_(itf,vlevel,llevel,req,...) \ - do{ \ - if(itf->verbosity>=vlevel) \ - afb_req_verbose(req,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ - }while(0) +# define AFB_VERBOSE_V1(itf,level,...) \ + afb_daemon_verbose2_v1(itf->daemon,level,__FILE__,__LINE__,__func__,__VA_ARGS__) + +# define AFB_REQ_VERBOSE_V1(req,level,...) \ + afb_req_x1_verbose(req,level,__FILE__,__LINE__,__func__,__VA_ARGS__) #endif -# include "afb-verbosity.h" -# define AFB_ERROR_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__) -# define AFB_WARNING_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__) -# define AFB_NOTICE_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__) -# define AFB_INFO_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__) -# define AFB_DEBUG_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__) -# define AFB_REQ_ERROR_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__) -# define AFB_REQ_WARNING_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__) -# define AFB_REQ_NOTICE_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__) -# define AFB_REQ_INFO_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__) -# define AFB_REQ_DEBUG_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__) +#define _AFB_LOGGING_V1_(itf,vlevel,llevel,...) \ + do{ if(itf->verbosity>=vlevel) AFB_VERBOSE_V1(itf,llevel,__VA_ARGS__); }while(0) +#define _AFB_REQ_LOGGING_V1_(itf,vlevel,llevel,req,...) \ + do{ if(itf->verbosity>=vlevel) AFB_REQ_VERBOSE_V1(itf,llevel,__VA_ARGS__); }while(0) + +# define AFB_ERROR_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_ERROR,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__) +# define AFB_WARNING_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_WARNING,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__) +# define AFB_NOTICE_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_NOTICE,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__) +# define AFB_INFO_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_INFO,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__) +# define AFB_DEBUG_V1(itf,...) _AFB_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_DEBUG,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__) + +# define AFB_REQ_ERROR_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_ERROR,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__) +# define AFB_REQ_WARNING_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_WARNING,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__) +# define AFB_REQ_NOTICE_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_NOTICE,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__) +# define AFB_REQ_INFO_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_INFO,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__) +# define AFB_REQ_DEBUG_V1(itf,...) _AFB_REQ_LOGGING_V1_(itf,AFB_VERBOSITY_LEVEL_DEBUG,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__) + +/******************************************************************************/ + +#if AFB_BINDING_VERSION == 1 && defined(AFB_BINDING_PRAGMA_KEEP_VERBOSE_UNPREFIX) +# define ERROR AFB_ERROR +# define WARNING AFB_WARNING +# define NOTICE AFB_NOTICE +# define INFO AFB_INFO +# define DEBUG AFB_DEBUG + +# define REQ_ERROR AFB_REQ_ERROR +# define REQ_WARNING AFB_REQ_WARNING +# define REQ_NOTICE AFB_REQ_NOTICE +# define REQ_INFO AFB_REQ_INFO +# define REQ_DEBUG AFB_REQ_DEBUG +#endif diff --git a/include/afb/afb-binding-v2.h b/include/afb/afb-binding-v2.h index 3aa61b23..1535f429 100644 --- a/include/afb/afb-binding-v2.h +++ b/include/afb/afb-binding-v2.h @@ -17,137 +17,156 @@ #pragma once -#include <stdint.h> +/******************************************************************************/ +#include "afb-verbosity.h" #include "afb-auth.h" -#include "afb-event.h" -#include "afb-req.h" -#include "afb-service-itf.h" -#include "afb-daemon-itf.h" +#include "afb-event-x1.h" +#include "afb-req-x1.h" +#include "afb-service-itf-x1.h" +#include "afb-daemon-itf-x1.h" #include "afb-req-v2.h" -#include "afb-session-v2.h" +#include "afb-session-x2.h" -struct json_object; +/******************************************************************************/ -/* - * Description of one verb of the API provided by the binding - * This enumeration is valid for bindings of type version 2 +/** + * @deprecated use bindings version 3 + * + * Description of one verb as provided for binding API version 2 */ struct afb_verb_v2 { - const char *verb; /* name of the verb, NULL only at end of the array */ - void (*callback)(struct afb_req req); /* callback function implementing the verb */ - const struct afb_auth *auth; /* required authorisation, can be NULL */ - const char *info; /* some info about the verb, can be NULL */ - uint32_t session; /* authorisation and session requirements of the verb */ + const char *verb; /**< name of the verb, NULL only at end of the array */ + void (*callback)(struct afb_req_x1 req);/**< callback function implementing the verb */ + const struct afb_auth *auth; /**< required authorisation, can be NULL */ + const char *info; /**< some info about the verb, can be NULL */ + uint32_t session; /**< authorisation and session requirements of the verb */ }; -/* +/** + * @deprecated use bindings version 3 + * * Description of the bindings of type version 2 */ struct afb_binding_v2 { - const char *api; /* api name for the binding */ - const char *specification; /* textual specification of the binding, can be NULL */ - const char *info; /* some info about the api, can be NULL */ - const struct afb_verb_v2 *verbs; /* array of descriptions of verbs terminated by a NULL name */ - int (*preinit)(); /* callback at load of the binding */ - int (*init)(); /* callback for starting the service */ - void (*onevent)(const char *event, struct json_object *object); /* callback for handling events */ - unsigned noconcurrency: 1; /* avoids concurrent requests to verbs */ + const char *api; /**< api name for the binding */ + const char *specification; /**< textual specification of the binding, can be NULL */ + const char *info; /**< some info about the api, can be NULL */ + const struct afb_verb_v2 *verbs; /**< array of descriptions of verbs terminated by a NULL name */ + int (*preinit)(); /**< callback at load of the binding */ + int (*init)(); /**< callback for starting the service */ + void (*onevent)(const char *event, struct json_object *object); /**< callback for handling events */ + unsigned noconcurrency: 1; /**< avoids concurrent requests to verbs */ }; +/** + * @deprecated use bindings version 3 + * + * structure for the global data of the binding + */ struct afb_binding_data_v2 { - int verbosity; /* level of verbosity */ - struct afb_daemon daemon; /* access to daemon APIs */ - struct afb_service service; /* access to service APIs */ + int verbosity; /**< level of verbosity */ + struct afb_daemon_x1 daemon; /**< access to daemon APIs */ + struct afb_service_x1 service; /**< access to service APIs */ }; -/* +/** + * @page validity-v2 Validity of a binding v2 + * * A binding V2 MUST have two exported symbols of name: * - * - afbBindingV2 - * - afbBindingV2data + * - @ref afbBindingV2 + * - @ref afbBindingV2data + */ + +/** + * @deprecated use bindings version 3 * + * The global mandatory description of the binding */ #if !defined(AFB_BINDING_MAIN_NAME_V2) extern const struct afb_binding_v2 afbBindingV2; #endif -#if !defined(AFB_BINDING_DATA_NAME_V2) -#define AFB_BINDING_DATA_NAME_V2 afbBindingV2data -#endif - +/** + * @deprecated use bindings version 3 + * + * The global auto declared internal data of the binding + */ #if AFB_BINDING_VERSION != 2 extern #endif -struct afb_binding_data_v2 AFB_BINDING_DATA_NAME_V2 __attribute__ ((weak)); +struct afb_binding_data_v2 afbBindingV2data __attribute__ ((weak)); -#define afb_get_verbosity_v2() (AFB_BINDING_DATA_NAME_V2.verbosity) -#define afb_get_daemon_v2() (AFB_BINDING_DATA_NAME_V2.daemon) -#define afb_get_service_v2() (AFB_BINDING_DATA_NAME_V2.service) +#define afb_get_verbosity_v2() (afbBindingV2data.verbosity) +#define afb_get_daemon_v2() (afbBindingV2data.daemon) +#define afb_get_service_v2() (afbBindingV2data.service) +/******************************************************************************/ /* * Macros for logging messages */ #if defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DATA) -# define _AFB_LOGGING_V2_(vlevel,llevel,...) \ - do{ \ - if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) {\ - if (llevel <= AFB_VERBOSITY_LEVEL_ERROR) \ - afb_daemon_verbose_v2(llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ - else \ - afb_daemon_verbose_v2(llevel,__FILE__,__LINE__,NULL,NULL); \ - } \ - }while(0) -# define _AFB_REQ_LOGGING_V2_(vlevel,llevel,req,...) \ - do{ \ - if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) \ - afb_req_verbose(req,llevel,__FILE__,__LINE__,NULL,NULL); \ - }while(0) +#define AFB_VERBOSE_V2(level,...) \ + do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \ + afb_daemon_verbose_v2(level,__FILE__,__LINE__,NULL,__VA_ARGS__); \ + else afb_daemon_verbose_v2(level,__FILE__,__LINE__,NULL); } while(0) + +#define AFB_REQ_VERBOSE_V2(req,level,...) \ + do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \ + afb_req_x1_verbose(req,level,__FILE__,__LINE__,NULL,__VA_ARGS__); \ + else afb_req_x1_verbose(req,level,__FILE__,__LINE__,NULL); } while(0) #elif defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS) -# define _AFB_LOGGING_V2_(vlevel,llevel,...) \ - do{ \ - if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) \ - afb_daemon_verbose_v2(llevel,NULL,0,NULL,__VA_ARGS__); \ - }while(0) -# define _AFB_REQ_LOGGING_V2_(vlevel,llevel,req,...) \ - do{ \ - if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) \ - afb_req_verbose(req,llevel,NULL,0,NULL,__VA_ARGS__); \ - }while(0) +#define AFB_VERBOSE_V2(level,...) \ + afb_daemon_verbose_v2(level,NULL,0,NULL,__VA_ARGS__) + +#define AFB_REQ_VERBOSE_V2(req,level,...) \ + afb_req_x1_verbose(req,level,NULL,0,NULL,__VA_ARGS__) #else -# define _AFB_LOGGING_V2_(vlevel,llevel,...) \ - do{ \ - if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) \ - afb_daemon_verbose_v2(llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ - }while(0) -# define _AFB_REQ_LOGGING_V2_(vlevel,llevel,req,...) \ - do{ \ - if(AFB_BINDING_DATA_NAME_V2.verbosity>=vlevel) \ - afb_req_verbose(req,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ - }while(0) +#define AFB_VERBOSE_V2(level,...) \ + afb_daemon_verbose_v2(level,__FILE__,__LINE__,__func__,__VA_ARGS__) + +#define AFB_REQ_VERBOSE_V2(req,level,...) \ + afb_req_x1_verbose(req,level,__FILE__,__LINE__,__func__,__VA_ARGS__) #endif -#include "afb-verbosity.h" -#define AFB_ERROR_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__) -#define AFB_WARNING_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__) -#define AFB_NOTICE_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__) -#define AFB_INFO_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__) -#define AFB_DEBUG_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__) -#define AFB_REQ_ERROR_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__) -#define AFB_REQ_WARNING_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__) -#define AFB_REQ_NOTICE_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__) -#define AFB_REQ_INFO_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__) -#define AFB_REQ_DEBUG_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__) +#define _AFB_LOGGING_V2_(vlevel,llevel,...) \ + do{ if(afb_get_verbosity_v2()>=vlevel) AFB_VERBOSE_V2(llevel,__VA_ARGS__); } while(0) +#define _AFB_REQ_LOGGING_V2_(vlevel,llevel,req,...) \ + do{ if(afb_get_verbosity_v2()>=vlevel) AFB_REQ_VERBOSE_V2(req,llevel,__VA_ARGS__); } while(0) + +#define AFB_ERROR_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_ERROR,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__) +#define AFB_WARNING_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_WARNING,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__) +#define AFB_NOTICE_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_NOTICE,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__) +#define AFB_INFO_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_INFO,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__) +#define AFB_DEBUG_V2(...) _AFB_LOGGING_V2_(AFB_VERBOSITY_LEVEL_DEBUG,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__) +#define AFB_REQ_ERROR_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_ERROR,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__) +#define AFB_REQ_WARNING_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_WARNING,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__) +#define AFB_REQ_NOTICE_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_NOTICE,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__) +#define AFB_REQ_INFO_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_INFO,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__) +#define AFB_REQ_DEBUG_V2(...) _AFB_REQ_LOGGING_V2_(AFB_VERBOSITY_LEVEL_DEBUG,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__) + +/******************************************************************************/ + +#if 0 && AFB_BINDING_VERSION >= 2 + +# define afb_verbose_error() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_ERROR) +# define afb_verbose_warning() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_WARNING) +# define afb_verbose_notice() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_NOTICE) +# define afb_verbose_info() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_INFO) +# define afb_verbose_debug() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_DEBUG) + +#endif #include "afb-daemon-v2.h" #include "afb-service-v2.h" diff --git a/include/afb/afb-binding-v3.h b/include/afb/afb-binding-v3.h new file mode 100644 index 00000000..ece3f1c4 --- /dev/null +++ b/include/afb/afb-binding-v3.h @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/**< @file afb/afb-binding-v3.h */ + +#pragma once + +/******************************************************************************/ + +#include "afb-auth.h" +#include "afb-event-x2.h" +#include "afb-req-x2.h" +#include "afb-session-x2.h" +#include "afb-api-x3.h" + +/******************************************************************************/ + +/** + * @page validity-v3 Validity of a binding v3 + * + * A binding V3 MUST have at least two exported symbols of name: + * + * - @ref afbBindingV3root + * - @ref afbBindingV3 and/or @ref afbBindingV3entry + * + * @ref afbBindingV3root is automatically created when **AFB_BINDING_VERSION == 3** + * without programmer action, as a hidden variable linked as *weak*. + * + * The symbols @ref afbBindingV3 and **afbBindingV3entry** are under control + * of the programmer. + * + * The symbol @ref afbBindingV3 if defined is used, as in binding v2, to describe + * an API that will be declared during pre-initialization of bindings. + * + * The symbol @ref afbBindingV3entry if defined will be called during + * pre-initialization. + * + * If @ref afbBindingV3entry and @ref afbBindingV3 are both defined, it is an + * error to fill the field @ref preinit of @ref afbBindingV3. + * + * @see afb_binding_v3 + * @see afbBindingV3root + * @see afbBindingV3entry + * @see afbBindingV3 + */ + +/** + * Description of one verb as provided for binding API version 3 + */ +struct afb_verb_v3 +{ + /** name of the verb, NULL only at end of the array */ + const char *verb; + + /** callback function implementing the verb */ + void (*callback)(struct afb_req_x2 *req); + + /** required authorization, can be NULL */ + const struct afb_auth *auth; + + /** some info about the verb, can be NULL */ + const char *info; + + /**< data for the verb callback */ + void *vcbdata; + + /** authorization and session requirements of the verb */ + uint16_t session; + + /** is the verb glob name */ + uint16_t glob: 1; +}; + +/** + * Description of the bindings of type version 3 + */ +struct afb_binding_v3 +{ + /** api name for the binding, can't be NULL */ + const char *api; + + /** textual specification of the binding, can be NULL */ + const char *specification; + + /** some info about the api, can be NULL */ + const char *info; + + /** array of descriptions of verbs terminated by a NULL name, can be NULL */ + const struct afb_verb_v3 *verbs; + + /** callback at load of the binding */ + int (*preinit)(struct afb_api_x3 *api); + + /** callback for starting the service */ + int (*init)(struct afb_api_x3 *api); + + /** callback for handling events */ + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object); + + /** userdata for afb_api_x3 */ + void *userdata; + + /** space separated list of provided class(es) */ + const char *provide_class; + + /** space separated list of required class(es) */ + const char *require_class; + + /** space separated list of required API(es) */ + const char *require_api; + + /** avoids concurrent requests to verbs */ + unsigned noconcurrency: 1; +}; + +/** + * Default root binding's api that can be used when no explicit context is + * available. + * + * When @ref afbBindingV3 is defined, this variable records the corresponding + * api handler. Otherwise, it points to an fake handles that allows logging + * and api creation. + * + * @see afbBindingV3entry + * @see afbBindingV3 + * @see @ref validity-v3 + */ +#if AFB_BINDING_VERSION != 3 +extern +#endif +struct afb_api_x3 *afbBindingV3root __attribute__((weak)); + +/** + * Pre-initialization function. + * + * If this function is defined and exported in the produced binding + * (shared object), it will be called during pre-initialization with the + * rootapi defined by \ref afbBindingV3root + * + * @param rootapi the root api (equals to afbBindingV3root) + * + * @return the function must return a negative integer on error to abort the + * initialization of the binding. Any positive or zero returned value is a + * interpreted as a success. + + * @see afbBindingV3root + * @see afbBindingV3 + * @see @ref validity-v3 + */ +extern int afbBindingV3entry(struct afb_api_x3 *rootapi); + +/** + * Static definition of the root api of the binding. + * + * This symbol if defined describes the API of the binding. + * + * If it is not defined then the function @ref afbBindingV3entry must be defined + * + * @see afbBindingV3root + * @see afbBindingV3entry + * @see @ref validity-v3 + */ +extern const struct afb_binding_v3 afbBindingV3; + +#include "afb-auth.h" +#include "afb-session-x2.h" +#include "afb-verbosity.h" + +#include "afb-event-x2.h" +#include "afb-req-x2.h" +#include "afb-api-x3.h" + +/* + * Macros for logging messages + */ + +#if defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DATA) + +# define AFB_API_VERBOSE_V3(api,level,...) \ + do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \ + afb_api_v3_verbose(api,level,__FILE__,__LINE__,NULL,__VA_ARGS__); \ + else afb_api_v3_verbose(api,level,__FILE__,__LINE__,NULL); } while(0) + +# define AFB_REQ_VERBOSE_V3(req,level,...) \ + do { if(level <= AFB_VERBOSITY_LEVEL_ERROR) \ + afb_req_x2_verbose(req,level,__FILE__,__LINE__,NULL,__VA_ARGS__); \ + else afb_req_x2_verbose(req,level,__FILE__,__LINE__,NULL); } while(0) + +#elif defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS) + +# define AFB_API_VERBOSE_V3(api,level,...) \ + afb_api_v3_verbose(api,level,NULL,0,NULL,__VA_ARGS__) + +# define AFB_REQ_VERBOSE_V3(req,level,...) \ + afb_req_x2_verbose(req,level,NULL,0,NULL,__VA_ARGS__) + +#else + +# define AFB_API_VERBOSE_V3(api,level,...) \ + afb_api_x3_verbose(api,level,__FILE__,__LINE__,__func__,__VA_ARGS__) + +# define AFB_REQ_VERBOSE_V3(req,level,...) \ + afb_req_x2_verbose(req,level,__FILE__,__LINE__,__func__,__VA_ARGS__) + +#endif + +#define _AFB_API_LOGGING_V3_(api,llevel,...) \ + do{ if(AFB_SYSLOG_MASK_WANT((api)->logmask,(llevel))) AFB_API_VERBOSE_V3((api),(llevel),__VA_ARGS__); }while(0) +#define _AFB_REQ_LOGGING_V3_(req,llevel,...) \ + do{ if(AFB_SYSLOG_MASK_WANT((req)->api->logmask,(llevel))) AFB_REQ_VERBOSE_V3((req),(llevel),__VA_ARGS__); }while(0) + +#define AFB_API_ERROR_V3(api,...) _AFB_API_LOGGING_V3_(api,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__) +#define AFB_API_WARNING_V3(api,...) _AFB_API_LOGGING_V3_(api,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__) +#define AFB_API_NOTICE_V3(api,...) _AFB_API_LOGGING_V3_(api,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__) +#define AFB_API_INFO_V3(api,...) _AFB_API_LOGGING_V3_(api,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__) +#define AFB_API_DEBUG_V3(api,...) _AFB_API_LOGGING_V3_(api,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__) + +#define AFB_REQ_ERROR_V3(req,...) _AFB_REQ_LOGGING_V3_(req,AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__) +#define AFB_REQ_WARNING_V3(req,...) _AFB_REQ_LOGGING_V3_(req,AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__) +#define AFB_REQ_NOTICE_V3(req,...) _AFB_REQ_LOGGING_V3_(req,AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__) +#define AFB_REQ_INFO_V3(req,...) _AFB_REQ_LOGGING_V3_(req,AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__) +#define AFB_REQ_DEBUG_V3(req,...) _AFB_REQ_LOGGING_V3_(req,AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__) + +#define AFB_ERROR_V3(...) AFB_API_ERROR_V3(afbBindingV3root,__VA_ARGS__) +#define AFB_WARNING_V3(...) AFB_API_WARNING_V3(afbBindingV3root,__VA_ARGS__) +#define AFB_NOTICE_V3(...) AFB_API_NOTICE_V3(afbBindingV3root,__VA_ARGS__) +#define AFB_INFO_V3(...) AFB_API_INFO_V3(afbBindingV3root,__VA_ARGS__) +#define AFB_DEBUG_V3(...) AFB_API_DEBUG_V3(afbBindingV3root,__VA_ARGS__) + +#define afb_get_root_api_v3() (afbBindingV3root) +#define afb_get_logmask_v3() (afbBindingV3root->logmask) +#define afb_get_verbosity_v3() AFB_SYSLOG_LEVEL_TO_VERBOSITY(_afb_verbomask_to_upper_level_(afbBindingV3root->logmask)) + +#define afb_daemon_get_event_loop_v3(...) afb_api_get_event_loop(afbBindingV3root,__VA_ARGS__) +#define afb_daemon_get_user_bus_v3(...) afb_api_get_user_bus(afbBindingV3root,__VA_ARGS__) +#define afb_daemon_get_system_bus_v3(...) afb_api_get_system_bus(afbBindingV3root,__VA_ARGS__) +#define afb_daemon_broadcast_event_v3(...) afb_api_broadcast_event(afbBindingV3root,__VA_ARGS__) +#define afb_daemon_make_event_v3(...) afb_api_make_event(afbBindingV3root,__VA_ARGS__) +#define afb_daemon_verbose_v3(...) afb_api_verbose(afbBindingV3root,__VA_ARGS__) +#define afb_daemon_rootdir_get_fd_v3() afb_api_rootdir_get_fd(afbBindingV3root) +#define afb_daemon_rootdir_open_locale_v3(...) afb_api_rootdir_open_locale(afbBindingV3root,__VA_ARGS__) +#define afb_daemon_queue_job_v3(...) afb_api_queue_job(afbBindingV3root,__VA_ARGS__) +#define afb_daemon_require_api_v3(...) afb_api_require_api(afbBindingV3root,__VA_ARGS__) +#define afb_daemon_add_alias_v3(...) afb_api_add_alias(afbBindingV3root,__VA_ARGS__) + +#define afb_service_call_v3(...) afb_api_call_legacy(afbBindingV3root,__VA_ARGS__) +#define afb_service_call_sync_v3(...) afb_api_call_sync_legacy(afbBindingV3root,__VA_ARGS__) + diff --git a/include/afb/afb-binding-vdyn.h b/include/afb/afb-binding-vdyn.h deleted file mode 100644 index 357a85f6..00000000 --- a/include/afb/afb-binding-vdyn.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "afb-auth.h" -#include "afb-session-v2.h" -#include "afb-verbosity.h" - -#include "afb-eventid.h" -#include "afb-request.h" -#include "afb-dynapi.h" - -/* - * The function afbBindingVdyn if exported allows to create - * pure dynamic bindings. When the binding is loaded, it receives - * a virtual dynapi that can be used to create apis. The - * given API can not be used except for creating dynamic apis. - */ -extern int afbBindingVdyn(struct afb_dynapi *dynapi); - -/* - * Macros for logging messages - */ -#if defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DATA) - -# define _AFB_DYNAPI_LOGGING_(vlevel,llevel,dynapi,...) \ - do{ \ - if(dynapi->verbosity>=vlevel) {\ - if (llevel <= AFB_VERBOSITY_LEVEL_ERROR) \ - afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ - else \ - afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,NULL,NULL); \ - } \ - }while(0) -# define _AFB_REQUEST_LOGGING_(vlevel,llevel,request,...) \ - do{ \ - if(request->dynapi->verbosity>=vlevel) \ - afb_request_verbose(request,llevel,__FILE__,__LINE__,NULL,NULL); \ - }while(0) - -#elif defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS) - -# define _AFB_DYNAPI_LOGGING_(vlevel,llevel,dynapi,...) \ - do{ \ - if(dynapi->verbosity>=vlevel) \ - afb_dynapi_verbose(dynapi,llevel,NULL,0,NULL,__VA_ARGS__); \ - }while(0) -# define _AFB_REQUEST_LOGGING_(vlevel,llevel,request,...) \ - do{ \ - if(request->dynapi->verbosity>=vlevel) \ - afb_request_verbose(request,llevel,NULL,0,NULL,__VA_ARGS__); \ - }while(0) - -#else - -# define _AFB_DYNAPI_LOGGING_(vlevel,llevel,dynapi,...) \ - do{ \ - if(dynapi->verbosity>=vlevel) \ - afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ - }while(0) -# define _AFB_REQUEST_LOGGING_(vlevel,llevel,request,...) \ - do{ \ - if(request->dynapi->verbosity>=vlevel) \ - afb_request_verbose(request,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ - }while(0) - -#endif - -#define AFB_DYNAPI_ERROR(...) _AFB_DYNAPI_LOGGING_(AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__) -#define AFB_DYNAPI_WARNING(...) _AFB_DYNAPI_LOGGING_(AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__) -#define AFB_DYNAPI_NOTICE(...) _AFB_DYNAPI_LOGGING_(AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__) -#define AFB_DYNAPI_INFO(...) _AFB_DYNAPI_LOGGING_(AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__) -#define AFB_DYNAPI_DEBUG(...) _AFB_DYNAPI_LOGGING_(AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__) -#define AFB_REQUEST_ERROR(...) _AFB_REQUEST_LOGGING_(AFB_VERBOSITY_LEVEL_ERROR,_AFB_SYSLOG_LEVEL_ERROR_,__VA_ARGS__) -#define AFB_REQUEST_WARNING(...) _AFB_REQUEST_LOGGING_(AFB_VERBOSITY_LEVEL_WARNING,_AFB_SYSLOG_LEVEL_WARNING_,__VA_ARGS__) -#define AFB_REQUEST_NOTICE(...) _AFB_REQUEST_LOGGING_(AFB_VERBOSITY_LEVEL_NOTICE,_AFB_SYSLOG_LEVEL_NOTICE_,__VA_ARGS__) -#define AFB_REQUEST_INFO(...) _AFB_REQUEST_LOGGING_(AFB_VERBOSITY_LEVEL_INFO,_AFB_SYSLOG_LEVEL_INFO_,__VA_ARGS__) -#define AFB_REQUEST_DEBUG(...) _AFB_REQUEST_LOGGING_(AFB_VERBOSITY_LEVEL_DEBUG,_AFB_SYSLOG_LEVEL_DEBUG_,__VA_ARGS__) - - diff --git a/include/afb/afb-binding.h b/include/afb/afb-binding.h index 37305991..085dc388 100644 --- a/include/afb/afb-binding.h +++ b/include/afb/afb-binding.h @@ -17,246 +17,105 @@ #pragma once +/** + * @mainpage + * + * @section brief Brief introduction + * + * This is part of the AGL framework micro-service binder and is provided as the + * API for writing bindings. + * + * The normal usage is to include only one file as below: + * + * ```C + * #define AFB_BINDING_VERSION 3 + * #include <afb/afb-binding.h> + * ``` + * + * @example tuto-1.c + * @example tuto-2.c + */ +/** + * @file afb/afb-binding.h + */ + #include <stdarg.h> +#include <stdint.h> +struct json_object; -/***************************************************************************** - * This files is the main file to include for writing bindings dedicated to +/** + * @def AFB_BINDING_INTERFACE_VERSION + + * * Version of the binding interface. * - * AFB-DAEMON + * This is intended to be test for tuning condition code. + * It is of the form MAJOR * 1000 + REVISION. * - * Functions of bindings of afb-daemon are accessible by authorized clients - * through the apis module of afb-daemon. + * @see AFB_BINDING_UPPER_VERSION that should match MAJOR */ +#define AFB_BINDING_INTERFACE_VERSION 3000 +/** + * @def AFB_BINDING_LOWER_VERSION + * + * Lowest binding API version supported. + * + * @see AFB_BINDING_VERSION + * @see AFB_BINDING_UPPER_VERSION + */ #define AFB_BINDING_LOWER_VERSION 1 -#define AFB_BINDING_UPPER_VERSION 2 + +/** + * @def AFB_BINDING_UPPER_VERSION + * + * Upper binding API version supported. + * + * @see AFB_BINDING_VERSION + * @see AFB_BINDING_LOWER_VERSION + */ +#define AFB_BINDING_UPPER_VERSION 3 + +/** + * @def AFB_BINDING_VERSION + * + * This macro must be defined before including <afb/afb-binding.h> to set + * the required binding API. + */ #ifndef AFB_BINDING_VERSION -#define AFB_BINDING_VERSION 1 -#pragma GCC warning "\ +#error "\ \n\ \n\ AFB_BINDING_VERSION should be defined before including <afb/afb-binding.h>\n\ AFB_BINDING_VERSION defines the version of binding that you use.\n\ - Currently, known versions are 1 or 2.\n\ - Setting now AFB_BINDING_VERSION to 1 (version 1 by default)\n\ - NOTE THAT VERSION 2 IS NOW RECOMMENDED!\n\ + Currently the version to use is 3 (older versions: 1 is obsolete, 2 is legacy).\n\ Consider to add one of the following define before including <afb/afb-binding.h>:\n\ \n\ - #define AFB_BINDING_VERSION 1\n\ - #define AFB_BINDING_VERSION 2\n\ + #define AFB_BINDING_VERSION 3\n\ \n\ - Note that in some case it will enforce you to include <stdio.h>\n\ " -#include <stdio.h> /* old version side effect */ #else # if AFB_BINDING_VERSION == 1 -# pragma GCC warning "Using binding version 1, consider to switch to version 2" +# pragma GCC warning "Using binding version 1, consider to switch to version 3" +# endif +# if AFB_BINDING_VERSION == 2 +# pragma GCC warning "Using binding version 2, consider to switch to version 3" # endif #endif #if AFB_BINDING_VERSION != 0 # if AFB_BINDING_VERSION < AFB_BINDING_LOWER_VERSION || AFB_BINDING_VERSION > AFB_BINDING_UPPER_VERSION -# error "Unsupported binding version AFB_BINDING_VERSION " #AFB_BINDING_VERSION +# error "Unsupported binding version AFB_BINDING_VERSION" # endif #endif -/* - * Some function of the library are exported to afb-daemon. - */ - +/***************************************************************************************************/ +#include "afb-binding-predefs.h" #include "afb-binding-v1.h" #include "afb-binding-v2.h" -#include "afb-binding-vdyn.h" - -typedef struct afb_verb_desc_v1 afb_verb_desc_v1; -typedef struct afb_binding_desc_v1 afb_binding_desc_v1; -typedef struct afb_binding_v1 afb_binding_v1; -typedef struct afb_binding_interface_v1 afb_binding_interface_v1; - -typedef struct afb_verb_v2 afb_verb_v2; -typedef struct afb_binding_v2 afb_binding_v2; - -typedef enum afb_auth_type afb_auth_type; -typedef struct afb_auth afb_auth; -typedef struct afb_daemon afb_daemon; -typedef struct afb_event afb_event; -typedef struct afb_arg afb_arg; -typedef struct afb_req afb_req; -typedef struct afb_stored_req afb_stored_req; -typedef struct afb_service afb_service; - -typedef struct afb_dynapi afb_dynapi; -typedef struct afb_request afb_request; -typedef struct afb_eventid afb_eventid; - -#if 0 -/* these typedef's shouldn't be needed */ -typedef enum afb_binding_type_v1 afb_binding_type_v1; -typedef enum afb_mode_v1 afb_mode_v1; -typedef enum afb_session_flags_v1 afb_session_flags_v1; -typedef enum afb_session_flags_v2 afb_session_flags_v2; -typedef struct afb_binding_data_v2 afb_binding_data_v2; -typedef struct afb_daemon_itf afb_daemon_itf; -typedef struct afb_event_itf afb_event_itf; -typedef struct afb_req_itf afb_req_itf; -typedef struct afb_service_itf afb_service_itf; -#endif - -/***************************************************************************************************/ - -#if AFB_BINDING_VERSION == 1 - -# define afb_binding afb_binding_v1 -# define afb_binding_interface afb_binding_interface_v1 - -# define AFB_SESSION_NONE AFB_SESSION_NONE_V1 -# define AFB_SESSION_CREATE AFB_SESSION_CREATE_V1 -# define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_V1 -# define AFB_SESSION_RENEW AFB_SESSION_RENEW_V1 -# define AFB_SESSION_CHECK AFB_SESSION_CHECK_V1 - -# define AFB_SESSION_LOA_GE AFB_SESSION_LOA_GE_V1 -# define AFB_SESSION_LOA_LE AFB_SESSION_LOA_LE_V1 -# define AFB_SESSION_LOA_EQ AFB_SESSION_LOA_EQ_V1 - -# define AFB_SESSION_LOA_SHIFT AFB_SESSION_LOA_SHIFT_V1 -# define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_V1 - -# define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_V1 -# define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_V1 -# define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_V1 -# define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_V1 -# define AFB_SESSION_LOA_4 AFB_SESSION_LOA_4_V1 - -# define AFB_SESSION_LOA_LE_0 AFB_SESSION_LOA_LE_0_V1 -# define AFB_SESSION_LOA_LE_1 AFB_SESSION_LOA_LE_1_V1 -# define AFB_SESSION_LOA_LE_2 AFB_SESSION_LOA_LE_2_V1 -# define AFB_SESSION_LOA_LE_3 AFB_SESSION_LOA_LE_3_V1 - -# define AFB_SESSION_LOA_EQ_0 AFB_SESSION_LOA_EQ_0_V1 -# define AFB_SESSION_LOA_EQ_1 AFB_SESSION_LOA_EQ_1_V1 -# define AFB_SESSION_LOA_EQ_2 AFB_SESSION_LOA_EQ_2_V1 -# define AFB_SESSION_LOA_EQ_3 AFB_SESSION_LOA_EQ_3_V1 - -# define AFB_SESSION_LOA_GE_0 AFB_SESSION_LOA_GE_0_V1 -# define AFB_SESSION_LOA_GE_1 AFB_SESSION_LOA_GE_1_V1 -# define AFB_SESSION_LOA_GE_2 AFB_SESSION_LOA_GE_2_V1 -# define AFB_SESSION_LOA_GE_3 AFB_SESSION_LOA_GE_3_V1 - -# define AFB_ERROR AFB_ERROR_V1 -# define AFB_WARNING AFB_WARNING_V1 -# define AFB_NOTICE AFB_NOTICE_V1 -# define AFB_INFO AFB_INFO_V1 -# define AFB_DEBUG AFB_DEBUG_V1 - -# define AFB_REQ_ERROR AFB_REQ_ERROR_V1 -# define AFB_REQ_WARNING AFB_REQ_WARNING_V1 -# define AFB_REQ_NOTICE AFB_REQ_NOTICE_V1 -# define AFB_REQ_INFO AFB_REQ_INFO_V1 -# define AFB_REQ_DEBUG AFB_REQ_DEBUG_V1 - -#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v1 -#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v1 -#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v1 -#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v1 -#define afb_daemon_make_event afb_daemon_make_event_v1 -#define afb_daemon_verbose afb_daemon_verbose_v1 -#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v1 -#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v1 -#define afb_daemon_queue_job afb_daemon_queue_job_v1 -#define afb_daemon_require_api afb_daemon_require_api_v1 -#define afb_daemon_rename_api afb_daemon_rename_api_v1 - -#define afb_service_call afb_service_call_v1 -#define afb_service_call_sync afb_service_call_sync_v1 - -#define afb_req_store afb_req_store_v1 -#define afb_req_unstore afb_req_unstore_v1 - -#endif - -/***************************************************************************************************/ - -#if AFB_BINDING_VERSION == 2 - -# define afb_binding afb_binding_v2 -# define afb_get_verbosity afb_get_verbosity_v2 -# define afb_get_daemon afb_get_daemon_v2 -# define afb_get_service afb_get_service_v2 - - -# define AFB_SESSION_NONE AFB_SESSION_NONE_V2 -# define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_V2 -# define AFB_SESSION_RENEW AFB_SESSION_REFRESH_V2 -# define AFB_SESSION_REFRESH AFB_SESSION_REFRESH_V2 -# define AFB_SESSION_CHECK AFB_SESSION_CHECK_V2 - -# define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_V2 - -# define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_V2 -# define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_V2 -# define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_V2 -# define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_V2 - -# define AFB_ERROR AFB_ERROR_V2 -# define AFB_WARNING AFB_WARNING_V2 -# define AFB_NOTICE AFB_NOTICE_V2 -# define AFB_INFO AFB_INFO_V2 -# define AFB_DEBUG AFB_DEBUG_V2 - -# define AFB_REQ_ERROR AFB_REQ_ERROR_V2 -# define AFB_REQ_WARNING AFB_REQ_WARNING_V2 -# define AFB_REQ_NOTICE AFB_REQ_NOTICE_V2 -# define AFB_REQ_INFO AFB_REQ_INFO_V2 -# define AFB_REQ_DEBUG AFB_REQ_DEBUG_V2 - -#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v2 -#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v2 -#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v2 -#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v2 -#define afb_daemon_make_event afb_daemon_make_event_v2 -#define afb_daemon_verbose afb_daemon_verbose_v2 -#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v2 -#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v2 -#define afb_daemon_queue_job afb_daemon_queue_job_v2 -#define afb_daemon_unstore_req afb_daemon_unstore_req_v2 -#define afb_daemon_require_api afb_daemon_require_api_v2 -#define afb_daemon_rename_api afb_daemon_rename_api_v2 - -#define afb_service_call afb_service_call_v2 -#define afb_service_call_sync afb_service_call_sync_v2 - -#define afb_req_store afb_req_store_v2 -#define afb_req_unstore afb_daemon_unstore_req_v2 - -#endif - -/***************************************************************************************************/ - -#if AFB_BINDING_VERSION >= 2 - -# define afb_verbose_error() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_ERROR) -# define afb_verbose_warning() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_WARNING) -# define afb_verbose_notice() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_NOTICE) -# define afb_verbose_info() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_INFO) -# define afb_verbose_debug() (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_DEBUG) - -#endif - -/***************************************************************************************************/ - -#if defined(AFB_BINDING_PRAGMA_KEEP_VERBOSE_UNPREFIX) -# define ERROR AFB_ERROR -# define WARNING AFB_WARNING -# define NOTICE AFB_NOTICE -# define INFO AFB_INFO -# define DEBUG AFB_DEBUG - -# define REQ_ERROR AFB_REQ_ERROR -# define REQ_WARNING AFB_REQ_WARNING -# define REQ_NOTICE AFB_REQ_NOTICE -# define REQ_INFO AFB_REQ_INFO -# define REQ_DEBUG AFB_REQ_DEBUG +#include "afb-binding-v3.h" +#if defined(AFB_BINDING_WANT_DYNAPI) +# include "afb-dynapi-legacy.h" #endif +#include "afb-binding-postdefs.h" diff --git a/include/afb/afb-binding.hpp b/include/afb/afb-binding.hpp index ee151339..27715f39 100644 --- a/include/afb/afb-binding.hpp +++ b/include/afb/afb-binding.hpp @@ -17,18 +17,19 @@ #pragma once +#include <cstddef> #include <cstdlib> #include <cstdarg> #include <functional> /* ensure version */ #ifndef AFB_BINDING_VERSION -# define AFB_BINDING_VERSION 2 +# define AFB_BINDING_VERSION 3 #endif /* check the version */ #if AFB_BINDING_VERSION < 2 -# error "AFB_BINDING_VERSION must be at least 2" +# error "AFB_BINDING_VERSION must be at least 2 but 3 is prefered" #endif /* get C definitions of bindings */ @@ -44,16 +45,11 @@ namespace afb { class arg; class event; class req; -class stored_req; /*************************************************************************/ /* declaration of functions */ /*************************************************************************/ -struct sd_event *get_event_loop(); -struct sd_bus *get_system_bus(); -struct sd_bus *get_user_bus(); - int broadcast_event(const char *name, json_object *object = nullptr); event make_event(const char *name); @@ -70,7 +66,7 @@ int queue_job(void (*callback)(int signum, void *arg), void *argument, void *gro int require_api(const char *apiname, bool initialized = true); -int rename_api(const char *apiname); +int add_alias(const char *apiname, const char *aliasname); int verbosity(); @@ -80,9 +76,17 @@ bool wants_notices(); bool wants_infos(); bool wants_debugs(); +#if AFB_BINDING_VERSION >= 3 +void call(const char *api, const char *verb, struct json_object *args, void (*callback)(void*closure, int iserror, struct json_object *result, afb_api_t api), void *closure); + +template <class T> void call(const char *api, const char *verb, struct json_object *args, void (*callback)(T*closure, int iserror, struct json_object *result, afb_api_t api), T *closure); + +bool callsync(const char *api, const char *verb, struct json_object *args, struct json_object *&result); +#else void call(const char *api, const char *verb, struct json_object *args, void (*callback)(void*closure, int iserror, struct json_object *result), void *closure); template <class T> void call(const char *api, const char *verb, struct json_object *args, void (*callback)(T*closure, int iserror, struct json_object *result), T *closure); +#endif bool callsync(const char *api, const char *verb, struct json_object *args, struct json_object *&result); @@ -93,14 +97,15 @@ bool callsync(const char *api, const char *verb, struct json_object *args, struc /* events */ class event { - struct afb_event event_; + afb_event_t event_; public: - event() { event_.itf = nullptr; event_.closure = nullptr; } - event(const struct afb_event &e); + event() { invalidate(); } + event(afb_event_t e); event(const event &other); event &operator=(const event &other); - operator const struct afb_event&() const; + operator afb_event_t() const; + afb_event_t operator->() const; operator bool() const; bool is_valid() const; @@ -139,30 +144,16 @@ public: /* req(uest) */ class req { - struct afb_req req_; -public: - class stored - { - struct afb_stored_req *sreq_; - - friend class req; - stored() = delete; - stored(struct afb_stored_req *sr); - public: - stored(const stored &other); - stored &operator =(const stored &other); - req unstore() const; - }; - - class stored; + afb_req_t req_; public: req() = delete; - req(const struct afb_req &r); + req(afb_req_t r); req(const req &other); req &operator=(const req &other); - operator const struct afb_req&() const; + operator afb_req_t() const; + afb_req_t operator->() const; operator bool() const; bool is_valid() const; @@ -175,22 +166,20 @@ public: json_object *json() const; + void reply(json_object *obj = nullptr, const char *error = nullptr, const char *info = nullptr) const; + void replyf(json_object *obj, const char *error, const char *info, ...) const; + void replyv(json_object *obj, const char *error, const char *info, va_list args) const; + void success(json_object *obj = nullptr, const char *info = nullptr) const; void successf(json_object *obj, const char *info, ...) const; + void successv(json_object *obj, const char *info, va_list args) const; - void fail(const char *status = "failed", const char *info = nullptr) const; - void failf(const char *status, const char *info, ...) const; - - void *context_get() const; - - void context_set(void *context, void (*free_context)(void*)) const; - - void *context(void *(*create_context)(), void (*free_context)(void*)) const; + void fail(const char *error = "failed", const char *info = nullptr) const; + void failf(const char *error, const char *info, ...) const; + void failv(const char *error, const char *info, va_list args) const; template < class T > T *context() const; - void context_clear() const; - void addref() const; void unref() const; @@ -199,19 +188,22 @@ public: bool session_set_LOA(unsigned level) const; - stored store() const; - bool subscribe(const event &event) const; bool unsubscribe(const event &event) const; - void subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result), void *closure) const; + void subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result, afb_req_t req), void *closure) const; + template <class T> void subcall(const char *api, const char *verb, json_object *args, void (*callback)(T *closure, int iserror, json_object *result, afb_req_t req), T *closure) const; - void subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result, afb_req req), void *closure) const; + bool subcallsync(const char *api, const char *verb, json_object *args, struct json_object *&result) const; - template <class T> void subcall(const char *api, const char *verb, json_object *args, void (*callback)(T *closure, int iserror, json_object *result), T *closure) const; +#if AFB_BINDING_VERSION >= 3 + void subcall(const char *api, const char *verb, json_object *args, int flags, void (*callback)(void *closure, json_object *object, const char *error, const char *info, afb_req_t req), void *closure) const; - bool subcallsync(const char *api, const char *verb, json_object *args, struct json_object *&result) const; + template <class T> void subcall(const char *api, const char *verb, json_object *args, int flags, void (*callback)(T *closure, json_object *object, const char *error, const char *info, afb_req_t req), T *closure) const; + + bool subcallsync(const char *api, const char *verb, json_object *args, int flags, struct json_object *&object, char *&error, char *&info) const; +#endif void verbose(int level, const char *file, int line, const char * func, const char *fmt, va_list args) const; @@ -222,6 +214,8 @@ public: char *get_application_id() const; int get_uid() const; + + json_object *get_client_info() const; }; /*************************************************************************/ @@ -250,18 +244,23 @@ public: /*************************************************************************/ /* events */ -inline event::event(const struct afb_event &e) : event_(e) { } +inline event::event(afb_event_t e) : event_(e) { } inline event::event(const event &other) : event_(other.event_) { } inline event &event::operator=(const event &other) { event_ = other.event_; return *this; } -inline event::operator const struct afb_event&() const { return event_; } +inline event::operator afb_event_t() const { return event_; } +inline afb_event_t event::operator->() const { return event_; } inline event::operator bool() const { return is_valid(); } -inline bool event::is_valid() const { return afb_event_is_valid(event_); } +inline bool event::is_valid() const { return afb_event_is_valid(event_); } -inline void event::invalidate() { event_.itf = NULL; event_.closure = NULL; } +#if AFB_BINDING_VERSION >= 3 +inline void event::invalidate() { event_ = nullptr; } +#else +inline void event::invalidate() { event_ = { nullptr, nullptr }; } +#endif -inline int event::broadcast(json_object *object) const { return afb_event_broadcast(event_, object); } +inline int event::broadcast(json_object *object) const { return afb_event_broadcast(event_, object); } inline int event::push(json_object *object) const { return afb_event_push(event_, object); } inline void event::unref() { afb_event_unref(event_); invalidate(); } @@ -285,23 +284,16 @@ inline const char *arg::path() const { return arg_.path; } /* req(uests)s */ -inline req::stored::stored(struct afb_stored_req *sr) : sreq_(sr) {} - -inline req::stored::stored(const req::stored &other) : sreq_(other.sreq_) {} - -inline req::stored &req::stored::operator =(const req::stored &other) { sreq_ = other.sreq_; return *this; } - -inline req req::stored::unstore() const { return req(afb_daemon_unstore_req_v2(sreq_)); } - -inline req::req(const struct afb_req &r) : req_(r) {} +inline req::req(afb_req_t r) : req_(r) {} inline req::req(const req &other) : req_(other.req_) {} inline req &req::operator=(const req &other) { req_ = other.req_; return *this; } -inline req::operator const struct afb_req&() const { return req_; } +inline req::operator afb_req_t() const { return req_; } +inline afb_req_t req::operator->() const { return req_; } -inline req::operator bool() const { return !!afb_req_is_valid(req_); } -inline bool req::is_valid() const { return !!afb_req_is_valid(req_); } +inline req::operator bool() const { return is_valid(); } +inline bool req::is_valid() const { return afb_req_is_valid(req_); } inline arg req::get(const char *name) const { return arg(afb_req_get(req_, name)); } @@ -311,160 +303,210 @@ inline const char *req::path(const char *name) const { return afb_req_path(req_, inline json_object *req::json() const { return afb_req_json(req_); } -inline void req::success(json_object *obj, const char *info) const { afb_req_success(req_, obj, info); } -inline void req::successf(json_object *obj, const char *info, ...) const +inline void req::reply(json_object *obj, const char *error, const char *info) const { afb_req_reply(req_, obj, error, info); } +inline void req::replyv(json_object *obj, const char *error, const char *info, va_list args) const { afb_req_reply_v(req_, obj, error, info, args); } +inline void req::replyf(json_object *obj, const char *error, const char *info, ...) const { va_list args; va_start(args, info); - afb_req_success_v(req_, obj, info, args); + replyv(obj, error, info, args); va_end(args); } -inline void req::fail(const char *status, const char *info) const { afb_req_fail(req_, status, info); } -inline void req::failf(const char *status, const char *info, ...) const +inline void req::success(json_object *obj, const char *info) const { reply(obj, nullptr, info); } +inline void req::successv(json_object *obj, const char *info, va_list args) const { replyv(obj, nullptr, info, args); } +inline void req::successf(json_object *obj, const char *info, ...) const { va_list args; va_start(args, info); - afb_req_fail_v(req_, status, info, args); + successv(obj, info, args); va_end(args); } -inline void *req::context_get() const { return afb_req_context_get(req_); } - -inline void req::context_set(void *context, void (*free_context)(void*)) const { afb_req_context_set(req_, context, free_context); } - -inline void *req::context(void *(*create_context)(), void (*free_context)(void*)) const { return afb_req_context(req_, create_context, free_context); } +inline void req::fail(const char *error, const char *info) const { reply(nullptr, error, info); } +inline void req::failv(const char *error, const char *info, va_list args) const { replyv(nullptr, error, info, args); } +inline void req::failf(const char *error, const char *info, ...) const +{ + va_list args; + va_start(args, info); + failv(error, info, args); + va_end(args); +} template < class T > inline T *req::context() const { +#if AFB_BINDING_VERSION >= 3 + T* (*creater)(void*) = [](){return new T();}; + void (*freer)(T*) = [](T*t){delete t;}; + return reinterpret_cast<T*>(afb_req_context(req_, 0, + reinterpret_cast<void *(*)(void*)>(creater), + reinterpret_cast<void (*)(void*)>(freer), nullptr)); +#else T* (*creater)() = [](){return new T();}; void (*freer)(T*) = [](T*t){delete t;}; return reinterpret_cast<T*>(afb_req_context(req_, reinterpret_cast<void *(*)()>(creater), reinterpret_cast<void (*)(void*)>(freer))); +#endif } -inline void req::context_clear() const { afb_req_context_clear(req_); } - inline void req::addref() const { afb_req_addref(req_); } inline void req::unref() const { afb_req_unref(req_); } inline void req::session_close() const { afb_req_session_close(req_); } -inline bool req::session_set_LOA(unsigned level) const { return !!afb_req_session_set_LOA(req_, level); } - -inline req::stored req::store() const { return stored(afb_req_store_v2(req_)); } +inline bool req::session_set_LOA(unsigned level) const { return !afb_req_session_set_LOA(req_, level); } inline bool req::subscribe(const event &event) const { return !afb_req_subscribe(req_, event); } inline bool req::unsubscribe(const event &event) const { return !afb_req_unsubscribe(req_, event); } -inline void req::subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result), void *closure) const + + + + +#if AFB_BINDING_VERSION >= 3 + +inline void req::subcall(const char *api, const char *verb, json_object *args, int flags, void (*callback)(void *closure, json_object *result, const char *error, const char *info, afb_req_t req), void *closure) const { - afb_req_subcall(req_, api, verb, args, callback, closure); + afb_req_subcall(req_, api, verb, args, flags, callback, closure); } -inline void req::subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result, struct afb_req req), void *closure) const +template <class T> +inline void req::subcall(const char *api, const char *verb, json_object *args, int flags, void (*callback)(T *closure, json_object *result, const char *error, const char *info, afb_req_t req), T *closure) const { + subcall(api, verb, args, flags, reinterpret_cast<void(*)(void*,json_object*,const char*,const char*,afb_req_t)>(callback), reinterpret_cast<void*>(closure)); +} + +inline bool req::subcallsync(const char *api, const char *verb, json_object *args, int flags, struct json_object *&object, char *&error, char *&info) const +{ + return !afb_req_subcall_sync(req_, api, verb, args, flags, &object, &error, &info); +} + +#endif + +inline void req::subcall(const char *api, const char *verb, json_object *args, void (*callback)(void *closure, int iserror, json_object *result, afb_req_t req), void *closure) const +{ +#if AFB_BINDING_VERSION >= 3 + afb_req_subcall_legacy(req_, api, verb, args, callback, closure); +#else afb_req_subcall_req(req_, api, verb, args, callback, closure); +#endif } template <class T> -inline void req::subcall(const char *api, const char *verb, json_object *args, void (*callback)(T *closure, int iserror, json_object *result), T *closure) const +inline void req::subcall(const char *api, const char *verb, json_object *args, void (*callback)(T *closure, int iserror, json_object *result, afb_req_t req), T *closure) const { - afb_req_subcall(req_, api, verb, args, reinterpret_cast<void(*)(void*,int,json_object*)>(callback), reinterpret_cast<void*>(closure)); + subcall(api, verb, args, reinterpret_cast<void(*)(void*,int,json_object*,afb_req_t)>(callback), reinterpret_cast<void*>(closure)); } inline bool req::subcallsync(const char *api, const char *verb, json_object *args, struct json_object *&result) const { - return !!afb_req_subcall_sync(req_, api, verb, args, &result); +#if AFB_BINDING_VERSION >= 3 + return !afb_req_subcall_sync_legacy(req_, api, verb, args, &result); +#else + return !afb_req_subcall_sync(req_, api, verb, args, &result); +#endif } inline void req::verbose(int level, const char *file, int line, const char * func, const char *fmt, va_list args) const { - req_.itf->vverbose(req_.closure, level, file, line, func, fmt, args); + afb_req_verbose(req_, level, file, line, func, fmt, args); } inline void req::verbose(int level, const char *file, int line, const char * func, const char *fmt, ...) const { va_list args; va_start(args, fmt); - req_.itf->vverbose(req_.closure, level, file, line, func, fmt, args); + afb_req_verbose(req_, level, file, line, func, fmt, args); va_end(args); } inline bool req::has_permission(const char *permission) const { - return bool(req_.itf->has_permission(req_.closure, permission)); + return bool(afb_req_has_permission(req_, permission)); } inline char *req::get_application_id() const { - return req_.itf->get_application_id(req_.closure); + return afb_req_get_application_id(req_); } inline int req::get_uid() const { - return req_.itf->get_uid(req_.closure); + return afb_req_get_uid(req_); } -/* commons */ -inline struct sd_event *get_event_loop() - { return afb_daemon_get_event_loop_v2(); } - -inline struct sd_bus *get_system_bus() - { return afb_daemon_get_system_bus_v2(); } - -inline struct sd_bus *get_user_bus() - { return afb_daemon_get_user_bus_v2(); } +inline json_object *req::get_client_info() const +{ + return afb_req_get_client_info(req_); +} +/* commons */ inline int broadcast_event(const char *name, json_object *object) - { return afb_daemon_broadcast_event_v2(name, object); } + { return afb_daemon_broadcast_event(name, object); } inline event make_event(const char *name) - { return afb_daemon_make_event_v2(name); } + { return afb_daemon_make_event(name); } inline void verbose(int level, const char *file, int line, const char * func, const char *fmt, va_list args) - { afb_daemon_verbose_v2(level, file, line, func, fmt, args); } + { afb_daemon_verbose(level, file, line, func, fmt, args); } inline void verbose(int level, const char *file, int line, const char * func, const char *fmt, ...) { va_list args; va_start(args, fmt); verbose(level, file, line, func, fmt, args); va_end(args); } inline int rootdir_get_fd() - { return afb_daemon_rootdir_get_fd_v2(); } + { return afb_daemon_rootdir_get_fd(); } inline int rootdir_open_locale_fd(const char *filename, int flags, const char *locale) - { return afb_daemon_rootdir_open_locale_v2(filename, flags, locale); } + { return afb_daemon_rootdir_open_locale(filename, flags, locale); } inline int queue_job(void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) - { return afb_daemon_queue_job_v2(callback, argument, group, timeout); } + { return afb_daemon_queue_job(callback, argument, group, timeout); } inline int require_api(const char *apiname, bool initialized) - { return afb_daemon_require_api_v2(apiname, int(initialized)); } + { return afb_daemon_require_api(apiname, int(initialized)); } -inline int rename_api(const char *apiname) - { return afb_daemon_rename_api_v2(apiname); } +inline int add_alias(const char *apiname, const char *aliasname) + { return afb_daemon_add_alias(apiname, aliasname); } -inline int verbosity() - { return afb_get_verbosity(); } +#if AFB_BINDING_VERSION >= 3 +inline int logmask() + { return afb_get_logmask(); } +#else +inline int logmask() + { return (1 << (1 + afb_get_verbosity() + AFB_SYSLOG_LEVEL_ERROR)) - 1; } +#endif inline bool wants_errors() - { return afb_verbose_error(); } + { return AFB_SYSLOG_MASK_WANT_ERROR(logmask()); } inline bool wants_warnings() - { return afb_verbose_warning(); } + { return AFB_SYSLOG_MASK_WANT_WARNING(logmask()); } inline bool wants_notices() - { return afb_verbose_notice(); } + { return AFB_SYSLOG_MASK_WANT_NOTICE(logmask()); } inline bool wants_infos() - { return afb_verbose_info(); } + { return AFB_SYSLOG_MASK_WANT_INFO(logmask()); } inline bool wants_debugs() - { return afb_verbose_debug(); } + { return AFB_SYSLOG_MASK_WANT_DEBUG(logmask()); } +#if AFB_BINDING_VERSION >= 3 +inline void call(const char *api, const char *verb, struct json_object *args, void (*callback)(void*closure, int iserror, struct json_object *result, afb_api_t api), void *closure) +{ + afb_service_call(api, verb, args, callback, closure); +} + +template <class T> +inline void call(const char *api, const char *verb, struct json_object *args, void (*callback)(T*closure, int iserror, struct json_object *result, afb_api_t api), T *closure) +{ + afb_service_call(api, verb, args, reinterpret_cast<void(*)(void*,int,json_object*,afb_api_t)>(callback), reinterpret_cast<void*>(closure)); +} +#else inline void call(const char *api, const char *verb, struct json_object *args, void (*callback)(void*closure, int iserror, struct json_object *result), void *closure) { afb_service_call(api, verb, args, callback, closure); @@ -475,6 +517,7 @@ inline void call(const char *api, const char *verb, struct json_object *args, vo { afb_service_call(api, verb, args, reinterpret_cast<void(*)(void*,int,json_object*)>(callback), reinterpret_cast<void*>(closure)); } +#endif inline bool callsync(const char *api, const char *verb, struct json_object *args, struct json_object *&result) { @@ -563,31 +606,67 @@ constexpr afb_auth auth_and(const afb_auth &first, const afb_auth &next) return auth_and(&first, &next); } -constexpr afb_verb_v2 verb(const char *name, void (*callback)(afb_req), const char *info = nullptr, unsigned session = 0, const afb_auth *auth = nullptr) +constexpr afb_verb_t verb( + const char *name, + void (*callback)(afb_req_t), + const char *info = nullptr, + uint16_t session = 0, + const afb_auth *auth = nullptr +#if AFB_BINDING_VERSION >= 3 + , + bool glob = false, + void *vcbdata = nullptr +#endif +) { - afb_verb_v2 r = { 0, 0, 0, 0, 0 }; +#if AFB_BINDING_VERSION >= 3 + afb_verb_t r = { 0, 0, 0, 0, 0, 0, 0 }; +#else + afb_verb_t r = { 0, 0, 0, 0, 0 }; +#endif r.verb = name; r.callback = callback; r.info = info; r.session = session; r.auth = auth; +#if AFB_BINDING_VERSION >= 3 + r.glob = (unsigned)glob; + r.vcbdata = vcbdata; +#endif return r; } -constexpr afb_verb_v2 verbend() +constexpr afb_verb_t verbend() { - afb_verb_v2 r = { 0, 0, 0, 0, 0 }; - r.verb = nullptr; - r.callback = nullptr; - r.info = nullptr; - r.session = 0; - r.auth = nullptr; + afb_verb_t r = verb(nullptr, nullptr); return r; } -constexpr afb_binding_v2 binding(const char *name, const struct afb_verb_v2 *verbs, const char *info = nullptr, int (*init)() = nullptr, const char *specification = nullptr, void (*onevent)(const char*, struct json_object*) = nullptr, bool noconcurrency = false, int (*preinit)() = nullptr) +constexpr afb_binding_t binding( + const char *name, + const afb_verb_t *verbs, + const char *info = nullptr, +#if AFB_BINDING_VERSION >= 3 + int (*init)(afb_api_t) = nullptr, + const char *specification = nullptr, + void (*onevent)(afb_api_t, const char*, struct json_object*) = nullptr, + bool noconcurrency = false, + int (*preinit)(afb_api_t) = nullptr, + void *userdata = nullptr +#else + int (*init)() = nullptr, + const char *specification = nullptr, + void (*onevent)(const char*, struct json_object*) = nullptr, + bool noconcurrency = false, + int (*preinit)() = nullptr +#endif +) { - afb_binding_v2 r = { 0, 0, 0, 0, 0, 0, 0, 0 }; +#if AFB_BINDING_VERSION >= 3 + afb_binding_t r = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +#else + afb_binding_t r = { 0, 0, 0, 0, 0, 0, 0, 0 }; +#endif r.api = name; r.specification = specification; r.info = info; @@ -596,6 +675,9 @@ constexpr afb_binding_v2 binding(const char *name, const struct afb_verb_v2 *ver r.init = init; r.onevent = onevent; r.noconcurrency = noconcurrency ? 1 : 0; +#if AFB_BINDING_VERSION >= 3 + r.userdata = userdata; +#endif return r; }; diff --git a/include/afb/afb-daemon-itf-x1.h b/include/afb/afb-daemon-itf-x1.h new file mode 100644 index 00000000..3ca12eba --- /dev/null +++ b/include/afb/afb-daemon-itf-x1.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdarg.h> + +/* declaration of features of libsystemd */ +struct sd_event; +struct sd_bus; +struct afb_stored_req; +struct afb_req_x1; +struct afb_event_x1; +struct afb_api_x3; + +/** + * @deprecated use bindings version 3 + * + * Definition of the facilities provided by the daemon. + */ +struct afb_daemon_itf_x1 +{ + /** broadcasts evant 'name' with 'object' */ + int (*event_broadcast)(struct afb_api_x3 *closure, const char *name, struct json_object *object); + + /** gets the common systemd's event loop */ + struct sd_event *(*get_event_loop)(struct afb_api_x3 *closure); + + /** gets the common systemd's user d-bus */ + struct sd_bus *(*get_user_bus)(struct afb_api_x3 *closure); + + /** gets the common systemd's system d-bus */ + struct sd_bus *(*get_system_bus)(struct afb_api_x3 *closure); + + /** logging messages */ + void (*vverbose_v1)(struct afb_api_x3*closure, int level, const char *file, int line, const char *fmt, va_list args); + + /** creates an event of 'name' */ + struct afb_event_x1 (*event_make)(struct afb_api_x3 *closure, const char *name); + + /** get the file descriptor of the install directory */ + int (*rootdir_get_fd)(struct afb_api_x3 *closure); + + /** opens a file of the install directory */ + int (*rootdir_open_locale)(struct afb_api_x3 *closure, const char *filename, int flags, const char *locale); + + /** queue a job */ + int (*queue_job)(struct afb_api_x3 *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout); + + /** logging messages */ + void (*vverbose_v2)(struct afb_api_x3*closure, int level, const char *file, int line, const char * func, const char *fmt, va_list args); + + /** retrieve a stored request */ + struct afb_req_x1 (*unstore_req)(struct afb_api_x3*closure, struct afb_stored_req *sreq); + + /** require an api */ + int (*require_api)(struct afb_api_x3*closure, const char *name, int initialized); + + /** aliases an api */ + int (*add_alias)(struct afb_api_x3*closure, const char *name, const char *as_name); + + /** creates a new api */ + struct afb_api_x3 *(*new_api)(struct afb_api_x3 *closure, const char *api, const char *info, int noconcurrency, int (*preinit)(void*, struct afb_api_x3 *), void *preinit_closure); +}; + +/** + * @deprecated use bindings version 3 + * + * Structure for accessing daemon. + * See also: afb_daemon_get_event_sender, afb_daemon_get_event_loop, afb_daemon_get_user_bus, afb_daemon_get_system_bus + */ +struct afb_daemon_x1 +{ + const struct afb_daemon_itf_x1 *itf; /**< the interfacing functions */ + struct afb_api_x3 *closure; /**< the closure when calling these functions */ +}; + diff --git a/include/afb/afb-daemon-itf.h b/include/afb/afb-daemon-itf.h deleted file mode 100644 index b8fa1931..00000000 --- a/include/afb/afb-daemon-itf.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <stdarg.h> - -/* declaration of features of libsystemd */ -struct sd_event; -struct sd_bus; -struct afb_stored_req; -struct afb_req; -struct afb_dynapi; - -/* - * Definition of the facilities provided by the daemon. - */ -struct afb_daemon_itf -{ - int (*event_broadcast)(void *closure, const char *name, struct json_object *object); /* broadcasts evant 'name' with 'object' */ - struct sd_event *(*get_event_loop)(void *closure); /* gets the common systemd's event loop */ - struct sd_bus *(*get_user_bus)(void *closure); /* gets the common systemd's user d-bus */ - struct sd_bus *(*get_system_bus)(void *closure); /* gets the common systemd's system d-bus */ - void (*vverbose_v1)(void*closure, int level, const char *file, int line, const char *fmt, va_list args); - struct afb_event (*event_make)(void *closure, const char *name); /* creates an event of 'name' */ - int (*rootdir_get_fd)(void *closure); - int (*rootdir_open_locale)(void *closure, const char *filename, int flags, const char *locale); - int (*queue_job)(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout); - void (*vverbose_v2)(void*closure, int level, const char *file, int line, const char * func, const char *fmt, va_list args); - struct afb_req (*unstore_req)(void*closure, struct afb_stored_req *sreq); - int (*require_api)(void*closure, const char *name, int initialized); - int (*rename_api)(void*closure, const char *name); - int (*new_api)(void *closure, const char *api, const char *info, int noconcurrency, int (*preinit)(void*, struct afb_dynapi *), void *preinit_closure); -}; - -/* - * Structure for accessing daemon. - * See also: afb_daemon_get_event_sender, afb_daemon_get_event_loop, afb_daemon_get_user_bus, afb_daemon_get_system_bus - */ -struct afb_daemon -{ - const struct afb_daemon_itf *itf; /* the interfacing functions */ - void *closure; /* the closure when calling these functions */ -}; - diff --git a/include/afb/afb-daemon-v1.h b/include/afb/afb-daemon-v1.h index 5a78b15d..d84517d1 100644 --- a/include/afb/afb-daemon-v1.h +++ b/include/afb/afb-daemon-v1.h @@ -17,36 +17,44 @@ #pragma once -#include "afb-daemon-itf.h" +#include "afb-daemon-itf-x1.h" -/* +/** + * @deprecated use bindings version 3 + * * Retrieves the common systemd's event loop of AFB * 'daemon' MUST be the daemon given in interface when activating the binding. */ -static inline struct sd_event *afb_daemon_get_event_loop_v1(struct afb_daemon daemon) +static inline struct sd_event *afb_daemon_get_event_loop_v1(struct afb_daemon_x1 daemon) { return daemon.itf->get_event_loop(daemon.closure); } -/* +/** + * @deprecated use bindings version 3 + * * Retrieves the common systemd's user/session d-bus of AFB * 'daemon' MUST be the daemon given in interface when activating the binding. */ -static inline struct sd_bus *afb_daemon_get_user_bus_v1(struct afb_daemon daemon) +static inline struct sd_bus *afb_daemon_get_user_bus_v1(struct afb_daemon_x1 daemon) { return daemon.itf->get_user_bus(daemon.closure); } -/* +/** + * @deprecated use bindings version 3 + * * Retrieves the common systemd's system d-bus of AFB * 'daemon' MUST be the daemon given in interface when activating the binding. */ -static inline struct sd_bus *afb_daemon_get_system_bus_v1(struct afb_daemon daemon) +static inline struct sd_bus *afb_daemon_get_system_bus_v1(struct afb_daemon_x1 daemon) { return daemon.itf->get_system_bus(daemon.closure); } -/* +/** + * @deprecated use bindings version 3 + * * Broadcasts widely the event of 'name' with the data 'object'. * 'object' can be NULL. * 'daemon' MUST be the daemon given in interface when activating the binding. @@ -59,12 +67,14 @@ static inline struct sd_bus *afb_daemon_get_system_bus_v1(struct afb_daemon daem * * Returns the count of clients that received the event. */ -static inline int afb_daemon_broadcast_event_v1(struct afb_daemon daemon, const char *name, struct json_object *object) +static inline int afb_daemon_broadcast_event_v1(struct afb_daemon_x1 daemon, const char *name, struct json_object *object) { return daemon.itf->event_broadcast(daemon.closure, name, object); } -/* +/** + * @deprecated use bindings version 3 + * * Creates an event of 'name' and returns it. * 'daemon' MUST be the daemon given in interface when activating the binding. * @@ -72,12 +82,14 @@ static inline int afb_daemon_broadcast_event_v1(struct afb_daemon daemon, const * * See afb_event_is_valid to check if there is an error. */ -static inline struct afb_event afb_daemon_make_event_v1(struct afb_daemon daemon, const char *name) +static inline struct afb_event_x1 afb_daemon_make_event_v1(struct afb_daemon_x1 daemon, const char *name) { return daemon.itf->event_make(daemon.closure, name); } -/* +/** + * @deprecated use bindings version 3 + * * Send a message described by 'fmt' and following parameters * to the journal for the verbosity 'level'. * @@ -96,8 +108,8 @@ static inline struct afb_event afb_daemon_make_event_v1(struct afb_daemon daemon * INFO 6 Informational * DEBUG 7 Debug-level messages */ -static inline void afb_daemon_verbose_v1(struct afb_daemon daemon, int level, const char *file, int line, const char *fmt, ...) __attribute__((format(printf, 5, 6))); -static inline void afb_daemon_verbose_v1(struct afb_daemon daemon, int level, const char *file, int line, const char *fmt, ...) +static inline void afb_daemon_verbose_v1(struct afb_daemon_x1 daemon, int level, const char *file, int line, const char *fmt, ...) __attribute__((format(printf, 5, 6))); +static inline void afb_daemon_verbose_v1(struct afb_daemon_x1 daemon, int level, const char *file, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -105,7 +117,9 @@ static inline void afb_daemon_verbose_v1(struct afb_daemon daemon, int level, co va_end(args); } -/* +/** + * @deprecated use bindings version 3 + * * Send a message described by 'fmt' and following parameters * to the journal for the verbosity 'level'. * @@ -124,8 +138,8 @@ static inline void afb_daemon_verbose_v1(struct afb_daemon daemon, int level, co * INFO 6 Informational * DEBUG 7 Debug-level messages */ -static inline void afb_daemon_verbose2_v1(struct afb_daemon daemon, int level, const char *file, int line, const char *func, const char *fmt, ...) __attribute__((format(printf, 6, 7))); -static inline void afb_daemon_verbose2_v1(struct afb_daemon daemon, int level, const char *file, int line, const char *func, const char *fmt, ...) +static inline void afb_daemon_verbose2_v1(struct afb_daemon_x1 daemon, int level, const char *file, int line, const char *func, const char *fmt, ...) __attribute__((format(printf, 6, 7))); +static inline void afb_daemon_verbose2_v1(struct afb_daemon_x1 daemon, int level, const char *file, int line, const char *func, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -133,26 +147,34 @@ static inline void afb_daemon_verbose2_v1(struct afb_daemon daemon, int level, c va_end(args); } -/* +/** + * @deprecated use bindings version 3 + * * Get the root directory file descriptor. This file descriptor can * be used with functions 'openat', 'fstatat', ... + * + * Returns the file descriptor or -1 in case of error. */ -static inline int afb_daemon_rootdir_get_fd_v1(struct afb_daemon daemon) +static inline int afb_daemon_rootdir_get_fd_v1(struct afb_daemon_x1 daemon) { return daemon.itf->rootdir_get_fd(daemon.closure); } -/* - * Opens 'filename' within the root directory with 'flags' (see function openat) +/** + * @deprecated use bindings version 3 + * * using the 'locale' definition (example: "jp,en-US") that can be NULL. + * * Returns the file descriptor or -1 in case of error. */ -static inline int afb_daemon_rootdir_open_locale_v1(struct afb_daemon daemon, const char *filename, int flags, const char *locale) +static inline int afb_daemon_rootdir_open_locale_v1(struct afb_daemon_x1 daemon, const char *filename, int flags, const char *locale) { return daemon.itf->rootdir_open_locale(daemon.closure, filename, flags, locale); } -/* +/** + * @deprecated use bindings version 3 + * * Queue the job defined by 'callback' and 'argument' for being executed asynchronously * in this thread (later) or in an other thread. * If 'group' is not NUL, the jobs queued with a same value (as the pointer value 'group') @@ -165,39 +187,52 @@ static inline int afb_daemon_rootdir_open_locale_v1(struct afb_daemon daemon, co * * Returns 0 in case of success or -1 in case of error. */ -static inline int afb_daemon_queue_job_v1(struct afb_daemon daemon, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) +static inline int afb_daemon_queue_job_v1(struct afb_daemon_x1 daemon, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) { return daemon.itf->queue_job(daemon.closure, callback, argument, group, timeout); } -/* +/** + * @deprecated use bindings version 3 + * * Tells that it requires the API of "name" to exist * and if 'initialized' is not null to be initialized. * Calling this function is only allowed within init. + * * Returns 0 in case of success or -1 in case of error. */ -static inline int afb_daemon_require_api_v1(struct afb_daemon daemon, const char *name, int initialized) +static inline int afb_daemon_require_api_v1(struct afb_daemon_x1 daemon, const char *name, int initialized) { return daemon.itf->require_api(daemon.closure, name, initialized); } -/* - * Set the name of the API to 'name'. +/** + * @deprecated use bindings version 3 + * + * Create an aliased name 'as_name' for the api 'name'. * Calling this function is only allowed within preinit. + * * Returns 0 in case of success or -1 in case of error. */ -static inline int afb_daemon_rename_api_v1(struct afb_daemon daemon, const char *name) +static inline int afb_daemon_add_alias_v1(struct afb_daemon_x1 daemon, const char *name, const char *as_name) { - return daemon.itf->rename_api(daemon.closure, name); + return daemon.itf->add_alias(daemon.closure, name, as_name); } +/** + * @deprecated use bindings version 3 + * + * Creates a new api of name 'api' with brief 'info'. + * + * Returns 0 in case of success or -1 in case of error. + */ static inline int afb_daemon_new_api_v1( - struct afb_daemon daemon, + struct afb_daemon_x1 daemon, const char *api, const char *info, int noconcurrency, - int (*preinit)(void*, struct afb_dynapi *), + int (*preinit)(void*, struct afb_api_x3 *), void *closure) { - return daemon.itf->new_api(daemon.closure, api, info, noconcurrency, preinit, closure); + return -!daemon.itf->new_api(daemon.closure, api, info, noconcurrency, preinit, closure); } diff --git a/include/afb/afb-daemon-v2.h b/include/afb/afb-daemon-v2.h index 4b8399c4..f3c2c904 100644 --- a/include/afb/afb-daemon-v2.h +++ b/include/afb/afb-daemon-v2.h @@ -17,9 +17,11 @@ #pragma once -#include "afb-daemon-itf.h" +#include "afb-daemon-itf-x1.h" -/* +/** + * @deprecated use bindings version 3 + * * Retrieves the common systemd's event loop of AFB */ static inline struct sd_event *afb_daemon_get_event_loop_v2() @@ -27,7 +29,9 @@ static inline struct sd_event *afb_daemon_get_event_loop_v2() return afb_get_daemon_v2().itf->get_event_loop(afb_get_daemon_v2().closure); } -/* +/** + * @deprecated use bindings version 3 + * * Retrieves the common systemd's user/session d-bus of AFB */ static inline struct sd_bus *afb_daemon_get_user_bus_v2() @@ -35,7 +39,9 @@ static inline struct sd_bus *afb_daemon_get_user_bus_v2() return afb_get_daemon_v2().itf->get_user_bus(afb_get_daemon_v2().closure); } -/* +/** + * @deprecated use bindings version 3 + * * Retrieves the common systemd's system d-bus of AFB */ static inline struct sd_bus *afb_daemon_get_system_bus_v2() @@ -43,7 +49,9 @@ static inline struct sd_bus *afb_daemon_get_system_bus_v2() return afb_get_daemon_v2().itf->get_system_bus(afb_get_daemon_v2().closure); } -/* +/** + * @deprecated use bindings version 3 + * * Broadcasts widely the event of 'name' with the data 'object'. * 'object' can be NULL. * @@ -60,19 +68,23 @@ static inline int afb_daemon_broadcast_event_v2(const char *name, struct json_ob return afb_get_daemon_v2().itf->event_broadcast(afb_get_daemon_v2().closure, name, object); } -/* +/** + * @deprecated use bindings version 3 + * * Creates an event of 'name' and returns it. * * Calling this function is only forbidden during preinit. * * See afb_event_is_valid to check if there is an error. */ -static inline struct afb_event afb_daemon_make_event_v2(const char *name) +static inline struct afb_event_x1 afb_daemon_make_event_v2(const char *name) { return afb_get_daemon_v2().itf->event_make(afb_get_daemon_v2().closure, name); } -/* +/** + * @deprecated use bindings version 3 + * * Send a message described by 'fmt' and following parameters * to the journal for the verbosity 'level'. * @@ -98,18 +110,25 @@ static inline void afb_daemon_verbose_v2(int level, const char *file, int line, va_end(args); } -/* +/** + * @deprecated use bindings version 3 + * * Get the root directory file descriptor. This file descriptor can * be used with functions 'openat', 'fstatat', ... + * + * Returns the file descriptor or -1 in case of error. */ static inline int afb_daemon_rootdir_get_fd_v2() { return afb_get_daemon_v2().itf->rootdir_get_fd(afb_get_daemon_v2().closure); } -/* +/** + * @deprecated use bindings version 3 + * * Opens 'filename' within the root directory with 'flags' (see function openat) * using the 'locale' definition (example: "jp,en-US") that can be NULL. + * * Returns the file descriptor or -1 in case of error. */ static inline int afb_daemon_rootdir_open_locale_v2(const char *filename, int flags, const char *locale) @@ -117,7 +136,9 @@ static inline int afb_daemon_rootdir_open_locale_v2(const char *filename, int fl return afb_get_daemon_v2().itf->rootdir_open_locale(afb_get_daemon_v2().closure, filename, flags, locale); } -/* +/** + * @deprecated use bindings version 3 + * * Queue the job defined by 'callback' and 'argument' for being executed asynchronously * in this thread (later) or in an other thread. * If 'group' is not NUL, the jobs queued with a same value (as the pointer value 'group') @@ -135,22 +156,27 @@ static inline int afb_daemon_queue_job_v2(void (*callback)(int signum, void *arg return afb_get_daemon_v2().itf->queue_job(afb_get_daemon_v2().closure, callback, argument, group, timeout); } -/* +/** + * @deprecated use bindings version 3 + * * Retrieves the afb_req stored at 'sreq'. * Returns the stored request. * The count of reference is UNCHANGED, thus, the * function 'afb_req_unref' should be called on the result * after that the asynchronous reply if sent. */ -static inline struct afb_req afb_daemon_unstore_req_v2(struct afb_stored_req *sreq) +static inline struct afb_req_x1 afb_daemon_unstore_req_v2(struct afb_stored_req *sreq) { return afb_get_daemon_v2().itf->unstore_req(afb_get_daemon_v2().closure, sreq); } -/* +/** + * @deprecated use bindings version 3 + * * Tells that it requires the API of "name" to exist * and if 'initialized' is not null to be initialized. * Calling this function is only allowed within init. + * * Returns 0 in case of success or -1 in case of error. */ static inline int afb_daemon_require_api_v2(const char *name, int initialized) @@ -158,23 +184,33 @@ static inline int afb_daemon_require_api_v2(const char *name, int initialized) return afb_get_daemon_v2().itf->require_api(afb_get_daemon_v2().closure, name, initialized); } -/* - * Set the name of the API to 'name'. +/** + * @deprecated use bindings version 3 + * + * Create an aliased name 'as_name' for the api 'name'. * Calling this function is only allowed within preinit. + * * Returns 0 in case of success or -1 in case of error. */ -static inline int afb_daemon_rename_api_v2(const char *name) +static inline int afb_daemon_add_alias_v2(const char *name, const char *as_name) { - return afb_get_daemon_v2().itf->rename_api(afb_get_daemon_v2().closure, name); + return afb_get_daemon_v2().itf->add_alias(afb_get_daemon_v2().closure, name, as_name); } +/** + * @deprecated use bindings version 3 + * + * Creates a new api of name 'api' with brief 'info'. + * + * Returns 0 in case of success or -1 in case of error. + */ static inline int afb_daemon_new_api_v2( const char *api, const char *info, int noconcurrency, - int (*preinit)(void*, struct afb_dynapi *), + int (*preinit)(void*, struct afb_api_x3 *), void *closure) { - return afb_get_daemon_v2().itf->new_api(afb_get_daemon_v2().closure, api, info, noconcurrency, preinit, closure); + return -!(afb_get_daemon_v2().itf->new_api(afb_get_daemon_v2().closure, api, info, noconcurrency, preinit, closure)); } diff --git a/include/afb/afb-dynapi-itf.h b/include/afb/afb-dynapi-itf.h deleted file mode 100644 index 979088d6..00000000 --- a/include/afb/afb-dynapi-itf.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -/* declared here */ -struct afb_dynapi; -struct afb_dynapi_itf; - -/* referenced here */ -#include <stdarg.h> -struct sd_event; -struct sd_bus; -struct afb_request; -struct afb_eventid; -struct afb_auth; -struct afb_verb_v2; - -/* - * structure for the dynapi - */ -struct afb_dynapi -{ - /* interface for the dynapi */ - const struct afb_dynapi_itf *itf; - - /* user defined data */ - void *userdata; - - /* current verbosity level */ - int verbosity; - - /* the name of the api */ - const char *apiname; -}; - -/* - * Definition of the interface for the API - */ -struct afb_dynapi_itf -{ - /* CAUTION: respect the order, add at the end */ - - void (*vverbose)( - void *dynapi, - int level, - const char *file, - int line, - const char * func, - const char *fmt, - va_list args); - - /* gets the common systemd's event loop */ - struct sd_event *(*get_event_loop)( - void *dynapi); - - /* gets the common systemd's user d-bus */ - struct sd_bus *(*get_user_bus)( - void *dynapi); - - /* gets the common systemd's system d-bus */ - struct sd_bus *(*get_system_bus)( - void *dynapi); - - int (*rootdir_get_fd)( - void *dynapi); - - int (*rootdir_open_locale)( - void *dynapi, - const char *filename, - int flags, - const char *locale); - - int (*queue_job)( - void *dynapi, - void (*callback)(int signum, void *arg), - void *argument, - void *group, - int timeout); - - int (*require_api)( - void *dynapi, - const char *name, - int initialized); - - int (*rename_api)( - void *dynapi, - const char *name); - - /* broadcasts event 'name' with 'object' */ - int (*event_broadcast)( - void *dynapi, - const char *name, - struct json_object *object); - - /* creates an event of 'name' */ - struct afb_eventid *(*eventid_make)( - void *dynapi, - const char *name); - - void (*call)( - struct afb_dynapi *dynapi, - const char *api, - const char *verb, - struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_dynapi *), - void *callback_closure); - - int (*call_sync)( - void *dynapi, - const char *api, - const char *verb, - struct json_object *args, - struct json_object **result); - - int (*api_new_api)( - void *dynapi, - const char *api, - const char *info, - int noconcurrency, - int (*preinit)(void*, struct afb_dynapi *), - void *closure); - - int (*api_set_verbs_v2)( - struct afb_dynapi *dynapi, - const struct afb_verb_v2 *verbs); - - int (*api_add_verb)( - struct afb_dynapi *dynapi, - const char *verb, - const char *info, - void (*callback)(struct afb_request *request), - void *vcbdata, - const struct afb_auth *auth, - uint32_t session); - - int (*api_sub_verb)( - struct afb_dynapi *dynapi, - const char *verb); - - int (*api_set_on_event)( - struct afb_dynapi *dynapi, - void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)); - - int (*api_set_on_init)( - struct afb_dynapi *dynapi, - int (*oninit)(struct afb_dynapi *dynapi)); - - void (*api_seal)( - struct afb_dynapi *dynapi); -}; - diff --git a/include/afb/afb-dynapi-legacy.h b/include/afb/afb-dynapi-legacy.h new file mode 100644 index 00000000..ffa0d92a --- /dev/null +++ b/include/afb/afb-dynapi-legacy.h @@ -0,0 +1,191 @@ + +/* + * Copyright (C) 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/***************************************************************************************************/ + +#define afb_dynapi afb_api_x3 +#define afb_dynapi_itf afb_api_x3_itf + +#define afb_request afb_req_x2 +#define afb_request_get_dynapi afb_req_x2_get_api +#define afb_request_get_vcbdata afb_req_x2_get_vcbdata +#define afb_request_get_api afb_req_x2_get_called_api +#define afb_request_get_verb afb_req_x2_get_called_verb +#define afb_request_wants_log_level afb_req_x2_wants_log_level + +#define afb_request_get afb_req_x2_get +#define afb_request_value afb_req_x2_value +#define afb_request_path afb_req_x2_path +#define afb_request_json afb_req_x2_json +#define afb_request_reply afb_req_x2_reply +#define afb_request_reply_f afb_req_x2_reply_f +#define afb_request_reply_v afb_req_x2_reply_v +#define afb_request_success(r,o,i) afb_req_x2_reply(r,o,0,i) +#define afb_request_success_f(r,o,...) afb_req_x2_reply_f(r,o,0,__VA_ARGS__) +#define afb_request_success_v(r,o,f,v) afb_req_x2_reply_v(r,o,0,f,v) +#define afb_request_fail(r,e,i) afb_req_x2_reply(r,0,e,i) +#define afb_request_fail_f(r,e,f,...) afb_req_x2_reply_f(r,0,e,f,__VA_ARGS__) +#define afb_request_fail_v(r,e,f,v) afb_req_x2_reply_v(r,0,e,f,v) +#define afb_request_context_get afb_req_x2_context_get +#define afb_request_context_set afb_req_x2_context_set +#define afb_request_context afb_req_x2_context +#define afb_request_context_clear afb_req_x2_context_clear +#define afb_request_addref afb_req_x2_addref +#define afb_request_unref afb_req_x2_unref +#define afb_request_session_close afb_req_x2_session_close +#define afb_request_session_set_LOA afb_req_x2_session_set_LOA +#define afb_request_subscribe afb_req_x2_subscribe +#define afb_request_unsubscribe afb_req_x2_unsubscribe +#define afb_request_subcall afb_req_x2_subcall_legacy +#define afb_request_subcall_sync afb_req_x2_subcall_sync_legacy +#define afb_request_verbose afb_req_x2_verbose +#define afb_request_has_permission afb_req_x2_has_permission +#define afb_request_get_application_id afb_req_x2_get_application_id +#define afb_request_get_uid afb_req_x2_get_uid +#define afb_request_get_client_info afb_req_x2_get_client_info + +#define afb_dynapi_name afb_api_x3_name +#define afb_dynapi_get_userdata afb_api_x3_get_userdata +#define afb_dynapi_set_userdata afb_api_x3_set_userdata +#define afb_dynapi_wants_log_level afb_api_x3_wants_log_level + +#define afb_dynapi_verbose afb_api_x3_verbose +#define afb_dynapi_vverbose afb_api_x3_vverbose +#define afb_dynapi_get_event_loop afb_api_x3_get_event_loop +#define afb_dynapi_get_user_bus afb_api_x3_get_user_bus +#define afb_dynapi_get_system_bus afb_api_x3_get_system_bus +#define afb_dynapi_rootdir_get_fd afb_api_x3_rootdir_get_fd +#define afb_dynapi_rootdir_open_locale afb_api_x3_rootdir_open_locale +#define afb_dynapi_queue_job afb_api_x3_queue_job +#define afb_dynapi_require_api afb_api_x3_require_api +#define afb_dynapi_rename_api afb_api_x3_add_alias +#define afb_dynapi_broadcast_event afb_api_x3_broadcast_event +#define afb_dynapi_make_eventid afb_api_x3_make_event_x2 +#define afb_dynapi_call afb_api_x3_call_legacy +#define afb_dynapi_call_sync afb_api_x3_call_sync_legacy +#define afb_dynapi_new_api(...) (-!afb_api_x3_new_api(__VA_ARGS__)) +#define afb_dynapi_set_verbs_v2 afb_api_x3_set_verbs_v2 +#define afb_dynapi_add_verb(a,b,c,d,e,f,g) afb_api_x3_add_verb(a,b,c,d,e,f,g,0) +#define afb_dynapi_sub_verb(a,b) afb_api_x3_del_verb(a,b,NULL) +#define afb_dynapi_on_event afb_api_x3_on_event +#define afb_dynapi_on_init afb_api_x3_on_init +#define afb_dynapi_seal afb_api_x3_seal + +#define afb_eventid_broadcast afb_event_x2_broadcast +#define afb_eventid_push afb_event_x2_push +#define afb_eventid_name afb_event_x2_name +#define afb_eventid_unref afb_event_x2_unref +#define afb_eventid_addref afb_event_x2_addref + +#define afb_eventid afb_event_x2 +#define afb_eventid_is_valid afb_event_x2_is_valid +#define afb_eventid_broadcast afb_event_x2_broadcast +#define afb_eventid_push afb_event_x2_push +#define afb_eventid_drop afb_event_x2_unref +#define afb_eventid_name afb_event_x2_name +#define afb_eventid_unref afb_event_x2_unref +#define afb_eventid_addref afb_event_x2_addref + +/* + * The function afbBindingVdyn if exported allows to create + * pure dynamic bindings. When the binding is loaded, it receives + * a virtual dynapi that can be used to create apis. The + * given API can not be used except for creating dynamic apis. + */ +extern int afbBindingVdyn(struct afb_dynapi *dynapi); + +/* + * Macros for logging messages + */ +/* macro for setting file, line and function automatically */ +# if !defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS) +#define AFB_REQUEST_VERBOSE(req,level,...) afb_req_x2_verbose(req,level,__FILE__,__LINE__,__func__,__VA_ARGS__) +#else +#define AFB_REQUEST_VERBOSE(req,level,...) afb_req_x2_verbose(req,level,NULL,0,NULL,__VA_ARGS__) +#endif + +#if defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DATA) + +# define _AFB_DYNAPI_LOGGING_(llevel,dynapi,...) \ + do{ \ + if(_AFB_SYSLOG_MASK_WANT_(dynapi->logmask,llevel)) {\ + if (llevel <= AFB_VERBOSITY_LEVEL_ERROR) \ + afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ + else \ + afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,NULL,NULL); \ + } \ + }while(0) +# define _AFB_REQUEST_LOGGING_(llevel,request,...) \ + do{ \ + if(request->_AFB_SYSLOG_MASK_WANT_(dynapi->logmask,llevel)) \ + afb_request_verbose(request,llevel,__FILE__,__LINE__,NULL,NULL); \ + }while(0) + +#elif defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS) + +# define _AFB_DYNAPI_LOGGING_(llevel,dynapi,...) \ + do{ \ + if(_AFB_SYSLOG_MASK_WANT_(dynapi->logmask,llevel)) \ + afb_dynapi_verbose(dynapi,llevel,NULL,0,NULL,__VA_ARGS__); \ + }while(0) +# define _AFB_REQUEST_LOGGING_(llevel,request,...) \ + do{ \ + if(request->_AFB_SYSLOG_MASK_WANT_(dynapi->logmask,llevel)) \ + afb_request_verbose(request,llevel,NULL,0,NULL,__VA_ARGS__); \ + }while(0) + +#else + +# define _AFB_DYNAPI_LOGGING_(llevel,dynapi,...) \ + do{ \ + if(AFB_SYSLOG_MASK_WANT(dynapi->logmask,llevel)) \ + afb_dynapi_verbose(dynapi,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ + }while(0) +# define _AFB_REQUEST_LOGGING_(llevel,request,...) \ + do{ \ + if(AFB_SYSLOG_MASK_WANT(request->api->logmask,llevel)) \ + afb_request_verbose(request,llevel,__FILE__,__LINE__,__func__,__VA_ARGS__); \ + }while(0) + +#endif + +#define AFB_DYNAPI_ERROR(...) _AFB_DYNAPI_LOGGING_(AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__) +#define AFB_DYNAPI_WARNING(...) _AFB_DYNAPI_LOGGING_(AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__) +#define AFB_DYNAPI_NOTICE(...) _AFB_DYNAPI_LOGGING_(AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__) +#define AFB_DYNAPI_INFO(...) _AFB_DYNAPI_LOGGING_(AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__) +#define AFB_DYNAPI_DEBUG(...) _AFB_DYNAPI_LOGGING_(AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__) +#define AFB_REQUEST_ERROR(...) _AFB_REQUEST_LOGGING_(AFB_SYSLOG_LEVEL_ERROR,__VA_ARGS__) +#define AFB_REQUEST_WARNING(...) _AFB_REQUEST_LOGGING_(AFB_SYSLOG_LEVEL_WARNING,__VA_ARGS__) +#define AFB_REQUEST_NOTICE(...) _AFB_REQUEST_LOGGING_(AFB_SYSLOG_LEVEL_NOTICE,__VA_ARGS__) +#define AFB_REQUEST_INFO(...) _AFB_REQUEST_LOGGING_(AFB_SYSLOG_LEVEL_INFO,__VA_ARGS__) +#define AFB_REQUEST_DEBUG(...) _AFB_REQUEST_LOGGING_(AFB_SYSLOG_LEVEL_DEBUG,__VA_ARGS__) + +typedef struct afb_eventid afb_eventid; +typedef struct afb_dynapi afb_dynapi; +typedef struct afb_request afb_request; + +#define _AFB_SYSLOG_LEVEL_EMERGENCY_ AFB_SYSLOG_LEVEL_EMERGENCY +#define _AFB_SYSLOG_LEVEL_ALERT_ AFB_SYSLOG_LEVEL_ALERT +#define _AFB_SYSLOG_LEVEL_CRITICAL_ AFB_SYSLOG_LEVEL_CRITICAL +#define _AFB_SYSLOG_LEVEL_ERROR_ AFB_SYSLOG_LEVEL_ERROR +#define _AFB_SYSLOG_LEVEL_WARNING_ AFB_SYSLOG_LEVEL_WARNING +#define _AFB_SYSLOG_LEVEL_NOTICE_ AFB_SYSLOG_LEVEL_NOTICE +#define _AFB_SYSLOG_LEVEL_INFO_ AFB_SYSLOG_LEVEL_INFO +#define _AFB_SYSLOG_LEVEL_DEBUG_ AFB_SYSLOG_LEVEL_DEBUG diff --git a/include/afb/afb-dynapi.h b/include/afb/afb-dynapi.h deleted file mode 100644 index 2a26915c..00000000 --- a/include/afb/afb-dynapi.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "afb-dynapi-itf.h" - -static inline const char *afb_dynapi_name(struct afb_dynapi *dynapi) -{ - return dynapi->apiname; -} - -static inline void *afb_dynapi_get_userdata(struct afb_dynapi *dynapi) -{ - return dynapi->userdata; -} - -static inline void afb_dynapi_set_userdata(struct afb_dynapi *dynapi, void *userdata) -{ - dynapi->userdata = userdata; -} - -/* - * Send a message described by 'fmt' and following parameters - * to the journal for the verbosity 'level'. - * - * 'file', 'line' and 'func' are indicators of position of the code in source files - * (see macros __FILE__, __LINE__ and __func__). - * - * - * 'level' is defined by syslog standard: - * EMERGENCY 0 System is unusable - * ALERT 1 Action must be taken immediately - * CRITICAL 2 Critical conditions - * ERROR 3 Error conditions - * WARNING 4 Warning conditions - * NOTICE 5 Normal but significant condition - * INFO 6 Informational - * DEBUG 7 Debug-level messages - */ -static inline void afb_dynapi_verbose(struct afb_dynapi *dynapi, int level, const char *file, int line, const char *func, const char *fmt, ...) __attribute__((format(printf, 6, 7))); -static inline void afb_dynapi_verbose(struct afb_dynapi *dynapi, int level, const char *file, int line, const char *func, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - dynapi->itf->vverbose(dynapi, level, file, line, func, fmt, args); - va_end(args); -} -static inline void afb_dynapi_vverbose(struct afb_dynapi *dynapi, int level, const char *file, int line, const char *func, const char *fmt, va_list args) -{ - dynapi->itf->vverbose(dynapi, level, file, line, func, fmt, args); -} - -/* - * Retrieves the common systemd's event loop of AFB - */ -static inline struct sd_event *afb_dynapi_get_event_loop(struct afb_dynapi *dynapi) -{ - return dynapi->itf->get_event_loop(dynapi); -} - -/* - * Retrieves the common systemd's user/session d-bus of AFB - */ -static inline struct sd_bus *afb_dynapi_get_user_bus(struct afb_dynapi *dynapi) -{ - return dynapi->itf->get_user_bus(dynapi); -} - -/* - * Retrieves the common systemd's system d-bus of AFB - */ -static inline struct sd_bus *afb_dynapi_get_system_bus(struct afb_dynapi *dynapi) -{ - return dynapi->itf->get_system_bus(dynapi); -} - -/* - * Get the root directory file descriptor. This file descriptor can - * be used with functions 'openat', 'fstatat', ... - */ -static inline int afb_dynapi_rootdir_get_fd(struct afb_dynapi *dynapi) -{ - return dynapi->itf->rootdir_get_fd(dynapi); -} - -/* - * Opens 'filename' within the root directory with 'flags' (see function openat) - * using the 'locale' definition (example: "jp,en-US") that can be NULL. - * Returns the file descriptor or -1 in case of error. - */ -static inline int afb_dynapi_rootdir_open_locale(struct afb_dynapi *dynapi, const char *filename, int flags, const char *locale) -{ - return dynapi->itf->rootdir_open_locale(dynapi, filename, flags, locale); -} - -/* - * Queue the job defined by 'callback' and 'argument' for being executed asynchronously - * in this thread (later) or in an other thread. - * If 'group' is not NUL, the jobs queued with a same value (as the pointer value 'group') - * are executed in sequence in the order of there submission. - * If 'timeout' is not 0, it represent the maximum execution time for the job in seconds. - * At first, the job is called with 0 as signum and the given argument. - * The job is executed with the monitoring of its time and some signals like SIGSEGV and - * SIGFPE. When a such signal is catched, the job is terminated and reexecuted but with - * signum being the signal number (SIGALRM when timeout expired). - * - * Returns 0 in case of success or -1 in case of error. - */ -static inline int afb_dynapi_queue_job(struct afb_dynapi *dynapi, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) -{ - return dynapi->itf->queue_job(dynapi, callback, argument, group, timeout); -} - -/* - * Tells that it requires the API of "name" to exist - * and if 'initialized' is not null to be initialized. - * Calling this function is only allowed within init. - * Returns 0 in case of success or -1 in case of error. - */ -static inline int afb_dynapi_require_api(struct afb_dynapi *dynapi, const char *name, int initialized) -{ - return dynapi->itf->require_api(dynapi, name, initialized); -} - -/* - * Set the name of the API to 'name'. - * Calling this function is only allowed within preinit. - * Returns 0 in case of success or -1 in case of error. - */ -static inline int afb_dynapi_rename_api(struct afb_dynapi *dynapi, const char *name) -{ - return dynapi->itf->rename_api(dynapi, name); -} - -/* - * Broadcasts widely the event of 'name' with the data 'object'. - * 'object' can be NULL. - * - * For convenience, the function calls 'json_object_put' for 'object'. - * Thus, in the case where 'object' should remain available after - * the function returns, the function 'json_object_get' shall be used. - * - * Calling this function is only forbidden during preinit. - * - * Returns the count of clients that received the event. - */ -static inline int afb_dynapi_broadcast_event(struct afb_dynapi *dynapi, const char *name, struct json_object *object) -{ - return dynapi->itf->event_broadcast(dynapi, name, object); -} - -/* - * Creates an event of 'name' and returns it. - * - * Calling this function is only forbidden during preinit. - * - * See afb_event_is_valid to check if there is an error. - */ -static inline struct afb_eventid *afb_dynapi_make_eventid(struct afb_dynapi *dynapi, const char *name) -{ - return dynapi->itf->eventid_make(dynapi, name); -} - -/** - * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. - * The result of the call is delivered to the 'callback' function with the 'callback_closure'. - * - * For convenience, the function calls 'json_object_put' for 'args'. - * Thus, in the case where 'args' should remain available after - * the function returns, the function 'json_object_get' shall be used. - * - * The 'callback' receives 3 arguments: - * 1. 'closure' the user defined closure pointer 'callback_closure', - * 2. 'status' a status being 0 on success or negative when an error occured, - * 2. 'result' the resulting data as a JSON object. - * - * @param dynapi The dynapi - * @param api The api name of the method to call - * @param verb The verb name of the method to call - * @param args The arguments to pass to the method - * @param callback The to call on completion - * @param callback_closure The closure to pass to the callback - * - * @see also 'afb_req_subcall' - */ -static inline void afb_dynapi_call( - struct afb_dynapi *dynapi, - const char *api, - const char *verb, - struct json_object *args, - void (*callback)(void *closure, int status, struct json_object *result, struct afb_dynapi *dynapi), - void *callback_closure) -{ - dynapi->itf->call(dynapi, api, verb, args, callback, callback_closure); -} - -/** - * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. - * 'result' will receive the response. - * - * For convenience, the function calls 'json_object_put' for 'args'. - * Thus, in the case where 'args' should remain available after - * the function returns, the function 'json_object_get' shall be used. - * - * @param dynapi The dynapi - * @param api The api name of the method to call - * @param verb The verb name of the method to call - * @param args The arguments to pass to the method - * @param result Where to store the result - should call json_object_put on it - - * - * @returns 0 in case of success or a negative value in case of error. - * - * @see also 'afb_req_subcall' - */ -static inline int afb_dynapi_call_sync( - struct afb_dynapi *dynapi, - const char *api, - const char *verb, - struct json_object *args, - struct json_object **result) -{ - return dynapi->itf->call_sync(dynapi, api, verb, args, result); -} - - -static inline int afb_dynapi_new_api( - struct afb_dynapi *dynapi, - const char *api, - const char *info, - int noconcurrency, - int (*preinit)(void*, struct afb_dynapi *), - void *closure) -{ - return dynapi->itf->api_new_api(dynapi, api, info, noconcurrency, preinit, closure); -} - -static inline int afb_dynapi_set_verbs_v2( - struct afb_dynapi *dynapi, - const struct afb_verb_v2 *verbs) -{ - return dynapi->itf->api_set_verbs_v2(dynapi, verbs); -} - -static inline int afb_dynapi_add_verb( - struct afb_dynapi *dynapi, - const char *verb, - const char *info, - void (*callback)(struct afb_request *request), - void *vcbdata, - const struct afb_auth *auth, - uint32_t session) -{ - return dynapi->itf->api_add_verb(dynapi, verb, info, callback, vcbdata, auth, session); -} - - -static inline int afb_dynapi_sub_verb( - struct afb_dynapi *dynapi, - const char *verb) -{ - return dynapi->itf->api_sub_verb(dynapi, verb); -} - - -static inline int afb_dynapi_on_event( - struct afb_dynapi *dynapi, - void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) -{ - return dynapi->itf->api_set_on_event(dynapi, onevent); -} - - -static inline int afb_dynapi_on_init( - struct afb_dynapi *dynapi, - int (*oninit)(struct afb_dynapi *dynapi)) -{ - return dynapi->itf->api_set_on_init(dynapi, oninit); -} - - -static inline void afb_dynapi_seal( - struct afb_dynapi *dynapi) -{ - dynapi->itf->api_seal(dynapi); -} - - diff --git a/include/afb/afb-event-x1-itf.h b/include/afb/afb-event-x1-itf.h new file mode 100644 index 00000000..afd033b8 --- /dev/null +++ b/include/afb/afb-event-x1-itf.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "afb-event-x2-itf.h" + +/** + * @deprecated use bindings version 3 + * + * Describes the request of afb-daemon for bindings + */ +struct afb_event_x1 +{ + const struct afb_event_x2_itf *itf; /**< the interface to use */ + struct afb_event_x2 *closure; /**< the closure argument for functions of 'itf' */ +}; + diff --git a/include/afb/afb-event.h b/include/afb/afb-event-x1.h index 0876d8cf..1fc7696f 100644 --- a/include/afb/afb-event.h +++ b/include/afb/afb-event-x1.h @@ -17,36 +17,33 @@ #pragma once -#include "afb-eventid-itf.h" +#include "afb-event-x1-itf.h" -/* - * Describes the request of afb-daemon for bindings - */ -struct afb_event -{ - const struct afb_eventid_itf *itf; /* the interface to use */ - struct afb_eventid *closure; /* the closure argument for functions of 'itf' */ -}; - -/* +/** + * @deprecated use bindings version 3 + * * Converts the 'event' to an afb_eventid. */ -static inline struct afb_eventid *afb_event_to_eventid(struct afb_event event) +static inline struct afb_event_x2 *afb_event_x1_to_event_x2(struct afb_event_x1 event) { return event.closure; } -/* +/** + * @deprecated use bindings version 3 + * * Checks wether the 'event' is valid or not. * * Returns 0 if not valid or 1 if valid. */ -static inline int afb_event_is_valid(struct afb_event event) +static inline int afb_event_x1_is_valid(struct afb_event_x1 event) { return !!event.itf; } -/* +/** + * @deprecated use bindings version 3 + * * Broadcasts widely the 'event' with the data 'object'. * 'object' can be NULL. * @@ -56,12 +53,14 @@ static inline int afb_event_is_valid(struct afb_event event) * * Returns the count of clients that received the event. */ -static inline int afb_event_broadcast(struct afb_event event, struct json_object *object) +static inline int afb_event_x1_broadcast(struct afb_event_x1 event, struct json_object *object) { return event.itf->broadcast(event.closure, object); } -/* +/** + * @deprecated use bindings version 3 + * * Pushes the 'event' with the data 'object' to its observers. * 'object' can be NULL. * @@ -71,35 +70,41 @@ static inline int afb_event_broadcast(struct afb_event event, struct json_object * * Returns the count of clients that received the event. */ -static inline int afb_event_push(struct afb_event event, struct json_object *object) +static inline int afb_event_x1_push(struct afb_event_x1 event, struct json_object *object) { return event.itf->push(event.closure, object); } /* OBSOLETE */ -#define afb_event_drop afb_event_unref +#define afb_event_x1_drop afb_event_x1_unref -/* +/** + * @deprecated use bindings version 3 + * * Gets the name associated to the 'event'. */ -static inline const char *afb_event_name(struct afb_event event) +static inline const char *afb_event_x1_name(struct afb_event_x1 event) { return event.itf->name(event.closure); } -/* +/** + * @deprecated use bindings version 3 + * * Decreases the count of reference to 'event' and * destroys the event when the reference count falls to zero. */ -static inline void afb_event_unref(struct afb_event event) +static inline void afb_event_x1_unref(struct afb_event_x1 event) { event.itf->unref(event.closure); } -/* +/** + * @deprecated use bindings version 3 + * * Increases the count of reference to 'event' */ -static inline void afb_event_addref(struct afb_event event) +static inline void afb_event_x1_addref(struct afb_event_x1 event) { event.itf->addref(event.closure); } diff --git a/include/afb/afb-eventid-itf.h b/include/afb/afb-event-x2-itf.h index 0af36581..ecc42c79 100644 --- a/include/afb/afb-eventid-itf.h +++ b/include/afb/afb-event-x2-itf.h @@ -17,31 +17,41 @@ #pragma once -struct json_object; -struct afb_eventid; -struct afb_eventid_itf; +struct afb_event_x2; +struct afb_event_x2_itf; -/* - * Interface for handling eventid. - * It records the functions to be called for the eventid. +/** + * Interface for handling event_x2. + * + * It records the functions to be called for the event_x2. + * * Don't use this structure directly. */ -struct afb_eventid_itf +struct afb_event_x2_itf { /* CAUTION: respect the order, add at the end */ - int (*broadcast)(struct afb_eventid *eventid, struct json_object *obj); - int (*push)(struct afb_eventid *eventid, struct json_object *obj); - void (*unref)(struct afb_eventid *eventid); /* aka drop */ - const char *(*name)(struct afb_eventid *eventid); - struct afb_eventid *(*addref)(struct afb_eventid *eventid); + /** broadcast the event */ + int (*broadcast)(struct afb_event_x2 *event, struct json_object *obj); + + /** push the event to its subscribers */ + int (*push)(struct afb_event_x2 *event, struct json_object *obj); + + /** unreference the event */ + void (*unref)(struct afb_event_x2 *event); /* aka drop */ + + /** get the event name */ + const char *(*name)(struct afb_event_x2 *event); + + /** rereference the event */ + struct afb_event_x2 *(*addref)(struct afb_event_x2 *event); }; -/* - * Describes the eventid +/** + * Describes the event_x2 */ -struct afb_eventid +struct afb_event_x2 { - const struct afb_eventid_itf *itf; /* the interface to use */ + const struct afb_event_x2_itf *itf; /**< the interface functions to use */ }; diff --git a/include/afb/afb-event-x2.h b/include/afb/afb-event-x2.h new file mode 100644 index 00000000..f0a27877 --- /dev/null +++ b/include/afb/afb-event-x2.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "afb-event-x2-itf.h" + +/** + * Checks whether the 'event' is valid or not. + * + * @param event the event to check + * + * @return 0 if not valid or 1 if valid. + */ +static inline int afb_event_x2_is_valid(struct afb_event_x2 *event) +{ + return !!event; +} + +/** + * Broadcasts widely an event of 'event' with the data 'object'. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param event the event to broadcast + * @param object the companion object to associate to the broadcasted event (can be NULL) + * + * @return the count of clients that received the event. + */ +static inline int afb_event_x2_broadcast( + struct afb_event_x2 *event, + struct json_object *object) +{ + return event->itf->broadcast(event, object); +} + +/** + * Pushes an event of 'event' with the data 'object' to its observers. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param event the event to push + * @param object the companion object to associate to the pushed event (can be NULL) + * + * @return the count of clients that received the event. + */ +static inline int afb_event_x2_push( + struct afb_event_x2 *event, + struct json_object *object) +{ + return event->itf->push(event, object); +} + +/** + * Gets the name associated to 'event'. + * + * @param event the event whose name is requested + * + * @return the name of the event + * + * The returned name can be used until call to 'afb_event_x2_unref'. + * It shouldn't be freed. + */ +static inline const char *afb_event_x2_name(struct afb_event_x2 *event) +{ + return event->itf->name(event); +} + +/** + * Decrease the count of references to 'event'. + * Call this function when the evenid is no more used. + * It destroys the event_x2 when the reference count falls to zero. + * + * @param event the event + */ +static inline void afb_event_x2_unref(struct afb_event_x2 *event) +{ + event->itf->unref(event); +} + +/** + * Increases the count of references to 'event' + * + * @param event the event + * + * @return the event + */ +static inline struct afb_event_x2 *afb_event_x2_addref( + struct afb_event_x2 *event) +{ + return event->itf->addref(event); +} + diff --git a/include/afb/afb-eventid.h b/include/afb/afb-eventid.h deleted file mode 100644 index 69d82a75..00000000 --- a/include/afb/afb-eventid.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "afb-eventid-itf.h" - -/* - * Broadcasts widely an event of 'eventid' with the data 'object'. - * 'object' can be NULL. - * - * For convenience, the function calls 'json_object_put' for 'object'. - * Thus, in the case where 'object' should remain available after - * the function returns, the function 'json_object_get' shall be used. - * - * Returns the count of clients that received the event. - */ -static inline int afb_eventid_broadcast( - struct afb_eventid *eventid, - struct json_object *object) -{ - return eventid->itf->broadcast(eventid, object); -} - -/* - * Pushes an event of 'eventid' with the data 'object' to its observers. - * 'object' can be NULL. - * - * For convenience, the function calls 'json_object_put' for 'object'. - * Thus, in the case where 'object' should remain available after - * the function returns, the function 'json_object_get' shall be used. - * - * Returns the count of clients that received the event. - */ -static inline int afb_eventid_push( - struct afb_eventid *eventid, - struct json_object *object) -{ - return eventid->itf->push(eventid, object); -} - -/* - * Gets the name associated to 'eventid'. - * The returned name can be used until call to 'afb_eventid_unref'. - */ -static inline const char *afb_eventid_name(struct afb_eventid *eventid) -{ - return eventid->itf->name(eventid); -} - -/* - * Decrease the count of references to 'eventid'. - * Call this function when the evenid is no more used. - * It destroys the eventid when the reference count falls to zero. - */ -static inline void afb_eventid_unref(struct afb_eventid *eventid) -{ - eventid->itf->unref(eventid); -} - -/* - * Increases the count of references to 'eventid' - */ -static inline struct afb_eventid *afb_eventid_addref( - struct afb_eventid *eventid) -{ - return eventid->itf->addref(eventid); -} - diff --git a/include/afb/afb-req-v1.h b/include/afb/afb-req-v1.h index f1bcd47d..40fb3b85 100644 --- a/include/afb/afb-req-v1.h +++ b/include/afb/afb-req-v1.h @@ -18,34 +18,38 @@ #pragma once #include <stdlib.h> -#include "afb-req.h" +#include "afb-req-x1.h" -/* +/** + * @deprecated use bindings version 3 + * * Stores 'req' on heap for asynchrnous use. * Returns a pointer to the stored 'req' or NULL on memory depletion. * The count of reference to 'req' is incremented on success * (see afb_req_addref). */ -static inline struct afb_req *afb_req_store_v1(struct afb_req req) +static inline struct afb_req_x1 *afb_req_x1_store_v1(struct afb_req_x1 req) { - struct afb_req *result = (struct afb_req*)malloc(sizeof *result); + struct afb_req_x1 *result = (struct afb_req_x1*)malloc(sizeof *result); if (result) { *result = req; - afb_req_addref(req); + afb_req_x1_addref(req); } return result; } -/* +/** + * @deprecated use bindings version 3 + * * Retrieves the afb_req stored at 'req' and frees the memory. * Returns the stored request. * The count of reference is UNCHANGED, thus, normally, the * function 'afb_req_unref' should be called on the result * after that the asynchronous reply if sent. */ -static inline struct afb_req afb_req_unstore_v1(struct afb_req *req) +static inline struct afb_req_x1 afb_req_unstore_x1_v1(struct afb_req_x1 *req) { - struct afb_req result = *req; + struct afb_req_x1 result = *req; free(req); return result; } diff --git a/include/afb/afb-req-v2.h b/include/afb/afb-req-v2.h index 34cbbdaa..f7901908 100644 --- a/include/afb/afb-req-v2.h +++ b/include/afb/afb-req-v2.h @@ -17,16 +17,18 @@ #pragma once -#include "afb-req.h" +#include "afb-req-x1.h" -/* +/** + * @deprecated use bindings version 3 + * * Stores 'req' on heap for asynchrnous use. * Returns a handler to the stored 'req' or NULL on memory depletion. * The count of reference to 'req' is incremented on success * (see afb_req_addref). */ -static inline struct afb_stored_req *afb_req_store_v2(struct afb_req req) +static inline struct afb_stored_req *afb_req_x1_store_v2(struct afb_req_x1 req) { - return req.itf->store(req.closure); + return req.itf->legacy_store_req(req.closure); } diff --git a/include/afb/afb-req-itf.h b/include/afb/afb-req-x1-itf.h index 2dd42d2e..dce936d1 100644 --- a/include/afb/afb-req-itf.h +++ b/include/afb/afb-req-x1-itf.h @@ -17,14 +17,16 @@ #pragma once -#include "afb-request-itf.h" +#include "afb-req-x2-itf.h" -/* - * Describes the request by bindings from afb-daemon +/** + * @deprecated use bindings version 3 + * + * Describes the request to bindings version 1 and 2 */ -struct afb_req +struct afb_req_x1 { - const struct afb_request_itf *itf; /* the interface to use */ - struct afb_request *closure; /* the closure argument for functions of 'itf' */ + const struct afb_req_x2_itf *itf; /**< the interface to use */ + struct afb_req_x2 *closure; /**< the closure argument for functions of 'itf' */ }; diff --git a/include/afb/afb-req.h b/include/afb/afb-req-x1.h index 77153ef1..cea17d0c 100644 --- a/include/afb/afb-req.h +++ b/include/afb/afb-req-x1.h @@ -17,28 +17,34 @@ #pragma once -#include "afb-req-itf.h" -#include "afb-event.h" +#include "afb-req-x1-itf.h" +#include "afb-event-x1.h" -/* +/** + * @deprecated use bindings version 3 + * * Converts the 'req' to an afb_request. */ -static inline struct afb_request *afb_req_to_request(struct afb_req req) +static inline struct afb_req_x2 *afb_req_x1_to_req_x2(struct afb_req_x1 req) { return req.closure; } -/* +/** + * @deprecated use bindings version 3 + * * Checks whether the request 'req' is valid or not. * * Returns 0 if not valid or 1 if valid. */ -static inline int afb_req_is_valid(struct afb_req req) +static inline int afb_req_x1_is_valid(struct afb_req_x1 req) { return !!req.itf; } -/* +/** + * @deprecated use bindings version 3 + * * Gets from the request 'req' the argument of 'name'. * Returns a PLAIN structure of type 'struct afb_arg'. * When the argument of 'name' is not found, all fields of result are set to NULL. @@ -50,157 +56,141 @@ static inline int afb_req_is_valid(struct afb_req req) * an HTTP POST of Content-Type "application/json". In that case, the * argument of name "" receives the value of the body of the HTTP request. */ -static inline struct afb_arg afb_req_get(struct afb_req req, const char *name) +static inline struct afb_arg afb_req_x1_get(struct afb_req_x1 req, const char *name) { return req.itf->get(req.closure, name); } -/* +/** + * @deprecated use bindings version 3 + * * Gets from the request 'req' the string value of the argument of 'name'. * Returns NULL if when there is no argument of 'name'. * Returns the value of the argument of 'name' otherwise. * * Shortcut for: afb_req_get(req, name).value */ -static inline const char *afb_req_value(struct afb_req req, const char *name) +static inline const char *afb_req_x1_value(struct afb_req_x1 req, const char *name) { - return afb_req_get(req, name).value; + return afb_req_x1_get(req, name).value; } -/* +/** + * @deprecated use bindings version 3 + * * Gets from the request 'req' the path for file attached to the argument of 'name'. * Returns NULL if when there is no argument of 'name' or when there is no file. * Returns the path of the argument of 'name' otherwise. * * Shortcut for: afb_req_get(req, name).path */ -static inline const char *afb_req_path(struct afb_req req, const char *name) +static inline const char *afb_req_x1_path(struct afb_req_x1 req, const char *name) { - return afb_req_get(req, name).path; + return afb_req_x1_get(req, name).path; } -/* +/** + * @deprecated use bindings version 3 + * * Gets from the request 'req' the json object hashing the arguments. * The returned object must not be released using 'json_object_put'. */ -static inline struct json_object *afb_req_json(struct afb_req req) +static inline struct json_object *afb_req_x1_json(struct afb_req_x1 req) { return req.itf->json(req.closure); } -/* - * Sends a reply of kind success to the request 'req'. - * The status of the reply is automatically set to "success". +/** + * @deprecated use bindings version 3 + * + * Sends a reply to the request 'req'. + * The status of the reply is set to 'error' (that must be NULL on success). * Its send the object 'obj' (can be NULL) with an - * informationnal comment 'info (can also be NULL). + * informational comment 'info (can also be NULL). * * For convenience, the function calls 'json_object_put' for 'obj'. * Thus, in the case where 'obj' should remain available after * the function returns, the function 'json_object_get' shall be used. */ -static inline void afb_req_success(struct afb_req req, struct json_object *obj, const char *info) +static inline void afb_req_x1_reply(struct afb_req_x1 req, struct json_object *obj, const char *error, const char *info) { - req.itf->success(req.closure, obj, info); + req.itf->reply(req.closure, obj, error, info); } -/* - * Same as 'afb_req_success' but the 'info' is a formatting +/** + * @deprecated use bindings version 3 + * + * Same as 'afb_req_x1_reply' but the 'info' is a formatting * string followed by arguments. * * For convenience, the function calls 'json_object_put' for 'obj'. * Thus, in the case where 'obj' should remain available after * the function returns, the function 'json_object_get' shall be used. */ -static inline void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...) __attribute__((format(printf, 3, 4))); -static inline void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...) +static inline void afb_req_x1_reply_f(struct afb_req_x1 req, struct json_object *obj, const char *error, const char *info, ...) __attribute__((format(printf, 4, 5))); +static inline void afb_req_x1_reply_f(struct afb_req_x1 req, struct json_object *obj, const char *error, const char *info, ...) { va_list args; va_start(args, info); - req.itf->vsuccess(req.closure, obj, info, args); + req.itf->vreply(req.closure, obj, error, info, args); va_end(args); } -/* - * Same as 'afb_req_success_f' but the arguments to the format 'info' +/** + * @deprecated use bindings version 3 + * + * Same as 'afb_req_x1_reply_f' but the arguments to the format 'info' * are given as a variable argument list instance. * * For convenience, the function calls 'json_object_put' for 'obj'. * Thus, in the case where 'obj' should remain available after * the function returns, the function 'json_object_get' shall be used. */ -static inline void afb_req_success_v(struct afb_req req, struct json_object *obj, const char *info, va_list args) +static inline void afb_req_x1_reply_v(struct afb_req_x1 req, struct json_object *obj, const char *error, const char *info, va_list args) { - req.itf->vsuccess(req.closure, obj, info, args); + req.itf->vreply(req.closure, obj, error, info, args); } -/* - * Sends a reply of kind failure to the request 'req'. - * The status of the reply is set to 'status' and an - * informationnal comment 'info' (can also be NULL) can be added. +/** + * @deprecated use bindings version 3 * - * Note that calling afb_req_fail("success", info) is equivalent - * to call afb_req_success(NULL, info). Thus even if possible it - * is strongly recommanded to NEVER use "success" for status. - */ -static inline void afb_req_fail(struct afb_req req, const char *status, const char *info) -{ - req.itf->fail(req.closure, status, info); -} - -/* - * Same as 'afb_req_fail' but the 'info' is a formatting - * string followed by arguments. - */ -static inline void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...) __attribute__((format(printf, 3, 4))); -static inline void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...) -{ - va_list args; - va_start(args, info); - req.itf->vfail(req.closure, status, info, args); - va_end(args); -} - -/* - * Same as 'afb_req_fail_f' but the arguments to the format 'info' - * are given as a variable argument list instance. - */ -static inline void afb_req_fail_v(struct afb_req req, const char *status, const char *info, va_list args) -{ - req.itf->vfail(req.closure, status, info, args); -} - -/* * Gets the pointer stored by the binding for the session of 'req'. * When the binding has not yet recorded a pointer, NULL is returned. */ -static inline void *afb_req_context_get(struct afb_req req) +static inline void *afb_req_x1_context_get(struct afb_req_x1 req) { - return req.itf->context_get(req.closure); + return req.itf->context_make(req.closure, 0, 0, 0, 0); } -/* +/** + * @deprecated use bindings version 3 + * * Stores for the binding the pointer 'context' to the session of 'req'. * The function 'free_context' will be called when the session is closed * or if binding stores an other pointer. */ -static inline void afb_req_context_set(struct afb_req req, void *context, void (*free_context)(void*)) +static inline void afb_req_x1_context_set(struct afb_req_x1 req, void *context, void (*free_context)(void*)) { - req.itf->context_set(req.closure, context, free_context); + req.itf->context_make(req.closure, 1, 0, free_context, context); } -/* +/** + * @deprecated use bindings version 3 + * * Gets the pointer stored by the binding for the session of 'req'. * If the stored pointer is NULL, indicating that no pointer was * already stored, afb_req_context creates a new context by calling * the function 'create_context' and stores it with the freeing function * 'free_context'. */ -static inline void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*)) +static inline void *afb_req_x1_context(struct afb_req_x1 req, void *(*create_context)(), void (*free_context)(void*)) { return req.itf->context_make(req.closure, 0, (void *(*)(void*))(void*)create_context, free_context, 0); } -/* +/** + * @deprecated use bindings version 3 + * * Gets the pointer stored by the binding for the session of 'request'. * If no previous pointer is stored or if 'replace' is not zero, a new value * is generated using the function 'create_context' called with the 'closure'. @@ -210,83 +200,99 @@ static inline void *afb_req_context(struct afb_req req, void *(*create_context)( * it is not more used. * This function is atomic: it ensures that 2 threads will not race together. */ -static inline void *afb_req_context_make(struct afb_req req, int replace, void *(*create_context)(void *closure), void (*free_context)(void*), void *closure) +static inline void *afb_req_x1_context_make(struct afb_req_x1 req, int replace, void *(*create_context)(void *closure), void (*free_context)(void*), void *closure) { return req.itf->context_make(req.closure, replace, create_context, free_context, closure); } -/* +/** + * @deprecated use bindings version 3 + * * Frees the pointer stored by the binding for the session of 'req' * and sets it to NULL. * * Shortcut for: afb_req_context_set(req, NULL, NULL) */ -static inline void afb_req_context_clear(struct afb_req req) +static inline void afb_req_x1_context_clear(struct afb_req_x1 req) { - afb_req_context_set(req, 0, 0); + req.itf->context_make(req.closure, 1, 0, 0, 0); } -/* +/** + * @deprecated use bindings version 3 + * * Adds one to the count of references of 'req'. * This function MUST be called by asynchronous implementations * of verbs if no reply was sent before returning. */ -static inline void afb_req_addref(struct afb_req req) +static inline void afb_req_x1_addref(struct afb_req_x1 req) { req.itf->addref(req.closure); } -/* +/** + * @deprecated use bindings version 3 + * * Substracts one to the count of references of 'req'. * This function MUST be called by asynchronous implementations * of verbs after sending the asynchronous reply. */ -static inline void afb_req_unref(struct afb_req req) +static inline void afb_req_x1_unref(struct afb_req_x1 req) { req.itf->unref(req.closure); } -/* +/** + * @deprecated use bindings version 3 + * * Closes the session associated with 'req' * and delete all associated contexts. */ -static inline void afb_req_session_close(struct afb_req req) +static inline void afb_req_x1_session_close(struct afb_req_x1 req) { req.itf->session_close(req.closure); } -/* +/** + * @deprecated use bindings version 3 + * * Sets the level of assurance of the session of 'req' * to 'level'. The effect of this function is subject of * security policies. * Returns 1 on success or 0 if failed. */ -static inline int afb_req_session_set_LOA(struct afb_req req, unsigned level) +static inline int afb_req_x1_session_set_LOA(struct afb_req_x1 req, unsigned level) { - return req.itf->session_set_LOA(req.closure, level); + return 1 + req.itf->session_set_LOA(req.closure, level); } -/* +/** + * @deprecated use bindings version 3 + * * Establishes for the client link identified by 'req' a subscription * to the 'event'. * Returns 0 in case of successful subscription or -1 in case of error. */ -static inline int afb_req_subscribe(struct afb_req req, struct afb_event event) +static inline int afb_req_x1_subscribe(struct afb_req_x1 req, struct afb_event_x1 event) { - return req.itf->subscribe(req.closure, event); + return req.itf->legacy_subscribe_event_x1(req.closure, event); } -/* +/** + * @deprecated use bindings version 3 + * * Revokes the subscription established to the 'event' for the client * link identified by 'req'. * Returns 0 in case of successful subscription or -1 in case of error. */ -static inline int afb_req_unsubscribe(struct afb_req req, struct afb_event event) +static inline int afb_req_x1_unsubscribe(struct afb_req_x1 req, struct afb_event_x1 event) { - return req.itf->unsubscribe(req.closure, event); + return req.itf->legacy_unsubscribe_event_x1(req.closure, event); } -/* +/** + * @deprecated use bindings version 3 + * * Makes a call to the method of name 'api' / 'verb' with the object 'args'. * This call is made in the context of the request 'req'. * On completion, the function 'callback' is invoked with the @@ -303,12 +309,14 @@ static inline int afb_req_unsubscribe(struct afb_req req, struct afb_event event * - 'afb_req_subcall_req' that is convenient to keep request alive automatically. * - 'afb_req_subcall_sync' the synchronous version */ -static inline void afb_req_subcall(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result), void *closure) +static inline void afb_req_x1_subcall(struct afb_req_x1 req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result), void *closure) { - req.itf->subcall(req.closure, api, verb, args, callback, closure); + req.itf->legacy_subcall(req.closure, api, verb, args, callback, closure); } -/* +/** + * @deprecated use bindings version 3 + * * Makes a call to the method of name 'api' / 'verb' with the object 'args'. * This call is made in the context of the request 'req'. * On completion, the function 'callback' is invoked with the @@ -326,12 +334,14 @@ static inline void afb_req_subcall(struct afb_req req, const char *api, const ch * - 'afb_req_subcall' that doesn't keep request alive automatically. * - 'afb_req_subcall_sync' the synchronous version */ -static inline void afb_req_subcall_req(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req req), void *closure) +static inline void afb_req_x1_subcall_req(struct afb_req_x1 req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req_x1 req), void *closure) { - req.itf->subcall_req(req.closure, api, verb, args, callback, closure); + req.itf->legacy_subcall_req(req.closure, api, verb, args, callback, closure); } -/* +/** + * @deprecated use bindings version 3 + * * Makes a call to the method of name 'api' / 'verb' with the object 'args'. * This call is made in the context of the request 'req'. * This call is synchronous, it waits untill completion of the request. @@ -347,12 +357,14 @@ static inline void afb_req_subcall_req(struct afb_req req, const char *api, cons * - 'afb_req_subcall_req' that is convenient to keep request alive automatically. * - 'afb_req_subcall' that doesn't keep request alive automatically. */ -static inline int afb_req_subcall_sync(struct afb_req req, const char *api, const char *verb, struct json_object *args, struct json_object **result) +static inline int afb_req_x1_subcall_sync(struct afb_req_x1 req, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - return req.itf->subcallsync(req.closure, api, verb, args, result); + return req.itf->legacy_subcallsync(req.closure, api, verb, args, result); } -/* +/** + * @deprecated use bindings version 3 + * * Send associated to 'req' a message described by 'fmt' and following parameters * to the journal for the verbosity 'level'. * @@ -369,8 +381,8 @@ static inline int afb_req_subcall_sync(struct afb_req req, const char *api, cons * INFO 6 Informational * DEBUG 7 Debug-level messages */ -static inline void afb_req_verbose(struct afb_req req, int level, const char *file, int line, const char * func, const char *fmt, ...) __attribute__((format(printf, 6, 7))); -static inline void afb_req_verbose(struct afb_req req, int level, const char *file, int line, const char * func, const char *fmt, ...) +static inline void afb_req_x1_verbose(struct afb_req_x1 req, int level, const char *file, int line, const char * func, const char *fmt, ...) __attribute__((format(printf, 6, 7))); +static inline void afb_req_x1_verbose(struct afb_req_x1 req, int level, const char *file, int line, const char * func, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -378,25 +390,22 @@ static inline void afb_req_verbose(struct afb_req req, int level, const char *fi va_end(args); } -/* macro for setting file, line and function automatically */ -# if !defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS) -#define AFB_REQ_VERBOSE(req,level,...) afb_req_verbose(req,level,__FILE__,__LINE__,__func__,__VA_ARGS__) -#else -#define AFB_REQ_VERBOSE(req,level,...) afb_req_verbose(req,level,NULL,0,NULL,__VA_ARGS__) -#endif - -/* +/** + * @deprecated use bindings version 3 + * * Check whether the 'permission' is granted or not to the client * identified by 'req'. * * Returns 1 if the permission is granted or 0 otherwise. */ -static inline int afb_req_has_permission(struct afb_req req, const char *permission) +static inline int afb_req_x1_has_permission(struct afb_req_x1 req, const char *permission) { return req.itf->has_permission(req.closure, permission); } -/* +/** + * @deprecated use bindings version 3 + * * Get the application identifier of the client application for the * request 'req'. * @@ -405,19 +414,40 @@ static inline int afb_req_has_permission(struct afb_req req, const char *permiss * * The returned value if not NULL must be freed by the caller */ -static inline char *afb_req_get_application_id(struct afb_req req) +static inline char *afb_req_x1_get_application_id(struct afb_req_x1 req) { return req.itf->get_application_id(req.closure); } -/* +/** + * @deprecated use bindings version 3 + * * Get the user identifier (UID) of the client application for the * request 'req'. * * Returns -1 when the application can not be identified. */ -static inline int afb_req_get_uid(struct afb_req req) +static inline int afb_req_x1_get_uid(struct afb_req_x1 req) { return req.itf->get_uid(req.closure); } +/** + * @deprecated use bindings version 3 + * + * Get informations about the client of the + * request 'req'. + * + * Returns an object with client informations: + * { + * "pid": int, "uid": int, "gid": int, + * "smack": string, "appid": string, + * "uuid": string, "LOA": int + * } + */ +static inline struct json_object *afb_req_x1_get_client_info(struct afb_req_x1 req) +{ + return req.itf->get_client_info(req.closure); +} + + diff --git a/include/afb/afb-req-x2-itf.h b/include/afb/afb-req-x2-itf.h new file mode 100644 index 00000000..9de7a214 --- /dev/null +++ b/include/afb/afb-req-x2-itf.h @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/* defined here */ +struct afb_req_x2; +struct afb_req_x2_itf; + +/* referenced here */ +#include "afb-arg.h" +struct afb_req_x1; +struct afb_event_x1; +struct afb_event_x2; +struct afb_api_x3; +struct afb_stored_req; + +/** + * structure for the request + */ +struct afb_req_x2 +{ + /** + * interface for the request + */ + const struct afb_req_x2_itf *itf; + + /** + * current api (if any) + */ + struct afb_api_x3 *api; + + /** + * closure associated with the callback processing the verb of the request + * as given at its declaration + */ + void *vcbdata; + + /** + * the name of the called api + */ + const char *called_api; + + /** + * the name of the called verb + */ + const char *called_verb; +}; + +/** + * subcall modes + * + * When making subcalls, it is now possible to explicitely set the subcall + * mode to a combination of the following mode using binary OR. + * + * In particular, the following combination of modes are to be known: + * + * - for **subcall** having a similar behaviour to the subcalls of bindings + * version 1 and 2: afb_req_x2_subcall_pass_events|afb_req_x2_subcall_on_behalf + * - for **subcall** having the behaviour of the **call**: + * afb_req_x2_subcall_catch_events|afb_req_x2_subcall_api_session + * + * Be aware that if none of mode afb_req_x2_subcall_catch_events or + * afb_req_x2_subcall_pass_events is set, subscrption to events will be ignored. + */ +enum afb_req_x2_subcall_flags +{ + /** + * the calling API wants to receive the events from subscription + */ + afb_req_x2_subcall_catch_events = 1, + + /** + * the original request will receive the events from subscription + */ + afb_req_x2_subcall_pass_events = 2, + + /** + * the calling API wants to use the credentials of the original request + */ + afb_req_x2_subcall_on_behalf = 4, + + /** + * the calling API wants to use its session instead of the one of the + * original request + */ + afb_req_x2_subcall_api_session = 8, +}; + +/** + * Interface for handling requests. + * + * It records the functions to be called for the request. + * Don't use this structure directly, Use the helper functions instead. + */ +struct afb_req_x2_itf +{ + /* CAUTION: respect the order, add at the end */ + + /** get the json */ + struct json_object *(*json)( + struct afb_req_x2 *req); + + /** get an argument */ + struct afb_arg (*get)( + struct afb_req_x2 *req, + const char *name); + + /** reply a success @deprecated use @ref reply */ + void (*legacy_success)( + struct afb_req_x2 *req, + struct json_object *obj, + const char *info); + + /** reply a failure @deprecated use @ref reply */ + void (*legacy_fail)( + struct afb_req_x2 *req, + const char *status, + const char *info); + + /** reply a success @deprecated use @ref vreply */ + void (*legacy_vsuccess)( + struct afb_req_x2 *req, + struct json_object *obj, + const char *fmt, + va_list args); + + /** reply a failure @deprecated use @ref vreply */ + void (*legacy_vfail)( + struct afb_req_x2 *req, + const char *status, + const char *fmt, + va_list args); + + /** get a client context @deprecated use @ref context_make */ + void *(*legacy_context_get)( + struct afb_req_x2 *req); + + /** set a client context @deprecated use @ref context_make */ + void (*legacy_context_set)( + struct afb_req_x2 *req, + void *value, + void (*free_value)(void*)); + + /** increase reference count of the request */ + struct afb_req_x2 *(*addref)( + struct afb_req_x2 *req); + + /** decrease reference count of the request */ + void (*unref)( + struct afb_req_x2 *req); + + /** close the client session related to the api of the request */ + void (*session_close)( + struct afb_req_x2 *req); + + /** set the levele of assurancy related to the api of the request */ + int (*session_set_LOA)( + struct afb_req_x2 *req, + unsigned level); + + /** make subscription of the client of the request to the event @deprecated use @ref subscribe_event_x2 */ + int (*legacy_subscribe_event_x1)( + struct afb_req_x2 *req, + struct afb_event_x1 event); + + /** remove subscription of the client of the request to the event @deprecated use @ref unsubscribe_event_x2 */ + int (*legacy_unsubscribe_event_x1)( + struct afb_req_x2 *req, + struct afb_event_x1 event); + + /** asynchronous subcall @deprecated use @ref subcall */ + void (*legacy_subcall)( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *cb_closure); + + /** synchronous subcall @deprecated use @ref subcallsync */ + int (*legacy_subcallsync)( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); + + /** log a message for the request */ + void (*vverbose)( + struct afb_req_x2 *req, + int level, + const char *file, + int line, + const char * func, + const char *fmt, + va_list args); + + /** store the request @deprecated no more needed */ + struct afb_stored_req *(*legacy_store_req)( + struct afb_req_x2 *req); + + /** asynchronous subcall with request @deprecated use @ref subcall */ + void (*legacy_subcall_req)( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x1), + void *cb_closure); + + /** store the request @deprecated no more needed */ + int (*has_permission)( + struct afb_req_x2 *req, + const char *permission); + + /** get the application id of the client of the request */ + char *(*get_application_id)( + struct afb_req_x2 *req); + + /** handle client context of the api getting the request */ + void *(*context_make)( + struct afb_req_x2 *req, + int replace, + void *(*create_value)(void *creation_closure), + void (*free_value)(void*), + void *creation_closure); + + /** make subscription of the client of the request to the event */ + int (*subscribe_event_x2)( + struct afb_req_x2 *req, + struct afb_event_x2 *event); + + /** remove subscription of the client of the request to the event */ + int (*unsubscribe_event_x2)( + struct afb_req_x2 *req, + struct afb_event_x2 *event); + + /** asynchronous subcall with request @deprecated use @ref subcall */ + void (*legacy_subcall_request)( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *req), + void *cb_closure); + + /** get the user id (unix) of the client of the request */ + int (*get_uid)( + struct afb_req_x2 *req); + + /** reply to the request */ + void (*reply)( + struct afb_req_x2 *req, + struct json_object *obj, + const char *error, + const char *info); + + /** reply to the request with formating of info */ + void (*vreply)( + struct afb_req_x2 *req, + struct json_object *obj, + const char *error, + const char *fmt, + va_list args); + + /** get description of the client of the request */ + struct json_object *(*get_client_info)( + struct afb_req_x2 *req); + + /** asynchronous subcall */ + void (*subcall)( + struct afb_req_x2 *req, + const char *apiname, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure); + + /** synchronous subcall */ + int (*subcallsync)( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info); +}; + diff --git a/include/afb/afb-req-x2.h b/include/afb/afb-req-x2.h new file mode 100644 index 00000000..70ffab80 --- /dev/null +++ b/include/afb/afb-req-x2.h @@ -0,0 +1,758 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "afb-req-x2-itf.h" +#include "afb-api-x3.h" + +/** + * Checks whether the request 'req' is valid or not. + * + * @param req the request to check + * + * @return 0 if not valid or 1 if valid. + */ +static inline +int afb_req_x2_is_valid( + struct afb_req_x2 *req) +{ + return !!req; +} + +/** + * Retrieves the api that serves the request + * + * @param req the request whose serving api is queried + * + * @return the api serving the request + */ +static inline +struct afb_api_x3 *afb_req_x2_get_api( + struct afb_req_x2 *req) +{ + return req->api; +} + +/** + * Retrieves the callback data of the verb. This callback data is set + * when the verb is created. + * + * @param req whose verb vcbdata is queried + * + * @return the callback data attached to the verb description + */ +static inline +void *afb_req_x2_get_vcbdata( + struct afb_req_x2 *req) +{ + return req->vcbdata; +} + +/** + * Retrieve the name of the called api. + * + * @param req the request + * + * @return the name of the called api + * + * @see afb_api_x3_add_alias + */ +static inline +const char *afb_req_x2_get_called_api( + struct afb_req_x2 *req) +{ + return req->called_api; +} + +/** + * Retrieve the name of the called verb + * + * @param req the request + * + * @return the name of the called verb + */ +static inline +const char *afb_req_x2_get_called_verb( + struct afb_req_x2 *req) +{ + return req->called_verb; +} + +/** + * Is the log message of 'level (as defined for syslog) required for the + * request 'req'? + * + * @param req the request + * @param level the level to check as defined for syslog: + * + * EMERGENCY 0 System is unusable + * ALERT 1 Action must be taken immediately + * CRITICAL 2 Critical conditions + * ERROR 3 Error conditions + * WARNING 4 Warning conditions + * NOTICE 5 Normal but significant condition + * INFO 6 Informational + * DEBUG 7 Debug-level messages + * + * @return 0 if not required or a value not null if required + * + * @see syslog + */ +static inline +int afb_req_x2_wants_log_level( + struct afb_req_x2 *req, + int level) +{ + return afb_api_x3_wants_log_level(afb_req_x2_get_api(req), level); +} + +/** + * Gets from the request 'req' the argument of 'name'. + * + * Returns a PLAIN structure of type 'struct afb_arg'. + * + * When the argument of 'name' is not found, all fields of result are set to NULL. + * + * When the argument of 'name' is found, the fields are filled, + * in particular, the field 'result.name' is set to 'name'. + * + * There is a special name value: the empty string. + * The argument of name "" is defined only if the request was made using + * an HTTP POST of Content-Type "application/json". In that case, the + * argument of name "" receives the value of the body of the HTTP request. + * + * @param req the request + * @param name the name of the argument to get + * + * @return a structure describing the retrieved argument for the request + * + * @see afb_req_x2_value + * @see afb_req_x2_path + */ +static inline +struct afb_arg afb_req_x2_get( + struct afb_req_x2 *req, + const char *name) +{ + return req->itf->get(req, name); +} + +/** + * Gets from the request 'req' the string value of the argument of 'name'. + * Returns NULL if when there is no argument of 'name'. + * Returns the value of the argument of 'name' otherwise. + * + * Shortcut for: afb_req_x2_get(req, name).value + * + * @param req the request + * @param name the name of the argument's value to get + * + * @return the value as a string or NULL + * + * @see afb_req_x2_get + * @see afb_req_x2_path + */ +static inline +const char *afb_req_x2_value( + struct afb_req_x2 *req, + const char *name) +{ + return afb_req_x2_get(req, name).value; +} + +/** + * Gets from the request 'req' the path for file attached to the argument of 'name'. + * Returns NULL if when there is no argument of 'name' or when there is no file. + * Returns the path of the argument of 'name' otherwise. + * + * Shortcut for: afb_req_x2_get(req, name).path + * + * @param req the request + * @param name the name of the argument's path to get + * + * @return the path if any or NULL + * + * @see afb_req_x2_get + * @see afb_req_x2_value + */ +static inline +const char *afb_req_x2_path( + struct afb_req_x2 *req, + const char *name) +{ + return afb_req_x2_get(req, name).path; +} + +/** + * Gets from the request 'req' the json object hashing the arguments. + * + * The returned object must not be released using 'json_object_put'. + * + * @param req the request + * + * @return the JSON object of the query + * + * @see afb_req_x2_get + * @see afb_req_x2_value + * @see afb_req_x2_path + */ +static inline +struct json_object *afb_req_x2_json( + struct afb_req_x2 *req) +{ + return req->itf->json(req); +} + +/** + * Sends a reply to the request 'req'. + * + * The status of the reply is set to 'error' (that must be NULL on success). + * Its send the object 'obj' (can be NULL) with an + * informational comment 'info (can also be NULL). + * + * For convenience, the function calls 'json_object_put' for 'obj'. + * Thus, in the case where 'obj' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param req the request + * @param obj the replied object or NULL + * @param error the error message if it is a reply error or NULL + * @param info an informative text or NULL + * + * @see afb_req_x2_reply_v + * @see afb_req_x2_reply_f + */ +static inline +void afb_req_x2_reply( + struct afb_req_x2 *req, + struct json_object *obj, + const char *error, + const char *info) +{ + req->itf->reply(req, obj, error, info); +} + +/** + * Same as 'afb_req_x2_reply_f' but the arguments to the format 'info' + * are given as a variable argument list instance. + * + * For convenience, the function calls 'json_object_put' for 'obj'. + * Thus, in the case where 'obj' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param req the request + * @param obj the replied object or NULL + * @param error the error message if it is a reply error or NULL + * @param info an informative text containing a format as for vprintf + * @param args the va_list of arguments to the format as for vprintf + * + * @see afb_req_x2_reply + * @see afb_req_x2_reply_f + * @see vprintf + */ +static inline +void afb_req_x2_reply_v( + struct afb_req_x2 *req, + struct json_object *obj, + const char *error, + const char *info, + va_list args) +{ + req->itf->vreply(req, obj, error, info, args); +} + +/** + * Same as 'afb_req_x2_reply' but the 'info' is a formatting + * string followed by arguments. + * + * For convenience, the function calls 'json_object_put' for 'obj'. + * Thus, in the case where 'obj' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param req the request + * @param obj the replied object or NULL + * @param error the error message if it is a reply error or NULL + * @param info an informative text containing a format as for printf + * @param ... the arguments to the format as for printf + * + * @see afb_req_x2_reply + * @see afb_req_x2_reply_v + * @see printf + */ +__attribute__((format(printf, 4, 5))) +static inline +void afb_req_x2_reply_f( + struct afb_req_x2 *req, + struct json_object *obj, + const char *error, + const char *info, + ...) +{ + va_list args; + va_start(args, info); + afb_req_x2_reply_v(req, obj, error, info, args); + va_end(args); +} + +/** + * Manage the pointer stored by the binding for the client session of 'req'. + * + * If no previous pointer is stored or if 'replace' is not zero, a new value + * is generated using the function 'create_context' called with the 'closure'. + * If 'create_context' is NULL the generated value is 'closure'. + * + * When a value is created, the function 'free_context' is recorded and will + * be called (with the created value as argument) to free the created value when + * it is not more used. + * + * This function is atomic: it ensures that 2 threads will not race together. + * + * @param req the request + * @param replace if not zero an existing value is replaced + * @param create_context the creation function or NULL + * @param free_context the destroying function or NULL + * @param closure the closure to the creation function + * + * @return the stored value + */ +static inline +void *afb_req_x2_context( + struct afb_req_x2 *req, + int replace, + void *(*create_context)(void *closure), + void (*free_context)(void*), + void *closure) +{ + return req->itf->context_make(req, replace, create_context, free_context, closure); +} + +/** + * Gets the pointer stored by the binding for the session of 'req'. + * When the binding has not yet recorded a pointer, NULL is returned. + * + * Shortcut for: afb_req_x2_context(req, 0, NULL, NULL, NULL) + * + * @param req the request + * + * @return the previously stored value + */ +static inline +void *afb_req_x2_context_get( + struct afb_req_x2 *req) +{ + return afb_req_x2_context(req, 0, 0, 0, 0); +} + +/** + * Stores for the binding the pointer 'context' to the session of 'req'. + * The function 'free_context' will be called when the session is closed + * or if binding stores an other pointer. + * + * Shortcut for: afb_req_x2_context(req, 1, NULL, free_context, context) + * + * + * @param req the request + * @param context the context value to store + * @param free_context the cleaning function for the stored context (can be NULL) + */ +static inline +void afb_req_x2_context_set( + struct afb_req_x2 *req, + void *context, + void (*free_context)(void*)) +{ + afb_req_x2_context(req, 1, 0, free_context, context); +} + +/** + * Frees the pointer stored by the binding for the session of 'req' + * and sets it to NULL. + * + * Shortcut for: afb_req_x2_context_set(req, NULL, NULL) + * + * @param req the request + */ +static inline +void afb_req_x2_context_clear( + struct afb_req_x2 *req) +{ + afb_req_x2_context(req, 1, 0, 0, 0); +} + +/** + * Increments the count of references of 'req'. + * + * @param req the request + * + * @return returns the request req + */ +static inline +struct afb_req_x2 *afb_req_x2_addref( + struct afb_req_x2 *req) +{ + return req->itf->addref(req); +} + +/** + * Decrement the count of references of 'req'. + * + * @param req the request + */ +static inline +void afb_req_x2_unref( + struct afb_req_x2 *req) +{ + req->itf->unref(req); +} + +/** + * Closes the session associated with 'req' + * and delete all associated contexts. + * + * @param req the request + */ +static inline +void afb_req_x2_session_close( + struct afb_req_x2 *req) +{ + req->itf->session_close(req); +} + +/** + * Sets the level of assurance of the session of 'req' + * to 'level'. The effect of this function is subject of + * security policies. + * + * @param req the request + * @param level of assurance from 0 to 7 + * + * @return 0 on success or -1 if failed. + */ +static inline +int afb_req_x2_session_set_LOA( + struct afb_req_x2 *req, + unsigned level) +{ + return req->itf->session_set_LOA(req, level); +} + +/** + * Establishes for the client link identified by 'req' a subscription + * to the 'event'. + * + * @param req the request + * @param event the event to subscribe + * + * @return 0 in case of successful subscription or -1 in case of error. + */ +static inline +int afb_req_x2_subscribe( + struct afb_req_x2 *req, + struct afb_event_x2 *event) +{ + return req->itf->subscribe_event_x2(req, event); +} + +/** + * Revokes the subscription established to the 'event' for the client + * link identified by 'req'. + * Returns 0 in case of successful subscription or -1 in case of error. + * + * @param req the request + * @param event the event to revoke + * + * @return 0 in case of successful subscription or -1 in case of error. + */ +static inline +int afb_req_x2_unsubscribe( + struct afb_req_x2 *req, + struct afb_event_x2 *event) +{ + return req->itf->unsubscribe_event_x2(req, event); +} + +/** + * @deprecated use @ref afb_req_x2_subcall + * + * Makes a call to the method of name 'api' / 'verb' with the object 'args'. + * This call is made in the context of the request 'req'. + * On completion, the function 'callback' is invoked with the + * 'closure' given at call and two other parameters: 'iserror' and 'result'. + * 'status' is 0 on success or negative when on an error reply. + * 'result' is the json object of the reply, you must not call json_object_put + * on the result. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param req the request + * @param api the name of the api to call + * @param verb the name of the verb to call + * @param args the arguments of the call as a JSON object + * @param callback the call back that will receive the reply + * @param closure the closure passed back to the callback + * + * @see afb_req_x2_subcall + * @see afb_req_x2_subcall_sync + */ +static inline +void afb_req_x2_subcall_legacy( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req_x2 *req), + void *closure) +{ + req->itf->legacy_subcall_request(req, api, verb, args, callback, closure); +} + +/** + * @deprecated use @ref afb_req_x2_subcall_sync + * + * Makes a call to the method of name 'api' / 'verb' with the object 'args'. + * This call is made in the context of the request 'req'. + * This call is synchronous, it waits untill completion of the request. + * It returns 0 on success or a negative value on error answer. + * The object pointed by 'result' is filled and must be released by the caller + * after its use by calling 'json_object_put'. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param req the request + * @param api the name of the api to call + * @param verb the name of the verb to call + * @param args the arguments of the call as a JSON object + * @param result the pointer to the JSON object pointer that will receive the result + * + * @return 0 on success or a negative value on error answer. + * + * @see afb_req_x2_subcall + * @see afb_req_x2_subcall_sync + */ +static inline +int afb_req_x2_subcall_sync_legacy( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + return req->itf->legacy_subcallsync(req, api, verb, args, result); +} + +/** + * Send associated to 'req' a message described by 'fmt' and following parameters + * to the journal for the verbosity 'level'. + * + * 'file', 'line' and 'func' are indicators of position of the code in source files + * (see macros __FILE__, __LINE__ and __func__). + * + * 'level' is defined by syslog standard: + * EMERGENCY 0 System is unusable + * ALERT 1 Action must be taken immediately + * CRITICAL 2 Critical conditions + * ERROR 3 Error conditions + * WARNING 4 Warning conditions + * NOTICE 5 Normal but significant condition + * INFO 6 Informational + * DEBUG 7 Debug-level messages + * + * @param req the request + * @param level the level of the message + * @param file the source filename that emits the message or NULL + * @param line the line number in the source filename that emits the message + * @param func the name of the function that emits the message or NULL + * @param fmt the message format as for printf + * @param ... the arguments of the printf + * + * @see printf + */ +__attribute__((format(printf, 6, 7))) +static inline +void afb_req_x2_verbose( + struct afb_req_x2 *req, + int level, const char *file, + int line, + const char * func, + const char *fmt, + ...) +{ + va_list args; + va_start(args, fmt); + req->itf->vverbose(req, level, file, line, func, fmt, args); + va_end(args); +} + +/** + * Check whether the 'permission' is granted or not to the client + * identified by 'req'. + * + * @param req the request + * @param permission string to check + * + * @return 1 if the permission is granted or 0 otherwise. + */ +static inline +int afb_req_x2_has_permission( + struct afb_req_x2 *req, + const char *permission) +{ + return req->itf->has_permission(req, permission); +} + +/** + * Get the application identifier of the client application for the + * request 'req'. + * + * Returns the application identifier or NULL when the application + * can not be identified. + * + * The returned value if not NULL must be freed by the caller + * + * @param req the request + * + * @return the string for the application id of the client MUST BE FREED + */ +static inline +char *afb_req_x2_get_application_id( + struct afb_req_x2 *req) +{ + return req->itf->get_application_id(req); +} + +/** + * Get the user identifier (UID) of the client for the + * request 'req'. + * + * @param req the request + * + * @return -1 when the application can not be identified or the unix uid. + * + */ +static inline +int afb_req_x2_get_uid( + struct afb_req_x2 *req) +{ + return req->itf->get_uid(req); +} + +/** + * Get informations about the client of the + * request 'req'. + * + * Returns an object with client informations: + * { + * "pid": int, "uid": int, "gid": int, + * "label": string, "id": string, "user": string, + * "uuid": string, "LOA": int + * } + * + * If some of this information can't be computed, the field of the return + * object will not be set at all. + * + * @param req the request + * + * @return a JSON object that must be freed using @ref json_object_put + */ +static inline +struct json_object *afb_req_x2_get_client_info( + struct afb_req_x2 *req) +{ + return req->itf->get_client_info(req); +} + +/** + * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. + * The result of the call is delivered to the 'callback' function with the 'callback_closure'. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * The 'callback' receives 5 arguments: + * 1. 'closure' the user defined closure pointer 'closure', + * 2. 'object' a JSON object returned (can be NULL) + * 3. 'error' a string not NULL in case of error + * 4. 'info' a string handling some info (can be NULL) + * 5. 'req' the req + * + * @param req The request + * @param api The api name of the method to call + * @param verb The verb name of the method to call + * @param args The arguments to pass to the method + * @param flags The bit field of flags for the subcall as defined by @ref afb_req_x2_subcall_flags + * @param callback The to call on completion + * @param closure The closure to pass to the callback + * + * @see also 'afb_req_subcall_sync' + */ +static inline +void afb_req_x2_subcall( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure) +{ + req->itf->subcall(req, api, verb, args, flags, callback, closure); +} + +/** + * Makes a call to the method of name 'api' / 'verb' with the object 'args'. + * This call is made in the context of the request 'req'. + * This call is synchronous, it waits untill completion of the request. + * It returns 0 on success or a negative value on error answer. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * See also: + * - 'afb_req_x2_subcall_req' that is convenient to keep request alive automatically. + * - 'afb_req_x2_subcall' that doesn't keep request alive automatically. + * + * @param req The request + * @param api The api name of the method to call + * @param verb The verb name of the method to call + * @param args The arguments to pass to the method + * @param flags The bit field of flags for the subcall as defined by @ref afb_req_x2_subcall_flags + * @param object a pointer where the replied JSON object is stored must be freed using @ref json_object_put (can be NULL) + * @param error a pointer where a copy of the replied error is stored must be freed using @ref free (can be NULL) + * @param info a pointer where a copy of the replied info is stored must be freed using @ref free (can be NULL) + * + * @return 0 in case of success or -1 in case of error + */ +static inline +int afb_req_x2_subcall_sync( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info) +{ + return req->itf->subcallsync(req, api, verb, args, flags, object, error, info); +} diff --git a/include/afb/afb-request-itf.h b/include/afb/afb-request-itf.h deleted file mode 100644 index 44066c66..00000000 --- a/include/afb/afb-request-itf.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -/* defined here */ -struct afb_arg; -struct afb_request; -struct afb_request_itf; - -/* referenced here */ -#include <stdarg.h> -struct json_object; -struct afb_req; -struct afb_event; -struct afb_eventid; -struct afb_dynapi; -struct afb_stored_req; - -/* - * Describes an argument (or parameter) of a request - */ -struct afb_arg -{ - const char *name; /* name of the argument or NULL if invalid */ - const char *value; /* string representation of the value of the argument */ - /* original filename of the argument if path != NULL */ - const char *path; /* if not NULL, path of the received file for the argument */ - /* when the request is finalized this file is removed */ -}; - -/* - * structure for the request - */ -struct afb_request -{ - /* interface for the request */ - const struct afb_request_itf *itf; - - /* current dynapi (if any) */ - struct afb_dynapi *dynapi; - - /* closure associated with the callback processing the verb of the request - * as given at its declaration */ - void *vcbdata; - - /* the name of the called verb */ - const char *api; - - /* the name of the called verb */ - const char *verb; -}; - -/* - * Interface for handling requests. - * It records the functions to be called for the request. - * Don't use this structure directly. - * Use the helper functions - */ -struct afb_request_itf -{ - /* CAUTION: respect the order, add at the end */ - - struct json_object *(*json)( - struct afb_request *request); - - struct afb_arg (*get)( - struct afb_request *request, - const char *name); - - void (*success)( - struct afb_request *request, - struct json_object *obj, - const char *info); - - void (*fail)( - struct afb_request *request, - const char *status, - const char *info); - - void (*vsuccess)( - struct afb_request *request, - struct json_object *obj, - const char *fmt, - va_list args); - - void (*vfail)( - struct afb_request *request, - const char *status, - const char *fmt, - va_list args); - - void *(*context_get)( - struct afb_request *request); - - void (*context_set)( - struct afb_request *request, - void *value, - void (*free_value)(void*)); - - struct afb_request *(*addref)( - struct afb_request *request); - - void (*unref)( - struct afb_request *request); - - void (*session_close)( - struct afb_request *request); - - int (*session_set_LOA)( - struct afb_request *request, - unsigned level); - - int (*subscribe)( - struct afb_request *request, - struct afb_event event); - - int (*unsubscribe)( - struct afb_request *request, - struct afb_event event); - - void (*subcall)( - struct afb_request *request, - const char *api, - const char *verb, - struct json_object *args, - void (*callback)(void*, int, struct json_object*), - void *cb_closure); - - int (*subcallsync)( - struct afb_request *request, - const char *api, - const char *verb, - struct json_object *args, - struct json_object **result); - - void (*vverbose)( - struct afb_request *request, - int level, - const char *file, - int line, - const char * func, - const char *fmt, - va_list args); - - struct afb_stored_req *(*store)( - struct afb_request *request); - - void (*subcall_req)( - struct afb_request *request, - const char *api, - const char *verb, - struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_req), - void *cb_closure); - - int (*has_permission)( - struct afb_request *request, - const char *permission); - - char *(*get_application_id)( - struct afb_request *request); - - void *(*context_make)( - struct afb_request *request, - int replace, - void *(*create_value)(void *creation_closure), - void (*free_value)(void*), - void *creation_closure); - - int (*subscribe_eventid)( - struct afb_request *request, - struct afb_eventid *eventid); - - int (*unsubscribe_eventid)( - struct afb_request *request, - struct afb_eventid *eventid); - - void (*subcall_request)( - struct afb_request *request, - const char *api, - const char *verb, - struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_request *request), - void *cb_closure); - - int (*get_uid)( - struct afb_request *request); - -}; - diff --git a/include/afb/afb-request.h b/include/afb/afb-request.h deleted file mode 100644 index 8e909bba..00000000 --- a/include/afb/afb-request.h +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "afb-request-itf.h" - -static inline struct afb_dynapi *afb_request_get_dynapi(struct afb_request *request) -{ - return request->dynapi; -} - -static inline void *afb_request_get_vcbdata(struct afb_request *request) -{ - return request->vcbdata; -} - -static inline const char *afb_request_get_api(struct afb_request *request) -{ - return request->api; -} - -static inline const char *afb_request_get_verb(struct afb_request *request) -{ - return request->verb; -} - -/* - * Gets from the request 'request' the argument of 'name'. - * Returns a PLAIN structure of type 'struct afb_arg'. - * When the argument of 'name' is not found, all fields of result are set to NULL. - * When the argument of 'name' is found, the fields are filled, - * in particular, the field 'result.name' is set to 'name'. - * - * There is a special name value: the empty string. - * The argument of name "" is defined only if the request was made using - * an HTTP POST of Content-Type "application/json". In that case, the - * argument of name "" receives the value of the body of the HTTP request. - */ -static inline struct afb_arg afb_request_get(struct afb_request *request, const char *name) -{ - return request->itf->get(request, name); -} - -/* - * Gets from the request 'request' the string value of the argument of 'name'. - * Returns NULL if when there is no argument of 'name'. - * Returns the value of the argument of 'name' otherwise. - * - * Shortcut for: afb_request_get(request, name).value - */ -static inline const char *afb_request_value(struct afb_request *request, const char *name) -{ - return afb_request_get(request, name).value; -} - -/* - * Gets from the request 'request' the path for file attached to the argument of 'name'. - * Returns NULL if when there is no argument of 'name' or when there is no file. - * Returns the path of the argument of 'name' otherwise. - * - * Shortcut for: afb_request_get(request, name).path - */ -static inline const char *afb_request_path(struct afb_request *request, const char *name) -{ - return afb_request_get(request, name).path; -} - -/* - * Gets from the request 'request' the json object hashing the arguments. - * The returned object must not be released using 'json_object_put'. - */ -static inline struct json_object *afb_request_json(struct afb_request *request) -{ - return request->itf->json(request); -} - -/* - * Sends a reply of kind success to the request 'request'. - * The status of the reply is automatically set to "success". - * Its send the object 'obj' (can be NULL) with an - * informationnal comment 'info (can also be NULL). - * - * For convenience, the function calls 'json_object_put' for 'obj'. - * Thus, in the case where 'obj' should remain available after - * the function returns, the function 'json_object_get' shall be used. - */ -static inline void afb_request_success(struct afb_request *request, struct json_object *obj, const char *info) -{ - request->itf->success(request, obj, info); -} - -/* - * Same as 'afb_request_success' but the 'info' is a formatting - * string followed by arguments. - * - * For convenience, the function calls 'json_object_put' for 'obj'. - * Thus, in the case where 'obj' should remain available after - * the function returns, the function 'json_object_get' shall be used. - */ -static inline void afb_request_success_f(struct afb_request *request, struct json_object *obj, const char *info, ...) __attribute__((format(printf, 3, 4))); -static inline void afb_request_success_f(struct afb_request *request, struct json_object *obj, const char *info, ...) -{ - va_list args; - va_start(args, info); - request->itf->vsuccess(request, obj, info, args); - va_end(args); -} - -/* - * Same as 'afb_request_success_f' but the arguments to the format 'info' - * are given as a variable argument list instance. - * - * For convenience, the function calls 'json_object_put' for 'obj'. - * Thus, in the case where 'obj' should remain available after - * the function returns, the function 'json_object_get' shall be used. - */ -static inline void afb_request_success_v(struct afb_request *request, struct json_object *obj, const char *info, va_list args) -{ - request->itf->vsuccess(request, obj, info, args); -} - -/* - * Sends a reply of kind failure to the request 'request'. - * The status of the reply is set to 'status' and an - * informationnal comment 'info' (can also be NULL) can be added. - * - * Note that calling afb_request_fail("success", info) is equivalent - * to call afb_request_success(NULL, info). Thus even if possible it - * is strongly recommanded to NEVER use "success" for status. - */ -static inline void afb_request_fail(struct afb_request *request, const char *status, const char *info) -{ - request->itf->fail(request, status, info); -} - -/* - * Same as 'afb_request_fail' but the 'info' is a formatting - * string followed by arguments. - */ -static inline void afb_request_fail_f(struct afb_request *request, const char *status, const char *info, ...) __attribute__((format(printf, 3, 4))); -static inline void afb_request_fail_f(struct afb_request *request, const char *status, const char *info, ...) -{ - va_list args; - va_start(args, info); - request->itf->vfail(request, status, info, args); - va_end(args); -} - -/* - * Same as 'afb_request_fail_f' but the arguments to the format 'info' - * are given as a variable argument list instance. - */ -static inline void afb_request_fail_v(struct afb_request *request, const char *status, const char *info, va_list args) -{ - request->itf->vfail(request, status, info, args); -} - -/* - * Gets the pointer stored by the binding for the session of 'request'. - * When the binding has not yet recorded a pointer, NULL is returned. - */ -static inline void *afb_request_context_get(struct afb_request *request) -{ - return request->itf->context_make(request, 0, 0, 0, 0); -} - -/* - * Stores for the binding the pointer 'context' to the session of 'request'. - * The function 'free_context' will be called when the session is closed - * or if binding stores an other pointer. - */ -static inline void afb_request_context_set(struct afb_request *request, void *context, void (*free_context)(void*)) -{ - request->itf->context_make(request, 1, 0, free_context, context); -} - -/* - * Gets the pointer stored by the binding for the session of 'request'. - * If no previous pointer is stored or if 'replace' is not zero, a new value - * is generated using the function 'create_context' called with the 'closure'. - * If 'create_context' is NULL the generated value is 'closure'. - * When a value is created, the function 'free_context' is recorded and will - * be called (with the created value as argument) to free the created value when - * it is not more used. - * This function is atomic: it ensures that 2 threads will not race together. - */ -static inline void *afb_request_context(struct afb_request *request, int replace, void *(*create_context)(void *closure), void (*free_context)(void*), void *closure) -{ - return request->itf->context_make(request, replace, create_context, free_context, closure); -} - -/* - * Frees the pointer stored by the binding for the session of 'request' - * and sets it to NULL. - * - * Shortcut for: afb_request_context_set(request, NULL, NULL) - */ -static inline void afb_request_context_clear(struct afb_request *request) -{ - request->itf->context_make(request, 1, 0, 0, 0); -} - -/* - * Adds one to the count of references of 'request'. - * This function MUST be called by asynchronous implementations - * of verbs if no reply was sent before returning. - */ -static inline struct afb_request *afb_request_addref(struct afb_request *request) -{ - return request->itf->addref(request); -} - -/* - * Substracts one to the count of references of 'request'. - * This function MUST be called by asynchronous implementations - * of verbs after sending the asynchronous reply. - */ -static inline void afb_request_unref(struct afb_request *request) -{ - request->itf->unref(request); -} - -/* - * Closes the session associated with 'request' - * and delete all associated contexts. - */ -static inline void afb_request_session_close(struct afb_request *request) -{ - request->itf->session_close(request); -} - -/* - * Sets the level of assurance of the session of 'request' - * to 'level'. The effect of this function is subject of - * security policies. - * Returns 1 on success or 0 if failed. - */ -static inline int afb_request_session_set_LOA(struct afb_request *request, unsigned level) -{ - return request->itf->session_set_LOA(request, level); -} - -/* - * Establishes for the client link identified by 'request' a subscription - * to the 'event'. - * Returns 0 in case of successful subscription or -1 in case of error. - */ -static inline int afb_request_subscribe(struct afb_request *request, struct afb_eventid *eventid) -{ - return request->itf->subscribe_eventid(request, eventid); -} - -/* - * Revokes the subscription established to the 'event' for the client - * link identified by 'request'. - * Returns 0 in case of successful subscription or -1 in case of error. - */ -static inline int afb_request_unsubscribe(struct afb_request *request, struct afb_eventid *eventid) -{ - return request->itf->unsubscribe_eventid(request, eventid); -} - -/* - * Makes a call to the method of name 'api' / 'verb' with the object 'args'. - * This call is made in the context of the request 'request'. - * On completion, the function 'callback' is invoked with the - * 'closure' given at call and two other parameters: 'iserror' and 'result'. - * 'status' is 0 on success or negative when on an error reply. - * 'result' is the json object of the reply, you must not call json_object_put - * on the result. - * - * For convenience, the function calls 'json_object_put' for 'args'. - * Thus, in the case where 'args' should remain available after - * the function returns, the function 'json_object_get' shall be used. - * - * See also: - * - 'afb_request_subcall_req' that is convenient to keep request alive automatically. - * - 'afb_request_subcall_sync' the synchronous version - */ -static inline void afb_request_subcall(struct afb_request *request, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_request *request), void *closure) -{ - request->itf->subcall_request(request, api, verb, args, callback, closure); -} - -/* - * Makes a call to the method of name 'api' / 'verb' with the object 'args'. - * This call is made in the context of the request 'request'. - * This call is synchronous, it waits untill completion of the request. - * It returns 0 on success or a negative value on error answer. - * The object pointed by 'result' is filled and must be released by the caller - * after its use by calling 'json_object_put'. - * - * For convenience, the function calls 'json_object_put' for 'args'. - * Thus, in the case where 'args' should remain available after - * the function returns, the function 'json_object_get' shall be used. - * - * See also: - * - 'afb_request_subcall_req' that is convenient to keep request alive automatically. - * - 'afb_request_subcall' that doesn't keep request alive automatically. - */ -static inline int afb_request_subcall_sync(struct afb_request *request, const char *api, const char *verb, struct json_object *args, struct json_object **result) -{ - return request->itf->subcallsync(request, api, verb, args, result); -} - -/* - * Send associated to 'request' a message described by 'fmt' and following parameters - * to the journal for the verbosity 'level'. - * - * 'file', 'line' and 'func' are indicators of position of the code in source files - * (see macros __FILE__, __LINE__ and __func__). - * - * 'level' is defined by syslog standard: - * EMERGENCY 0 System is unusable - * ALERT 1 Action must be taken immediately - * CRITICAL 2 Critical conditions - * ERROR 3 Error conditions - * WARNING 4 Warning conditions - * NOTICE 5 Normal but significant condition - * INFO 6 Informational - * DEBUG 7 Debug-level messages - */ -static inline void afb_request_verbose(struct afb_request *request, int level, const char *file, int line, const char * func, const char *fmt, ...) __attribute__((format(printf, 6, 7))); -static inline void afb_request_verbose(struct afb_request *request, int level, const char *file, int line, const char * func, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - request->itf->vverbose(request, level, file, line, func, fmt, args); - va_end(args); -} - -/* macro for setting file, line and function automatically */ -# if !defined(AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS) -#define AFB_REQUEST_VERBOSE(request,level,...) afb_request_verbose(request,level,__FILE__,__LINE__,__func__,__VA_ARGS__) -#else -#define AFB_REQUEST_VERBOSE(request,level,...) afb_request_verbose(request,level,NULL,0,NULL,__VA_ARGS__) -#endif - -/* - * Check whether the 'permission' is granted or not to the client - * identified by 'request'. - * - * Returns 1 if the permission is granted or 0 otherwise. - */ -static inline int afb_request_has_permission(struct afb_request *request, const char *permission) -{ - return request->itf->has_permission(request, permission); -} - -/* - * Get the application identifier of the client application for the - * request 'request'. - * - * Returns the application identifier or NULL when the application - * can not be identified. - * - * The returned value if not NULL must be freed by the caller - */ -static inline char *afb_request_get_application_id(struct afb_request *request) -{ - return request->itf->get_application_id(request); -} - -/* - * Get the user identifier (UID) of the client for the - * request 'request'. - * - * Returns -1 when the application can not be identified. - */ -static inline int afb_request_get_uid(struct afb_request *request) -{ - return request->itf->get_uid(request); -} - diff --git a/include/afb/afb-service-itf.h b/include/afb/afb-service-itf-x1.h index dd79bdde..fcdd08e1 100644 --- a/include/afb/afb-service-itf.h +++ b/include/afb/afb-service-itf-x1.h @@ -17,32 +17,35 @@ #pragma once -/* avoid inclusion of <json-c/json.h> */ -struct json_object; +struct afb_api_x3; -/* +/** + * @deprecated use bindings version 3 + * * Interface for internal of services * It records the functions to be called for the request. * Don't use this structure directly. * Use the helper functions documented below. */ -struct afb_service_itf +struct afb_service_itf_x1 { /* CAUTION: respect the order, add at the end */ - void (*call)(void *closure, const char *api, const char *verb, struct json_object *args, + void (*call)(struct afb_api_x3 *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *callback_closure); - int (*call_sync)(void *closure, const char *api, const char *verb, struct json_object *args, + int (*call_sync)(struct afb_api_x3 *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result); }; -/* +/** + * @deprecated use bindings version 3 + * * Object that encapsulate accesses to service items */ -struct afb_service +struct afb_service_x1 { - const struct afb_service_itf *itf; - void *closure; + const struct afb_service_itf_x1 *itf; + struct afb_api_x3 *closure; }; diff --git a/include/afb/afb-service-v1.h b/include/afb/afb-service-v1.h index 6a24ecb0..a3265af8 100644 --- a/include/afb/afb-service-v1.h +++ b/include/afb/afb-service-v1.h @@ -17,9 +17,11 @@ #pragma once -#include "afb-service-itf.h" +#include "afb-service-itf-x1.h" /** + * @deprecated use bindings version 3 + * * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. * The result of the call is delivered to the 'callback' function with the 'callback_closure'. * @@ -42,7 +44,7 @@ * @see also 'afb_req_subcall' */ static inline void afb_service_call_v1( - struct afb_service service, + struct afb_service_x1 service, const char *api, const char *verb, struct json_object *args, @@ -53,6 +55,8 @@ static inline void afb_service_call_v1( } /** + * @deprecated use bindings version 3 + * * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. * 'result' will receive the response. * @@ -71,7 +75,7 @@ static inline void afb_service_call_v1( * @see also 'afb_req_subcall' */ static inline int afb_service_call_sync_v1( - struct afb_service service, + struct afb_service_x1 service, const char *api, const char *verb, struct json_object *args, diff --git a/include/afb/afb-service-v2.h b/include/afb/afb-service-v2.h index df751bd5..da59786d 100644 --- a/include/afb/afb-service-v2.h +++ b/include/afb/afb-service-v2.h @@ -17,9 +17,11 @@ #pragma once -#include "afb-service-itf.h" +#include "afb-service-itf-x1.h" /** + * @deprecated use bindings version 3 + * * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. * The result of the call is delivered to the 'callback' function with the 'callback_closure'. * @@ -51,6 +53,8 @@ static inline void afb_service_call_v2( } /** + * @deprecated use bindings version 3 + * * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. * 'result' will receive the response. * diff --git a/include/afb/afb-session-v1.h b/include/afb/afb-session-v1.h deleted file mode 100644 index a606679b..00000000 --- a/include/afb/afb-session-v1.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -/* - * Enum for Session/Token/Assurance middleware. - */ -enum afb_session_flags_v1 -{ - AFB_SESSION_NONE_V1 = 0, /* nothing required */ - AFB_SESSION_CREATE_V1 = 1, /* Obsolete */ - AFB_SESSION_CLOSE_V1 = 2, /* After token authentification, closes the session at end */ - AFB_SESSION_RENEW_V1 = 4, /* After token authentification, refreshes the token at end */ - AFB_SESSION_CHECK_V1 = 8, /* Requires token authentification */ - - AFB_SESSION_LOA_GE_V1 = 16, /* check that the LOA is greater or equal to the given value */ - AFB_SESSION_LOA_LE_V1 = 32, /* check that the LOA is lesser or equal to the given value */ - AFB_SESSION_LOA_EQ_V1 = 48, /* check that the LOA is equal to the given value */ - - AFB_SESSION_LOA_SHIFT_V1 = 6, /* shift for LOA */ - AFB_SESSION_LOA_MASK_V1 = 7, /* mask for LOA */ - - AFB_SESSION_LOA_0_V1 = 0, /* value for LOA of 0 */ - AFB_SESSION_LOA_1_V1 = 64, /* value for LOA of 1 */ - AFB_SESSION_LOA_2_V1 = 128, /* value for LOA of 2 */ - AFB_SESSION_LOA_3_V1 = 192, /* value for LOA of 3 */ - AFB_SESSION_LOA_4_V1 = 256, /* value for LOA of 4 */ - - AFB_SESSION_LOA_LE_0_V1 = AFB_SESSION_LOA_LE_V1 | AFB_SESSION_LOA_0_V1, /* check LOA <= 0 */ - AFB_SESSION_LOA_LE_1_V1 = AFB_SESSION_LOA_LE_V1 | AFB_SESSION_LOA_1_V1, /* check LOA <= 1 */ - AFB_SESSION_LOA_LE_2_V1 = AFB_SESSION_LOA_LE_V1 | AFB_SESSION_LOA_2_V1, /* check LOA <= 2 */ - AFB_SESSION_LOA_LE_3_V1 = AFB_SESSION_LOA_LE_V1 | AFB_SESSION_LOA_3_V1, /* check LOA <= 3 */ - - AFB_SESSION_LOA_EQ_0_V1 = AFB_SESSION_LOA_EQ_V1 | AFB_SESSION_LOA_0_V1, /* check LOA == 0 */ - AFB_SESSION_LOA_EQ_1_V1 = AFB_SESSION_LOA_EQ_V1 | AFB_SESSION_LOA_1_V1, /* check LOA == 1 */ - AFB_SESSION_LOA_EQ_2_V1 = AFB_SESSION_LOA_EQ_V1 | AFB_SESSION_LOA_2_V1, /* check LOA == 2 */ - AFB_SESSION_LOA_EQ_3_V1 = AFB_SESSION_LOA_EQ_V1 | AFB_SESSION_LOA_3_V1, /* check LOA == 3 */ - - AFB_SESSION_LOA_GE_0_V1 = AFB_SESSION_LOA_GE_V1 | AFB_SESSION_LOA_0_V1, /* check LOA >= 0 */ - AFB_SESSION_LOA_GE_1_V1 = AFB_SESSION_LOA_GE_V1 | AFB_SESSION_LOA_1_V1, /* check LOA >= 1 */ - AFB_SESSION_LOA_GE_2_V1 = AFB_SESSION_LOA_GE_V1 | AFB_SESSION_LOA_2_V1, /* check LOA >= 2 */ - AFB_SESSION_LOA_GE_3_V1 = AFB_SESSION_LOA_GE_V1 | AFB_SESSION_LOA_3_V1 /* check LOA >= 3 */ -}; - diff --git a/include/afb/afb-session-v2.h b/include/afb/afb-session-v2.h deleted file mode 100644 index 3f940ed6..00000000 --- a/include/afb/afb-session-v2.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -/* - * Enum for Session/Token/Assurance middleware. - */ -enum afb_session_flags_v2 -{ - AFB_SESSION_LOA_MASK_V2 = 3, /* mask for LOA */ - - AFB_SESSION_LOA_0_V2 = 0, /* value for LOA of 0 */ - AFB_SESSION_LOA_1_V2 = 1, /* value for LOA of 1 */ - AFB_SESSION_LOA_2_V2 = 2, /* value for LOA of 2 */ - AFB_SESSION_LOA_3_V2 = 3, /* value for LOA of 3 */ - - AFB_SESSION_CHECK_V2 = 4, /* Requires token authentification */ - AFB_SESSION_REFRESH_V2 = 8, /* After token authentification, refreshes the token at end */ - AFB_SESSION_CLOSE_V2 = 16, /* After token authentification, closes the session at end */ - - AFB_SESSION_NONE_V2 = 0 /* nothing required */ -}; - diff --git a/include/afb/afb-session-x1.h b/include/afb/afb-session-x1.h new file mode 100644 index 00000000..776cb8f5 --- /dev/null +++ b/include/afb/afb-session-x1.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/** + * @deprecated use bindings version 3 + * + * Enum for Session/Token/Assurance of bindings version 1. + */ +enum afb_session_flags_x1 +{ + AFB_SESSION_NONE_X1 = 0, /**< nothing required */ + AFB_SESSION_CREATE_X1 = 1, /**< Obsolete */ + AFB_SESSION_CLOSE_X1 = 2, /**< After token authentification, closes the session at end */ + AFB_SESSION_RENEW_X1 = 4, /**< After token authentification, refreshes the token at end */ + AFB_SESSION_CHECK_X1 = 8, /**< Requires token authentification */ + + AFB_SESSION_LOA_GE_X1 = 16, /**< check that the LOA is greater or equal to the given value */ + AFB_SESSION_LOA_LE_X1 = 32, /**< check that the LOA is lesser or equal to the given value */ + AFB_SESSION_LOA_EQ_X1 = 48, /**< check that the LOA is equal to the given value */ + + AFB_SESSION_LOA_SHIFT_X1 = 6, /**< shift for LOA */ + AFB_SESSION_LOA_MASK_X1 = 7, /**< mask for LOA */ + + AFB_SESSION_LOA_0_X1 = 0, /**< value for LOA of 0 */ + AFB_SESSION_LOA_1_X1 = 64, /**< value for LOA of 1 */ + AFB_SESSION_LOA_2_X1 = 128, /**< value for LOA of 2 */ + AFB_SESSION_LOA_3_X1 = 192, /**< value for LOA of 3 */ + AFB_SESSION_LOA_4_X1 = 256, /**< value for LOA of 4 */ + + AFB_SESSION_LOA_LE_0_X1 = AFB_SESSION_LOA_LE_X1 | AFB_SESSION_LOA_0_X1, /**< check LOA <= 0 */ + AFB_SESSION_LOA_LE_1_X1 = AFB_SESSION_LOA_LE_X1 | AFB_SESSION_LOA_1_X1, /**< check LOA <= 1 */ + AFB_SESSION_LOA_LE_2_X1 = AFB_SESSION_LOA_LE_X1 | AFB_SESSION_LOA_2_X1, /**< check LOA <= 2 */ + AFB_SESSION_LOA_LE_3_X1 = AFB_SESSION_LOA_LE_X1 | AFB_SESSION_LOA_3_X1, /**< check LOA <= 3 */ + + AFB_SESSION_LOA_EQ_0_X1 = AFB_SESSION_LOA_EQ_X1 | AFB_SESSION_LOA_0_X1, /**< check LOA == 0 */ + AFB_SESSION_LOA_EQ_1_X1 = AFB_SESSION_LOA_EQ_X1 | AFB_SESSION_LOA_1_X1, /**< check LOA == 1 */ + AFB_SESSION_LOA_EQ_2_X1 = AFB_SESSION_LOA_EQ_X1 | AFB_SESSION_LOA_2_X1, /**< check LOA == 2 */ + AFB_SESSION_LOA_EQ_3_X1 = AFB_SESSION_LOA_EQ_X1 | AFB_SESSION_LOA_3_X1, /**< check LOA == 3 */ + + AFB_SESSION_LOA_GE_0_X1 = AFB_SESSION_LOA_GE_X1 | AFB_SESSION_LOA_0_X1, /**< check LOA >= 0 */ + AFB_SESSION_LOA_GE_1_X1 = AFB_SESSION_LOA_GE_X1 | AFB_SESSION_LOA_1_X1, /**< check LOA >= 1 */ + AFB_SESSION_LOA_GE_2_X1 = AFB_SESSION_LOA_GE_X1 | AFB_SESSION_LOA_2_X1, /**< check LOA >= 2 */ + AFB_SESSION_LOA_GE_3_X1 = AFB_SESSION_LOA_GE_X1 | AFB_SESSION_LOA_3_X1 /**< check LOA >= 3 */ +}; + diff --git a/include/afb/afb-session-x2.h b/include/afb/afb-session-x2.h new file mode 100644 index 00000000..b4a24c77 --- /dev/null +++ b/include/afb/afb-session-x2.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/** + * Enum for Session/Token/Assurance middleware of bindings version 2 and 3. + */ +enum afb_session_flags_x2 +{ + AFB_SESSION_LOA_MASK_X2 = 3, /**< mask for LOA */ + + AFB_SESSION_LOA_0_X2 = 0, /**< value for LOA of 0 */ + AFB_SESSION_LOA_1_X2 = 1, /**< value for LOA of 1 */ + AFB_SESSION_LOA_2_X2 = 2, /**< value for LOA of 2 */ + AFB_SESSION_LOA_3_X2 = 3, /**< value for LOA of 3 */ + + AFB_SESSION_CHECK_X2 = 4, /**< Requires token authentification */ + AFB_SESSION_REFRESH_X2 = 8, /**< After token authentification, refreshes the token at end */ + AFB_SESSION_CLOSE_X2 = 16, /**< After token authentification, closes the session at end */ + + AFB_SESSION_NONE_X2 = 0 /**< nothing required */ +}; + diff --git a/include/afb/afb-verbosity.h b/include/afb/afb-verbosity.h index 9f122056..dd34f841 100644 --- a/include/afb/afb-verbosity.h +++ b/include/afb/afb-verbosity.h @@ -23,9 +23,42 @@ #define AFB_VERBOSITY_LEVEL_INFO 3 #define AFB_VERBOSITY_LEVEL_DEBUG 4 -#define _AFB_SYSLOG_LEVEL_ERROR_ 3 -#define _AFB_SYSLOG_LEVEL_WARNING_ 4 -#define _AFB_SYSLOG_LEVEL_NOTICE_ 5 -#define _AFB_SYSLOG_LEVEL_INFO_ 6 -#define _AFB_SYSLOG_LEVEL_DEBUG_ 7 +#define AFB_SYSLOG_LEVEL_EMERGENCY 0 +#define AFB_SYSLOG_LEVEL_ALERT 1 +#define AFB_SYSLOG_LEVEL_CRITICAL 2 +#define AFB_SYSLOG_LEVEL_ERROR 3 +#define AFB_SYSLOG_LEVEL_WARNING 4 +#define AFB_SYSLOG_LEVEL_NOTICE 5 +#define AFB_SYSLOG_LEVEL_INFO 6 +#define AFB_SYSLOG_LEVEL_DEBUG 7 + +#define AFB_VERBOSITY_LEVEL_WANT(verbosity,level) ((verbosity) >= (level)) + +#define AFB_VERBOSITY_LEVEL_WANT_ERROR(x) AFB_VERBOSITY_LEVEL_WANT(x,AFB_VERBOSITY_LEVEL_ERROR) +#define AFB_VERBOSITY_LEVEL_WANT_WARNING(x) AFB_VERBOSITY_LEVEL_WANT(x,AFB_VERBOSITY_LEVEL_WARNING) +#define AFB_VERBOSITY_LEVEL_WANT_NOTICE(x) AFB_VERBOSITY_LEVEL_WANT(x,AFB_VERBOSITY_LEVEL_NOTICE) +#define AFB_VERBOSITY_LEVEL_WANT_INFO(x) AFB_VERBOSITY_LEVEL_WANT(x,AFB_VERBOSITY_LEVEL_INFO) +#define AFB_VERBOSITY_LEVEL_WANT_DEBUG(x) AFB_VERBOSITY_LEVEL_WANT(x,AFB_VERBOSITY_LEVEL_DEBUG) + +#define AFB_SYSLOG_MASK_WANT(verbomask,level) ((verbomask) & (1 << (level))) + +#define AFB_SYSLOG_MASK_WANT_EMERGENCY(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_EMERGENCY) +#define AFB_SYSLOG_MASK_WANT_ALERT(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_ALERT) +#define AFB_SYSLOG_MASK_WANT_CRITICAL(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_CRITICAL) +#define AFB_SYSLOG_MASK_WANT_ERROR(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_ERROR) +#define AFB_SYSLOG_MASK_WANT_WARNING(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_WARNING) +#define AFB_SYSLOG_MASK_WANT_NOTICE(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_NOTICE) +#define AFB_SYSLOG_MASK_WANT_INFO(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_INFO) +#define AFB_SYSLOG_MASK_WANT_DEBUG(x) AFB_SYSLOG_MASK_WANT(x,AFB_SYSLOG_LEVEL_DEBUG) + +#define AFB_SYSLOG_LEVEL_FROM_VERBOSITY(x) ((x) + (AFB_SYSLOG_LEVEL_ERROR - AFB_VERBOSITY_LEVEL_ERROR)) +#define AFB_SYSLOG_LEVEL_TO_VERBOSITY(x) ((x) + (AFB_VERBOSITY_LEVEL_ERROR - AFB_SYSLOG_LEVEL_ERROR)) + +static inline int _afb_verbomask_to_upper_level_(int verbomask) +{ + int result = 0; + while ((verbomask >>= 1) && result < AFB_SYSLOG_LEVEL_DEBUG) + result++; + return result; +} diff --git a/memo-supervisor.txt b/memo-supervisor.txt index ae1147aa..f38c05d8 100644 --- a/memo-supervisor.txt +++ b/memo-supervisor.txt @@ -282,3 +282,14 @@ ON-EVENT supervisor/trace: } +Usefull commands: +----------------- + + TARGET=... + + afb-client-demo -H ws://$TARGET:1619/api?token=HELLO\&uuid=HELLO supervisor list + + afb-client-demo -H ws://$TARGET:1619/api?token=HELLO\&uuid=HELLO config '{"pid":XXXX}' + + + diff --git a/memo-v3.txt b/memo-v3.txt new file mode 100644 index 00000000..bf082306 --- /dev/null +++ b/memo-v3.txt @@ -0,0 +1,9 @@ +sub_verb -> del_verb +hookable : $ -> . +glob added every where +event filtering facility +incompatibility of afb-proto-ws +afb_req_context -> signature changed to afb_req_context_make +get_client_info + + @@ -1,4 +1,4 @@ -site_name: AGL Application Framework Binder +site_name: AGL Framework Binder theme: readthedocs docs_dir: docs pages: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c789fca3..ed59ac0c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,16 +24,18 @@ ADD_DEFINITIONS(-DBINDING_INSTALL_DIR="${binding_install_dir}") # Always add INFER_EXTENSION (more details in afb-hreq.c) ADD_DEFINITIONS(-DINFER_EXTENSION) -ADD_LIBRARY(afb-lib STATIC +SET(AFB_LIB_SOURCES afb-api.c - afb-api-dyn.c afb-api-so.c - afb-api-so-v1.c afb-api-so-v2.c + afb-api-so-v3.c afb-api-so-vdyn.c + afb-api-v3.c afb-api-ws.c afb-apiset.c afb-auth.c + afb-autoset.c + afb-calls.c afb-common.c afb-config.c afb-context.c @@ -66,6 +68,7 @@ ADD_LIBRARY(afb-lib STATIC fdev-systemd.c jobs.c locale-root.c + pearson.c process-name.c sig-monitor.c subpath.c @@ -74,15 +77,26 @@ ADD_LIBRARY(afb-lib STATIC wrap-json.c ) +IF(INCLUDE_LEGACY_BINDING_V1) + ADD_DEFINITIONS(-DWITH_LEGACY_BINDING_V1) + SET(AFB_LIB_SOURCES ${AFB_LIB_SOURCES} afb-api-so-v1.c) +ENDIF(INCLUDE_LEGACY_BINDING_V1) +IF(INCLUDE_LEGACY_BINDING_VDYN) + ADD_DEFINITIONS(-DWITH_LEGACY_BINDING_VDYN) + SET(AFB_LIB_SOURCES ${AFB_LIB_SOURCES} afb-api-so-vdyn.c) +ENDIF(INCLUDE_LEGACY_BINDING_VDYN) + IF(INCLUDE_DBUS_TRANSPARENCY) ADD_DEFINITIONS(-DWITH_DBUS_TRANSPARENCY) - TARGET_SOURCES(afb-lib PUBLIC afb-api-dbus.c) + SET(AFB_LIB_SOURCES ${AFB_LIB_SOURCES} afb-api-dbus.c) ENDIF() +ADD_LIBRARY(afb-lib STATIC ${AFB_LIB_SOURCES}) + ########################################### # build and install afb-daemon ########################################### -ADD_EXECUTABLE(afb-daemon main.c) +ADD_EXECUTABLE(afb-daemon main-afb-daemon.c) TARGET_LINK_LIBRARIES(afb-daemon afb-lib ${link_libraries} @@ -94,7 +108,7 @@ INSTALL(TARGETS afb-daemon # build and install afb-daemon ########################################### IF(INCLUDE_SUPERVISOR) - ADD_EXECUTABLE(afs-supervisor afs-main.c afs-supervisor.c afs-discover.c afs-config.c) + ADD_EXECUTABLE(afs-supervisor main-afs-supervisor.c afs-supervisor.c afs-discover.c afs-config.c) TARGET_LINK_LIBRARIES(afs-supervisor afb-lib ${link_libraries} @@ -124,7 +138,7 @@ INSTALL(FILES afb-wsj1.h afb-ws-client.h afb-proto-ws.h DESTINATION ${CMAKE_INST ########################################### # build and install afb-client-demo ########################################### -ADD_EXECUTABLE(afb-client-demo afb-client-demo.c) +ADD_EXECUTABLE(afb-client-demo main-afb-client-demo.c) TARGET_LINK_LIBRARIES(afb-client-demo afbwsc ${link_libraries} diff --git a/src/afb-api-dbus.c b/src/afb-api-dbus.c index 98c26930..a1e15fd3 100644 --- a/src/afb-api-dbus.c +++ b/src/afb-api-dbus.c @@ -27,7 +27,7 @@ #include <systemd/sd-bus.h> #include <json-c/json.h> -#include <afb/afb-event.h> +#include <afb/afb-event-x2.h> #include "afb-systemd.h" @@ -76,9 +76,6 @@ struct api_dbus }; }; -#define RETOK 1 -#define RETERR 2 - /******************* common part **********************************/ /* @@ -113,7 +110,7 @@ static struct api_dbus *make_api_dbus_3(int system, const char *path, size_t pat goto error2; } api->api++; - if (!afb_api_is_valid_name(api->api, 1)) { + if (!afb_api_is_valid_name(api->api)) { errno = EINVAL; goto error2; } @@ -226,7 +223,7 @@ struct dbus_memo { struct dbus_event { struct dbus_event *next; - struct afb_eventid *eventid; + struct afb_event_x2 *event; int id; int refcount; }; @@ -283,32 +280,19 @@ static int api_dbus_client_on_reply(sd_bus_message *message, void *userdata, sd_ { int rc; struct dbus_memo *memo; - const char *first, *second; - uint8_t type; - uint32_t flags; + const char *json, *error, *info; /* retrieve the recorded data */ memo = userdata; /* get the answer */ - rc = sd_bus_message_read(message, "yssu", &type, &first, &second, &flags); + rc = sd_bus_message_read(message, "sss", &json, &error, &info); if (rc < 0) { /* failing to have the answer */ - afb_xreq_fail(memo->xreq, "error", "dbus error"); + afb_xreq_reply(memo->xreq, NULL, "error", "dbus error"); } else { /* report the answer */ - memo->xreq->context.flags = (unsigned)flags; - switch(type) { - case RETOK: - afb_xreq_success(memo->xreq, json_tokener_parse(first), *second ? second : NULL); - break; - case RETERR: - afb_xreq_fail(memo->xreq, first, *second ? second : NULL); - break; - default: - afb_xreq_fail(memo->xreq, "error", "dbus link broken"); - break; - } + afb_xreq_reply(memo->xreq, *json ? json_tokener_parse(json) : NULL, *error ? error : NULL, *info ? info : NULL); } api_dbus_client_memo_destroy(memo); return 1; @@ -322,24 +306,27 @@ static void api_dbus_client_call(void *closure, struct afb_xreq *xreq) int rc; struct dbus_memo *memo; struct sd_bus_message *msg; + const char *creds; /* create the recording data */ memo = api_dbus_client_memo_make(api, xreq); if (memo == NULL) { - afb_xreq_fail(xreq, "error", "out of memory"); + afb_xreq_reply(memo->xreq, NULL, "error", "out of memory"); return; } /* creates the message */ msg = NULL; - rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, xreq->request.verb); + rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, xreq->request.called_verb); if (rc < 0) goto error; - rc = sd_bus_message_append(msg, "ssu", + creds = xreq_on_behalf_cred_export(xreq); + rc = sd_bus_message_append(msg, "ssus", afb_xreq_raw(xreq, &size), afb_session_uuid(xreq->context.session), - (uint32_t)xreq->context.flags); + (uint32_t)xreq->context.flags, + creds ?: ""); if (rc < 0) goto error; @@ -355,7 +342,7 @@ static void api_dbus_client_call(void *closure, struct afb_xreq *xreq) error: /* if there was an error report it directly */ errno = -rc; - afb_xreq_fail(xreq, "error", "dbus error"); + afb_xreq_reply(memo->xreq, NULL, "error", "dbus error"); api_dbus_client_memo_destroy(memo); end: sd_bus_message_unref(msg); @@ -382,7 +369,7 @@ static struct dbus_event *api_dbus_client_event_search(struct api_dbus *api, int struct dbus_event *ev; ev = api->client.events; - while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_eventid_fullname(ev->eventid), name))) + while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_event_x2_fullname(ev->event), name))) ev = ev->next; return ev; @@ -403,8 +390,8 @@ static void api_dbus_client_event_create(struct api_dbus *api, int id, const cha /* no conflict, try to add it */ ev = malloc(sizeof *ev); if (ev != NULL) { - ev->eventid = afb_evt_eventid_create(name); - if (ev->eventid == NULL) + ev->event = afb_evt_event_x2_create(name); + if (ev->event == NULL) free(ev); else { ev->refcount = 1; @@ -440,7 +427,7 @@ static void api_dbus_client_event_drop(struct api_dbus *api, int id, const char *prv = ev->next; /* destroys the event */ - afb_evt_eventid_unref(ev->eventid); + afb_evt_event_x2_unref(ev->event); free(ev); } @@ -459,7 +446,7 @@ static void api_dbus_client_event_push(struct api_dbus *api, int id, const char /* destroys the event */ object = json_tokener_parse(data); - afb_evt_eventid_push(ev->eventid, object); + afb_evt_event_x2_push(ev->event, object); } /* subscribes an event */ @@ -484,7 +471,7 @@ static void api_dbus_client_event_subscribe(struct api_dbus *api, int id, const } /* subscribe the request to the event */ - rc = afb_xreq_subscribe(memo->xreq, ev->eventid); + rc = afb_xreq_subscribe(memo->xreq, ev->event); if (rc < 0) ERROR("can't subscribe: %m"); } @@ -511,7 +498,7 @@ static void api_dbus_client_event_unsubscribe(struct api_dbus *api, int id, cons } /* unsubscribe the request from the event */ - rc = afb_xreq_unsubscribe(memo->xreq, ev->eventid); + rc = afb_xreq_unsubscribe(memo->xreq, ev->event); if (rc < 0) ERROR("can't unsubscribe: %m"); } @@ -572,11 +559,11 @@ static struct afb_api_itf dbus_api_itf = { }; /* adds a afb-dbus-service client api */ -int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset) +int afb_api_dbus_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) { int rc; struct api_dbus *api; - struct afb_api afb_api; + struct afb_api_item afb_api; char *match; /* create the dbus client api */ @@ -611,7 +598,7 @@ int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset) afb_api.closure = api; afb_api.itf = &dbus_api_itf; afb_api.group = NULL; - if (afb_apiset_add(apiset, api->api, afb_api) < 0) + if (afb_apiset_add(declare_set, api->api, afb_api) < 0) goto error2; return 0; @@ -816,77 +803,51 @@ static struct json_object *dbus_req_json(struct afb_xreq *xreq) return dreq->json; } -/* get the argument of the request of 'name' */ -static void dbus_req_reply(struct dbus_req *dreq, uint8_t type, const char *first, const char *second) +void dbus_req_raw_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { + struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq); int rc; - rc = sd_bus_reply_method_return(dreq->message, - "yssu", type, first ? : "", second ? : "", (uint32_t)dreq->xreq.context.flags); + + rc = sd_bus_reply_method_return(dreq->message, "sss", + obj ? json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN) : "", + error ? : "", + info ? : ""); if (rc < 0) ERROR("sending the reply failed"); } -static void dbus_req_success(struct afb_xreq *xreq, struct json_object *obj, const char *info) -{ - struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq); - - dbus_req_reply(dreq, RETOK, json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN), info); -} - -static void dbus_req_fail(struct afb_xreq *xreq, const char *status, const char *info) -{ - struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq); - - dbus_req_reply(dreq, RETERR, status, info); -} - static void afb_api_dbus_server_event_send(struct origin *origin, char order, const char *event, int eventid, const char *data, uint64_t msgid); -static int dbus_req_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid) +static int dbus_req_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event) { struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq); uint64_t msgid; int rc; - rc = afb_evt_eventid_add_watch(dreq->listener->listener, eventid); + rc = afb_evt_event_x2_add_watch(dreq->listener->listener, event); sd_bus_message_get_cookie(dreq->message, &msgid); - afb_api_dbus_server_event_send(dreq->listener->origin, 'S', afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), "", msgid); + afb_api_dbus_server_event_send(dreq->listener->origin, 'S', afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event), "", msgid); return rc; } -static int dbus_req_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid) +static int dbus_req_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event) { struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq); uint64_t msgid; int rc; sd_bus_message_get_cookie(dreq->message, &msgid); - afb_api_dbus_server_event_send(dreq->listener->origin, 'U', afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), "", msgid); - rc = afb_evt_eventid_remove_watch(dreq->listener->listener, eventid); + afb_api_dbus_server_event_send(dreq->listener->origin, 'U', afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event), "", msgid); + rc = afb_evt_event_x2_remove_watch(dreq->listener->listener, event); return rc; } -static void dbus_req_subcall( - struct afb_xreq *xreq, - const char *api, - const char *verb, - struct json_object *args, - void (*callback)(void*, int, struct json_object*), - void *cb_closure) -{ - ERROR("DBUS API doesn't support subcalls, info: %s/%s(%s)", api, verb, json_object_to_json_string(args)); - callback(cb_closure, 1, afb_msg_json_reply_error("error", "subcall isn't supported", NULL, NULL)); - json_object_put(args); -} - const struct afb_xreq_query_itf afb_api_dbus_xreq_itf = { .json = dbus_req_json, - .success = dbus_req_success, - .fail = dbus_req_fail, + .reply = dbus_req_raw_reply, .unref = dbus_req_destroy, .subscribe = dbus_req_subscribe, .unsubscribe = dbus_req_unsubscribe, - .subcall = dbus_req_subcall }; /******************* server part **********************************/ @@ -954,6 +915,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd int rc; const char *method; const char *uuid; + const char *creds; struct dbus_req *dreq; struct api_dbus *api = userdata; uint32_t flags; @@ -973,7 +935,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd goto out_of_memory; /* get the data */ - rc = sd_bus_message_read(message, "ssu", &dreq->request, &uuid, &flags); + rc = sd_bus_message_read(message, "ssus", &dreq->request, &uuid, &flags, &creds); if (rc < 0) { sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_SIGNATURE, "invalid signature"); goto error; @@ -992,6 +954,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd /* fulfill the request and emit it */ dreq->xreq.context.flags = flags; + dreq->xreq.cred = afb_cred_mixed_on_behalf_import(listener->origin->cred, uuid, creds && creds[0] ? creds : NULL); dreq->message = sd_bus_message_ref(message); dreq->json = json_tokener_parse(dreq->request); if (dreq->json == NULL && strcmp(dreq->request, "null")) { @@ -999,8 +962,8 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd dreq->json = json_object_new_string(dreq->request); } dreq->listener = listener; - dreq->xreq.request.api = api->api; - dreq->xreq.request.verb = method; + dreq->xreq.request.called_api = api->api; + dreq->xreq.request.called_verb = method; afb_xreq_process(&dreq->xreq, api->server.apiset); return 1; @@ -1012,7 +975,7 @@ error: } /* create the service */ -int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset) +int afb_api_dbus_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) { int rc; struct api_dbus *api; @@ -1040,7 +1003,7 @@ int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset) INFO("afb service over dbus installed, name %s, path %s", api->name, api->path); api->server.listener = afb_evt_listener_create(&evt_broadcast_itf, api); - api->server.apiset = afb_apiset_addref(apiset); + api->server.apiset = afb_apiset_addref(call_set); return 0; error3: sd_bus_release_name(api->sdbus, api->name); diff --git a/src/afb-api-dbus.h b/src/afb-api-dbus.h index 90f20c16..1c47685b 100644 --- a/src/afb-api-dbus.h +++ b/src/afb-api-dbus.h @@ -20,8 +20,8 @@ struct afb_req_itf; -extern int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset); +extern int afb_api_dbus_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); -extern int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset); +extern int afb_api_dbus_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); diff --git a/src/afb-api-dyn.c b/src/afb-api-dyn.c deleted file mode 100644 index c2d6cdc4..00000000 --- a/src/afb-api-dyn.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE - -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <errno.h> - -#include <json-c/json.h> - -#define AFB_BINDING_VERSION 0 -#include <afb/afb-binding.h> - -#include "afb-api.h" -#include "afb-api-dyn.h" -#include "afb-apiset.h" -#include "afb-auth.h" -#include "afb-export.h" -#include "afb-xreq.h" -#include "verbose.h" - -/* - * Description of a binding - */ -struct afb_api_dyn { - int count; - struct afb_api_dyn_verb **verbs; - const struct afb_verb_v2 *verbsv2; - struct afb_export *export; - char info[1]; -}; - -void afb_api_dyn_set_verbs_v2( - struct afb_api_dyn *dynapi, - const struct afb_verb_v2 *verbs) -{ - dynapi->verbsv2 = verbs; -} - -int afb_api_dyn_add_verb( - struct afb_api_dyn *dynapi, - const char *verb, - const char *info, - void (*callback)(struct afb_request *request), - void *vcbdata, - const struct afb_auth *auth, - uint32_t session) -{ - struct afb_api_dyn_verb *v, **vv; - - afb_api_dyn_sub_verb(dynapi, verb); - - vv = realloc(dynapi->verbs, (1 + dynapi->count) * sizeof *vv); - if (!vv) - goto oom; - dynapi->verbs = vv; - - v = malloc(sizeof *v + strlen(verb) + (info ? 1 + strlen(info) : 0)); - if (!v) - goto oom; - - v->callback = callback; - v->vcbdata = vcbdata; - v->auth = auth; - v->session = session; - - v->info = 1 + stpcpy(v->verb, verb); - if (info) - strcpy((char*)v->info, info); - else - v->info = NULL; - - dynapi->verbs[dynapi->count++] = v; - return 0; -oom: - errno = ENOMEM; - return -1; -} - -int afb_api_dyn_sub_verb( - struct afb_api_dyn *dynapi, - const char *verb) -{ - struct afb_api_dyn_verb *v; - int i; - - /* look first in dyna mic verbs */ - for (i = 0 ; i < dynapi->count ; i++) { - v = dynapi->verbs[i]; - if (!strcasecmp(v->verb, verb)) { - if (i != --dynapi->count) - dynapi->verbs[i] = dynapi->verbs[dynapi->count]; - free(v); - return 0; - } - } - - errno = ENOENT; - return -1; -} - -static void call_cb(void *closure, struct afb_xreq *xreq) -{ - struct afb_api_dyn *dynapi = closure; - struct afb_api_dyn_verb **verbs, *v; - const struct afb_verb_v2 *verbsv2; - int i; - const char *name; - - name = xreq->request.verb; - xreq->request.dynapi = (void*)dynapi->export; /* hack: this avoids to export afb_export structure */ - - /* look first in dyna mic verbs */ - verbs = dynapi->verbs; - i = dynapi->count; - while (i) { - v = verbs[--i]; - if (!strcasecmp(v->verb, name)) { - xreq->request.vcbdata = v->vcbdata; - afb_xreq_call_verb_vdyn(xreq, verbs[i]); - return; - } - } - - verbsv2 = dynapi->verbsv2; - if (verbsv2) { - while (verbsv2->verb) { - if (strcasecmp(verbsv2->verb, name)) - verbsv2++; - else { - afb_xreq_call_verb_v2(xreq, verbsv2); - return; - } - } - } - - afb_xreq_fail_unknown_verb(xreq); -} - -static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset) -{ - struct afb_api_dyn *dynapi = closure; - return afb_export_start(dynapi->export, share_session, onneed, apiset); -} - -static void update_hooks_cb(void *closure) -{ - struct afb_api_dyn *dynapi = closure; - afb_export_update_hook(dynapi->export); -} - -static int get_verbosity_cb(void *closure) -{ - struct afb_api_dyn *dynapi = closure; - return afb_export_verbosity_get(dynapi->export); -} - -static void set_verbosity_cb(void *closure, int level) -{ - struct afb_api_dyn *dynapi = closure; - afb_export_verbosity_set(dynapi->export, level); -} - -static struct json_object *make_description_openAPIv3(struct afb_api_dyn *dynapi) -{ - char buffer[256]; - struct afb_api_dyn_verb **iter, **end, *verb; - struct json_object *r, *f, *a, *i, *p, *g; - - r = json_object_new_object(); - json_object_object_add(r, "openapi", json_object_new_string("3.0.0")); - - i = json_object_new_object(); - json_object_object_add(r, "info", i); - json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(dynapi->export))); - json_object_object_add(i, "version", json_object_new_string("0.0.0")); - json_object_object_add(i, "description", json_object_new_string(dynapi->info)); - - p = json_object_new_object(); - json_object_object_add(r, "paths", p); - iter = dynapi->verbs; - end = iter + dynapi->count; - while (iter != end) { - verb = *iter++; - buffer[0] = '/'; - strncpy(buffer + 1, verb->verb, sizeof buffer - 1); - buffer[sizeof buffer - 1] = 0; - f = json_object_new_object(); - json_object_object_add(p, buffer, f); - g = json_object_new_object(); - json_object_object_add(f, "get", g); - - a = afb_auth_json_v2(verb->auth, verb->session); - if (a) - json_object_object_add(g, "x-permissions", a); - - a = json_object_new_object(); - json_object_object_add(g, "responses", a); - f = json_object_new_object(); - json_object_object_add(a, "200", f); - json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb)); - } - return r; -} - -static struct json_object *describe_cb(void *closure) -{ - struct afb_api_dyn *dynapi = closure; - struct json_object *r = make_description_openAPIv3(dynapi); - return r; -} - -static struct afb_api_itf dyn_api_itf = { - .call = call_cb, - .service_start = service_start_cb, - .update_hooks = update_hooks_cb, - .get_verbosity = get_verbosity_cb, - .set_verbosity = set_verbosity_cb, - .describe = describe_cb -}; - -int afb_api_dyn_add(struct afb_apiset *apiset, const char *name, const char *info, int noconcurrency, int (*preinit)(void*, struct afb_dynapi*), void *closure) -{ - int rc; - struct afb_api_dyn *dynapi; - struct afb_api afb_api; - struct afb_export *export; - - INFO("Starting creation of dynamic API %s", name); - - /* allocates the description */ - info = info ?: ""; - dynapi = calloc(1, sizeof *dynapi + strlen(info)); - export = afb_export_create_vdyn(apiset, name, dynapi); - if (!dynapi || !export) { - ERROR("out of memory"); - goto error; - } - strcpy(dynapi->info, info); - dynapi->export = export; - - /* preinit the api */ - rc = afb_export_preinit_vdyn(export, preinit, closure); - if (rc < 0) { - ERROR("dynamic api %s preinit function failed, ABORTING it!", - afb_export_apiname(dynapi->export)); - goto error; - } - - /* records the binding */ - afb_api.closure = dynapi; - afb_api.itf = &dyn_api_itf; - afb_api.group = noconcurrency ? dynapi : NULL; - if (afb_apiset_add(apiset, afb_export_apiname(dynapi->export), afb_api) < 0) { - ERROR("dynamic api %s can't be registered to set %s, ABORTING it!", - afb_export_apiname(dynapi->export), - afb_apiset_name(apiset)); - goto error; - } - INFO("binding %s added to set %s", afb_export_apiname(dynapi->export), afb_apiset_name(apiset)); - return 0; - -error: - afb_export_destroy(export); - free(dynapi); - - return -1; -} - diff --git a/src/afb-api-dyn.h b/src/afb-api-dyn.h deleted file mode 100644 index 107d944e..00000000 --- a/src/afb-api-dyn.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#pragma once - -struct afb_apiset; -struct afb_dynapi; -struct afb_auth; -struct afb_request; -struct afb_verb_v2; - -struct afb_api_dyn_verb -{ - void (*callback)(struct afb_request *request); - void *vcbdata; - const struct afb_auth *auth; - const char *info; - int session; - char verb[1]; -}; - -struct afb_api_dyn; - -extern int afb_api_dyn_add( - struct afb_apiset *apiset, - const char *name, - const char *info, - int noconcurrency, - int (*preinit)(void*, struct afb_dynapi*), - void *closure); - -extern void afb_api_dyn_set_verbs_v2( - struct afb_api_dyn *dynapi, - const struct afb_verb_v2 *verbs); - -extern int afb_api_dyn_add_verb( - struct afb_api_dyn *dynapi, - const char *verb, - const char *info, - void (*callback)(struct afb_request *request), - void *vcbdata, - const struct afb_auth *auth, - uint32_t session); - -extern int afb_api_dyn_sub_verb( - struct afb_api_dyn *dynapi, - const char *verb); - diff --git a/src/afb-api-so-v1.c b/src/afb-api-so-v1.c index 985a113d..7db686d8 100644 --- a/src/afb-api-so-v1.c +++ b/src/afb-api-so-v1.c @@ -21,9 +21,9 @@ #include <string.h> #include <dlfcn.h> #include <assert.h> +#include <stdarg.h> #include <json-c/json.h> - #include <afb/afb-binding-v1.h> #include "afb-api.h" @@ -43,59 +43,24 @@ static const char afb_api_so_v1_register[] = "afbBindingV1Register"; static const char afb_api_so_v1_service_init[] = "afbBindingV1ServiceInit"; static const char afb_api_so_v1_service_event[] = "afbBindingV1ServiceEvent"; -/* - * Description of a binding - */ -struct api_so_v1 { - struct afb_binding_v1 *binding; /* descriptor */ - void *handle; /* context of dlopen */ - struct afb_export *export; /* export */ -}; - -static const struct afb_verb_desc_v1 *search(struct api_so_v1 *desc, const char *name) +static const struct afb_verb_desc_v1 *search(struct afb_binding_v1 *binding, const char *name) { const struct afb_verb_desc_v1 *verb; - verb = desc->binding->v1.verbs; + verb = binding->v1.verbs; while (verb->name && strcasecmp(verb->name, name)) verb++; return verb->name ? verb : NULL; } -static void call_cb(void *closure, struct afb_xreq *xreq) +void afb_api_so_v1_process_call(struct afb_binding_v1 *binding, struct afb_xreq *xreq) { const struct afb_verb_desc_v1 *verb; - struct api_so_v1 *desc = closure; - xreq->request.dynapi = (void*)desc->export; /* hack: this avoids to export afb_export structure */ - verb = search(desc, xreq->request.verb); + verb = search(binding, xreq->request.called_verb); afb_xreq_call_verb_v1(xreq, verb); } -static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset) -{ - struct api_so_v1 *desc = closure; - return afb_export_start(desc->export, share_session, onneed, apiset); -} - -static void update_hooks_cb(void *closure) -{ - struct api_so_v1 *desc = closure; - afb_export_update_hook(desc->export); -} - -static int get_verbosity_cb(void *closure) -{ - struct api_so_v1 *desc = closure; - return afb_export_verbosity_get(desc->export); -} - -static void set_verbosity_cb(void *closure, int level) -{ - struct api_so_v1 *desc = closure; - afb_export_verbosity_set(desc->export, level); -} - static struct json_object *addperm(struct json_object *o, struct json_object *x) { struct json_object *a; @@ -130,7 +95,7 @@ static struct json_object *addperm_key_valint(struct json_object *o, const char return addperm_key_val(o, key, json_object_new_int(val)); } -static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc) +struct json_object *afb_api_so_v1_make_description_openAPIv3(struct afb_binding_v1 *binding, const char *apiname) { char buffer[256]; const struct afb_verb_desc_v1 *verb; @@ -141,13 +106,13 @@ static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc) i = json_object_new_object(); json_object_object_add(r, "info", i); - json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(desc->export))); + json_object_object_add(i, "title", json_object_new_string(apiname)); json_object_object_add(i, "version", json_object_new_string("0.0.0")); - json_object_object_add(i, "description", json_object_new_string(desc->binding->v1.info ?: afb_export_apiname(desc->export))); + json_object_object_add(i, "description", json_object_new_string(binding->v1.info ?: apiname)); p = json_object_new_object(); json_object_object_add(r, "paths", p); - verb = desc->binding->v1.verbs; + verb = binding->v1.verbs; while (verb->name) { buffer[0] = '/'; strncpy(buffer + 1, verb->name, sizeof buffer - 1); @@ -158,14 +123,14 @@ static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc) json_object_object_add(f, "get", g); a = NULL; - if (verb->session & AFB_SESSION_CLOSE_V1) + if (verb->session & AFB_SESSION_CLOSE_X1) a = addperm_key_valstr(a, "session", "close"); - if (verb->session & AFB_SESSION_CHECK_V1) + if (verb->session & AFB_SESSION_CHECK_X1) a = addperm_key_valstr(a, "session", "check"); - if (verb->session & AFB_SESSION_RENEW_V1) + if (verb->session & AFB_SESSION_RENEW_X1) a = addperm_key_valstr(a, "token", "refresh"); - if (verb->session & AFB_SESSION_LOA_MASK_V1) - a = addperm_key_valint(a, "LOA", (verb->session >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1); + if (verb->session & AFB_SESSION_LOA_MASK_X1) + a = addperm_key_valint(a, "LOA", (verb->session >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1); if (a) json_object_object_add(g, "x-permissions", a); @@ -179,95 +144,75 @@ static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc) return r; } -static struct json_object *describe_cb(void *closure) +int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set) { - struct api_so_v1 *desc = closure; - - return make_description_openAPIv3(desc); -} - -static struct afb_api_itf so_v1_api_itf = { - .call = call_cb, - .service_start = service_start_cb, - .update_hooks = update_hooks_cb, - .get_verbosity = get_verbosity_cb, - .set_verbosity = set_verbosity_cb, - .describe = describe_cb -}; - -int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *apiset) -{ - struct api_so_v1 *desc; + struct afb_binding_v1 *binding; /* descriptor */ struct afb_binding_v1 *(*register_function) (const struct afb_binding_interface_v1 *interface); - int (*init)(struct afb_service service); + int (*init)(struct afb_service_x1 service); void (*onevent)(const char *event, struct json_object *object); - struct afb_api afb_api; struct afb_export *export; /* retrieves the register function */ register_function = dlsym(handle, afb_api_so_v1_register); if (!register_function) return 0; + INFO("binding [%s] is a valid AFB binding V1", path); /* allocates the description */ init = dlsym(handle, afb_api_so_v1_service_init); onevent = dlsym(handle, afb_api_so_v1_service_event); - export = afb_export_create_v1(apiset, path, init, onevent); - desc = calloc(1, sizeof *desc); - if (desc == NULL || export == NULL) { - ERROR("out of memory"); + export = afb_export_create_v1(declare_set, call_set, path, init, onevent); + if (export == NULL) { + ERROR("binding [%s] creation failure...", path); goto error; } - desc->export = export; - desc->handle = handle; - - /* init the binding */ - INFO("binding [%s] calling registering function %s", path, afb_api_so_v1_register); - desc->binding = afb_export_register_v1(desc->export, register_function); - if (desc->binding == NULL) { - ERROR("binding [%s] register function failed. continuing...", path); + binding = afb_export_register_v1(export, register_function); + if (binding == NULL) { + ERROR("binding [%s] register failure...", path); goto error; } /* check the returned structure */ - if (desc->binding->type != AFB_BINDING_VERSION_1) { - ERROR("binding [%s] invalid type %d...", path, desc->binding->type); + if (binding->type != AFB_BINDING_VERSION_1) { + ERROR("binding [%s] invalid type %d...", path, binding->type); goto error; } - if (desc->binding->v1.prefix == NULL || *desc->binding->v1.prefix == 0) { + if (binding->v1.prefix == NULL || *binding->v1.prefix == 0) { ERROR("binding [%s] bad prefix...", path); goto error; } - if (!afb_api_is_valid_name(desc->binding->v1.prefix, 1)) { + if (!afb_api_is_valid_name(binding->v1.prefix)) { ERROR("binding [%s] invalid prefix...", path); goto error; } - if (desc->binding->v1.info == NULL || *desc->binding->v1.info == 0) { + if (binding->v1.info == NULL || *binding->v1.info == 0) { ERROR("binding [%s] bad description...", path); goto error; } - if (desc->binding->v1.verbs == NULL) { - ERROR("binding [%s] no APIs...", path); + if (binding->v1.verbs == NULL) { + ERROR("binding [%s] no verbs...", path); goto error; } /* records the binding */ - if (!strcmp(path, afb_export_apiname(desc->export))) - afb_export_rename(desc->export, desc->binding->v1.prefix); - afb_api.closure = desc; - afb_api.itf = &so_v1_api_itf; - afb_api.group = NULL; - if (afb_apiset_add(apiset, afb_export_apiname(desc->export), afb_api) < 0) { + if (!strcmp(path, afb_export_apiname(export))) { + if (afb_export_rename(export, binding->v1.prefix) < 0) { + ERROR("binding [%s] can't be renamed to %s", path, binding->v1.prefix); + goto error; + } + } + + if (afb_export_declare(export, 0) < 0) { ERROR("binding [%s] can't be registered...", path); goto error; } - INFO("binding %s loaded with API prefix %s", path, afb_export_apiname(desc->export)); + INFO("binding %s loaded with API prefix %s", path, afb_export_apiname(export)); + afb_export_unref(export); return 1; error: - afb_export_destroy(export); - free(desc); + afb_export_unref(export); return -1; } diff --git a/src/afb-api-so-v1.h b/src/afb-api-so-v1.h index 42f18a19..ebe00950 100644 --- a/src/afb-api-so-v1.h +++ b/src/afb-api-so-v1.h @@ -18,4 +18,12 @@ #pragma once -extern int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *apiset); +struct afb_apiset; +struct afb_binding_v1; +struct afb_xreq; +struct json_object; + +extern int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set); + +extern void afb_api_so_v1_process_call(struct afb_binding_v1 *binding, struct afb_xreq *xreq); +extern struct json_object *afb_api_so_v1_make_description_openAPIv3(struct afb_binding_v1 *binding, const char *apiname); diff --git a/src/afb-api-so-v2.c b/src/afb-api-so-v2.c index fb901f58..a13c00e4 100644 --- a/src/afb-api-so-v2.c +++ b/src/afb-api-so-v2.c @@ -21,9 +21,10 @@ #include <string.h> #include <dlfcn.h> #include <assert.h> +#include <stdarg.h> -#include <afb/afb-binding-v2.h> #include <json-c/json.h> +#include <afb/afb-binding-v2.h> #include "afb-api.h" #include "afb-api-so-v2.h" @@ -42,78 +43,50 @@ static const char afb_api_so_v2_descriptor[] = "afbBindingV2"; static const char afb_api_so_v2_data[] = "afbBindingV2data"; -/* - * Description of a binding - */ -struct api_so_v2 { - const struct afb_binding_v2 *binding; /* descriptor */ - void *handle; /* context of dlopen */ - struct afb_export *export; /* exportations */ -}; - -static const struct afb_verb_v2 *search(struct api_so_v2 *desc, const char *name) +static const struct afb_verb_v2 *search(const struct afb_binding_v2 *binding, const char *name) { const struct afb_verb_v2 *verb; - verb = desc->binding->verbs; + verb = binding->verbs; while (verb->verb && strcasecmp(verb->verb, name)) verb++; return verb->verb ? verb : NULL; return NULL; } -static void call_cb(void *closure, struct afb_xreq *xreq) +void afb_api_so_v2_process_call(const struct afb_binding_v2 *binding, struct afb_xreq *xreq) { - struct api_so_v2 *desc = closure; const struct afb_verb_v2 *verb; - xreq->request.dynapi = (void*)desc->export; /* hack: this avoids to export afb_export structure */ - verb = search(desc, xreq->request.verb); + verb = search(binding, xreq->request.called_verb); afb_xreq_call_verb_v2(xreq, verb); } -static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset) -{ - struct api_so_v2 *desc = closure; - return afb_export_start(desc->export, share_session, onneed, apiset); -} - -static void update_hooks_cb(void *closure) -{ - struct api_so_v2 *desc = closure; - afb_export_update_hook(desc->export); -} - -static int get_verbosity_cb(void *closure) -{ - struct api_so_v2 *desc = closure; - return afb_export_verbosity_get(desc->export); -} - -static void set_verbosity_cb(void *closure, int level) -{ - struct api_so_v2 *desc = closure; - afb_export_verbosity_set(desc->export, level); -} - -static struct json_object *make_description_openAPIv3(struct api_so_v2 *desc) +struct json_object *afb_api_so_v2_make_description_openAPIv3(const struct afb_binding_v2 *binding, const char *apiname) { char buffer[256]; const struct afb_verb_v2 *verb; struct json_object *r, *f, *a, *i, *p, *g; + + if (binding->specification) { + r = json_tokener_parse(binding->specification); + if (r) + return r; + } + r = json_object_new_object(); json_object_object_add(r, "openapi", json_object_new_string("3.0.0")); i = json_object_new_object(); json_object_object_add(r, "info", i); - json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(desc->export))); + json_object_object_add(i, "title", json_object_new_string(apiname)); json_object_object_add(i, "version", json_object_new_string("0.0.0")); - json_object_object_add(i, "description", json_object_new_string(desc->binding->info ?: afb_export_apiname(desc->export))); + json_object_object_add(i, "description", json_object_new_string(binding->info ?: apiname)); p = json_object_new_object(); json_object_object_add(r, "paths", p); - verb = desc->binding->verbs; + verb = binding->verbs; while (verb->verb) { buffer[0] = '/'; strncpy(buffer + 1, verb->verb, sizeof buffer - 1); @@ -137,29 +110,9 @@ static struct json_object *make_description_openAPIv3(struct api_so_v2 *desc) return r; } -static struct json_object *describe_cb(void *closure) -{ - struct api_so_v2 *desc = closure; - struct json_object *r = desc->binding->specification ? json_tokener_parse(desc->binding->specification) : NULL; - if (!r) - r = make_description_openAPIv3(desc); - return r; -} - -static struct afb_api_itf so_v2_api_itf = { - .call = call_cb, - .service_start = service_start_cb, - .update_hooks = update_hooks_cb, - .get_verbosity = get_verbosity_cb, - .set_verbosity = set_verbosity_cb, - .describe = describe_cb -}; - -int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *apiset, struct afb_binding_data_v2 *data) +int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set, struct afb_binding_data_v2 *data) { int rc; - struct api_so_v2 *desc; - struct afb_api afb_api; struct afb_export *export; /* basic checks */ @@ -169,45 +122,38 @@ int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle assert(data); /* allocates the description */ - export = afb_export_create_v2(apiset, binding->api, data, binding->init, binding->onevent); - desc = calloc(1, sizeof *desc); - if (!desc || !export) { + export = afb_export_create_v2(declare_set, call_set, binding->api, binding, data, binding->init, binding->onevent); + if (!export) { ERROR("out of memory"); goto error; } - desc->binding = binding; - desc->handle = handle; - desc->export = export; + /* records the binding */ + if (afb_export_declare(export, binding->noconcurrency) < 0) { + ERROR("binding %s can't be registered to set %s...", afb_export_apiname(export), afb_apiset_name(declare_set)); + goto error; + } /* init the binding */ if (binding->preinit) { INFO("binding %s calling preinit function", binding->api); rc = binding->preinit(); if (rc < 0) { - ERROR("binding %s preinit function failed...", afb_export_apiname(desc->export)); + ERROR("binding %s preinit function failed...", afb_export_apiname(export)); + afb_export_undeclare(export); goto error; } } - /* records the binding */ - afb_api.closure = desc; - afb_api.itf = &so_v2_api_itf; - afb_api.group = binding->noconcurrency ? export : NULL; - if (afb_apiset_add(apiset, afb_export_apiname(desc->export), afb_api) < 0) { - ERROR("binding %s can't be registered to set %s...", afb_export_apiname(desc->export), afb_apiset_name(apiset)); - goto error; - } - INFO("binding %s added to set %s", afb_export_apiname(desc->export), afb_apiset_name(apiset)); + INFO("binding %s added to set %s", afb_export_apiname(export), afb_apiset_name(declare_set)); return 1; error: - afb_export_destroy(export); - free(desc); + afb_export_unref(export); return -1; } -int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset) +int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set) { const struct afb_binding_v2 *binding; struct afb_binding_data_v2 *data; @@ -230,22 +176,17 @@ int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset) ERROR("binding [%s] bad api name...", path); goto error; } - if (!afb_api_is_valid_name(binding->api, 1)) { + if (!afb_api_is_valid_name(binding->api)) { ERROR("binding [%s] invalid api name...", path); goto error; } -#if 0 - if (binding->specification == NULL || *binding->specification == 0) { - ERROR("binding [%s] bad specification...", path); - goto error; - } -#endif + if (binding->verbs == NULL) { ERROR("binding [%s] no verbs...", path); goto error; } - return afb_api_so_v2_add_binding(binding, handle, apiset, data); + return afb_api_so_v2_add_binding(binding, handle, declare_set, call_set, data); error: return -1; diff --git a/src/afb-api-so-v2.h b/src/afb-api-so-v2.h index 87cd80d5..d53206d3 100644 --- a/src/afb-api-so-v2.h +++ b/src/afb-api-so-v2.h @@ -21,6 +21,11 @@ struct afb_apiset; struct afb_binding_v2; struct afb_binding_data_v2; +struct afb_xreq; +struct json_object; -extern int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset); -extern int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *apiset, struct afb_binding_data_v2 *data); +extern int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set); +extern int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set, struct afb_binding_data_v2 *data); + +extern void afb_api_so_v2_process_call(const struct afb_binding_v2 *binding, struct afb_xreq *xreq); +extern struct json_object *afb_api_so_v2_make_description_openAPIv3(const struct afb_binding_v2 *binding, const char *apiname); diff --git a/src/afb-api-so-v3.c b/src/afb-api-so-v3.c new file mode 100644 index 00000000..415c13d9 --- /dev/null +++ b/src/afb-api-so-v3.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <assert.h> +#include <stdarg.h> + +#include <json-c/json.h> +#include <afb/afb-binding-v3.h> + +#include "afb-api.h" +#include "afb-api-so-v3.h" +#include "afb-api-v3.h" +#include "afb-apiset.h" +#include "afb-export.h" +#include "verbose.h" + +/* + * names of symbols + */ +static const char afb_api_so_v3_desc[] = "afbBindingV3"; +static const char afb_api_so_v3_root[] = "afbBindingV3root"; +static const char afb_api_so_v3_entry[] = "afbBindingV3entry"; + +struct args +{ + struct afb_api_x3 **root; + const struct afb_binding_v3 *desc; + int (*entry)(struct afb_api_x3 *); +}; + +static int init(void *closure, struct afb_api_x3 *api) +{ + const struct args *a = closure; + int rc = 0; + + *a->root = api; + if (a->desc) { + api->userdata = a->desc->userdata; + rc = afb_api_v3_set_binding_fields(a->desc, api); + } + + if (rc >= 0 && a->entry) + rc = a->entry(api); + + if (rc >= 0) + afb_api_x3_seal(api); + + return rc; +} + +int afb_api_so_v3_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set) +{ + struct args a; + struct afb_api_v3 *api; + struct afb_export *export; + + /* retrieves the register function */ + a.root = dlsym(handle, afb_api_so_v3_root); + a.desc = dlsym(handle, afb_api_so_v3_desc); + a.entry = dlsym(handle, afb_api_so_v3_entry); + if (!a.root && !a.desc && !a.entry) + return 0; + + INFO("binding [%s] looks like an AFB binding V3", path); + + /* basic checks */ + if (!a.root) { + ERROR("binding [%s] incomplete symbol set: %s is missing", + path, afb_api_so_v3_root); + goto error; + } + if (a.desc) { + if (a.desc->api == NULL || *a.desc->api == 0) { + ERROR("binding [%s] bad api name...", path); + goto error; + } + if (!afb_api_is_valid_name(a.desc->api)) { + ERROR("binding [%s] invalid api name...", path); + goto error; + } + if (!a.entry) + a.entry = a.desc->preinit; + else if (a.desc->preinit) { + ERROR("binding [%s] clash: you can't define %s and %s.preinit, choose only one", + path, afb_api_so_v3_entry, afb_api_so_v3_desc); + goto error; + } + + api = afb_api_v3_create(declare_set, call_set, a.desc->api, a.desc->info, a.desc->noconcurrency, init, &a, 0); + if (api) + return 1; + } else { + if (!a.entry) { + ERROR("binding [%s] incomplete symbol set: %s is missing", + path, afb_api_so_v3_entry); + goto error; + } + + export = afb_export_create_none_for_path(declare_set, call_set, path, init, &a); + if (export) + return 1; + } + + ERROR("binding [%s] initialisation failed", path); + +error: + return -1; +} + diff --git a/src/afb-api-so-v3.h b/src/afb-api-so-v3.h new file mode 100644 index 00000000..52ec22ac --- /dev/null +++ b/src/afb-api-so-v3.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#pragma once + +struct afb_apiset; + +extern int afb_api_so_v3_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set); diff --git a/src/afb-api-so-vdyn.c b/src/afb-api-so-vdyn.c index 300aa130..17344945 100644 --- a/src/afb-api-so-vdyn.c +++ b/src/afb-api-so-vdyn.c @@ -20,6 +20,10 @@ #include <stdlib.h> #include <dlfcn.h> +#define AFB_BINDING_VERSION 0 +#include <afb/afb-binding.h> + +#include "afb-api-so-v3.h" #include "afb-api-so-vdyn.h" #include "afb-export.h" #include "verbose.h" @@ -29,19 +33,15 @@ */ static const char afb_api_so_vdyn_entry[] = "afbBindingVdyn"; -/* - * Description of a binding - */ -static int vdyn_preinit(void *closure, struct afb_dynapi *dynapi) +static int preinit(void *closure, struct afb_api_x3 *api) { - int (*entry)(struct afb_dynapi*) = closure; - return entry(dynapi); + int (*entry)(struct afb_api_x3*) = closure; + return entry(api); } -int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *apiset) +int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set) { - int rc; - int (*entry)(void*, struct afb_dynapi*); + int (*entry)(struct afb_api_x3*); struct afb_export *export; entry = dlsym(handle, afb_api_so_vdyn_entry); @@ -50,15 +50,12 @@ int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *apise INFO("binding [%s] looks like an AFB binding Vdyn", path); - export = afb_export_create_vdyn(apiset, path, NULL); + export = afb_export_create_none_for_path(declare_set, call_set, path, preinit, entry); if (!export) { - ERROR("can't create export for %s", path); + INFO("binding [%s] creation failed", path); return -1; } - INFO("binding [%s] calling dynamic initialisation %s", path, afb_api_so_vdyn_entry); - rc = afb_export_preinit_vdyn(export, vdyn_preinit, entry); - afb_export_destroy(export); - return rc < 0 ? rc : 1; + return 1; } diff --git a/src/afb-api-so-vdyn.h b/src/afb-api-so-vdyn.h index 05d96235..d8a43f75 100644 --- a/src/afb-api-so-vdyn.h +++ b/src/afb-api-so-vdyn.h @@ -20,4 +20,4 @@ struct afb_apiset; -extern int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *apiset); +extern int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set); diff --git a/src/afb-api-so.c b/src/afb-api-so.c index 87916cbb..3167ffad 100644 --- a/src/afb-api-so.c +++ b/src/afb-api-so.c @@ -25,12 +25,18 @@ #include <sys/stat.h> #include "afb-api-so.h" -#include "afb-api-so-v1.h" #include "afb-api-so-v2.h" -#include "afb-api-so-vdyn.h" +#include "afb-api-so-v3.h" #include "verbose.h" #include "sig-monitor.h" +#if defined(WITH_LEGACY_BINDING_V1) +# include "afb-api-so-v1.h" +#endif +#if defined(WITH_LEGACY_BINDING_VDYN) +# include "afb-api-so-vdyn.h" +#endif + struct safe_dlopen { const char *path; @@ -59,8 +65,9 @@ static void *safe_dlopen(const char *filename, int flags) return sd.handle; } -static int load_binding(const char *path, int force, struct afb_apiset *apiset) +static int load_binding(const char *path, int force, struct afb_apiset *declare_set, struct afb_apiset * call_set) { + int obsolete = 0; int rc; void *handle; @@ -76,7 +83,16 @@ static int load_binding(const char *path, int force, struct afb_apiset *apiset) } /* try the version 2 */ - rc = afb_api_so_v2_add(path, handle, apiset); + rc = afb_api_so_v3_add(path, handle, declare_set, call_set); + if (rc < 0) { + /* error when loading a valid v3 binding */ + goto error2; + } + if (rc) + return 0; /* yes version 2 */ + + /* try the version 2 */ + rc = afb_api_so_v2_add(path, handle, declare_set, call_set); if (rc < 0) { /* error when loading a valid v2 binding */ goto error2; @@ -84,29 +100,41 @@ static int load_binding(const char *path, int force, struct afb_apiset *apiset) if (rc) return 0; /* yes version 2 */ +#if defined(WITH_LEGACY_BINDING_VDYN) /* try the version dyn */ - rc = afb_api_so_vdyn_add(path, handle, apiset); + rc = afb_api_so_vdyn_add(path, handle, declare_set, call_set); if (rc < 0) { /* error when loading a valid dyn binding */ goto error2; } if (rc) return 0; /* yes version dyn */ +#else + if (dlsym(handle, "afbBindingVdyn")) { + WARNING("binding [%s]: version DYN not supported", path); + obsolete = 1; + } +#endif +#if defined(WITH_LEGACY_BINDING_V1) /* try the version 1 */ - rc = afb_api_so_v1_add(path, handle, apiset); + rc = afb_api_so_v1_add(path, handle, declare_set, call_set); if (rc < 0) { /* error when loading a valid v1 binding */ goto error2; } if (rc) return 0; /* yes version 1 */ +#else + if (dlsym(handle, "afbBindingV1Register")) { + WARNING("binding [%s]: version 1 not supported", path); + obsolete = 1; + } +#endif /* not a valid binding */ - if (force) - ERROR("binding [%s] is not an AFB binding", path); - else - INFO("binding [%s] is not an AFB binding", path); + _VERBOSE_(force ? Log_Level_Error : Log_Level_Info, "binding [%s] %s", + path, obsolete ? "is obsolete" : "isn't an AFB binding"); error2: dlclose(handle); @@ -115,12 +143,12 @@ error: } -int afb_api_so_add_binding(const char *path, struct afb_apiset *apiset) +int afb_api_so_add_binding(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set) { - return load_binding(path, 1, apiset); + return load_binding(path, 1, declare_set, call_set); } -static int adddirs(char path[PATH_MAX], size_t end, struct afb_apiset *apiset, int failstops) +static int adddirs(char path[PATH_MAX], size_t end, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops) { DIR *dir; struct dirent *dent; @@ -159,12 +187,12 @@ static int adddirs(char path[PATH_MAX], size_t end, struct afb_apiset *apiset, i Exclude from the search of bindings any directory starting with a dot (.) by default. -It is possible to reactivate the prvious behaviour +It is possible to reactivate the prvious behaviour by defining the following preprocessor variables - AFB_API_SO_ACCEPT_DOT_PREFIXED_DIRS - When this variable is defined, the directories + When this variable is defined, the directories starting with a dot are searched except if their name is "." or ".." or ".debug" @@ -181,7 +209,7 @@ This change is intended to definitely solve the issue SPEC-662. Yocto installed the debugging symbols in the subdirectory .debug. For example the binding.so also had a .debug/binding.so file attached. Opening that -debug file made dlopen crashing. +debug file made dlopen crashing. See https://sourceware.org/bugzilla/show_bug.cgi?id=22101 */ #if !defined(AFB_API_SO_ACCEPT_DOT_PREFIXED_DIRS) /* not defined by default */ @@ -203,13 +231,13 @@ See https://sourceware.org/bugzilla/show_bug.cgi?id=22101 #endif } memcpy(&path[end], dent->d_name, len+1); - rc = adddirs(path, end+len, apiset, failstops); + rc = adddirs(path, end+len, declare_set, call_set, failstops); } else if (dent->d_type == DT_REG) { /* case of files */ if (memcmp(&dent->d_name[len - 3], ".so", 4)) continue; memcpy(&path[end], dent->d_name, len+1); - rc = load_binding(path, 0, apiset); + rc = load_binding(path, 0, declare_set, call_set); } if (rc < 0 && failstops) { closedir(dir); @@ -220,7 +248,7 @@ See https://sourceware.org/bugzilla/show_bug.cgi?id=22101 return 0; } -int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset, int failstops) +int afb_api_so_add_directory(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops) { size_t length; char buffer[PATH_MAX]; @@ -232,10 +260,10 @@ int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset, int fa } memcpy(buffer, path, length + 1); - return adddirs(buffer, length, apiset, failstops); + return adddirs(buffer, length, declare_set, call_set, failstops); } -int afb_api_so_add_path(const char *path, struct afb_apiset *apiset, int failstops) +int afb_api_so_add_path(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops) { struct stat st; int rc; @@ -244,15 +272,15 @@ int afb_api_so_add_path(const char *path, struct afb_apiset *apiset, int failsto if (rc < 0) ERROR("Invalid binding path [%s]: %m", path); else if (S_ISDIR(st.st_mode)) - rc = afb_api_so_add_directory(path, apiset, failstops); + rc = afb_api_so_add_directory(path, declare_set, call_set, failstops); else if (strstr(path, ".so")) - rc = load_binding(path, 0, apiset); + rc = load_binding(path, 0, declare_set, call_set); else INFO("not a binding [%s], skipped", path); return rc; } -int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset, int failstops) +int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops) { static char sep[] = ":"; char *ps, *p; @@ -263,19 +291,19 @@ int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset, int f p = strsep(&ps, sep); if (!p) return 0; - rc = afb_api_so_add_path(p, apiset, failstops); + rc = afb_api_so_add_path(p, declare_set, call_set, failstops); if (rc < 0) return rc; } } -int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *apiset) +int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set) { - return afb_api_so_add_pathset(pathset, apiset, 1); + return afb_api_so_add_pathset(pathset, declare_set, call_set, 1); } -int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *apiset) +int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set) { - return afb_api_so_add_pathset(pathset, apiset, 0); + return afb_api_so_add_pathset(pathset, declare_set, call_set, 0); } diff --git a/src/afb-api-so.h b/src/afb-api-so.h index d37f77c6..e6527469 100644 --- a/src/afb-api-so.h +++ b/src/afb-api-so.h @@ -20,15 +20,15 @@ struct afb_apiset; -extern int afb_api_so_add_binding(const char *path, struct afb_apiset *apiset); +extern int afb_api_so_add_binding(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set); -extern int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset, int failstops); +extern int afb_api_so_add_directory(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops); -extern int afb_api_so_add_path(const char *path, struct afb_apiset *apiset, int failstops); +extern int afb_api_so_add_path(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops); -extern int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset, int failstops); +extern int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops); -extern int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *apiset); -extern int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *apiset); +extern int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set); +extern int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set); diff --git a/src/afb-api-v3.c b/src/afb-api-v3.c new file mode 100644 index 00000000..8c755f94 --- /dev/null +++ b/src/afb-api-v3.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <fnmatch.h> + +#include <json-c/json.h> + +#define AFB_BINDING_VERSION 0 +#include <afb/afb-binding.h> + +#include "afb-api.h" +#include "afb-api-v3.h" +#include "afb-apiset.h" +#include "afb-auth.h" +#include "afb-export.h" +#include "afb-xreq.h" +#include "verbose.h" + +/* + * Description of a binding + */ +struct afb_api_v3 { + int refcount; + int count; + struct afb_verb_v3 **verbs; + const struct afb_verb_v2 *verbsv2; + const struct afb_verb_v3 *verbsv3; + struct afb_export *export; + const char *info; +}; + +static const char nulchar = 0; + +static int verb_name_compare(const struct afb_verb_v3 *verb, const char *name) +{ + return verb->glob + ? fnmatch(verb->verb, name, FNM_NOESCAPE|FNM_PATHNAME|FNM_CASEFOLD|FNM_PERIOD) + : strcasecmp(verb->verb, name); +} + +static struct afb_verb_v3 *search_dynamic_verb(struct afb_api_v3 *api, const char *name) +{ + struct afb_verb_v3 **v, **e, *i; + + v = api->verbs; + e = &v[api->count]; + while (v != e) { + i = *v; + if (!verb_name_compare(i, name)) + return i; + v++; + } + return 0; +} + +void afb_api_v3_process_call(struct afb_api_v3 *api, struct afb_xreq *xreq) +{ + const struct afb_verb_v3 *verbsv3; + const struct afb_verb_v2 *verbsv2; + const char *name; + + name = xreq->request.called_verb; + + /* look first in dynamic set */ + verbsv3 = search_dynamic_verb(api, name); + if (!verbsv3) { + /* look then in static set */ + verbsv3 = api->verbsv3; + while (verbsv3) { + if (!verbsv3->verb) + verbsv3 = 0; + else if (!verb_name_compare(verbsv3, name)) + break; + else + verbsv3++; + } + } + /* is it a v3 verb ? */ + if (verbsv3) { + /* yes */ + xreq->request.vcbdata = verbsv3->vcbdata; + afb_xreq_call_verb_v3(xreq, verbsv3); + return; + } + + /* look in legacy set */ + verbsv2 = api->verbsv2; + if (verbsv2) { + while (verbsv2->verb) { + if (strcasecmp(verbsv2->verb, name)) + verbsv2++; + else { + afb_xreq_call_verb_v2(xreq, verbsv2); + return; + } + } + } + + afb_xreq_reply_unknown_verb(xreq); +} + +struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname) +{ + char buffer[256]; + struct afb_verb_v3 **iter, **end, *verb; + struct json_object *r, *f, *a, *i, *p, *g; + + r = json_object_new_object(); + json_object_object_add(r, "openapi", json_object_new_string("3.0.0")); + + i = json_object_new_object(); + json_object_object_add(r, "info", i); + json_object_object_add(i, "title", json_object_new_string(apiname)); + json_object_object_add(i, "version", json_object_new_string("0.0.0")); + json_object_object_add(i, "description", json_object_new_string(api->info)); + + p = json_object_new_object(); + json_object_object_add(r, "paths", p); + iter = api->verbs; + end = iter + api->count; + while (iter != end) { + verb = *iter++; + buffer[0] = '/'; + strncpy(buffer + 1, verb->verb, sizeof buffer - 1); + buffer[sizeof buffer - 1] = 0; + f = json_object_new_object(); + json_object_object_add(p, buffer, f); + g = json_object_new_object(); + json_object_object_add(f, "get", g); + + a = afb_auth_json_v2(verb->auth, verb->session); + if (a) + json_object_object_add(g, "x-permissions", a); + + a = json_object_new_object(); + json_object_object_add(g, "responses", a); + f = json_object_new_object(); + json_object_object_add(a, "200", f); + json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb)); + } + return r; +} + +struct afb_api_v3 *afb_api_v3_create( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + const char *info, + int noconcurrency, + int (*preinit)(void*, struct afb_api_x3 *), + void *closure, + int copy_info +) +{ + struct afb_api_v3 *api; + + /* allocates the description */ + api = calloc(1, sizeof *api + (copy_info && info ? 1 + strlen(info) : 0)); + if (!api) + goto oom; + api->refcount = 1; + if (!info) + api->info = &nulchar; + else if (copy_info) + api->info = strcpy((char*)(api + 1), info); + else + api->info = info; + + api->export = afb_export_create_v3(declare_set, call_set, apiname, api); + if (!api->export) + goto oom2; + + if (afb_export_declare(api->export, noconcurrency) < 0) + goto oom3; + + if (preinit && afb_export_preinit_x3(api->export, preinit, closure) < 0) + goto oom4; + + return api; + +oom4: + afb_export_undeclare(api->export); +oom3: + afb_export_unref(api->export); +oom2: + free(api); +oom: + ERROR("out of memory"); + return NULL; +} + +struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api) +{ + if (api) + __atomic_add_fetch(&api->refcount, 1, __ATOMIC_RELAXED); + return api; +} + +void afb_api_v3_unref(struct afb_api_v3 *api) +{ + if (api && !__atomic_sub_fetch(&api->refcount, 1, __ATOMIC_RELAXED)) { + afb_export_destroy(api->export); + free(api); + } +} + +struct afb_export *afb_api_v3_export(struct afb_api_v3 *api) +{ + return api->export; +} + +void afb_api_v3_set_verbs_v2( + struct afb_api_v3 *api, + const struct afb_verb_v2 *verbs) +{ + api->verbsv2 = verbs; +} + +void afb_api_v3_set_verbs_v3( + struct afb_api_v3 *api, + const struct afb_verb_v3 *verbs) +{ + api->verbsv3 = verbs; +} + +int afb_api_v3_add_verb( + struct afb_api_v3 *api, + const char *verb, + const char *info, + void (*callback)(struct afb_req_x2 *req), + void *vcbdata, + const struct afb_auth *auth, + uint16_t session, + int glob) +{ + struct afb_verb_v3 *v, **vv; + char *txt; + int i; + + for (i = 0 ; i < api->count ; i++) { + v = api->verbs[i]; + if (glob == v->glob && !strcasecmp(verb, v->verb)) { + /* refuse to redefine a dynamic verb */ + errno = EEXIST; + return -1; + } + } + + vv = realloc(api->verbs, (1 + api->count) * sizeof *vv); + if (!vv) + goto oom; + api->verbs = vv; + + v = malloc(sizeof *v + (1 + strlen(verb)) + (info ? 1 + strlen(info) : 0)); + if (!v) + goto oom; + + v->callback = callback; + v->vcbdata = vcbdata; + v->auth = auth; + v->session = session; + v->glob = !!glob; + + txt = (char*)(v + 1); + v->verb = txt; + txt = stpcpy(txt, verb); + if (!info) + v->info = NULL; + else { + v->info = ++txt; + strcpy(txt, info); + } + + api->verbs[api->count++] = v; + return 0; +oom: + errno = ENOMEM; + return -1; +} + +int afb_api_v3_del_verb( + struct afb_api_v3 *api, + const char *verb, + void **vcbdata) +{ + struct afb_verb_v3 **v, **e, *i; + + v = api->verbs; + e = &v[api->count]; + while (v != e) { + i = *v++; + if (!strcasecmp(i->verb, verb)) { + api->count--; + if (vcbdata) + *vcbdata = i->vcbdata; + if (v != e) + *--v = *--e; + free(i); + return 0; + } + } + + errno = ENOENT; + return -1; +} + +int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api) +{ + int rc = 0; + if (desc->verbs) + rc = afb_api_x3_set_verbs_v3(api, desc->verbs); + if (!rc && desc->onevent) + rc = afb_api_x3_on_event(api, desc->onevent); + if (!rc && desc->init) + rc = afb_api_x3_on_init(api, desc->init); + if (!rc && desc->provide_class) + rc = afb_api_x3_provide_class(api, desc->provide_class); + if (!rc && desc->require_class) + rc = afb_api_x3_require_class(api, desc->require_class); + if (!rc && desc->require_api) + rc = afb_api_x3_require_api(api, desc->require_api, 1); + return rc; +} + +static int init_binding(void *closure, struct afb_api_x3 *api) +{ + const struct afb_binding_v3 *desc = closure; + int rc = afb_api_v3_set_binding_fields(desc, api); + if (!rc && desc->preinit) + rc = desc->preinit(api); + return rc; +} + +struct afb_api_v3 *afb_api_v3_from_binding(const struct afb_binding_v3 *desc, struct afb_apiset *declare_set, struct afb_apiset * call_set) +{ + return afb_api_v3_create(declare_set, call_set, desc->api, desc->info, desc->noconcurrency, init_binding, (void*)desc, 0); +} + diff --git a/src/afb-api-v3.h b/src/afb-api-v3.h new file mode 100644 index 00000000..33649f35 --- /dev/null +++ b/src/afb-api-v3.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#pragma once + +struct afb_apiset; +struct afb_api_v3; +struct afb_api_x3; +struct afb_auth; +struct afb_req_x2; +struct afb_verb_v2; +struct afb_verb_v3; +struct afb_binding_v3; +struct afb_xreq; +struct json_object; +struct afb_export; + +extern struct afb_api_v3 *afb_api_v3_create( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + const char *info, + int noconcurrency, + int (*preinit)(void*, struct afb_api_x3 *), + void *closure, + int copy_info +); + +extern struct afb_api_v3 *afb_api_v3_from_binding( + const struct afb_binding_v3 *desc, + struct afb_apiset *declare_set, + struct afb_apiset * call_set); + +extern int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api); + +extern struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api); +extern void afb_api_v3_unref(struct afb_api_v3 *api); + +extern struct afb_export *afb_api_v3_export(struct afb_api_v3 *api); + +extern void afb_api_v3_set_verbs_v2( + struct afb_api_v3 *api, + const struct afb_verb_v2 *verbs); + +extern void afb_api_v3_set_verbs_v3( + struct afb_api_v3 *api, + const struct afb_verb_v3 *verbs); + +extern int afb_api_v3_add_verb( + struct afb_api_v3 *api, + const char *verb, + const char *info, + void (*callback)(struct afb_req_x2 *req), + void *vcbdata, + const struct afb_auth *auth, + uint16_t session, + int glob); + +extern int afb_api_v3_del_verb( + struct afb_api_v3 *api, + const char *verb, + void **vcbdata); + +extern void afb_api_v3_process_call(struct afb_api_v3 *api, struct afb_xreq *xreq); +extern struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname); + diff --git a/src/afb-api-ws.c b/src/afb-api-ws.c index 190c2fd8..c1ccd329 100644 --- a/src/afb-api-ws.c +++ b/src/afb-api-ws.c @@ -34,6 +34,7 @@ #include "afb-systemd.h" #include "afb-api.h" #include "afb-apiset.h" +#include "afb-api-ws.h" #include "afb-stub-ws.h" #include "verbose.h" #include "fdev.h" @@ -72,7 +73,7 @@ static struct api_ws *api_ws_make(const char *path) while (length && path[length - 1] != '/' && path[length - 1] != ':') length = length - 1; api->api = &api->path[length]; - if (api->api == NULL || !afb_api_is_valid_name(api->api, 1)) { + if (api->api == NULL || !afb_api_is_valid_name(api->api)) { errno = EINVAL; goto error2; } @@ -219,7 +220,7 @@ static struct fdev *api_ws_socket_fdev(const char *path, int server) /**********************************************************************************/ -int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int strong) +int afb_api_ws_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set, int strong) { struct api_ws *apiws; struct afb_stub_ws *stubws; @@ -234,12 +235,12 @@ int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int stron if (!apiws->fdev) goto error2; - stubws = afb_stub_ws_create_client(apiws->fdev, apiws->api, apiset); + stubws = afb_stub_ws_create_client(apiws->fdev, apiws->api, call_set); if (!stubws) { ERROR("can't setup client ws service to %s", apiws->path); goto error3; } - if (afb_stub_ws_client_add(stubws, apiset) < 0) { + if (afb_stub_ws_client_add(stubws, declare_set) < 0) { ERROR("can't add the client to the apiset for service %s", apiws->path); goto error3; } @@ -253,14 +254,14 @@ error: return -!!strong; } -int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *apiset) +int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) { - return afb_api_ws_add_client(path, apiset, 1); + return afb_api_ws_add_client(path, declare_set, call_set, 1); } -int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *apiset) +int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) { - return afb_api_ws_add_client(path, apiset, 0); + return afb_api_ws_add_client(path, declare_set, call_set, 0); } static int api_ws_server_accept_client(struct api_ws *apiws, struct fdev *fdev) @@ -329,7 +330,7 @@ static int api_ws_server_connect(struct api_ws *apiws) } /* create the service */ -int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset) +int afb_api_ws_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) { int rc; struct api_ws *apiws; @@ -340,7 +341,7 @@ int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset) goto error; /* check api name */ - if (!afb_apiset_lookup(apiset, apiws->api, 1)) { + if (!afb_apiset_lookup(call_set, apiws->api, 1)) { ERROR("Can't provide ws-server for %s: API %s doesn't exist", path, apiws->api); goto error2; } @@ -350,7 +351,7 @@ int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset) if (rc < 0) goto error2; - apiws->apiset = afb_apiset_addref(apiset); + apiws->apiset = afb_apiset_addref(call_set); return 0; error2: diff --git a/src/afb-api-ws.h b/src/afb-api-ws.h index 123efb73..812cff59 100644 --- a/src/afb-api-ws.h +++ b/src/afb-api-ws.h @@ -20,10 +20,10 @@ struct afb_apiset; -extern int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int strong); -extern int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *apiset); -extern int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *apiset); +extern int afb_api_ws_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set, int strong); +extern int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); +extern int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); -extern int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset); +extern int afb_api_ws_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); diff --git a/src/afb-api.c b/src/afb-api.c index 54ee5945..de603d3e 100644 --- a/src/afb-api.c +++ b/src/afb-api.c @@ -29,7 +29,7 @@ * Checks wether 'name' is a valid API name. * @return 1 if valid, 0 otherwise */ -int afb_api_is_valid_name(const char *name, int hookable) +int afb_api_is_valid_name(const char *name) { unsigned char c; @@ -60,6 +60,6 @@ int afb_api_is_valid_name(const char *name, int hookable) } c = (unsigned char)*++name; } while(c != 0); - return !hookable || afb_api_is_hookable(name); + return 1; } diff --git a/src/afb-api.h b/src/afb-api.h index 3f2e7f15..d03aaca5 100644 --- a/src/afb-api.h +++ b/src/afb-api.h @@ -24,24 +24,21 @@ struct json_object; struct afb_api_itf { void (*call)(void *closure, struct afb_xreq *xreq); - int (*service_start)(void *closure, int share_session, int onneed, struct afb_apiset *apiset); + int (*service_start)(void *closure, int share_session, int onneed); void (*update_hooks)(void *closure); - int (*get_verbosity)(void *closure); - void (*set_verbosity)(void *closure, int level); + int (*get_logmask)(void *closure); + void (*set_logmask)(void *closure, int level); struct json_object *(*describe)(void *closure); void (*unref)(void *closure); }; -struct afb_api +struct afb_api_item { void *closure; struct afb_api_itf *itf; const void *group; }; -extern int afb_api_is_valid_name(const char *name, int hookable); +extern int afb_api_is_valid_name(const char *name); -#define AFB_API_UNHOOKABLE_PREFIX_CHAR '$' -#define AFB_API_UNHOOKABLE_PREFIX_STRING "$" -#define afb_api_is_hookable(api) ((api)[0] != AFB_API_UNHOOKABLE_PREFIX_CHAR) diff --git a/src/afb-apiset.c b/src/afb-apiset.c index 8d76bbfe..af5a8652 100644 --- a/src/afb-apiset.c +++ b/src/afb-apiset.c @@ -1,6 +1,5 @@ /* * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author "Fulup Ar Foll" * Author José Bollo <jose.bollo@iot.bzh> * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,14 +31,68 @@ #define INCR 8 /* CAUTION: must be a power of 2 */ +struct afb_apiset; +struct api_desc; +struct api_class; +struct api_alias; +struct api_depend; + +/** + * array of items + */ +struct api_array { + int count; /* count of items */ + union { + void **anys; + struct api_desc **apis; + struct api_class **classes; + struct api_alias **aliases; + struct api_depend **depends; + }; +}; + /** * Internal description of an api */ struct api_desc { - int status; - const char *name; /**< name of the api */ - struct afb_api api; /**< handler of the api */ + struct api_desc *next; + const char *name; /**< name of the api */ + int status; /**< initialisation status */ + struct afb_api_item api; /**< handler of the api */ + struct { + struct api_array classes; + struct api_array apis; + } require; +}; + +/** + * internal description of aliases + */ +struct api_alias +{ + struct api_alias *next; + struct api_desc *api; + char name[1]; +}; + +/** + * + */ +struct api_class +{ + struct api_class *next; + struct api_array providers; + char name[1]; +}; + +/** + * + */ +struct api_depend +{ + struct afb_apiset *set; + char name[1]; }; /** @@ -47,15 +100,133 @@ struct api_desc */ struct afb_apiset { - struct api_desc *apis; /**< description of apis */ + struct api_array apis; /**< the apis */ + struct api_alias *aliases; /**< the aliases */ struct afb_apiset *subset; /**< subset if any */ - int count; /**< count of apis in the set */ + struct { + int (*callback)(void*, struct afb_apiset*, const char*); /* not found handler */ + void *closure; + void (*cleanup)(void*); + } onlack; /** not found handler */ int timeout; /**< the timeout in second for the apiset */ int refcount; /**< reference count for freeing resources */ char name[1]; /**< name of the apiset */ }; /** + * global apis + */ +static struct api_desc *all_apis; + +/** + * global classes + */ +static struct api_class *all_classes; + +/** + * Ensure enough room in 'array' for 'count' items + */ +static int api_array_ensure_count(struct api_array *array, int count) +{ + int c; + void **anys; + + c = (count + INCR - 1) & ~(INCR - 1); + anys = realloc(array->anys, c * sizeof *anys); + if (!anys) { + errno = ENOMEM; + return -1; + } + + array->count = count; + array->anys = anys; + return 0; +} + +/** + * Insert in 'array' the item 'any' at the 'index' + */ +static int api_array_insert(struct api_array *array, void *any, int index) +{ + int n = array->count; + + if (api_array_ensure_count(array, n + 1) < 0) + return -1; + + while (index < n) { + array->anys[n] = array->anys[n - 1]; + n--; + } + + array->anys[index] = any; + return 0; +} + +/** + * Add the item 'any' to the 'array' + */ +static int api_array_add(struct api_array *array, void *any) +{ + int i, n = array->count; + + for (i = 0 ; i < n ; i++) { + if (array->anys[i] == any) + return 0; + } + + if (api_array_ensure_count(array, n + 1) < 0) + return -1; + + array->anys[n] = any; + return 0; +} + +/** + * Delete the 'api' from the 'array' + * Returns 1 if delete or 0 if not found + */ +static int api_array_del(struct api_array *array, void *any) +{ + int i = array->count; + while (i) { + if (array->anys[--i] == any) { + array->anys[i] = array->anys[--array->count]; + return 1; + } + } + return 0; +} + +/** + * Search the class of 'name' and return it. + * In case where the class of 'namle' isn't found, it returns + * NULL when 'create' is null or a fresh created instance if 'create' isn't + * zero (but NULL on allocation failure). + */ +static struct api_class *class_search(const char *name, int create) +{ + struct api_class *c; + + for (c= all_classes ; c ; c = c->next) { + if (!strcasecmp(name, c->name)) + return c; + } + + if (!create) + return NULL; + + c = calloc(1, strlen(name) + sizeof *c); + if (!c) + errno = ENOMEM; + else { + strcpy(c->name, name); + c->next = all_classes; + all_classes = c; + } + return c; +} + +/** * Search the api of 'name'. * @param set the api set * @param name the api name to search @@ -65,20 +236,16 @@ static struct api_desc *search(struct afb_apiset *set, const char *name) { int i, c, up, lo; struct api_desc *a; + struct api_alias *aliases; /* dichotomic search of the api */ /* initial slice */ lo = 0; - up = set->count; - for (;;) { - /* check remaining slice */ - if (lo >= up) { - /* not found */ - return NULL; - } + up = set->apis.count; + while (lo < up) { /* check the mid of the slice */ i = (lo + up) >> 1; - a = &set->apis[i]; + a = set->apis.apis[i]; c = strcasecmp(a->name, name); if (c == 0) { /* found */ @@ -90,6 +257,37 @@ static struct api_desc *search(struct afb_apiset *set, const char *name) else up = i; } + + /* linear search of aliases */ + aliases = set->aliases; + for(;;) { + if (!aliases) + break; + c = strcasecmp(aliases->name, name); + if (!c) + return aliases->api; + if (c > 0) + break; + aliases = aliases->next; + } + return NULL; +} + +/** + * Search the api of 'name' in the apiset and in its subsets. + * @param set the api set + * @param name the api name to search + * @return the descriptor if found or NULL otherwise + */ +static struct api_desc *searchrec(struct afb_apiset *set, const char *name) +{ + struct api_desc *result; + + do { + result = search(set, name); + } while (result == NULL && (set = set->subset) != NULL); + + return result; } /** @@ -111,9 +309,24 @@ struct afb_apiset *afb_apiset_addref(struct afb_apiset *set) */ void afb_apiset_unref(struct afb_apiset *set) { + struct api_alias *a; + struct api_desc *d; + if (set && !__atomic_sub_fetch(&set->refcount, 1, __ATOMIC_RELAXED)) { afb_apiset_unref(set->subset); - free(set->apis); + if (set->onlack.cleanup) + set->onlack.cleanup(set->onlack.closure); + while((a = set->aliases)) { + set->aliases = a->next; + free(a); + } + while (set->apis.count) { + d = set->apis.apis[--set->apis.count]; + if (d->api.itf->unref) + d->api.itf->unref(d->api.closure); + free(d); + } + free(set->apis.apis); free(set); } } @@ -128,22 +341,49 @@ struct afb_apiset *afb_apiset_create(const char *name, int timeout) { struct afb_apiset *set; - set = malloc((name ? strlen(name) : 0) + sizeof *set); + set = calloc(1, (name ? strlen(name) : 0) + sizeof *set); if (set) { - set->apis = malloc(INCR * sizeof *set->apis); - set->count = 0; set->timeout = timeout; set->refcount = 1; - set->subset = NULL; if (name) strcpy(set->name, name); - else - set->name[0] = 0; } return set; } /** + * Create an apiset being the last subset of 'set' + * @param set the set to extend with the created subset (can be NULL) + * @param name the name of the created apiset (can be NULL) + * @param timeout the default timeout in seconds for the created apiset + * @return the created apiset or NULL in case of error + */ +struct afb_apiset *afb_apiset_create_subset_last(struct afb_apiset *set, const char *name, int timeout) +{ + if (set) + while (set->subset) + set = set->subset; + return afb_apiset_create_subset_first(set, name, timeout); +} + +/** + * Create an apiset being the first subset of 'set' + * @param set the set to extend with the created subset (can be NULL) + * @param name the name of the created apiset (can be NULL) + * @param timeout the default timeout in seconds for the created apiset + * @return the created apiset or NULL in case of error + */ +struct afb_apiset *afb_apiset_create_subset_first(struct afb_apiset *set, const char *name, int timeout) +{ + struct afb_apiset *result = afb_apiset_create(name, timeout); + if (result && set) { + result->subset = set->subset; + set->subset = result; + } + return result; +} + +/** * the name of the apiset * @param set the api set * @return the name of the set @@ -200,6 +440,15 @@ void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset) afb_apiset_unref(tmp); } +void afb_apiset_onlack_set(struct afb_apiset *set, int (*callback)(void*, struct afb_apiset*, const char*), void *closure, void (*cleanup)(void*)) +{ + if (set->onlack.cleanup) + set->onlack.cleanup(set->onlack.closure); + set->onlack.callback = callback; + set->onlack.closure = closure; + set->onlack.cleanup = cleanup; +} + /** * Adds the api of 'name' described by 'api'. * @param set the api set @@ -210,52 +459,117 @@ void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset) * - EEXIST if name already registered * - ENOMEM when out of memory */ -int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api) +int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api_item api) { - struct api_desc *apis; + struct api_desc *desc; int i, c; - /* check previously existing plugin */ - for (i = 0 ; i < set->count ; i++) { - c = strcasecmp(set->apis[i].name, name); - if (c == 0) { - ERROR("api of name %s already exists", name); - errno = EEXIST; - goto error; - } + /* check whether it exists already */ + if (search(set, name)) { + ERROR("api of name %s already exists", name); + errno = EEXIST; + goto error; + } + + /* search insertion place */ + for (i = 0 ; i < set->apis.count ; i++) { + c = strcasecmp(set->apis.apis[i]->name, name); if (c > 0) break; } - /* allocates enough memory */ - c = (set->count + INCR) & ~(INCR - 1); - apis = realloc(set->apis, ((unsigned)c) * sizeof * apis); - if (apis == NULL) { - ERROR("out of memory"); - errno = ENOMEM; + /* allocates memory */ + desc = calloc(1, sizeof *desc); + if (!desc) + goto oom; + + desc->status = -1; + desc->api = api; + desc->name = name; + + if (api_array_insert(&set->apis, desc, i) < 0) { + free(desc); goto error; } - set->apis = apis; - /* copy higher part of the array */ - apis += i; - if (i != set->count) - memmove(apis + 1, apis, ((unsigned)(set->count - i)) * sizeof *apis); - - /* record the plugin */ - apis->status = -1; - apis->api = api; - apis->name = name; - set->count++; + desc->next = all_apis; + all_apis = desc; INFO("API %s added", name); return 0; +oom: + ERROR("out of memory"); + errno = ENOMEM; +error: + return -1; +} + +/** + * Adds a the 'alias' name to the api of 'name'. + * @params set the api set + * @param name the name of the api to alias + * @param alias the aliased name to add to the api of name + * @returns 0 in case of success or -1 in case + * of error with errno set: + * - ENOENT if the api doesn't exist + * - EEXIST if name (of alias) already registered + * - ENOMEM when out of memory + */ +int afb_apiset_add_alias(struct afb_apiset *set, const char *name, const char *alias) +{ + struct api_desc *api; + struct api_alias *ali, **pali; + + /* check alias doesn't already exist */ + if (search(set, alias)) { + ERROR("api of name %s already exists", alias); + errno = EEXIST; + goto error; + } + + /* check aliased api exists */ + api = search(set, name); + if (api == NULL) { + ERROR("api of name %s doesn't exists", name); + errno = ENOENT; + goto error; + } + + /* allocates and init the struct */ + ali = malloc(sizeof *ali + strlen(alias)); + if (ali == NULL) { + ERROR("out of memory"); + errno = ENOMEM; + goto error; + } + ali->api = api; + strcpy(ali->name, alias); + + /* insert the alias in the sorted order */ + pali = &set->aliases; + while(*pali && strcmp((*pali)->name, alias) < 0) + pali = &(*pali)->next; + ali->next = *pali; + *pali = ali; + return 0; error: return -1; } +int afb_apiset_is_alias(struct afb_apiset *set, const char *name) +{ + struct api_desc *api = searchrec(set, name); + return api && strcasecmp(api->name, name); +} + +const char *afb_apiset_unalias(struct afb_apiset *set, const char *name) +{ + struct api_desc *api = searchrec(set, name); + return api ? api->name : NULL; +} + /** * Delete from the 'set' the api of 'name'. * @param set the set to be changed @@ -264,28 +578,72 @@ error: */ int afb_apiset_del(struct afb_apiset *set, const char *name) { - struct api_desc *i, *e; - int c; + struct api_class *cla; + struct api_alias *ali, **pali; + struct api_desc *desc, **pdesc, *odesc; + int i, c; + + /* search the alias */ + pali = &set->aliases; + while ((ali = *pali)) { + c = strcasecmp(ali->name, name); + if (!c) { + *pali = ali->next; + free(ali); + return 0; + } + if (c > 0) + break; + pali = &ali->next; + } /* search the api */ - i = set->apis; - e = i + set->count; - while (i != e) { - c = strcasecmp(i->name, name); + for (i = 0 ; i < set->apis.count ; i++) { + desc = set->apis.apis[i]; + c = strcasecmp(desc->name, name); if (c == 0) { - if (i->api.itf->unref) - i->api.itf->unref(i->api.closure); - set->count--; - e--; - while (i != e) { - i[0] = i[1]; + /* remove from classes */ + for (cla = all_classes ; cla ; cla = cla->next) + api_array_del(&cla->providers, desc); + + /* unlink from the whole set and their requires */ + pdesc = &all_apis; + while ((odesc = *pdesc) != desc) { + pdesc = &odesc->next; + } + *pdesc = odesc = desc->next; + while (odesc) { + odesc = odesc->next; + } + + /* remove references from classes */ + free(desc->require.classes.classes); + + /* drop the aliases */ + pali = &set->aliases; + while ((ali = *pali)) { + if (ali->api != desc) + pali = &ali->next; + else { + *pali = ali->next; + free(ali); + } + } + + /* unref the api */ + if (desc->api.itf->unref) + desc->api.itf->unref(desc->api.closure); + + set->apis.count--; + while(i < set->apis.count) { + set->apis.apis[i] = set->apis.apis[i + 1]; i++; } + free(desc); return 0; } if (c > 0) break; - i++; } errno = ENOENT; return -1; @@ -300,8 +658,21 @@ int afb_apiset_del(struct afb_apiset *set, const char *name) */ static struct api_desc *lookup(struct afb_apiset *set, const char *name, int rec) { - struct api_desc *i = search(set, name); - return i || !rec || !set->subset ? i : lookup(set->subset, name, rec); + struct api_desc *result; + + result = search(set, name); + while (!result) { + /* lacking the api, try onlack behaviour */ + if (set->onlack.callback && set->onlack.callback(set->onlack.closure, set, name) > 0) { + result = search(set, name); + if (result) + break; + } + if (!rec || !(set = set->subset)) + break; + result = search(set, name); + } + return result; } /** @@ -311,7 +682,7 @@ static struct api_desc *lookup(struct afb_apiset *set, const char *name, int rec * @param rec if not zero look also recursively in subsets * @return the api pointer in case of success or NULL in case of error */ -const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec) +const struct afb_api_item *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec) { struct api_desc *i; @@ -322,6 +693,78 @@ const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name return NULL; } +static int start_api(struct api_desc *api, int share_session, int onneed); + +/** + * Start the apis of the 'array' + * The attribute 'share_session' is sent to the start function. + */ +static int start_array_apis(struct api_array *array, int share_session) +{ + int i, rc = 0, rc2; + + i = array->count; + while (i) { + rc2 = start_api(array->apis[--i], share_session, 1); + if (rc2 < 0) { + rc = rc2; + } + } + return rc; +} + +/** + * Start the class 'cla' (start the apis that provide it). + * The attribute 'share_session' is sent to the start function. + */ +static int start_class(struct api_class *cla, int share_session) +{ + return start_array_apis(&cla->providers, share_session); +} + +/** + * Start the classes of the 'array' + * The attribute 'share_session' is sent to the start function. + */ +static int start_array_classes(struct api_array *array, int share_session) +{ + int i, rc = 0, rc2; + + i = array->count; + while (i) { + rc2 = start_class(array->classes[--i], share_session); + if (rc2 < 0) { + rc = rc2; + } + } + return rc; +} + +/** + * Start the depends of the 'array' + * The attribute 'share_session' is sent to the start function. + */ +static int start_array_depends(struct api_array *array, int share_session) +{ + struct api_desc *api; + int i, rc = 0, rc2; + + i = array->count; + while (i) { + i--; + api = searchrec(array->depends[i]->set, array->depends[i]->name); + if (!api) + rc = -1; + else { + rc2 = start_api(api, share_session, 1); + if (rc2 < 0) { + rc = rc2; + } + } + } + return rc; +} + /** * Starts the service 'api'. * @param api the api @@ -331,7 +774,7 @@ const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name * must be a service * @return a positive number on success */ -static int start_api(struct afb_apiset *set, struct api_desc *api, int share_session, int onneed) +static int start_api(struct api_desc *api, int share_session, int onneed) { int rc; @@ -343,9 +786,11 @@ static int start_api(struct afb_apiset *set, struct api_desc *api, int share_ses } INFO("API %s starting...", api->name); + rc = start_array_classes(&api->require.classes, share_session); + rc = start_array_depends(&api->require.apis, share_session); if (api->api.itf->service_start) { api->status = EBUSY; - rc = api->api.itf->service_start(api->api.closure, share_session, onneed, set); + rc = api->api.itf->service_start(api->api.closure, share_session, onneed); if (rc < 0) { api->status = errno ?: ECANCELED; ERROR("The api %s failed to start (%d)", api->name, rc); @@ -369,13 +814,13 @@ static int start_api(struct afb_apiset *set, struct api_desc *api, int share_ses * @param rec if not zero look also recursively in subsets * @return 0 in case of success or -1 in case of error */ -const struct afb_api *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec) +const struct afb_api_item *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec) { struct api_desc *i; i = lookup(set, name, rec); if (i) - return i->status && start_api(set, i, 1, 1) ? NULL : &i->api; + return i->status && start_api(i, 1, 1) ? NULL : &i->api; errno = ENOENT; return NULL; } @@ -394,14 +839,14 @@ int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share { struct api_desc *a; - a = search(set, name); + a = searchrec(set, name); if (!a) { ERROR("can't find service %s", name); errno = ENOENT; return -1; } - return start_api(set, a, share_session, onneed); + return start_api(a, share_session, onneed); } /** @@ -414,18 +859,19 @@ int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share int afb_apiset_start_all_services(struct afb_apiset *set, int share_session) { int rc; - struct api_desc *i, *e; + int i; - i = set->apis; - e = &set->apis[set->count]; - while (i != e) { - rc = start_api(set, i, share_session, 1); - if (rc < 0) - return rc; - i++; + while (set) { + i = 0; + while (i < set->apis.count) { + rc = start_api(set->apis.apis[i], share_session, 1); + if (rc < 0) + return rc; + i++; + } + set = set->subset; } - - return set->subset ? afb_apiset_start_all_services(set->subset, share_session) : 0; + return 0; } /** @@ -435,65 +881,66 @@ int afb_apiset_start_all_services(struct afb_apiset *set, int share_session) */ void afb_apiset_update_hooks(struct afb_apiset *set, const char *name) { - const struct api_desc *i, *e; + struct api_desc **i, **e, *d; if (!name) { - i = set->apis; - e = &set->apis[set->count]; + i = set->apis.apis; + e = &set->apis.apis[set->apis.count]; + while (i != e) { + d = *i++; + if (d->api.itf->update_hooks) + d->api.itf->update_hooks(d->api.closure); + } } else { - i = search(set, name); - e = &i[!!i]; - } - while (i != e) { - if (i->api.itf->update_hooks) - i->api.itf->update_hooks(i->api.closure); - i++; + d = searchrec(set, name); + if (d && d->api.itf->update_hooks) + d->api.itf->update_hooks(d->api.closure); } } /** - * Set the verbosity level of the 'api' + * Set the logmask of the 'api' to 'mask' * @param set the api set * @param name the api to set (NULL set all) */ -void afb_apiset_set_verbosity(struct afb_apiset *set, const char *name, int level) +void afb_apiset_set_logmask(struct afb_apiset *set, const char *name, int mask) { - const struct api_desc *i, *e; + int i; + struct api_desc *d; if (!name) { - i = set->apis; - e = &set->apis[set->count]; + for (i = 0 ; i < set->apis.count ; i++) { + d = set->apis.apis[i];; + if (d->api.itf->set_logmask) + d->api.itf->set_logmask(d->api.closure, mask); + } } else { - i = search(set, name); - e = &i[!!i]; - } - while (i != e) { - if (i->api.itf->set_verbosity) - i->api.itf->set_verbosity(i->api.closure, level); - i++; + d = searchrec(set, name); + if (d && d->api.itf->set_logmask) + d->api.itf->set_logmask(d->api.closure, mask); } } /** - * Get the verbosity level of the 'api' + * Get the logmask level of the 'api' * @param set the api set * @param name the api to get - * @return the verbosity level or -1 in case of error + * @return the logmask level or -1 in case of error */ -int afb_apiset_get_verbosity(struct afb_apiset *set, const char *name) +int afb_apiset_get_logmask(struct afb_apiset *set, const char *name) { const struct api_desc *i; - i = name ? search(set, name) : NULL; + i = name ? searchrec(set, name) : NULL; if (!i) { errno = ENOENT; return -1; } - if (!i->api.itf->get_verbosity) - return verbosity; + if (!i->api.itf->get_logmask) + return logmask; - return i->api.itf->get_verbosity(i->api.closure); + return i->api.itf->get_logmask(i->api.closure); } /** @@ -506,36 +953,79 @@ struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name { const struct api_desc *i; - i = name ? search(set, name) : NULL; + i = name ? searchrec(set, name) : NULL; return i && i->api.itf->describe ? i->api.itf->describe(i->api.closure) : NULL; } +struct get_names { + union { + struct { + size_t count; + size_t size; + }; + struct { + const char **ptr; + char *data; + }; + }; + int type; +}; + +static void get_names_count(void *closure, struct afb_apiset *set, const char *name, int isalias) +{ + struct get_names *gc = closure; + if ((1 + isalias) & gc->type) { + gc->size += strlen(name); + gc->count++; + } +} + +static void get_names_value(void *closure, struct afb_apiset *set, const char *name, int isalias) +{ + struct get_names *gc = closure; + if ((1 + isalias) & gc->type) { + *gc->ptr++ = gc->data; + gc->data = stpcpy(gc->data, name) + 1; + } +} + +#if !defined(APISET_NO_SORT) +static int get_names_sortcb(const void *a, const void *b) +{ + return strcasecmp(*(const char **)a, *(const char **)b); +} +#endif + /** * Get the list of api names * @param set the api set + * @param rec recursive + * @param type expected type: 1 names, 3 names+aliases, 2 aliases * @return a NULL terminated array of api names. Must be freed. */ -const char **afb_apiset_get_names(struct afb_apiset *set) +const char **afb_apiset_get_names(struct afb_apiset *set, int rec, int type) { + struct get_names gc; size_t size; - char *dest; const char **names; - int i; - size = set->count * (1 + sizeof(*names)) + sizeof(*names); - for (i = 0 ; i < set->count ; i++) - size += strlen(set->apis[i].name); + gc.count = gc.size = 0; + gc.type = type >= 1 && type <= 3 ? type : 1; + afb_apiset_enum(set, rec, get_names_count, &gc); + size = gc.size + gc.count * (1 + sizeof *names) + sizeof(*names); names = malloc(size); + if (!names) errno = ENOMEM; else { - dest = (void*)&names[set->count+1]; - for (i = 0 ; i < set->count ; i++) { - names[i] = dest; - dest = stpcpy(dest, set->apis[i].name) + 1; - } - names[i] = NULL; + gc.data = (char*)&names[gc.count + 1]; + gc.ptr = names; + afb_apiset_enum(set, rec, get_names_value, &gc); +#if !defined(APISET_NO_SORT) + qsort(names, gc.ptr - names, sizeof *names, get_names_sortcb); +#endif + *gc.ptr = NULL; } return names; } @@ -543,24 +1033,97 @@ const char **afb_apiset_get_names(struct afb_apiset *set) /** * Enumerate the api names to a callback. * @param set the api set + * @param rec should the enumeration be recursive * @param callback the function to call for each name * @param closure the closure for the callback */ -void afb_apiset_enum(struct afb_apiset *set, int rec, void (*callback)(struct afb_apiset *set, const char *name, void *closure), void *closure) +void afb_apiset_enum( + struct afb_apiset *set, + int rec, + void (*callback)(void *closure, struct afb_apiset *set, const char *name, int isalias), + void *closure) { + int i; struct afb_apiset *iset; - struct api_desc *i, *e; + struct api_desc *d; + struct api_alias *a; iset = set; while (iset) { - i = iset->apis; - e = &i[iset->count]; - while (i != e) { - if (lookup(set, i->name, 1) == i) - callback(iset, i->name, closure); - i++; + for (i = 0 ; i < set->apis.count ; i++) { + d = set->apis.apis[i];; + if (searchrec(set, d->name) == d) + callback(closure, iset, d->name, 0); + } + a = iset->aliases; + while (a) { + if (searchrec(set, a->name) == a->api) + callback(closure, iset, a->name, 1); + a = a->next; } iset = rec ? iset->subset : NULL; } } +/** + * Declare that the api of 'name' requires the api of name 'required'. + * The api is searched in the apiset 'set' and if 'rec' isn't null also in its subset. + * Returns 0 if the declaration successed or -1 in case of failure + * (ENOMEM: allocation failure, ENOENT: api name not found) + */ +int afb_apiset_require(struct afb_apiset *set, const char *name, const char *required) +{ + struct api_desc *a; + struct api_depend *d; + int rc = -1; + + a = searchrec(set, name); + if (!a) + errno = ENOENT; + else { + d = malloc(strlen(required) + sizeof *d); + if (!d) + errno = ENOMEM; + else { + d->set = set; + strcpy(d->name, required); + rc = api_array_add(&a->require.apis, d); + } + } + return rc; +} + +/** + * Declare that the api of name 'apiname' requires the class of name 'classname'. + * Returns 0 if the declaration successed or -1 in case of failure + * (ENOMEM: allocation failure, ENOENT: api name not found) + */ +int afb_apiset_require_class(struct afb_apiset *set, const char *apiname, const char *classname) +{ + struct api_desc *a = searchrec(set, apiname); + struct api_class *c = class_search(classname, 1); + return a && c ? api_array_add(&a->require.classes, c) : (errno = ENOENT, -1); +} + +/** + * Declare that the api of name 'apiname' provides the class of name 'classname' + * Returns 0 if the declaration successed or -1 in case of failure + * (ENOMEM: allocation failure, ENOENT: api name not found) + */ +int afb_apiset_provide_class(struct afb_apiset *set, const char *apiname, const char *classname) +{ + struct api_desc *a = searchrec(set, apiname); + struct api_class *c = class_search(classname, 1); + return a && c ? api_array_add(&c->providers, a) : (errno = ENOENT, -1); +} + +/** + * Start any API that provides the class of name 'classname' + * The attribute 'share_session' is sent to the start function. + */ +int afb_apiset_class_start(const char *classname, int share_session) +{ + struct api_class *cla = class_search(classname, 0); + return cla ? start_class(cla, share_session) : (errno = ENOENT, -1); +} + diff --git a/src/afb-apiset.h b/src/afb-apiset.h index 55068dd3..fc8bc266 100644 --- a/src/afb-apiset.h +++ b/src/afb-apiset.h @@ -17,28 +17,57 @@ #pragma once -struct afb_api; +struct afb_api_item; struct afb_apiset; struct json_object; +extern struct afb_apiset *afb_apiset_create(const char *name, int timeout); +extern struct afb_apiset *afb_apiset_create_subset_last(struct afb_apiset *set, const char *name, int timeout); +extern struct afb_apiset *afb_apiset_create_subset_first(struct afb_apiset *set, const char *name, int timeout); extern struct afb_apiset *afb_apiset_addref(struct afb_apiset *set); extern void afb_apiset_unref(struct afb_apiset *set); -extern struct afb_apiset *afb_apiset_create(const char *name, int timeout); + extern const char *afb_apiset_name(struct afb_apiset *set); + extern int afb_apiset_timeout_get(struct afb_apiset *set); extern void afb_apiset_timeout_set(struct afb_apiset *set, int to); + +extern void afb_apiset_onlack_set( + struct afb_apiset *set, + int (*callback)(void *closure, struct afb_apiset *set, const char *name), + void *closure, + void (*cleanup)(void*closure)); + extern void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset); extern struct afb_apiset *afb_apiset_subset_get(struct afb_apiset *set); -extern int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api); + +extern int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api_item api); extern int afb_apiset_del(struct afb_apiset *set, const char *name); -extern const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec); -extern const struct afb_api *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec); + +extern int afb_apiset_add_alias(struct afb_apiset *set, const char *name, const char *alias); +extern int afb_apiset_is_alias(struct afb_apiset *set, const char *name); +extern const char *afb_apiset_unalias(struct afb_apiset *set, const char *name); + +extern const struct afb_api_item *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec); +extern const struct afb_api_item *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec); + extern int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share_session, int onneed); extern int afb_apiset_start_all_services(struct afb_apiset *set, int share_session); + extern void afb_apiset_update_hooks(struct afb_apiset *set, const char *name); -extern void afb_apiset_set_verbosity(struct afb_apiset *set, const char *name, int level); -extern int afb_apiset_get_verbosity(struct afb_apiset *set, const char *name); +extern void afb_apiset_set_logmask(struct afb_apiset *set, const char *name, int mask); +extern int afb_apiset_get_logmask(struct afb_apiset *set, const char *name); + extern struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name); -extern const char **afb_apiset_get_names(struct afb_apiset *set); -extern void afb_apiset_enum(struct afb_apiset *set, int rec, void (*callback)(struct afb_apiset *set, const char *name, void *closure), void *closure); +extern const char **afb_apiset_get_names(struct afb_apiset *set, int rec, int type); +extern void afb_apiset_enum( + struct afb_apiset *set, + int rec, + void (*callback)(void *closure, struct afb_apiset *set, const char *name, int isalias), + void *closure); + +extern int afb_apiset_require(struct afb_apiset *set, const char *name, const char *required); +extern int afb_apiset_require_class(struct afb_apiset *set, const char *apiname, const char *classname); +extern int afb_apiset_provide_class(struct afb_apiset *set, const char *apiname, const char *classname); +extern int afb_apiset_class_start(const char *classname, int share_session); diff --git a/src/afb-auth.c b/src/afb-auth.c index 47a98d5a..4a3c445f 100644 --- a/src/afb-auth.c +++ b/src/afb-auth.c @@ -22,7 +22,7 @@ #include <json-c/json.h> #include <afb/afb-auth.h> -#include <afb/afb-session-v2.h> +#include <afb/afb-session-x2.h> #include "afb-auth.h" #include "afb-context.h" @@ -60,56 +60,10 @@ int afb_auth_check(struct afb_xreq *xreq, const struct afb_auth *auth) } } -/*********************************************************************************/ -#ifdef BACKEND_PERMISSION_IS_CYNARA - -#include <pthread.h> -#include <cynara-client.h> - -static cynara *handle; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -int afb_auth_has_permission(struct afb_xreq *xreq, const char *permission) -{ - int rc; - - if (!xreq->cred) { - /* case of permission for self */ - return 1; - } - if (!permission) { - ERROR("Got a null permission!"); - return 0; - } - - /* cynara isn't reentrant */ - pthread_mutex_lock(&mutex); - - /* lazy initialisation */ - if (!handle) { - rc = cynara_initialize(&handle, NULL); - if (rc != CYNARA_API_SUCCESS) { - handle = NULL; - ERROR("cynara initialisation failed with code %d", rc); - return 0; - } - } - - /* query cynara permission */ - rc = cynara_check(handle, xreq->cred->label, afb_context_uuid(&xreq->context), xreq->cred->user, permission); - - pthread_mutex_unlock(&mutex); - return rc == CYNARA_API_ACCESS_ALLOWED; -} - -/*********************************************************************************/ -#else int afb_auth_has_permission(struct afb_xreq *xreq, const char *permission) { - WARNING("Granting permission %s by default of backend", permission ?: "(null)"); - return !!permission; + return afb_cred_has_permission(xreq->cred, permission, afb_context_uuid(&xreq->context)); } -#endif /*********************************************************************************/ @@ -180,17 +134,17 @@ struct json_object *afb_auth_json_v2(const struct afb_auth *auth, int session) { struct json_object *result = NULL; - if (session & AFB_SESSION_CLOSE_V2) + if (session & AFB_SESSION_CLOSE_X2) result = addperm_key_valstr(result, "session", "close"); - if (session & AFB_SESSION_CHECK_V2) + if (session & AFB_SESSION_CHECK_X2) result = addperm_key_valstr(result, "session", "check"); - if (session & AFB_SESSION_REFRESH_V2) + if (session & AFB_SESSION_REFRESH_X2) result = addperm_key_valstr(result, "token", "refresh"); - if (session & AFB_SESSION_LOA_MASK_V2) - result = addperm_key_valint(result, "LOA", session & AFB_SESSION_LOA_MASK_V2); + if (session & AFB_SESSION_LOA_MASK_X2) + result = addperm_key_valint(result, "LOA", session & AFB_SESSION_LOA_MASK_X2); if (auth) result = addauth(result, auth); diff --git a/src/afb-autoset.c b/src/afb-autoset.c new file mode 100644 index 00000000..102830cb --- /dev/null +++ b/src/afb-autoset.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "verbose.h" +#include "afb-api-ws.h" +#include "afb-api-so.h" +#include "afb-apiset.h" +#include "afb-autoset.h" + +static void cleanup(void *closure) +{ + struct afb_apiset *call_set = closure; + afb_apiset_unref(call_set); +} + +static int onlack(void *closure, struct afb_apiset *set, const char *name, int (*create)(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)) +{ + struct afb_apiset *call_set = closure; + char *path; + const char *base; + size_t lbase, lname; + + base = afb_apiset_name(set); + lbase = strlen(base); + lname = strlen(name); + + path = alloca(2 + lbase + lname); + memcpy(path, base, lbase); + path[lbase] = '/'; + memcpy(&path[lbase + 1], name, lname + 1); + + return create(path, set, call_set); +} + +static int add(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set, int (*callback)(void *, struct afb_apiset *, const char*)) +{ + struct afb_apiset *ownset; + + /* create a sub-apiset */ + ownset = afb_apiset_create_subset_last(declare_set, path, 3600); + if (!ownset) { + ERROR("Can't create apiset autoset-ws %s", path); + return -1; + } + + /* set the onlack behaviour on this set */ + afb_apiset_onlack_set(ownset, callback, afb_apiset_addref(call_set), cleanup); + return 0; +} + +static int create_ws(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) +{ + return afb_api_ws_add_client(path, declare_set, call_set, 0) >= 0; +} + +static int onlack_ws(void *closure, struct afb_apiset *set, const char *name) +{ + return onlack(closure, set, name, create_ws); +} + +int afb_autoset_add_ws(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) +{ + return add(path, declare_set, call_set, onlack_ws); +} + +static int create_so(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) +{ + return afb_api_so_add_binding(path, declare_set, call_set) >= 0; +} + +static int onlack_so(void *closure, struct afb_apiset *set, const char *name) +{ + return onlack(closure, set, name, create_so); +} + +int afb_autoset_add_so(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) +{ + return add(path, declare_set, call_set, onlack_so); +} diff --git a/src/afb-autoset.h b/src/afb-autoset.h new file mode 100644 index 00000000..50fdec1a --- /dev/null +++ b/src/afb-autoset.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +struct afb_apiset; + +extern int afb_autoset_add_ws(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); +extern int afb_autoset_add_so(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); diff --git a/src/afb-calls.c b/src/afb-calls.c new file mode 100644 index 00000000..73b89bf0 --- /dev/null +++ b/src/afb-calls.c @@ -0,0 +1,818 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <json-c/json.h> + +#define AFB_BINDING_VERSION 0 +#include <afb/afb-binding.h> + +#include "afb-calls.h" +#include "afb-cred.h" +#include "afb-evt.h" +#include "afb-export.h" +#include "afb-hook.h" +#include "afb-msg-json.h" +#include "afb-session.h" +#include "afb-xreq.h" + +#include "jobs.h" +#include "verbose.h" + +#define CALLFLAGS (afb_req_x2_subcall_api_session|afb_req_x2_subcall_catch_events) +#define LEGACY_SUBCALLFLAGS (afb_req_x2_subcall_pass_events|afb_req_x2_subcall_on_behalf) + + +/************************************************************************/ + +struct modes +{ + unsigned hooked: 1; + unsigned sync: 1; + unsigned legacy: 1; +}; + +#define mode_sync ((struct modes){ .hooked=0, .sync=1, .legacy=0 }) +#define mode_async ((struct modes){ .hooked=0, .sync=0, .legacy=0 }) +#define mode_legacy_sync ((struct modes){ .hooked=0, .sync=1, .legacy=1 }) +#define mode_legacy_async ((struct modes){ .hooked=0, .sync=0, .legacy=1 }) +#define mode_hooked_sync ((struct modes){ .hooked=1, .sync=1, .legacy=0 }) +#define mode_hooked_async ((struct modes){ .hooked=1, .sync=0, .legacy=0 }) +#define mode_hooked_legacy_sync ((struct modes){ .hooked=1, .sync=1, .legacy=1 }) +#define mode_hooked_legacy_async ((struct modes){ .hooked=1, .sync=0, .legacy=1 }) + +union callback { + void *any; + union { + void (*legacy_v1)(void*, int, struct json_object*); + void (*legacy_v2)(void*, int, struct json_object*, struct afb_req_x1); + void (*legacy_v3)(void*, int, struct json_object*, struct afb_req_x2*); + void (*x3)(void*, struct json_object*, const char*, const char *, struct afb_req_x2*); + } subcall; + union { + void (*legacy_v12)(void*, int, struct json_object*); + void (*legacy_v3)(void*, int, struct json_object*, struct afb_api_x3*); + void (*x3)(void*, struct json_object*, const char*, const char*, struct afb_api_x3*); + } call; +}; + +struct callreq +{ + struct afb_xreq xreq; + + struct afb_export *export; + + struct modes mode; + + int flags; + + union { + struct { + struct jobloop *jobloop; + int returned; + int status; + struct json_object **object; + char **error; + char **info; + }; + struct { + union callback callback; + void *closure; + union { + void (*final)(void*, struct json_object*, const char*, const char*, union callback, struct afb_export*,struct afb_xreq*); + void (*legacy_final)(void*, int, struct json_object*, union callback, struct afb_export*,struct afb_xreq*); + }; + }; + }; +}; + +/******************************************************************************/ + +static int store_reply( + struct json_object *iobject, const char *ierror, const char *iinfo, + struct json_object **sobject, char **serror, char **sinfo) +{ + if (serror) { + if (!ierror) + *serror = NULL; + else if (!(*serror = strdup(ierror))) { + ERROR("can't report error %s", ierror); + json_object_put(iobject); + iobject = NULL; + iinfo = NULL; + } + } + + if (sobject) + *sobject = iobject; + else + json_object_put(iobject); + + if (sinfo) { + if (!iinfo) + *sinfo = NULL; + else if (!(*sinfo = strdup(iinfo))) + ERROR("can't report info %s", iinfo); + } + + return -!!ierror; +} + +/******************************************************************************/ + +static void sync_leave(struct callreq *callreq) +{ + struct jobloop *jobloop = __atomic_exchange_n(&callreq->jobloop, NULL, __ATOMIC_RELAXED); + if (jobloop) + jobs_leave(jobloop); +} + +static void sync_enter(int signum, void *closure, struct jobloop *jobloop) +{ + struct callreq *callreq = closure; + if (!signum) { + callreq->jobloop = jobloop; + afb_export_process_xreq(callreq->export, &callreq->xreq); + } else { + afb_xreq_reply(&callreq->xreq, NULL, "internal-error", NULL); + } +} + +/******************************************************************************/ + +static void callreq_destroy_cb(struct afb_xreq *xreq) +{ + struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq); + + afb_context_disconnect(&callreq->xreq.context); + json_object_put(callreq->xreq.json); + afb_cred_unref(callreq->xreq.cred); + free(callreq); +} + +static void callreq_reply_cb(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) +{ + struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq); + + /* centralized hooking */ + if (callreq->mode.hooked) { + if (callreq->mode.sync) { + if (callreq->xreq.caller) + afb_hook_xreq_subcallsync_result(callreq->xreq.caller, -!!error, object, error, info); + else + afb_hook_api_callsync_result(callreq->export, -!!error, object, error, info); + } else { + if (callreq->xreq.caller) + afb_hook_xreq_subcall_result(callreq->xreq.caller, object, error, info); + else + afb_hook_api_call_result(callreq->export, object, error, info); + } + } + + /* true report of the result */ + if (callreq->mode.sync) { + callreq->returned = 1; + if (callreq->mode.legacy) { + callreq->status = -!!error; + if (callreq->object) + *callreq->object = afb_msg_json_reply(object, error, info, NULL); + else + json_object_put(object); + } else { + callreq->status = store_reply(object, error, info, + callreq->object, callreq->error, callreq->info); + } + sync_leave(callreq); + } else { + if (callreq->mode.legacy) { + object = afb_msg_json_reply(object, error, info, NULL); + callreq->legacy_final(callreq->closure, -!!error, object, callreq->callback, callreq->export, callreq->xreq.caller); + } else { + callreq->final(callreq->closure, object, error, info, callreq->callback, callreq->export, callreq->xreq.caller); + } + json_object_put(object); + } +} + +static int callreq_subscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event) +{ + int rc = 0, rc2; + struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq); + + if (callreq->flags & afb_req_x2_subcall_pass_events) + rc = afb_xreq_subscribe(callreq->xreq.caller, event); + if (callreq->flags & afb_req_x2_subcall_catch_events) { + rc2 = afb_export_subscribe(callreq->export, event); + if (rc2 < 0) + rc = rc2; + } + return rc; +} + +static int callreq_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event) +{ + int rc = 0, rc2; + struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq); + + if (callreq->flags & afb_req_x2_subcall_pass_events) + rc = afb_xreq_unsubscribe(callreq->xreq.caller, event); + if (callreq->flags & afb_req_x2_subcall_catch_events) { + rc2 = afb_export_unsubscribe(callreq->export, event); + if (rc2 < 0) + rc = rc2; + } + return rc; +} + +/******************************************************************************/ + +const struct afb_xreq_query_itf afb_calls_xreq_itf = { + .unref = callreq_destroy_cb, + .reply = callreq_reply_cb, + .subscribe = callreq_subscribe_cb, + .unsubscribe = callreq_unsubscribe_cb +}; + +/******************************************************************************/ + +static struct callreq *callreq_create( + struct afb_export *export, + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct modes mode) +{ + struct callreq *callreq; + size_t lenapi, lenverb; + char *api2, *verb2; + + lenapi = 1 + strlen(api); + lenverb = 1 + strlen(verb); + callreq = malloc(lenapi + lenverb + sizeof *callreq); + if (!callreq) { + ERROR("out of memory"); + json_object_put(args); + errno = ENOMEM; + } else { + afb_xreq_init(&callreq->xreq, &afb_calls_xreq_itf); + callreq->xreq.context.validated = 1; + api2 = (char*)&callreq[1]; + callreq->xreq.request.called_api = memcpy(api2, api, lenapi);; + verb2 = &api2[lenapi]; + callreq->xreq.request.called_verb = memcpy(verb2, verb, lenverb); + callreq->xreq.json = args; + callreq->mode = mode; + if (caller) { + export = afb_export_from_api_x3(caller->request.api); + if (flags & afb_req_x2_subcall_on_behalf) + callreq->xreq.cred = afb_cred_addref(caller->cred); + callreq->xreq.caller = caller; + afb_xreq_unhooked_addref(caller); + } + if (caller && (flags & afb_req_x2_subcall_api_session)) + afb_context_subinit(&callreq->xreq.context, &caller->context); + else + afb_export_context_init(export, &callreq->xreq.context); + callreq->export = export; + callreq->flags = flags; + } + return callreq; +} + +/******************************************************************************/ + +static int do_sync( + struct afb_export *export, + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info, + struct modes mode) +{ + struct callreq *callreq; + int rc; + + /* allocates the request */ + callreq = callreq_create(export, caller, api, verb, args, flags, mode); + if (!callreq) + goto interr; + + /* initializes the request */ + callreq->jobloop = NULL; + callreq->returned = 0; + callreq->status = 0; + callreq->object = object; + callreq->error = error; + callreq->info = info; + + afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */ + + rc = jobs_enter(NULL, 0, sync_enter, callreq); + if (rc >= 0 && callreq->returned) { + rc = callreq->status; + afb_xreq_unhooked_unref(&callreq->xreq); + return rc; + } + + afb_xreq_unhooked_unref(&callreq->xreq); +interr: + return store_reply(NULL, "internal-error", NULL, object, info, error); +} + +/******************************************************************************/ + +static void do_async( + struct afb_export *export, + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void *callback, + void *closure, + void (*final)(void*, struct json_object*, const char*, const char*, union callback, struct afb_export*,struct afb_xreq*), + struct modes mode) +{ + struct callreq *callreq; + + callreq = callreq_create(export, caller, api, verb, args, flags, mode); + + if (!callreq) + final(closure, NULL, "internal-error", NULL, (union callback){ .any = callback }, export, caller); + else { + callreq->callback.any = callback; + callreq->closure = closure; + callreq->final = final; + + afb_export_process_xreq(callreq->export, &callreq->xreq); + } +} + +/******************************************************************************/ + +static void final_call( + void *closure, + struct json_object *object, + const char *error, + const char *info, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.call.x3) + callback.call.x3(closure, object, error, info, afb_export_to_api_x3(export)); +} + +static void final_subcall( + void *closure, + struct json_object *object, + const char *error, + const char *info, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.subcall.x3) + callback.subcall.x3(closure, object, error, info, xreq_to_req_x2(caller)); +} + +/******************************************************************************/ + +void afb_calls_call( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure) +{ + do_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_call, mode_async); +} + +void afb_calls_hooked_call( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure) +{ + afb_hook_api_call(export, api, verb, args); + do_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_call, mode_hooked_async); +} + +int afb_calls_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info) +{ + return do_sync(export, NULL, api, verb, args, CALLFLAGS, object, error, info, mode_sync); +} + +int afb_calls_hooked_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info) +{ + afb_hook_api_callsync(export, api, verb, args); + return do_sync(export, NULL, api, verb, args, CALLFLAGS, object, error, info, mode_hooked_sync); +} + +void afb_calls_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure) +{ + do_async(NULL, xreq, api, verb, args, flags, callback, closure, final_subcall, mode_async); +} + +void afb_calls_hooked_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure) +{ + afb_hook_xreq_subcall(xreq, api, verb, args, flags); + do_async(NULL, xreq, api, verb, args, flags, callback, closure, final_subcall, mode_hooked_async); +} + +int afb_calls_subcall_sync( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info) +{ + return do_sync(NULL, xreq, api, verb, args, flags, object, error, info, mode_sync); +} + +int afb_calls_hooked_subcall_sync( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info) +{ + afb_hook_xreq_subcallsync(xreq, api, verb, args, flags); + return do_sync(NULL, xreq, api, verb, args, flags, object, error, info, mode_hooked_sync); +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +static int do_legacy_sync( + struct afb_export *export, + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + struct modes mode) +{ + struct callreq *callreq; + int rc; + + /* allocates the request */ + callreq = callreq_create(export, caller, api, verb, args, flags, mode); + if (!callreq) + goto interr; + + /* initializes the request */ + callreq->jobloop = NULL; + callreq->returned = 0; + callreq->status = 0; + callreq->object = object; + + afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */ + + rc = jobs_enter(NULL, 0, sync_enter, callreq); + if (rc >= 0 && callreq->returned) { + rc = callreq->status; + afb_xreq_unhooked_unref(&callreq->xreq); + return rc; + } + + afb_xreq_unhooked_unref(&callreq->xreq); +interr: + if (object) + *object = afb_msg_json_internal_error(); + return -1; +} + +/******************************************************************************/ + +static void do_legacy_async( + struct afb_export *export, + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void *callback, + void *closure, + void (*final)(void*, int, struct json_object*, union callback, struct afb_export*,struct afb_xreq*), + struct modes mode) +{ + struct callreq *callreq; + struct json_object *ie; + + callreq = callreq_create(export, caller, api, verb, args, flags, mode); + + if (!callreq) { + ie = afb_msg_json_internal_error(); + final(closure, -1, ie, (union callback){ .any = callback }, export, caller); + json_object_put(ie); + } else { + callreq->callback.any = callback; + callreq->closure = closure; + callreq->legacy_final = final; + + afb_export_process_xreq(callreq->export, &callreq->xreq); + } +} + +/******************************************************************************/ + +static void final_legacy_call_v12( + void *closure, + int status, + struct json_object *object, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.call.legacy_v12) + callback.call.legacy_v12(closure, status, object); +} + +static void final_legacy_call_v3( + void *closure, + int status, + struct json_object *object, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.call.legacy_v3) + callback.call.legacy_v3(closure, status, object, afb_export_to_api_x3(export)); +} + +/******************************************************************************/ + +void afb_calls_legacy_call_v12( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure) +{ + do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v12, mode_legacy_async); +} + +void afb_calls_legacy_hooked_call_v12( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure) +{ + afb_hook_api_call(export, api, verb, args); + do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v12, mode_hooked_legacy_async); +} + +void afb_calls_legacy_call_v3( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *), + void *closure) +{ + do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v3, mode_legacy_async); +} + +void afb_calls_legacy_hooked_call_v3( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *), + void *closure) +{ + afb_hook_api_call(export, api, verb, args); + do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v3, mode_hooked_legacy_async); +} + +int afb_calls_legacy_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + return do_legacy_sync(export, NULL, api, verb, args, CALLFLAGS, result, mode_legacy_sync); +} + +int afb_calls_legacy_hooked_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + int rc; + struct json_object *object; + + afb_hook_api_callsync(export, api, verb, args); + rc = do_legacy_sync(export, NULL, api, verb, args, CALLFLAGS, &object, mode_hooked_legacy_sync); + if (result) + *result = object; + else + json_object_put(object); + return rc; +} + +/******************************************************************************/ + +static void final_legacy_subcall_v1( + void *closure, + int status, + struct json_object *object, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.subcall.legacy_v1) + callback.subcall.legacy_v1(closure, status, object); +} + +static void final_legacy_subcall_v2( + void *closure, + int status, + struct json_object *object, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.subcall.legacy_v2) + callback.subcall.legacy_v2(closure, status, object, xreq_to_req_x1(caller)); +} + +static void final_legacy_subcall_v3( + void *closure, + int status, + struct json_object *object, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.subcall.legacy_v3) + callback.subcall.legacy_v3(closure, status, object, xreq_to_req_x2(caller)); +} + +/******************************************************************************/ + +void afb_calls_legacy_subcall_v1( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure) +{ + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v1, mode_legacy_async); +} + +void afb_calls_legacy_hooked_subcall_v1( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure) +{ + afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS); + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v1, mode_hooked_legacy_async); +} + +void afb_calls_legacy_subcall_v2( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x1), + void *closure) +{ + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v2, mode_legacy_async); +} + +void afb_calls_legacy_hooked_subcall_v2( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x1), + void *closure) +{ + afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS); + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v2, mode_hooked_legacy_async); +} + +void afb_calls_legacy_subcall_v3( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), + void *closure) +{ + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v3, mode_legacy_async); +} + +void afb_calls_legacy_hooked_subcall_v3( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), + void *closure) +{ + afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS); + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v3, mode_hooked_legacy_async); +} + +int afb_calls_legacy_subcall_sync( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + return do_legacy_sync(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, result, mode_legacy_sync); +} + +int afb_calls_legacy_hooked_subcall_sync( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + afb_hook_xreq_subcallsync(caller, api, verb, args, LEGACY_SUBCALLFLAGS); + return do_legacy_sync(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, result, mode_hooked_legacy_sync); +} diff --git a/src/afb-calls.h b/src/afb-calls.h new file mode 100644 index 00000000..15b71bf2 --- /dev/null +++ b/src/afb-calls.h @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +struct json_object; + +struct afb_export; +struct afb_xreq; + +struct afb_api_x3; +struct afb_req_x1; +struct afb_req_x2; + +/******************************************************************************/ + +extern +void afb_calls_call( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure); + +extern +void afb_calls_hooked_call( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure); + +extern +int afb_calls_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info); + +extern +int afb_calls_hooked_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info); + +extern +void afb_calls_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure); + +extern +void afb_calls_hooked_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure); + +extern +int afb_calls_subcall_sync( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info); + +extern +int afb_calls_hooked_subcall_sync( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info); + +/******************************************************************************/ + +extern +void afb_calls_legacy_call_v12( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure); + +extern +void afb_calls_legacy_hooked_call_v12( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure); + +extern +void afb_calls_legacy_call_v3( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *), + void *closure); + +extern +void afb_calls_legacy_hooked_call_v3( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *), + void *closure); + +extern +int afb_calls_legacy_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); + +extern +int afb_calls_legacy_hooked_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); + +/******************************************************************************/ + +extern +void afb_calls_legacy_subcall_v1( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure); + +extern +void afb_calls_legacy_hooked_subcall_v1( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure); + +extern +void afb_calls_legacy_subcall_v2( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x1), + void *closure); + +extern +void afb_calls_legacy_hooked_subcall_v2( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x1), + void *closure); + +extern +void afb_calls_legacy_subcall_v3( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), + void *closure); + +extern +void afb_calls_legacy_hooked_subcall_v3( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), + void *closure); + +extern +int afb_calls_legacy_subcall_sync( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); + +extern +int afb_calls_legacy_hooked_subcall_sync( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); diff --git a/src/afb-config.c b/src/afb-config.c index 2a6f931f..f3f48fd6 100644 --- a/src/afb-config.c +++ b/src/afb-config.c @@ -23,6 +23,7 @@ #include <getopt.h> #include <limits.h> #include <unistd.h> +#include <ctype.h> #include <json-c/json.h> @@ -30,8 +31,6 @@ #include "afb-config.h" #include "afb-hook.h" -#include <afb/afb-binding-v1.h> - #if !defined(BINDING_INSTALL_DIR) #error "you should define BINDING_INSTALL_DIR" #endif @@ -51,17 +50,25 @@ # define HAS_DBUS 0 #endif -// default -#define DEFLT_CNTX_TIMEOUT 32000000 // default Client Connection - // Timeout: few more than one year -#define DEFLT_API_TIMEOUT 20 // default Plugin API Timeout [0=NoLimit - // for Debug Only] -#define DEFLT_CACHE_TIMEOUT 100000 // default Static File Chache - // [Client Side Cache - // 100000~=1day] -#define CTX_NBCLIENTS 10 // allow a default of 10 authenticated - // clients +/** + * The default timeout of sessions in seconds + */ +#define DEFAULT_SESSION_TIMEOUT 32000000 + +/** + * The default timeout of api calls in seconds + */ +#define DEFAULT_API_TIMEOUT 20 + +/** + * The default timeout of cache in seconds + */ +#define DEFAULT_CACHE_TIMEOUT 100000 +/** + * The default maximum count of sessions + */ +#define DEFAULT_MAX_SESSION_COUNT 200 // Define command line option #define SET_BACKGROUND 2 @@ -81,14 +88,15 @@ #define SET_WEAK_LDPATH 16 #define NO_LDPATH 17 +#if defined(KEEP_LEGACY_MODE) #define SET_MODE 18 +#endif #if HAS_DBUS # define DBUS_CLIENT 20 # define DBUS_SERVICE 21 #endif -#define SO_BINDING 22 #define SET_SESSIONMAX 23 @@ -99,11 +107,18 @@ #define SET_NO_HTTPD 28 +#define AUTO_WS 'a' +#define AUTO_LINK 'A' +#define SO_BINDING 'b' #define ADD_CALL 'c' +#if !defined(REMOVE_LEGACY_TRACE) #define SET_TRACEDITF 'D' +#endif #define SET_TRACEEVT 'E' #define SET_EXEC 'e' #define DISPLAY_HELP 'h' +#define SET_LOG 'l' +#define SET_TRACEAPI 'I' #if HAS_MONITORING # define SET_MONITORING 'M' #endif @@ -111,7 +126,9 @@ #define SET_TCP_PORT 'p' #define SET_QUIET 'q' #define SET_RNDTOKEN 'r' +#if !defined(REMOVE_LEGACY_TRACE) #define SET_TRACESVC 'S' +#endif #define SET_TRACESES 's' #define SET_TRACEREQ 'T' #define SET_AUTH_TOKEN 't' @@ -121,7 +138,15 @@ #define SET_WORK_DIR 'w' const char shortopts[] = - "c:D:E:ehn:p:qrS:s:T:t:u:Vvw:" + "a:A:b:c:" +#if !defined(REMOVE_LEGACY_TRACE) + "D:" +#endif + "E:ehl:n:p:qr" +#if !defined(REMOVE_LEGACY_TRACE) + "S:" +#endif + "s:T:t:u:Vvw:" #if HAS_MONITORING "M" #endif @@ -140,6 +165,7 @@ static AFB_options cliOptions[] = { /* *INDENT-OFF* */ {SET_VERBOSE, 0, "verbose", "Verbose Mode, repeat to increase verbosity"}, {SET_QUIET, 0, "quiet", "Quiet Mode, repeat to decrease verbosity"}, + {SET_LOG, 1, "log", "tune log level"}, {SET_FORGROUND, 0, "foreground", "Get all in foreground mode"}, {SET_BACKGROUND, 0, "daemon", "Get all in background mode"}, @@ -172,7 +198,9 @@ static AFB_options cliOptions[] = { {DISPLAY_VERSION, 0, "version", "Display version and copyright"}, {DISPLAY_HELP, 0, "help", "Display this help"}, +#if defined(KEEP_LEGACY_MODE) {SET_MODE, 1, "mode", "Set the mode: either local, remote or global"}, +#endif #if HAS_DBUS {DBUS_CLIENT, 1, "dbus-client", "Bind to an afb service through dbus"}, @@ -181,13 +209,19 @@ static AFB_options cliOptions[] = { {WS_CLIENT, 1, "ws-client", "Bind to an afb service through websocket"}, {WS_SERVICE, 1, "ws-server", "Provides an afb service through websockets"}, + {AUTO_WS, 1, "auto-ws", "Automatic bind on need to remote service through websocket"}, + {AUTO_LINK, 1, "auto-link", "Automatic load on need to binding shared objects"}, + {SET_SESSIONMAX, 1, "session-max", "Max count of session simultaneously [default 10]"}, {SET_TRACEREQ, 1, "tracereq", "Log the requests: no, common, extra, all"}, - {SET_TRACEDITF, 1, "traceditf", "Log the requests: no, common, extra, all"}, - {SET_TRACESVC, 1, "tracesvc", "Log the requests: no, all"}, - {SET_TRACEEVT, 1, "traceevt", "Log the requests: no, common, extra, all"}, +#if !defined(REMOVE_LEGACY_TRACE) + {SET_TRACEDITF, 1, "traceditf", "Log the daemons: no, common, all"}, + {SET_TRACESVC, 1, "tracesvc", "Log the services: no, all"}, +#endif + {SET_TRACEEVT, 1, "traceevt", "Log the events: no, common, extra, all"}, {SET_TRACESES, 1, "traceses", "Log the sessions: no, all"}, + {SET_TRACEAPI, 1, "traceapi", "Log the apis: no, common, api, event, all"}, {ADD_CALL, 1, "call", "call at start format of val: API/VERB:json-args"}, @@ -216,19 +250,20 @@ static struct enumdesc tracereq_desc[] = { { NULL, 0 } }; +#if !defined(REMOVE_LEGACY_TRACE) static struct enumdesc traceditf_desc[] = { { "no", 0 }, - { "common", afb_hook_flags_ditf_common }, - { "extra", afb_hook_flags_ditf_extra }, - { "all", afb_hook_flags_ditf_all }, + { "common", afb_hook_flags_api_ditf_common }, + { "all", afb_hook_flags_api_ditf_all }, { NULL, 0 } }; static struct enumdesc tracesvc_desc[] = { { "no", 0 }, - { "all", afb_hook_flags_svc_all }, + { "all", afb_hook_flags_api_svc_all }, { NULL, 0 } }; +#endif static struct enumdesc traceevt_desc[] = { { "no", 0 }, @@ -245,12 +280,25 @@ static struct enumdesc traceses_desc[] = { { NULL, 0 } }; +static struct enumdesc traceapi_desc[] = { + { "no", 0 }, + { "common", afb_hook_flags_api_common }, + { "api", afb_hook_flags_api_api|afb_hook_flag_api_start }, + { "event", afb_hook_flags_api_event|afb_hook_flag_api_start }, + { "all", afb_hook_flags_api_all }, + { NULL, 0 } +}; + +#if defined(KEEP_LEGACY_MODE) +#include <afb/afb-binding-v1.h> + static struct enumdesc mode_desc[] = { { "local", AFB_MODE_LOCAL }, { "remote", AFB_MODE_REMOTE }, { "global", AFB_MODE_GLOBAL }, { NULL, 0 } }; +#endif /*---------------------------------------------------------- | printversion @@ -453,6 +501,53 @@ static char **make_exec(char **argv) } /*--------------------------------------------------------- + | set the log levels + +--------------------------------------------------------- */ + +static void set_log(char *args) +{ + char o = 0, s, *p, *i = args; + int lvl; + + for(;;) switch (*i) { + case 0: + return; + case '+': + case '-': + o = *i; + /*@fallthrough@*/ + case ' ': + case ',': + i++; + break; + default: + p = i; + while (isalpha(*p)) p++; + s = *p; + *p = 0; + lvl = verbose_level_of_name(i); + if (lvl < 0) { + i = strdupa(p); + *p = s; + ERROR("Bad log name '%s' in %s", i, args); + exit(1); + } + *p = s; + i = p; + if (o == '-') + verbose_sub(lvl); + else { + if (!o) { + verbose_clear(); + o = '+'; + } + verbose_add(lvl); + } + break; + } +} + +/*--------------------------------------------------------- | Parse option and launch action +--------------------------------------------------------- */ @@ -479,23 +574,27 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) while ((optc = getopt_long(argc, argv, shortopts, gnuOptions, NULL)) != EOF) { switch (optc) { case SET_VERBOSE: - verbosity++; + verbose_inc(); break; case SET_QUIET: - verbosity--; + verbose_dec(); + break; + + case SET_LOG: + set_log(argvalstr(optc)); break; case SET_TCP_PORT: - config->httpdPort = argvalintdec(optc, 1024, 32767); + config->http_port = argvalintdec(optc, 1024, 32767); break; case SET_APITIMEOUT: - config->apiTimeout = argvalintdec(optc, 0, INT_MAX); + config->api_timeout = argvalintdec(optc, 0, INT_MAX); break; case SET_CNTXTIMEOUT: - config->cntxTimeout = argvalintdec(optc, 0, INT_MAX); + config->session_timeout = argvalintdec(optc, 0, INT_MAX); break; case SET_ROOT_DIR: @@ -557,11 +656,11 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) break; case SET_CACHE_TIMEOUT: - config->cacheTimeout = argvalintdec(optc, 0, INT_MAX); + config->cache_timeout = argvalintdec(optc, 0, INT_MAX); break; case SET_SESSIONMAX: - config->nbSessionMax = argvalintdec(optc, 1, INT_MAX); + config->max_session_count = argvalintdec(optc, 1, INT_MAX); break; case SET_FORGROUND: @@ -578,9 +677,11 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) config->name = argvalstr(optc); break; +#if defined(KEEP_LEGACY_MODE) case SET_MODE: config->mode = argvalenum(optc, mode_desc); break; +#endif #if HAS_DBUS case DBUS_CLIENT: @@ -604,10 +705,19 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) list_add(&config->so_bindings, argvalstr(optc)); break; + case AUTO_WS: + list_add(&config->auto_ws, argvalstr(optc)); + break; + + case AUTO_LINK: + list_add(&config->auto_link, argvalstr(optc)); + break; + case SET_TRACEREQ: config->tracereq = argvalenum(optc, tracereq_desc); break; +#if !defined(REMOVE_LEGACY_TRACE) case SET_TRACEDITF: config->traceditf = argvalenum(optc, traceditf_desc); break; @@ -615,6 +725,7 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) case SET_TRACESVC: config->tracesvc = argvalenum(optc, tracesvc_desc); break; +#endif case SET_TRACEEVT: config->traceevt = argvalenum(optc, traceevt_desc); @@ -624,9 +735,13 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) config->traceses = argvalenum(optc, traceses_desc); break; + case SET_TRACEAPI: + config->traceapi = argvalenum(optc, traceapi_desc); + break; + case SET_NO_HTTPD: noarg(optc); - config->noHttpd = 1; + config->no_httpd = 1; break; case SET_EXEC: @@ -663,28 +778,28 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) static void fulfill_config(struct afb_config *config) { // default HTTP port - if (config->httpdPort == 0) - config->httpdPort = 1234; + if (config->http_port == 0) + config->http_port = 1234; // default binding API timeout - if (config->apiTimeout == 0) - config->apiTimeout = DEFLT_API_TIMEOUT; + if (config->api_timeout == 0) + config->api_timeout = DEFAULT_API_TIMEOUT; // default AUTH_TOKEN if (config->random_token) config->token = NULL; // cache timeout default one hour - if (config->cacheTimeout == 0) - config->cacheTimeout = DEFLT_CACHE_TIMEOUT; + if (config->cache_timeout == 0) + config->cache_timeout = DEFAULT_CACHE_TIMEOUT; // cache timeout default one hour - if (config->cntxTimeout == 0) - config->cntxTimeout = DEFLT_CNTX_TIMEOUT; + if (config->session_timeout == 0) + config->session_timeout = DEFAULT_SESSION_TIMEOUT; // max count of sessions - if (config->nbSessionMax == 0) - config->nbSessionMax = CTX_NBCLIENTS; + if (config->max_session_count == 0) + config->max_session_count = DEFAULT_MAX_SESSION_COUNT; /* set directories */ if (config->workdir == NULL) @@ -717,6 +832,10 @@ static void fulfill_config(struct afb_config *config) strncpy(config->console, config->uploaddir, 512); strncat(config->console, "/AFB-console.out", 512); } + +#if !defined(REMOVE_LEGACY_TRACE) + config->traceapi |= config->traceditf | config->tracesvc; +#endif } void afb_config_dump(struct afb_config *config) @@ -761,21 +880,26 @@ void afb_config_dump(struct afb_config *config) V(exec) - D(httpdPort) - D(cacheTimeout) - D(apiTimeout) - D(cntxTimeout) - D(nbSessionMax) + D(http_port) + D(cache_timeout) + D(api_timeout) + D(session_timeout) + D(max_session_count) +#if defined(KEEP_LEGACY_MODE) E(mode,mode_desc) +#endif E(tracereq,tracereq_desc) +#if !defined(REMOVE_LEGACY_TRACE) E(traceditf,traceditf_desc) E(tracesvc,tracesvc_desc) +#endif E(traceevt,traceevt_desc) E(traceses,traceses_desc) + E(traceapi,traceapi_desc) B(no_ldpaths) - B(noHttpd) + B(no_httpd) B(background) #if HAS_MONITORING B(monitoring) @@ -823,10 +947,13 @@ static void on_environment_enum(int *to, const char *name, struct enumdesc *desc static void parse_environment(struct afb_config *config) { on_environment_enum(&config->tracereq, "AFB_TRACEREQ", tracereq_desc); +#if !defined(REMOVE_LEGACY_TRACE) on_environment_enum(&config->traceditf, "AFB_TRACEDITF", traceditf_desc); on_environment_enum(&config->tracesvc, "AFB_TRACESVC", tracesvc_desc); +#endif on_environment_enum(&config->traceevt, "AFB_TRACEEVT", traceevt_desc); on_environment_enum(&config->traceses, "AFB_TRACESES", traceses_desc); + on_environment_enum(&config->traceapi, "AFB_TRACEAPI", traceapi_desc); on_environment_list(&config->ldpaths, "AFB_LDPATHS"); } @@ -839,7 +966,7 @@ struct afb_config *afb_config_parse_arguments(int argc, char **argv) parse_environment(result); parse_arguments(argc, argv, result); fulfill_config(result); - if (verbosity >= 3) + if (verbose_wants(Log_Level_Info)) afb_config_dump(result); return result; } @@ -895,21 +1022,26 @@ struct json_object *afb_config_json(struct afb_config *config) V(exec) - D(httpdPort) - D(cacheTimeout) - D(apiTimeout) - D(cntxTimeout) - D(nbSessionMax) + D(http_port) + D(cache_timeout) + D(api_timeout) + D(session_timeout) + D(max_session_count) +#if defined(KEEP_LEGACY_MODE) E(mode,mode_desc) +#endif E(tracereq,tracereq_desc) +#if !defined(REMOVE_LEGACY_TRACE) E(traceditf,traceditf_desc) E(tracesvc,tracesvc_desc) +#endif E(traceevt,traceevt_desc) E(traceses,traceses_desc) + E(traceapi,traceapi_desc) B(no_ldpaths) - B(noHttpd) + B(no_httpd) B(background) #if HAS_MONITORING B(monitoring) diff --git a/src/afb-config.h b/src/afb-config.h index 89b1f78e..30fd398c 100644 --- a/src/afb-config.h +++ b/src/afb-config.h @@ -22,22 +22,27 @@ struct json_object; * other definitions --------------------------------------------------- */ +/** + * list of configuration values + */ struct afb_config_list { struct afb_config_list *next; char *value; }; -// main config structure +/** + * main config structure + */ struct afb_config { - char *console; // console device name (can be a file or a tty) - char *rootdir; // base dir for files - char *roothttp; // directory for http files - char *rootbase; // Angular HTML5 base URL - char *rootapi; // Base URL for REST APIs - char *workdir; // where to run the program - char *uploaddir; // where to store transient files - char *token; // initial authentication token [default NULL no session] - char *name; /* name to set to the daemon */ + char *console; /*< console device name (can be a file or a tty) */ + char *rootdir; /*< base dir for files */ + char *roothttp; /*< directory for http files */ + char *rootbase; /*< Angular HTML5 base URL */ + char *rootapi; /*< Base URL for REST APIs */ + char *workdir; /*< where to run the program */ + char *uploaddir; /*< where to store transient files */ + char *token; /*< initial authentication token [default NULL no session] */ + char *name; /*< name to set to the daemon */ struct afb_config_list *aliases; #if defined(WITH_DBUS_TRANSPARENCY) @@ -50,32 +55,39 @@ struct afb_config { struct afb_config_list *ldpaths; struct afb_config_list *weak_ldpaths; struct afb_config_list *calls; + struct afb_config_list *auto_ws; + struct afb_config_list *auto_link; char **exec; /* integers */ - int httpdPort; - int cacheTimeout; - int apiTimeout; - int cntxTimeout; // Client Session Context timeout - int nbSessionMax; // max count of sessions + int http_port; + int cache_timeout; + int api_timeout; + int session_timeout; /*< session timeout */ + int max_session_count; /*< max count of sessions */ /* enums */ +#if defined(KEEP_LEGACY_MODE) int mode; // mode of listening +#endif int tracereq; +#if !defined(REMOVE_LEGACY_TRACE) int traceditf; int tracesvc; +#endif int traceevt; int traceses; + int traceapi; /* booleans */ - unsigned no_ldpaths: 1; /* disable default ldpaths */ - unsigned noHttpd: 1; - unsigned background: 1; /* run in backround mode */ + unsigned no_ldpaths: 1; /**< disable default ldpaths */ + unsigned no_httpd: 1; + unsigned background: 1; /**< run in backround mode */ + unsigned random_token: 1; /**< expects a random token */ #if defined(WITH_MONITORING_OPTION) - unsigned monitoring: 1; /* activates monitoring */ + unsigned monitoring: 1; /**< activates monitoring */ #endif - unsigned random_token: 1; /* expects a random token */ }; extern struct afb_config *afb_config_parse_arguments(int argc, char **argv); diff --git a/src/afb-context.c b/src/afb-context.c index 13733ce6..6b3d6e9d 100644 --- a/src/afb-context.c +++ b/src/afb-context.c @@ -21,6 +21,7 @@ #include <assert.h> #include <stdlib.h> #include <stdint.h> +#include <errno.h> #include "afb-session.h" #include "afb-context.h" @@ -184,10 +185,12 @@ static inline unsigned ptr2loa(void *ptr) int afb_context_change_loa(struct afb_context *context, unsigned loa) { - if (!context->validated || loa > 7) - return 0; + if (!context->validated || loa > 7) { + errno = EINVAL; + return -1; + } - return 0 <= afb_session_set_cookie(context->session, loa_key(context), loa2ptr(loa), NULL); + return afb_session_set_cookie(context->session, loa_key(context), loa2ptr(loa), NULL); } unsigned afb_context_get_loa(struct afb_context *context) @@ -195,5 +198,3 @@ unsigned afb_context_get_loa(struct afb_context *context) assert(context->session != NULL); return ptr2loa(afb_session_get_cookie(context->session, loa_key(context))); } - - diff --git a/src/afb-cred.c b/src/afb-cred.c index f09d4441..b7b3175e 100644 --- a/src/afb-cred.c +++ b/src/afb-cred.c @@ -18,6 +18,7 @@ #define _GNU_SOURCE #include <stdlib.h> +#include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> @@ -26,6 +27,8 @@ #include <sys/socket.h> #include "afb-cred.h" +#include "verbose.h" + #define MAX_LABEL_LENGTH 1024 @@ -46,6 +49,10 @@ # define DEFAULT_PEERCRED_PID 0 /* no process */ #endif +static char on_behalf_credential_permission[] = "urn:AGL:permission:*:partner:on-behalf-credentials"; +static char export_format[] = "%x:%x:%x-%s"; +static char import_format[] = "%x:%x:%x-%n"; + static struct afb_cred *current; static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *label, size_t size) @@ -70,6 +77,7 @@ static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *labe cred->uid = uid; cred->gid = gid; cred->pid = pid; + cred->exported = NULL; dest = (char*)(&cred[1]); cred->user = dest; while(i) @@ -175,3 +183,105 @@ struct afb_cred *afb_cred_current() return afb_cred_addref(current); } +const char *afb_cred_export(struct afb_cred *cred) +{ + int rc; + + if (!cred->exported) { + rc = asprintf((char**)&cred->exported, + export_format, + (int)cred->uid, + (int)cred->gid, + (int)cred->pid, + cred->label); + if (rc < 0) { + errno = ENOMEM; + cred->exported = NULL; + } + } + return cred->exported; +} + +struct afb_cred *afb_cred_import(const char *string) +{ + struct afb_cred *cred; + int rc, uid, gid, pid, pos; + + rc = sscanf(string, import_format, &uid, &gid, &pid, &pos); + if (rc == 3) + cred = afb_cred_create((uid_t)uid, (gid_t)gid, (pid_t)pid, &string[pos]); + else { + errno = EINVAL; + cred = NULL; + } + return cred; +} + +struct afb_cred *afb_cred_mixed_on_behalf_import(struct afb_cred *cred, const char *context, const char *exported) + +{ + struct afb_cred *imported; + if (exported) { + if (afb_cred_has_permission(cred, on_behalf_credential_permission, context)) { + imported = afb_cred_import(exported); + if (imported) + return imported; + ERROR("Can't import on behalf credentials: %m"); + } else { + ERROR("On behalf credentials refused"); + } + } + return afb_cred_addref(cred); +} + +/*********************************************************************************/ +#ifdef BACKEND_PERMISSION_IS_CYNARA + +#include <pthread.h> +#include <cynara-client.h> + +static cynara *handle; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context) +{ + int rc; + + if (!cred) { + /* case of permission for self */ + return 1; + } + if (!permission) { + ERROR("Got a null permission!"); + return 0; + } + + /* cynara isn't reentrant */ + pthread_mutex_lock(&mutex); + + /* lazy initialisation */ + if (!handle) { + rc = cynara_initialize(&handle, NULL); + if (rc != CYNARA_API_SUCCESS) { + handle = NULL; + ERROR("cynara initialisation failed with code %d", rc); + return 0; + } + } + + /* query cynara permission */ + rc = cynara_check(handle, cred->label, context ?: "", cred->user, permission); + + pthread_mutex_unlock(&mutex); + return rc == CYNARA_API_ACCESS_ALLOWED; +} + +/*********************************************************************************/ +#else +int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context) +{ + WARNING("Granting permission %s by default of backend", permission ?: "(null)"); + return !!permission; +} +#endif + diff --git a/src/afb-cred.h b/src/afb-cred.h index 7ee4723c..614fa4bc 100644 --- a/src/afb-cred.h +++ b/src/afb-cred.h @@ -28,6 +28,7 @@ struct afb_cred const char *user; const char *label; const char *id; + const char *exported; }; extern struct afb_cred *afb_cred_current(); @@ -36,4 +37,10 @@ extern struct afb_cred *afb_cred_create_for_socket(int fd); extern struct afb_cred *afb_cred_addref(struct afb_cred *cred); extern void afb_cred_unref(struct afb_cred *cred); +extern int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context); + +extern const char *afb_cred_export(struct afb_cred *cred); +extern struct afb_cred *afb_cred_import(const char *string); + +extern struct afb_cred *afb_cred_mixed_on_behalf_import(struct afb_cred *cred, const char *context, const char *exported); diff --git a/src/afb-evt.c b/src/afb-evt.c index 6b94ce8c..ed3e4672 100644 --- a/src/afb-evt.c +++ b/src/afb-evt.c @@ -24,8 +24,8 @@ #include <pthread.h> #include <json-c/json.h> -#include <afb/afb-eventid-itf.h> -#include <afb/afb-event.h> +#include <afb/afb-event-x2-itf.h> +#include <afb/afb-event-x1.h> #include "afb-evt.h" #include "afb-hook.h" @@ -50,8 +50,8 @@ struct afb_evt_listener { /* head of the list of events listened */ struct afb_evt_watch *watchs; - /* mutex of the listener */ - pthread_mutex_t mutex; + /* rwlock of the listener */ + pthread_rwlock_t rwlock; /* count of reference to the listener */ int refcount; @@ -63,7 +63,7 @@ struct afb_evt_listener { struct afb_evtid { /* interface */ - struct afb_eventid eventid; + struct afb_event_x2 eventid; /* next event */ struct afb_evtid *next; @@ -71,8 +71,8 @@ struct afb_evtid { /* head of the list of listeners watching the event */ struct afb_evt_watch *watchs; - /* mutex of the event */ - pthread_mutex_t mutex; + /* rwlock of the event */ + pthread_rwlock_t rwlock; /* hooking */ int hookflags; @@ -109,7 +109,7 @@ struct afb_evt_watch { }; /* the interface for events */ -static struct afb_eventid_itf afb_evt_eventid_itf = { +static struct afb_event_x2_itf afb_evt_event_x2_itf = { .broadcast = (void*)afb_evt_evtid_broadcast, .push = (void*)afb_evt_evtid_push, .unref = (void*)afb_evt_evtid_unref, @@ -118,7 +118,7 @@ static struct afb_eventid_itf afb_evt_eventid_itf = { }; /* the interface for events */ -static struct afb_eventid_itf afb_evt_hooked_eventid_itf = { +static struct afb_event_x2_itf afb_evt_hooked_eventid_itf = { .broadcast = (void*)afb_evt_evtid_hooked_broadcast, .push = (void*)afb_evt_evtid_hooked_push, .unref = (void*)afb_evt_evtid_hooked_unref, @@ -127,11 +127,11 @@ static struct afb_eventid_itf afb_evt_hooked_eventid_itf = { }; /* head of the list of listeners */ -static pthread_mutex_t listeners_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_rwlock_t listeners_rwlock = PTHREAD_RWLOCK_INITIALIZER; static struct afb_evt_listener *listeners = NULL; /* handling id of events */ -static pthread_mutex_t events_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_rwlock_t events_rwlock = PTHREAD_RWLOCK_INITIALIZER; static struct afb_evtid *evtids = NULL; static int event_id_counter = 0; static int event_id_wrapped = 0; @@ -147,7 +147,8 @@ static int broadcast(const char *event, struct json_object *obj, int id) struct afb_evt_listener *listener; result = 0; - pthread_mutex_lock(&listeners_mutex); + + pthread_rwlock_rdlock(&listeners_rwlock); listener = listeners; while(listener) { if (listener->itf->broadcast != NULL) { @@ -156,7 +157,7 @@ static int broadcast(const char *event, struct json_object *obj, int id) } listener = listener->next; } - pthread_mutex_unlock(&listeners_mutex); + pthread_rwlock_unlock(&listeners_rwlock); json_object_put(obj); return result; } @@ -228,7 +229,7 @@ int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj) struct afb_evt_listener *listener; result = 0; - pthread_mutex_lock(&evtid->mutex); + pthread_rwlock_rdlock(&evtid->rwlock); watch = evtid->watchs; while(watch) { listener = watch->listener; @@ -239,7 +240,7 @@ int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj) } watch = watch->next_by_evtid; } - pthread_mutex_unlock(&evtid->mutex); + pthread_rwlock_unlock(&evtid->rwlock); json_object_put(obj); return result; } @@ -252,6 +253,7 @@ int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj) */ int afb_evt_evtid_hooked_push(struct afb_evtid *evtid, struct json_object *obj) { + int result; /* lease the object */ @@ -319,7 +321,7 @@ struct afb_evtid *afb_evt_evtid_create(const char *fullname) goto error; /* allocates the id */ - pthread_mutex_lock(&events_mutex); + pthread_rwlock_wrlock(&events_rwlock); do { if (++event_id_counter < 0) { event_id_wrapped = 1; @@ -335,15 +337,16 @@ struct afb_evtid *afb_evt_evtid_create(const char *fullname) /* initialize the event */ memcpy(evtid->fullname, fullname, len + 1); evtid->next = evtids; + evtid->refcount = 1; evtid->watchs = NULL; evtid->id = event_id_counter; - pthread_mutex_init(&evtid->mutex, NULL); + pthread_rwlock_init(&evtid->rwlock, NULL); evtids = evtid; evtid->hookflags = afb_hook_flags_evt(evtid->fullname); - evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_eventid_itf; + evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_event_x2_itf; if (evtid->hookflags & afb_hook_flag_evt_create) afb_hook_evt_create(evtid->fullname, evtid->id); - pthread_mutex_unlock(&events_mutex); + pthread_rwlock_unlock(&events_rwlock); /* returns the event */ return evtid; @@ -402,14 +405,14 @@ void afb_evt_evtid_unref(struct afb_evtid *evtid) if (!__atomic_sub_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED)) { /* unlinks the event if valid! */ - pthread_mutex_lock(&events_mutex); + pthread_rwlock_wrlock(&events_rwlock); found = 0; prv = &evtids; while (*prv && !(found = (*prv == evtid))) prv = &(*prv)->next; if (found) *prv = evtid->next; - pthread_mutex_unlock(&events_mutex); + pthread_rwlock_unlock(&events_rwlock); /* destroys the event */ if (!found) @@ -418,15 +421,15 @@ void afb_evt_evtid_unref(struct afb_evtid *evtid) /* removes all watchers */ while(evtid->watchs != NULL) { listener = evtid->watchs->listener; - pthread_mutex_lock(&listener->mutex); - pthread_mutex_lock(&evtid->mutex); + pthread_rwlock_wrlock(&listener->rwlock); + pthread_rwlock_wrlock(&evtid->rwlock); remove_watch(evtid->watchs); - pthread_mutex_unlock(&evtid->mutex); - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&evtid->rwlock); + pthread_rwlock_unlock(&listener->rwlock); } /* free */ - pthread_mutex_destroy(&evtid->mutex); + pthread_rwlock_destroy(&evtid->rwlock); free(evtid); } } @@ -489,7 +492,7 @@ struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf, struct afb_evt_listener *listener; /* search if an instance already exists */ - pthread_mutex_lock(&listeners_mutex); + pthread_rwlock_wrlock(&listeners_rwlock); listener = listeners; while (listener != NULL) { if (listener->itf == itf && listener->closure == closure) { @@ -507,12 +510,12 @@ struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf, listener->closure = closure; listener->watchs = NULL; listener->refcount = 1; - pthread_mutex_init(&listener->mutex, NULL); + pthread_rwlock_init(&listener->rwlock, NULL); listener->next = listeners; listeners = listener; } found: - pthread_mutex_unlock(&listeners_mutex); + pthread_rwlock_unlock(&listeners_rwlock); return listener; } @@ -537,25 +540,25 @@ void afb_evt_listener_unref(struct afb_evt_listener *listener) if (!__atomic_sub_fetch(&listener->refcount, 1, __ATOMIC_RELAXED)) { /* unlink the listener */ - pthread_mutex_lock(&listeners_mutex); + pthread_rwlock_wrlock(&listeners_rwlock); prv = &listeners; while (*prv != listener) prv = &(*prv)->next; *prv = listener->next; - pthread_mutex_unlock(&listeners_mutex); + pthread_rwlock_unlock(&listeners_rwlock); /* remove the watchers */ - pthread_mutex_lock(&listener->mutex); + pthread_rwlock_wrlock(&listener->rwlock); while (listener->watchs != NULL) { evtid = listener->watchs->evtid; - pthread_mutex_lock(&evtid->mutex); + pthread_rwlock_wrlock(&evtid->rwlock); remove_watch(listener->watchs); - pthread_mutex_unlock(&evtid->mutex); + pthread_rwlock_unlock(&evtid->rwlock); } - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&listener->rwlock); /* free the listener */ - pthread_mutex_destroy(&listener->mutex); + pthread_rwlock_destroy(&listener->rwlock); free(listener); } } @@ -575,7 +578,7 @@ int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid } /* search the existing watch for the listener */ - pthread_mutex_lock(&listener->mutex); + pthread_rwlock_wrlock(&listener->rwlock); watch = listener->watchs; while(watch != NULL) { if (watch->evtid == evtid) @@ -586,7 +589,7 @@ int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid /* not found, allocate a new */ watch = malloc(sizeof *watch); if (watch == NULL) { - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&listener->rwlock); errno = ENOMEM; return -1; } @@ -597,16 +600,16 @@ int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid watch->listener = listener; watch->next_by_listener = listener->watchs; listener->watchs = watch; - pthread_mutex_lock(&evtid->mutex); + pthread_rwlock_wrlock(&evtid->rwlock); watch->next_by_evtid = evtid->watchs; evtid->watchs = watch; - pthread_mutex_unlock(&evtid->mutex); + pthread_rwlock_unlock(&evtid->rwlock); found: if (watch->activity == 0 && listener->itf->add != NULL) listener->itf->add(listener->closure, evtid->fullname, evtid->id); watch->activity++; - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&listener->rwlock); return 0; } @@ -620,7 +623,7 @@ int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb_evtid struct afb_evt_watch *watch; /* search the existing watch */ - pthread_mutex_lock(&listener->mutex); + pthread_rwlock_wrlock(&listener->rwlock); watch = listener->watchs; while(watch != NULL) { if (watch->evtid == evtid) { @@ -629,12 +632,12 @@ int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb_evtid if (watch->activity == 0 && listener->itf->remove != NULL) listener->itf->remove(listener->closure, evtid->fullname, evtid->id); } - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&listener->rwlock); return 0; } watch = watch->next_by_listener; } - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&listener->rwlock); errno = ENOENT; return -1; } @@ -646,20 +649,20 @@ void afb_evt_update_hooks() { struct afb_evtid *evtid; - pthread_mutex_lock(&events_mutex); + pthread_rwlock_rdlock(&events_rwlock); for (evtid = evtids ; evtid ; evtid = evtid->next) { evtid->hookflags = afb_hook_flags_evt(evtid->fullname); - evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_eventid_itf; + evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_event_x2_itf; } - pthread_mutex_unlock(&events_mutex); + pthread_rwlock_unlock(&events_rwlock); } -inline struct afb_evtid *afb_evt_eventid_to_evtid(struct afb_eventid *eventid) +inline struct afb_evtid *afb_evt_event_x2_to_evtid(struct afb_event_x2 *eventid) { return (struct afb_evtid*)eventid; } -inline struct afb_eventid *afb_evt_eventid_from_evtid(struct afb_evtid *evtid) +inline struct afb_event_x2 *afb_evt_event_x2_from_evtid(struct afb_evtid *evtid) { return &evtid->eventid; } @@ -668,35 +671,35 @@ inline struct afb_eventid *afb_evt_eventid_from_evtid(struct afb_evtid *evtid) * Creates an event of 'fullname' and returns it. * Returns an event with closure==NULL in case of error. */ -struct afb_eventid *afb_evt_eventid_create(const char *fullname) +struct afb_event_x2 *afb_evt_event_x2_create(const char *fullname) { - return afb_evt_eventid_from_evtid(afb_evt_evtid_create(fullname)); + return afb_evt_event_x2_from_evtid(afb_evt_evtid_create(fullname)); } /* * Creates an event of name 'prefix'/'name' and returns it. * Returns an event with closure==NULL in case of error. */ -struct afb_eventid *afb_evt_eventid_create2(const char *prefix, const char *name) +struct afb_event_x2 *afb_evt_event_x2_create2(const char *prefix, const char *name) { - return afb_evt_eventid_from_evtid(afb_evt_evtid_create2(prefix, name)); + return afb_evt_event_x2_from_evtid(afb_evt_evtid_create2(prefix, name)); } /* * Returns the fullname of the 'eventid' */ -const char *afb_evt_eventid_fullname(struct afb_eventid *eventid) +const char *afb_evt_event_x2_fullname(struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); return evtid ? evtid->fullname : NULL; } /* * Returns the id of the 'eventid' */ -int afb_evt_eventid_id(struct afb_eventid *eventid) +int afb_evt_event_x2_id(struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); return evtid ? evtid->id : 0; } @@ -704,9 +707,9 @@ int afb_evt_eventid_id(struct afb_eventid *eventid) * Makes the 'listener' watching 'eventid' * Returns 0 in case of success or else -1. */ -int afb_evt_eventid_add_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid) +int afb_evt_event_x2_add_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); /* check parameter */ if (!evtid) { @@ -722,9 +725,9 @@ int afb_evt_eventid_add_watch(struct afb_evt_listener *listener, struct afb_even * Avoids the 'listener' to watch 'eventid' * Returns 0 in case of success or else -1. */ -int afb_evt_eventid_remove_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid) +int afb_evt_event_x2_remove_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); /* check parameter */ if (!evtid) { @@ -736,41 +739,41 @@ int afb_evt_eventid_remove_watch(struct afb_evt_listener *listener, struct afb_e return afb_evt_watch_sub_evtid(listener, evtid); } -int afb_evt_eventid_push(struct afb_eventid *eventid, struct json_object *object) +int afb_evt_event_x2_push(struct afb_event_x2 *eventid, struct json_object *object) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); if (evtid) return afb_evt_evtid_hooked_push(evtid, object); json_object_put(object); return 0; } -int afb_evt_eventid_unhooked_push(struct afb_eventid *eventid, struct json_object *object) +int afb_evt_event_x2_unhooked_push(struct afb_event_x2 *eventid, struct json_object *object) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); if (evtid) return afb_evt_evtid_push(evtid, object); json_object_put(object); return 0; } -struct afb_event afb_evt_event_from_evtid(struct afb_evtid *evtid) +struct afb_event_x1 afb_evt_event_from_evtid(struct afb_evtid *evtid) { return evtid - ? (struct afb_event){ .itf = &afb_evt_hooked_eventid_itf, .closure = &evtid->eventid } - : (struct afb_event){ .itf = NULL, .closure = NULL }; + ? (struct afb_event_x1){ .itf = &afb_evt_hooked_eventid_itf, .closure = &evtid->eventid } + : (struct afb_event_x1){ .itf = NULL, .closure = NULL }; } -void afb_evt_eventid_unref(struct afb_eventid *eventid) +void afb_evt_event_x2_unref(struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); if (evtid) afb_evt_evtid_unref(evtid); } -struct afb_eventid *afb_evt_eventid_addref(struct afb_eventid *eventid) +struct afb_event_x2 *afb_evt_event_x2_addref(struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); if (evtid) afb_evt_evtid_addref(evtid); return eventid; diff --git a/src/afb-evt.h b/src/afb-evt.h index c3999df2..ceb1b1b9 100644 --- a/src/afb-evt.h +++ b/src/afb-evt.h @@ -17,8 +17,8 @@ #pragma once -struct afb_event; -struct afb_eventid; +struct afb_event_x1; +struct afb_event_x2; struct afb_evtid; struct afb_session; struct json_object; @@ -66,20 +66,20 @@ extern int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb extern void afb_evt_update_hooks(); -extern struct afb_eventid *afb_evt_eventid_create(const char *fullname); -extern struct afb_eventid *afb_evt_eventid_create2(const char *prefix, const char *name); -extern const char *afb_evt_eventid_fullname(struct afb_eventid *eventid); -extern int afb_evt_eventid_id(struct afb_eventid *eventid); -extern struct afb_eventid *afb_evt_eventid_addref(struct afb_eventid *eventid); -extern void afb_evt_eventid_unref(struct afb_eventid *eventid); +extern struct afb_event_x2 *afb_evt_event_x2_create(const char *fullname); +extern struct afb_event_x2 *afb_evt_event_x2_create2(const char *prefix, const char *name); +extern const char *afb_evt_event_x2_fullname(struct afb_event_x2 *event); +extern int afb_evt_event_x2_id(struct afb_event_x2 *eventid); +extern struct afb_event_x2 *afb_evt_event_x2_addref(struct afb_event_x2 *eventid); +extern void afb_evt_event_x2_unref(struct afb_event_x2 *eventid); -extern int afb_evt_eventid_push(struct afb_eventid *eventid, struct json_object *object); -extern int afb_evt_eventid_unhooked_push(struct afb_eventid *eventid, struct json_object *object); +extern int afb_evt_event_x2_push(struct afb_event_x2 *eventid, struct json_object *object); +extern int afb_evt_event_x2_unhooked_push(struct afb_event_x2 *eventid, struct json_object *object); -extern int afb_evt_eventid_add_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid); -extern int afb_evt_eventid_remove_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid); +extern int afb_evt_event_x2_add_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid); +extern int afb_evt_event_x2_remove_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid); -extern struct afb_evtid *afb_evt_eventid_to_evtid(struct afb_eventid *eventid); -extern struct afb_eventid *afb_evt_eventid_from_evtid(struct afb_evtid *evtid); -extern struct afb_event afb_evt_event_from_evtid(struct afb_evtid *evtid); +extern struct afb_evtid *afb_evt_event_x2_to_evtid(struct afb_event_x2 *eventid); +extern struct afb_event_x2 *afb_evt_event_x2_from_evtid(struct afb_evtid *evtid); +extern struct afb_event_x1 afb_evt_event_from_evtid(struct afb_evtid *evtid); diff --git a/src/afb-export.c b/src/afb-export.c index 12adf08d..fbf77f86 100644 --- a/src/afb-export.c +++ b/src/afb-export.c @@ -20,6 +20,8 @@ #include <stdio.h> #include <string.h> #include <errno.h> +#include <fnmatch.h> +#include <ctype.h> #include <json-c/json.h> @@ -28,7 +30,11 @@ #include "afb-api.h" #include "afb-apiset.h" -#include "afb-api-dyn.h" +#if defined(WITH_LEGACY_BINDING_V1) +#include "afb-api-so-v1.h" +#endif +#include "afb-api-so-v2.h" +#include "afb-api-v3.h" #include "afb-common.h" #include "afb-systemd.h" #include "afb-cred.h" @@ -38,20 +44,48 @@ #include "afb-msg-json.h" #include "afb-session.h" #include "afb-xreq.h" +#include "afb-calls.h" #include "jobs.h" #include "verbose.h" /************************************************************************* - * internal types and structures + * internal types ************************************************************************/ +/* + * structure for handling events + */ +struct event_handler +{ + /* link to the next event handler of the list */ + struct event_handler *next; + + /* function to call on the case of the event */ + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*); + + /* closure for the callback */ + void *closure; + + /* the handled pattern */ + char pattern[1]; +}; + +/* + * Actually supported versions + */ enum afb_api_version { - Api_Version_Dyn = 0, + Api_Version_None = 0, +#if defined(WITH_LEGACY_BINDING_V1) Api_Version_1 = 1, +#endif Api_Version_2 = 2, + Api_Version_3 = 3 }; +/* + * The states of exported APIs + */ enum afb_api_state { Api_State_Pre_Init, @@ -59,13 +93,16 @@ enum afb_api_state Api_State_Run }; +/* + * structure of the exported API + */ struct afb_export { /* keep it first */ - struct afb_dynapi dynapi; + struct afb_api_x3 api; - /* name of the api */ - char *apiname; + /* reference count */ + int refcount; /* version of the api */ unsigned version: 4; @@ -73,124 +110,157 @@ struct afb_export /* current state */ unsigned state: 4; + /* declared */ + unsigned declared: 1; + + /* unsealed */ + unsigned unsealed: 1; + /* hooking flags */ int hookditf; int hooksvc; - /* dynamic api */ - struct afb_api_dyn *apidyn; - /* session for service */ struct afb_session *session; - /* apiset for service */ - struct afb_apiset *apiset; + /* apiset the API is declared in */ + struct afb_apiset *declare_set; + + /* apiset for calls */ + struct afb_apiset *call_set; /* event listener for service or NULL */ struct afb_evt_listener *listener; + /* event handler list */ + struct event_handler *event_handlers; + + /* internal descriptors */ + union { +#if defined(WITH_LEGACY_BINDING_V1) + struct afb_binding_v1 *v1; +#endif + const struct afb_binding_v2 *v2; + struct afb_api_v3 *v3; + } desc; + /* start function */ union { - int (*v1)(struct afb_service); +#if defined(WITH_LEGACY_BINDING_V1) + int (*v1)(struct afb_service_x1); +#endif int (*v2)(); - int (*vdyn)(struct afb_dynapi *dynapi); + int (*v3)(struct afb_api_x3 *api); } init; /* event handling */ - union { - void (*v12)(const char *event, struct json_object *object); - void (*vdyn)(struct afb_dynapi *dynapi, const char *event, struct json_object *object); - } on_event; + void (*on_any_event_v12)(const char *event, struct json_object *object); + void (*on_any_event_v3)(struct afb_api_x3 *api, const char *event, struct json_object *object); /* exported data */ union { +#if defined(WITH_LEGACY_BINDING_V1) struct afb_binding_interface_v1 v1; +#endif struct afb_binding_data_v2 *v2; } export; + + /* initial name */ + char name[1]; }; -/************************************************************************************************************/ +/*****************************************************************************/ + +static inline struct afb_api_x3 *to_api_x3(struct afb_export *export) +{ + return (struct afb_api_x3*)export; +} -static inline struct afb_dynapi *to_dynapi(struct afb_export *export) +static inline struct afb_export *from_api_x3(struct afb_api_x3 *api) { - return (struct afb_dynapi*)export; + return (struct afb_export*)api; } -static inline struct afb_export *from_dynapi(struct afb_dynapi *dynapi) +struct afb_export *afb_export_from_api_x3(struct afb_api_x3 *api) { - return (struct afb_export*)dynapi; + return from_api_x3(api); } -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +struct afb_api_x3 *afb_export_to_api_x3(struct afb_export *export) +{ + return to_api_x3(export); +} + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M D I T F - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ /********************************************** * normal flow **********************************************/ -static void vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void vverbose_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { char *p; - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); if (!fmt || vasprintf(&p, fmt, args) < 0) vverbose(level, file, line, function, fmt, args); else { - verbose(level, file, line, function, "[API %s] %s", export->apiname, p); + verbose(level, file, line, function, "[API %s] %s", export->api.apiname, p); free(p); } } -static void old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args) +static void legacy_vverbose_v1_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *fmt, va_list args) { vverbose_cb(closure, level, file, line, NULL, fmt, args); } -static struct afb_eventid *eventid_make_cb(void *closure, const char *name) +static struct afb_event_x2 *event_x2_make_cb(struct afb_api_x3 *closure, const char *name) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); /* check daemon state */ if (export->state == Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->apiname, name); + ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->api.apiname, name); errno = EINVAL; return NULL; } /* create the event */ - return afb_evt_eventid_create2(export->apiname, name); + return afb_evt_event_x2_create2(export->api.apiname, name); } -static struct afb_event event_make_cb(void *closure, const char *name) +static struct afb_event_x1 legacy_event_x1_make_cb(struct afb_api_x3 *closure, const char *name) { - struct afb_eventid *eventid = eventid_make_cb(closure, name); - return afb_evt_event_from_evtid(afb_evt_eventid_to_evtid(eventid)); + struct afb_event_x2 *event = event_x2_make_cb(closure, name); + return afb_evt_event_from_evtid(afb_evt_event_x2_to_evtid(event)); } -static int event_broadcast_cb(void *closure, const char *name, struct json_object *object) +static int event_broadcast_cb(struct afb_api_x3 *closure, const char *name, struct json_object *object) { size_t plen, nlen; char *event; - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); /* check daemon state */ if (export->state == Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit", export->apiname, name, json_object_to_json_string(object)); + ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit", export->api.apiname, name, json_object_to_json_string(object)); errno = EINVAL; return 0; } /* makes the event name */ - plen = strlen(export->apiname); + plen = strlen(export->api.apiname); nlen = strlen(name); event = alloca(nlen + plen + 2); - memcpy(event, export->apiname, plen); + memcpy(event, export->api.apiname, plen); event[plen] = '/'; memcpy(event + plen + 1, name, nlen + 1); @@ -198,190 +268,218 @@ static int event_broadcast_cb(void *closure, const char *name, struct json_objec return afb_evt_broadcast(event, object); } -static int rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale) +static int rootdir_open_locale_cb(struct afb_api_x3 *closure, const char *filename, int flags, const char *locale) { return afb_common_rootdir_open_locale(filename, flags, locale); } -static int queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) +static int queue_job_cb(struct afb_api_x3 *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) { return jobs_queue(group, timeout, callback, argument); } -static struct afb_req unstore_req_cb(void *closure, struct afb_stored_req *sreq) +static struct afb_req_x1 legacy_unstore_req_cb(struct afb_api_x3 *closure, struct afb_stored_req *sreq) { return afb_xreq_unstore(sreq); } -static int require_api_cb(void *closure, const char *name, int initialized) -{ - struct afb_export *export = closure; - if (export->state != Api_State_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_require(%s, %d)', must be in Init", export->apiname, name, initialized); - errno = EINVAL; - return -1; +static int require_api_cb(struct afb_api_x3 *closure, const char *name, int initialized) +{ + struct afb_export *export = from_api_x3(closure); + int rc, rc2; + char *iter, *end, save; + + /* scan the names in a local copy */ + rc = 0; + iter = strdupa(name); + for(;;) { + /* skip any space */ + save = *iter; + while(isspace(save)) + save = *++iter; + if (!save) /* at end? */ + return rc; + + /* search for the end */ + end = iter; + while (save && !isspace(save)) + save = *++end; + *end = 0; + + /* check the required api */ + if (export->state == Api_State_Pre_Init) + rc2 = afb_apiset_require(export->declare_set, export->api.apiname, name); + else + rc2 = -!((initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->call_set, iter, 1)); + if (rc2 < 0) + rc = rc2; + + *end = save; + iter = end; } - return -!(initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->apiset, name, 1); } -static int rename_api_cb(void *closure, const char *name) +static int add_alias_cb(struct afb_api_x3 *closure, const char *apiname, const char *aliasname) { - struct afb_export *export = closure; - if (export->state != Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_rename(%s)', must be in PreInit", export->apiname, name); - errno = EINVAL; - return -1; - } - if (!afb_api_is_valid_name(name, 1)) { - ERROR("[API %s] Can't rename to %s: bad API name", export->apiname, name); + struct afb_export *export = from_api_x3(closure); + if (!afb_api_is_valid_name(aliasname)) { + ERROR("[API %s] Can't add alias to %s: bad API name", export->api.apiname, aliasname); errno = EINVAL; return -1; } - NOTICE("[API %s] renamed to [API %s]", export->apiname, name); - afb_export_rename(export, name); + NOTICE("[API %s] aliasing [API %s] to [API %s]", export->api.apiname, apiname?:"<null>", aliasname); + afb_export_add_alias(export, apiname, aliasname); return 0; } -static int api_new_api_cb( - void *closure, +static struct afb_api_x3 *api_new_api_cb( + struct afb_api_x3 *closure, const char *api, const char *info, int noconcurrency, - int (*preinit)(void*, struct afb_dynapi *), + int (*preinit)(void*, struct afb_api_x3 *), void *preinit_closure) { - struct afb_export *export = closure; - return afb_api_dyn_add(export->apiset, api, info, noconcurrency, preinit, preinit_closure); + struct afb_export *export = from_api_x3(closure); + struct afb_api_v3 *apiv3 = afb_api_v3_create(export->declare_set, export->call_set, api, info, noconcurrency, preinit, preinit_closure, 1); + return apiv3 ? to_api_x3(afb_api_v3_export(apiv3)) : NULL; } /********************************************** * hooked flow **********************************************/ -static void hooked_vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void hooked_vverbose_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); va_list ap; va_copy(ap, args); vverbose_cb(closure, level, file, line, function, fmt, args); - afb_hook_ditf_vverbose(export, level, file, line, function, fmt, ap); + afb_hook_api_vverbose(export, level, file, line, function, fmt, ap); va_end(ap); } -static void hooked_old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args) +static void legacy_hooked_vverbose_v1_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *fmt, va_list args) { hooked_vverbose_cb(closure, level, file, line, NULL, fmt, args); } -static struct afb_eventid *hooked_eventid_make_cb(void *closure, const char *name) +static struct afb_event_x2 *hooked_event_x2_make_cb(struct afb_api_x3 *closure, const char *name) { - struct afb_export *export = closure; - struct afb_eventid *r = eventid_make_cb(closure, name); - afb_hook_ditf_event_make(export, name, r); + struct afb_export *export = from_api_x3(closure); + struct afb_event_x2 *r = event_x2_make_cb(closure, name); + afb_hook_api_event_make(export, name, r); return r; } -static struct afb_event hooked_event_make_cb(void *closure, const char *name) +static struct afb_event_x1 legacy_hooked_event_x1_make_cb(struct afb_api_x3 *closure, const char *name) { - struct afb_eventid *eventid = hooked_eventid_make_cb(closure, name); - return (struct afb_event){ .itf = eventid ? eventid->itf : NULL, .closure = eventid }; + struct afb_event_x2 *event = hooked_event_x2_make_cb(closure, name); + struct afb_event_x1 e; + e.closure = event; + e.itf = event ? event->itf : NULL; + return e; } -static int hooked_event_broadcast_cb(void *closure, const char *name, struct json_object *object) +static int hooked_event_broadcast_cb(struct afb_api_x3 *closure, const char *name, struct json_object *object) { int r; - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); json_object_get(object); - afb_hook_ditf_event_broadcast_before(export, name, json_object_get(object)); + afb_hook_api_event_broadcast_before(export, name, json_object_get(object)); r = event_broadcast_cb(closure, name, object); - afb_hook_ditf_event_broadcast_after(export, name, object, r); + afb_hook_api_event_broadcast_after(export, name, object, r); json_object_put(object); return r; } -static struct sd_event *hooked_get_event_loop(void *closure) +static struct sd_event *hooked_get_event_loop(struct afb_api_x3 *closure) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); struct sd_event *r = afb_systemd_get_event_loop(); - return afb_hook_ditf_get_event_loop(export, r); + return afb_hook_api_get_event_loop(export, r); } -static struct sd_bus *hooked_get_user_bus(void *closure) +static struct sd_bus *hooked_get_user_bus(struct afb_api_x3 *closure) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); struct sd_bus *r = afb_systemd_get_user_bus(); - return afb_hook_ditf_get_user_bus(export, r); + return afb_hook_api_get_user_bus(export, r); } -static struct sd_bus *hooked_get_system_bus(void *closure) +static struct sd_bus *hooked_get_system_bus(struct afb_api_x3 *closure) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); struct sd_bus *r = afb_systemd_get_system_bus(); - return afb_hook_ditf_get_system_bus(export, r); + return afb_hook_api_get_system_bus(export, r); } -static int hooked_rootdir_get_fd(void *closure) +static int hooked_rootdir_get_fd(struct afb_api_x3 *closure) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); int r = afb_common_rootdir_get_fd(); - return afb_hook_ditf_rootdir_get_fd(export, r); + return afb_hook_api_rootdir_get_fd(export, r); } -static int hooked_rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale) +static int hooked_rootdir_open_locale_cb(struct afb_api_x3 *closure, const char *filename, int flags, const char *locale) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); int r = rootdir_open_locale_cb(closure, filename, flags, locale); - return afb_hook_ditf_rootdir_open_locale(export, filename, flags, locale, r); + return afb_hook_api_rootdir_open_locale(export, filename, flags, locale, r); } -static int hooked_queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) +static int hooked_queue_job_cb(struct afb_api_x3 *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); int r = queue_job_cb(closure, callback, argument, group, timeout); - return afb_hook_ditf_queue_job(export, callback, argument, group, timeout, r); + return afb_hook_api_queue_job(export, callback, argument, group, timeout, r); } -static struct afb_req hooked_unstore_req_cb(void *closure, struct afb_stored_req *sreq) +static struct afb_req_x1 legacy_hooked_unstore_req_cb(struct afb_api_x3 *closure, struct afb_stored_req *sreq) { - struct afb_export *export = closure; - afb_hook_ditf_unstore_req(export, sreq); - return unstore_req_cb(closure, sreq); + struct afb_export *export = from_api_x3(closure); + afb_hook_api_legacy_unstore_req(export, sreq); + return legacy_unstore_req_cb(closure, sreq); } -static int hooked_require_api_cb(void *closure, const char *name, int initialized) +static int hooked_require_api_cb(struct afb_api_x3 *closure, const char *name, int initialized) { int result; - struct afb_export *export = closure; - afb_hook_ditf_require_api(export, name, initialized); + struct afb_export *export = from_api_x3(closure); + afb_hook_api_require_api(export, name, initialized); result = require_api_cb(closure, name, initialized); - return afb_hook_ditf_require_api_result(export, name, initialized, result); + return afb_hook_api_require_api_result(export, name, initialized, result); } -static int hooked_rename_api_cb(void *closure, const char *name) +static int hooked_add_alias_cb(struct afb_api_x3 *closure, const char *apiname, const char *aliasname) { - struct afb_export *export = closure; - const char *oldname = export->apiname; - int result = rename_api_cb(closure, name); - return afb_hook_ditf_rename_api(export, oldname, name, result); + struct afb_export *export = from_api_x3(closure); + int result = add_alias_cb(closure, apiname, aliasname); + return afb_hook_api_add_alias(export, apiname, aliasname, result); } -static int hooked_api_new_api_cb( - void *closure, +static struct afb_api_x3 *hooked_api_new_api_cb( + struct afb_api_x3 *closure, const char *api, const char *info, int noconcurrency, - int (*preinit)(void*, struct afb_dynapi *), + int (*preinit)(void*, struct afb_api_x3 *), void *preinit_closure) { - /* TODO */ - return api_new_api_cb(closure, api, info, noconcurrency, preinit, preinit_closure); + struct afb_api_x3 *result; + struct afb_export *export = from_api_x3(closure); + afb_hook_api_new_api_before(export, api, info, noconcurrency); + result = api_new_api_cb(closure, api, info, noconcurrency, preinit, preinit_closure); + afb_hook_api_new_api_after(export, -!result, api); + return result; } + /********************************************** * vectors **********************************************/ -static const struct afb_daemon_itf daemon_itf = { - .vverbose_v1 = old_vverbose_cb, +static const struct afb_daemon_itf_x1 daemon_itf = { + .vverbose_v1 = legacy_vverbose_v1_cb, .vverbose_v2 = vverbose_cb, - .event_make = event_make_cb, + .event_make = legacy_event_x1_make_cb, .event_broadcast = event_broadcast_cb, .get_event_loop = afb_systemd_get_event_loop, .get_user_bus = afb_systemd_get_user_bus, @@ -389,16 +487,16 @@ static const struct afb_daemon_itf daemon_itf = { .rootdir_get_fd = afb_common_rootdir_get_fd, .rootdir_open_locale = rootdir_open_locale_cb, .queue_job = queue_job_cb, - .unstore_req = unstore_req_cb, + .unstore_req = legacy_unstore_req_cb, .require_api = require_api_cb, - .rename_api = rename_api_cb, + .add_alias = add_alias_cb, .new_api = api_new_api_cb, }; -static const struct afb_daemon_itf hooked_daemon_itf = { - .vverbose_v1 = hooked_old_vverbose_cb, +static const struct afb_daemon_itf_x1 hooked_daemon_itf = { + .vverbose_v1 = legacy_hooked_vverbose_v1_cb, .vverbose_v2 = hooked_vverbose_cb, - .event_make = hooked_event_make_cb, + .event_make = legacy_hooked_event_x1_make_cb, .event_broadcast = hooked_event_broadcast_cb, .get_event_loop = hooked_get_event_loop, .get_user_bus = hooked_get_user_bus, @@ -406,422 +504,185 @@ static const struct afb_daemon_itf hooked_daemon_itf = { .rootdir_get_fd = hooked_rootdir_get_fd, .rootdir_open_locale = hooked_rootdir_open_locale_cb, .queue_job = hooked_queue_job_cb, - .unstore_req = hooked_unstore_req_cb, + .unstore_req = legacy_hooked_unstore_req_cb, .require_api = hooked_require_api_cb, - .rename_api = hooked_rename_api_cb, + .add_alias = hooked_add_alias_cb, .new_api = hooked_api_new_api_cb, }; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M S V C - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ /* the common session for services sharing their session */ static struct afb_session *common_session; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M S V C - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ - -/* - * Structure for requests initiated by the service - */ -struct call_req -{ - struct afb_xreq xreq; - - struct afb_export *export; - - /* the args */ - union { - void (*callback)(void*, int, struct json_object*); - void (*callback_dynapi)(void*, int, struct json_object*, struct afb_dynapi*); - }; - void *closure; - - /* sync */ - struct jobloop *jobloop; - struct json_object *result; - int status; -}; - -/* - * destroys the call_req - */ -static void callreq_destroy(struct afb_xreq *xreq) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - - afb_context_disconnect(&callreq->xreq.context); - json_object_put(callreq->xreq.json); - afb_cred_unref(callreq->xreq.cred); - free(callreq); -} - -static void callreq_reply_async(struct afb_xreq *xreq, int status, json_object *obj) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - if (callreq->callback) - callreq->callback(callreq->closure, status, obj); - json_object_put(obj); -} - -static void callreq_reply_async_dynapi(struct afb_xreq *xreq, int status, json_object *obj) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - if (callreq->callback_dynapi) - callreq->callback_dynapi(callreq->closure, status, obj, to_dynapi(callreq->export)); - json_object_put(obj); -} + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ -static void callreq_sync_leave(struct call_req *callreq) -{ - struct jobloop *jobloop = callreq->jobloop; - - if (jobloop) { - callreq->jobloop = NULL; - jobs_leave(jobloop); - } -} - -static void callreq_reply_sync(struct afb_xreq *xreq, int status, json_object *obj) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - callreq->status = status; - callreq->result = obj; - callreq_sync_leave(callreq); -} - -static void callreq_sync_enter(int signum, void *closure, struct jobloop *jobloop) +static void call_x3( + struct afb_api_x3 *apix3, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure) { - struct call_req *callreq = closure; - - if (!signum) { - callreq->jobloop = jobloop; - afb_xreq_process(&callreq->xreq, callreq->export->apiset); - } else { - callreq->result = afb_msg_json_internal_error(); - callreq->status = -1; - callreq_sync_leave(callreq); - } + struct afb_export *export = from_api_x3(apix3); + return afb_calls_call(export, api, verb, args, callback, closure); } -/* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_async_itf = { - .unref = callreq_destroy, - .reply = callreq_reply_async -}; - -/* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_async_dynapi_itf = { - .unref = callreq_destroy, - .reply = callreq_reply_async_dynapi -}; - -/* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_sync_itf = { - .unref = callreq_destroy, - .reply = callreq_reply_sync -}; - -/* - * create an call_req - */ -static struct call_req *callreq_create( - struct afb_export *export, +static int call_sync_x3( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - const struct afb_xreq_query_itf *itf) -{ - struct call_req *callreq; - size_t lenapi, lenverb; - char *copy; - - /* allocates the request */ - lenapi = 1 + strlen(api); - lenverb = 1 + strlen(verb); - callreq = malloc(lenapi + lenverb + sizeof *callreq); - if (callreq != NULL) { - /* initialises the request */ - afb_xreq_init(&callreq->xreq, itf); - afb_context_init(&callreq->xreq.context, export->session, NULL); - callreq->xreq.context.validated = 1; - copy = (char*)&callreq[1]; - memcpy(copy, api, lenapi); - callreq->xreq.request.api = copy; - copy = ©[lenapi]; - memcpy(copy, verb, lenverb); - callreq->xreq.request.verb = copy; - callreq->xreq.listener = export->listener; - callreq->xreq.json = args; - callreq->export = export; - } - return callreq; + struct json_object **object, + char **error, + char **info) +{ + struct afb_export *export = from_api_x3(apix3); + return afb_calls_call_sync(export, api, verb, args, object, error, info); } -/* - * Initiates a call for the service - */ -static void svc_call( - void *closure, +static void legacy_call_v12( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), - void *cbclosure) + void *closure) { - struct afb_export *export = closure; - struct call_req *callreq; - struct json_object *ierr; - - /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_async_itf); - if (callreq == NULL) { - ERROR("out of memory"); - json_object_put(args); - ierr = afb_msg_json_internal_error(); - if (callback) - callback(cbclosure, -1, ierr); - json_object_put(ierr); - return; - } - - /* initialises the request */ - callreq->jobloop = NULL; - callreq->callback = callback; - callreq->closure = cbclosure; - - /* terminates and frees ressources if needed */ - afb_xreq_process(&callreq->xreq, export->apiset); + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_call_v12(export, api, verb, args, callback, closure); } -static void svc_call_dynapi( - struct afb_dynapi *dynapi, +static void legacy_call_x3( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_dynapi*), - void *cbclosure) -{ - struct afb_export *export = from_dynapi(dynapi); - struct call_req *callreq; - struct json_object *ierr; - - /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_async_dynapi_itf); - if (callreq == NULL) { - ERROR("out of memory"); - json_object_put(args); - ierr = afb_msg_json_internal_error(); - if (callback) - callback(cbclosure, -1, ierr, to_dynapi(export)); - json_object_put(ierr); - return; - } - - /* initialises the request */ - callreq->jobloop = NULL; - callreq->callback_dynapi = callback; - callreq->closure = cbclosure; - - /* terminates and frees ressources if needed */ - afb_xreq_process(&callreq->xreq, export->apiset); + void (*callback)(void*, int, struct json_object*, struct afb_api_x3*), + void *closure) +{ + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_call_v3(export, api, verb, args, callback, closure); } -static int svc_call_sync( - void *closure, +static int legacy_call_sync( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - struct afb_export *export = closure; - struct call_req *callreq; - struct json_object *resu; - int rc; - - /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_sync_itf); - if (callreq == NULL) { - ERROR("out of memory"); - errno = ENOMEM; - json_object_put(args); - resu = afb_msg_json_internal_error(); - rc = -1; - } else { - /* initialises the request */ - callreq->jobloop = NULL; - callreq->callback = NULL; - callreq->result = NULL; - callreq->status = 0; - afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */ - rc = jobs_enter(NULL, 0, callreq_sync_enter, callreq); - if (rc >= 0) - rc = callreq->status; - resu = (rc >= 0 || callreq->result) ? callreq->result : afb_msg_json_internal_error(); - afb_xreq_unhooked_unref(&callreq->xreq); - } - if (result) - *result = resu; - else - json_object_put(resu); - return rc; + struct afb_export *export = from_api_x3(apix3); + return afb_calls_legacy_call_sync(export, api, verb, args, result); } -struct hooked_call -{ - struct afb_export *export; - union { - void (*callback)(void*, int, struct json_object*); - void (*callback_dynapi)(void*, int, struct json_object*, struct afb_dynapi*); - }; - void *cbclosure; -}; - -static void svc_hooked_call_result(void *closure, int status, struct json_object *result) +static void hooked_call_x3( + struct afb_api_x3 *apix3, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_api_x3*), + void *closure) { - struct hooked_call *hc = closure; - afb_hook_svc_call_result(hc->export, status, result); - hc->callback(hc->cbclosure, status, result); - free(hc); + struct afb_export *export = from_api_x3(apix3); + afb_calls_hooked_call(export, api, verb, args, callback, closure); } -static void svc_hooked_call_dynapi_result(void *closure, int status, struct json_object *result, struct afb_dynapi *dynapi) +static int hooked_call_sync_x3( + struct afb_api_x3 *apix3, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info) { - struct hooked_call *hc = closure; - afb_hook_svc_call_result(hc->export, status, result); - hc->callback_dynapi(hc->cbclosure, status, result, dynapi); - free(hc); + struct afb_export *export = from_api_x3(apix3); + return afb_calls_hooked_call_sync(export, api, verb, args, object, error, info); } -static void svc_hooked_call( - void *closure, +static void legacy_hooked_call_v12( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), - void *cbclosure) + void *closure) { - struct afb_export *export = closure; - struct hooked_call *hc; - - if (export->hooksvc & afb_hook_flag_svc_call) - afb_hook_svc_call(export, api, verb, args); - - if (export->hooksvc & afb_hook_flag_svc_call_result) { - hc = malloc(sizeof *hc); - if (!hc) - WARNING("allocation failed"); - else { - hc->export = export; - hc->callback = callback; - hc->cbclosure = cbclosure; - callback = svc_hooked_call_result; - cbclosure = hc; - } - } - svc_call(closure, api, verb, args, callback, cbclosure); + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_hooked_call_v12(export, api, verb, args, callback, closure); } -static void svc_hooked_call_dynapi( - struct afb_dynapi *dynapi, +static void legacy_hooked_call_x3( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_dynapi*), - void *cbclosure) + void (*callback)(void*, int, struct json_object*, struct afb_api_x3*), + void *closure) { - struct afb_export *export = from_dynapi(dynapi); - struct hooked_call *hc; - - if (export->hooksvc & afb_hook_flag_svc_call) - afb_hook_svc_call(export, api, verb, args); - - if (export->hooksvc & afb_hook_flag_svc_call_result) { - hc = malloc(sizeof *hc); - if (!hc) - WARNING("allocation failed"); - else { - hc->export = export; - hc->callback_dynapi = callback; - hc->cbclosure = cbclosure; - callback = svc_hooked_call_dynapi_result; - cbclosure = hc; - } - } - svc_call_dynapi(dynapi, api, verb, args, callback, cbclosure); + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_hooked_call_v3(export, api, verb, args, callback, closure); } -static int svc_hooked_call_sync( - void *closure, +static int legacy_hooked_call_sync( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - struct afb_export *export = closure; - struct json_object *resu; - int rc; - - if (export->hooksvc & afb_hook_flag_svc_callsync) - afb_hook_svc_callsync(export, api, verb, args); - - rc = svc_call_sync(closure, api, verb, args, &resu); - - if (export->hooksvc & afb_hook_flag_svc_callsync_result) - afb_hook_svc_callsync_result(export, rc, resu); - - if (result) - *result = resu; - else - json_object_put(resu); - - return rc; + struct afb_export *export = from_api_x3(apix3); + return afb_calls_legacy_hooked_call_sync(export, api, verb, args, result); } /* the interface for services */ -static const struct afb_service_itf service_itf = { - .call = svc_call, - .call_sync = svc_call_sync +static const struct afb_service_itf_x1 service_itf = { + .call = legacy_call_v12, + .call_sync = legacy_call_sync }; /* the interface for services */ -static const struct afb_service_itf hooked_service_itf = { - .call = svc_hooked_call, - .call_sync = svc_hooked_call_sync +static const struct afb_service_itf_x1 hooked_service_itf = { + .call = legacy_hooked_call_v12, + .call_sync = legacy_hooked_call_sync }; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M D Y N A P I - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ static int api_set_verbs_v2_cb( - struct afb_dynapi *dynapi, + struct afb_api_x3 *api, const struct afb_verb_v2 *verbs) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - if (export->apidyn) { - afb_api_dyn_set_verbs_v2(export->apidyn, verbs); + if (export->unsealed) { + afb_api_v3_set_verbs_v2(export->desc.v3, verbs); return 0; } @@ -829,115 +690,292 @@ static int api_set_verbs_v2_cb( return -1; } +static int api_set_verbs_v3_cb( + struct afb_api_x3 *api, + const struct afb_verb_v3 *verbs) +{ + struct afb_export *export = from_api_x3(api); + + if (!export->unsealed) { + errno = EPERM; + return -1; + } + + afb_api_v3_set_verbs_v3(export->desc.v3, verbs); + return 0; +} + static int api_add_verb_cb( - struct afb_dynapi *dynapi, + struct afb_api_x3 *api, const char *verb, const char *info, - void (*callback)(struct afb_request *request), + void (*callback)(struct afb_req_x2 *req), void *vcbdata, const struct afb_auth *auth, - uint32_t session) + uint32_t session, + int glob) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - if (export->apidyn) - return afb_api_dyn_add_verb(export->apidyn, verb, info, callback, vcbdata, auth, session); + if (!export->unsealed) { + errno = EPERM; + return -1; + } - errno = EPERM; - return -1; + return afb_api_v3_add_verb(export->desc.v3, verb, info, callback, vcbdata, auth, (uint16_t)session, glob); } -static int api_sub_verb_cb( - struct afb_dynapi *dynapi, - const char *verb) +static int api_del_verb_cb( + struct afb_api_x3 *api, + const char *verb, + void **vcbdata) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - if (export->apidyn) - return afb_api_dyn_sub_verb(export->apidyn, verb); + if (!export->unsealed) { + errno = EPERM; + return -1; + } - errno = EPERM; - return -1; + return afb_api_v3_del_verb(export->desc.v3, verb, vcbdata); } static int api_set_on_event_cb( - struct afb_dynapi *dynapi, - void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) + struct afb_api_x3 *api, + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object)) { - struct afb_export *export = from_dynapi(dynapi); - return afb_export_handle_events_vdyn(export, onevent); + struct afb_export *export = from_api_x3(api); + return afb_export_handle_events_v3(export, onevent); } static int api_set_on_init_cb( - struct afb_dynapi *dynapi, - int (*oninit)(struct afb_dynapi *dynapi)) + struct afb_api_x3 *api, + int (*oninit)(struct afb_api_x3 *api)) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - return afb_export_handle_init_vdyn(export, oninit); + return afb_export_handle_init_v3(export, oninit); } static void api_seal_cb( - struct afb_dynapi *dynapi) + struct afb_api_x3 *api) +{ + struct afb_export *export = from_api_x3(api); + + export->unsealed = 0; +} + +static int event_handler_add_cb( + struct afb_api_x3 *api, + const char *pattern, + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*), + void *closure) +{ + struct afb_export *export = from_api_x3(api); + + return afb_export_event_handler_add(export, pattern, callback, closure); +} + +static int event_handler_del_cb( + struct afb_api_x3 *api, + const char *pattern, + void **closure) +{ + struct afb_export *export = from_api_x3(api); + + return afb_export_event_handler_del(export, pattern, closure); +} + +static int class_provide_cb(struct afb_api_x3 *api, const char *name) +{ + struct afb_export *export = from_api_x3(api); + + int rc = 0, rc2; + char *iter, *end, save; + + iter = strdupa(name); + for(;;) { + /* skip any space */ + save = *iter; + while(isspace(save)) + save = *++iter; + if (!save) /* at end? */ + return rc; + + /* search for the end */ + end = iter; + while (save && !isspace(save)) + save = *++end; + *end = 0; + + rc2 = afb_apiset_provide_class(export->declare_set, api->apiname, iter); + if (rc2 < 0) + rc = rc2; + + *end = save; + iter = end; + } +} + +static int class_require_cb(struct afb_api_x3 *api, const char *name) +{ + struct afb_export *export = from_api_x3(api); + + int rc = 0, rc2; + char *iter, *end, save; + + iter = strdupa(name); + for(;;) { + /* skip any space */ + save = *iter; + while(isspace(save)) + save = *++iter; + if (!save) /* at end? */ + return rc; + + /* search for the end */ + end = iter; + while (save && !isspace(save)) + save = *++end; + *end = 0; + + rc2 = afb_apiset_require_class(export->declare_set, api->apiname, iter); + if (rc2 < 0) + rc = rc2; + + *end = save; + iter = end; + } +} + +static int delete_api_cb(struct afb_api_x3 *api) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); + + if (!export->unsealed) { + errno = EPERM; + return -1; + } - export->apidyn = NULL; + afb_export_undeclare(export); + afb_export_unref(export); + return 0; } static int hooked_api_set_verbs_v2_cb( - struct afb_dynapi *dynapi, + struct afb_api_x3 *api, const struct afb_verb_v2 *verbs) { - /* TODO */ - return api_set_verbs_v2_cb(dynapi, verbs); + struct afb_export *export = from_api_x3(api); + int result = api_set_verbs_v2_cb(api, verbs); + return afb_hook_api_api_set_verbs_v2(export, result, verbs); +} + +static int hooked_api_set_verbs_v3_cb( + struct afb_api_x3 *api, + const struct afb_verb_v3 *verbs) +{ + struct afb_export *export = from_api_x3(api); + int result = api_set_verbs_v3_cb(api, verbs); + return afb_hook_api_api_set_verbs_v3(export, result, verbs); } static int hooked_api_add_verb_cb( - struct afb_dynapi *dynapi, + struct afb_api_x3 *api, const char *verb, const char *info, - void (*callback)(struct afb_request *request), + void (*callback)(struct afb_req_x2 *req), void *vcbdata, const struct afb_auth *auth, - uint32_t session) + uint32_t session, + int glob) { - /* TODO */ - return api_add_verb_cb(dynapi, verb, info, callback, vcbdata, auth, session); + struct afb_export *export = from_api_x3(api); + int result = api_add_verb_cb(api, verb, info, callback, vcbdata, auth, session, glob); + return afb_hook_api_api_add_verb(export, result, verb, info, glob); } -static int hooked_api_sub_verb_cb( - struct afb_dynapi *dynapi, - const char *verb) +static int hooked_api_del_verb_cb( + struct afb_api_x3 *api, + const char *verb, + void **vcbdata) { - /* TODO */ - return api_sub_verb_cb(dynapi, verb); + struct afb_export *export = from_api_x3(api); + int result = api_del_verb_cb(api, verb, vcbdata); + return afb_hook_api_api_del_verb(export, result, verb); } static int hooked_api_set_on_event_cb( - struct afb_dynapi *dynapi, - void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) + struct afb_api_x3 *api, + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object)) { - /* TODO */ - return api_set_on_event_cb(dynapi, onevent); + struct afb_export *export = from_api_x3(api); + int result = api_set_on_event_cb(api, onevent); + return afb_hook_api_api_set_on_event(export, result); } static int hooked_api_set_on_init_cb( - struct afb_dynapi *dynapi, - int (*oninit)(struct afb_dynapi *dynapi)) + struct afb_api_x3 *api, + int (*oninit)(struct afb_api_x3 *api)) { - /* TODO */ - return api_set_on_init_cb(dynapi, oninit); + struct afb_export *export = from_api_x3(api); + int result = api_set_on_init_cb(api, oninit); + return afb_hook_api_api_set_on_init(export, result); } static void hooked_api_seal_cb( - struct afb_dynapi *dynapi) + struct afb_api_x3 *api) { - /* TODO */ - api_seal_cb(dynapi); + struct afb_export *export = from_api_x3(api); + afb_hook_api_api_seal(export); + api_seal_cb(api); } -static const struct afb_dynapi_itf dynapi_itf = { +static int hooked_event_handler_add_cb( + struct afb_api_x3 *api, + const char *pattern, + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*), + void *closure) +{ + struct afb_export *export = from_api_x3(api); + int result = event_handler_add_cb(api, pattern, callback, closure); + return afb_hook_api_event_handler_add(export, result, pattern); +} + +static int hooked_event_handler_del_cb( + struct afb_api_x3 *api, + const char *pattern, + void **closure) +{ + struct afb_export *export = from_api_x3(api); + int result = event_handler_del_cb(api, pattern, closure); + return afb_hook_api_event_handler_del(export, result, pattern); +} + +static int hooked_class_provide_cb(struct afb_api_x3 *api, const char *name) +{ + struct afb_export *export = from_api_x3(api); + int result = class_provide_cb(api, name); + return afb_hook_api_class_provide(export, result, name); +} + +static int hooked_class_require_cb(struct afb_api_x3 *api, const char *name) +{ + struct afb_export *export = from_api_x3(api); + int result = class_require_cb(api, name); + return afb_hook_api_class_require(export, result, name); +} + +static int hooked_delete_api_cb(struct afb_api_x3 *api) +{ + struct afb_export *export = afb_export_addref(from_api_x3(api)); + int result = delete_api_cb(api); + result = afb_hook_api_delete_api(export, result); + afb_export_unref(export); + return result; +} + +static const struct afb_api_x3_itf api_x3_itf = { .vverbose = (void*)vverbose_cb, @@ -949,24 +987,35 @@ static const struct afb_dynapi_itf dynapi_itf = { .queue_job = queue_job_cb, .require_api = require_api_cb, - .rename_api = rename_api_cb, + .add_alias = add_alias_cb, .event_broadcast = event_broadcast_cb, - .eventid_make = eventid_make_cb, + .event_make = event_x2_make_cb, - .call = svc_call_dynapi, - .call_sync = svc_call_sync, + .legacy_call = legacy_call_x3, + .legacy_call_sync = legacy_call_sync, .api_new_api = api_new_api_cb, .api_set_verbs_v2 = api_set_verbs_v2_cb, .api_add_verb = api_add_verb_cb, - .api_sub_verb = api_sub_verb_cb, + .api_del_verb = api_del_verb_cb, .api_set_on_event = api_set_on_event_cb, .api_set_on_init = api_set_on_init_cb, .api_seal = api_seal_cb, + .api_set_verbs_v3 = api_set_verbs_v3_cb, + .event_handler_add = event_handler_add_cb, + .event_handler_del = event_handler_del_cb, + + .call = call_x3, + .call_sync = call_sync_x3, + + .class_provide = class_provide_cb, + .class_require = class_require_cb, + + .delete_api = delete_api_cb, }; -static const struct afb_dynapi_itf hooked_dynapi_itf = { +static const struct afb_api_x3_itf hooked_api_x3_itf = { .vverbose = hooked_vverbose_cb, @@ -978,86 +1027,187 @@ static const struct afb_dynapi_itf hooked_dynapi_itf = { .queue_job = hooked_queue_job_cb, .require_api = hooked_require_api_cb, - .rename_api = hooked_rename_api_cb, + .add_alias = hooked_add_alias_cb, .event_broadcast = hooked_event_broadcast_cb, - .eventid_make = hooked_eventid_make_cb, + .event_make = hooked_event_x2_make_cb, - .call = svc_hooked_call_dynapi, - .call_sync = svc_hooked_call_sync, + .legacy_call = legacy_hooked_call_x3, + .legacy_call_sync = legacy_hooked_call_sync, .api_new_api = hooked_api_new_api_cb, .api_set_verbs_v2 = hooked_api_set_verbs_v2_cb, .api_add_verb = hooked_api_add_verb_cb, - .api_sub_verb = hooked_api_sub_verb_cb, + .api_del_verb = hooked_api_del_verb_cb, .api_set_on_event = hooked_api_set_on_event_cb, .api_set_on_init = hooked_api_set_on_init_cb, .api_seal = hooked_api_seal_cb, + .api_set_verbs_v3 = hooked_api_set_verbs_v3_cb, + .event_handler_add = hooked_event_handler_add_cb, + .event_handler_del = hooked_event_handler_del_cb, + + .call = hooked_call_x3, + .call_sync = hooked_call_sync_x3, + + .class_provide = hooked_class_provide_cb, + .class_require = hooked_class_require_cb, + + .delete_api = hooked_delete_api_cb, }; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - F R O M S V C - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + L I S T E N E R S + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ /* * Propagates the event to the service */ -static void export_on_event_v12(void *closure, const char *event, int eventid, struct json_object *object) -{ - struct afb_export *export = closure; +static void listener_of_events(void *closure, const char *event, int eventid, struct json_object *object) +{ + struct event_handler *handler; + struct afb_export *export = from_api_x3(closure); + + /* hook the event before */ + if (export->hooksvc & afb_hook_flag_api_on_event) + afb_hook_api_on_event_before(export, event, eventid, object); + + /* transmit to specific handlers */ + /* search the handler */ + handler = export->event_handlers; + while (handler) { + if (fnmatch(handler->pattern, event, 0)) { + if (!(export->hooksvc & afb_hook_flag_api_on_event_handler)) + handler->callback(handler->closure, event, object, to_api_x3(export)); + else { + afb_hook_api_on_event_handler_before(export, event, eventid, object, handler->pattern); + handler->callback(handler->closure, event, object, to_api_x3(export)); + afb_hook_api_on_event_handler_after(export, event, eventid, object, handler->pattern); + } + } + handler = handler->next; + } + + /* transmit to default handler */ + if (export->on_any_event_v3) + export->on_any_event_v3(to_api_x3(export), event, object); + else if (export->on_any_event_v12) + export->on_any_event_v12(event, object); - if (export->hooksvc & afb_hook_flag_svc_on_event_before) - afb_hook_svc_on_event_before(export, event, eventid, object); - export->on_event.v12(event, object); - if (export->hooksvc & afb_hook_flag_svc_on_event_after) - afb_hook_svc_on_event_after(export, event, eventid, object); + /* hook the event after */ + if (export->hooksvc & afb_hook_flag_api_on_event) + afb_hook_api_on_event_after(export, event, eventid, object); json_object_put(object); } /* the interface for events */ -static const struct afb_evt_itf evt_v12_itf = { - .broadcast = export_on_event_v12, - .push = export_on_event_v12 +static const struct afb_evt_itf evt_itf = { + .broadcast = listener_of_events, + .push = listener_of_events }; -/* - * Propagates the event to the service - */ -static void export_on_event_vdyn(void *closure, const char *event, int eventid, struct json_object *object) +/* ensure an existing listener */ +static int ensure_listener(struct afb_export *export) { - struct afb_export *export = closure; + if (!export->listener) { + export->listener = afb_evt_listener_create(&evt_itf, export); + if (export->listener == NULL) + return -1; + } + return 0; +} - if (export->hooksvc & afb_hook_flag_svc_on_event_before) - afb_hook_svc_on_event_before(export, event, eventid, object); - export->on_event.vdyn(to_dynapi(export), event, object); - if (export->hooksvc & afb_hook_flag_svc_on_event_after) - afb_hook_svc_on_event_after(export, event, eventid, object); - json_object_put(object); +int afb_export_event_handler_add( + struct afb_export *export, + const char *pattern, + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*), + void *closure) +{ + int rc; + struct event_handler *handler, **previous; + + rc = ensure_listener(export); + if (rc < 0) + return rc; + + /* search the handler */ + previous = &export->event_handlers; + while ((handler = *previous) && strcasecmp(handler->pattern, pattern)) + previous = &handler->next; + + /* error if found */ + if (handler) { + ERROR("[API %s] event handler %s already exists", export->api.apiname, pattern); + errno = EEXIST; + return -1; + } + + /* create the event */ + handler = malloc(strlen(pattern) + strlen(pattern)); + if (!handler) { + ERROR("[API %s] can't allocate event handler %s", export->api.apiname, pattern); + errno = ENOMEM; + return -1; + } + + /* init and record */ + handler->next = NULL; + handler->callback = callback; + handler->closure = closure; + strcpy(handler->pattern, pattern); + export->event_handlers = handler; + + return 0; } -/* the interface for events */ -static const struct afb_evt_itf evt_vdyn_itf = { - .broadcast = export_on_event_vdyn, - .push = export_on_event_vdyn -}; +int afb_export_event_handler_del( + struct afb_export *export, + const char *pattern, + void **closure) +{ + struct event_handler *handler, **previous; + + /* search the handler */ + previous = &export->event_handlers; + while ((handler = *previous) && strcasecmp(handler->pattern, pattern)) + previous = &handler->next; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* + /* error if found */ + if (!handler) { + ERROR("[API %s] event handler %s already exists", export->api.apiname, pattern); + errno = ENOENT; + return -1; + } + + /* remove the found event */ + if (closure) + *closure = handler->closure; + + *previous = handler->next; + free(handler); + return 0; +} + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** M E R G E D - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ -static struct afb_export *create(struct afb_apiset *apiset, const char *apiname, enum afb_api_version version) +static struct afb_export *create( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + enum afb_api_version version) { struct afb_export *export; @@ -1067,96 +1217,179 @@ static struct afb_export *create(struct afb_apiset *apiset, const char *apiname, if (common_session == NULL) return NULL; } - export = calloc(1, sizeof *export); + export = calloc(1, sizeof *export + strlen(apiname)); if (!export) errno = ENOMEM; else { - memset(export, 0, sizeof *export); - export->apiname = strdup(apiname); - export->dynapi.apiname = export->apiname; + export->refcount = 1; + strcpy(export->name, apiname); + export->api.apiname = export->name; export->version = version; export->state = Api_State_Pre_Init; export->session = afb_session_addref(common_session); - export->apiset = afb_apiset_addref(apiset); + export->declare_set = afb_apiset_addref(declare_set); + export->call_set = afb_apiset_addref(call_set); } return export; } +struct afb_export *afb_export_addref(struct afb_export *export) +{ + if (export) + __atomic_add_fetch(&export->refcount, 1, __ATOMIC_RELAXED); + return export; +} + +void afb_export_unref(struct afb_export *export) +{ + if (export && !__atomic_sub_fetch(&export->refcount, 1, __ATOMIC_RELAXED)) + afb_export_destroy(export); +} + void afb_export_destroy(struct afb_export *export) { + struct event_handler *handler; + if (export) { + while ((handler = export->event_handlers)) { + export->event_handlers = handler->next; + free(handler); + } if (export->listener != NULL) afb_evt_listener_unref(export->listener); afb_session_unref(export->session); - afb_apiset_unref(export->apiset); - free(export->apiname); + afb_apiset_unref(export->declare_set); + afb_apiset_unref(export->call_set); + if (export->api.apiname != export->name) + free((void*)export->api.apiname); free(export); } } -struct afb_export *afb_export_create_v1(struct afb_apiset *apiset, const char *apiname, int (*init)(struct afb_service), void (*onevent)(const char*, struct json_object*)) +struct afb_export *afb_export_create_none_for_path( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *path, + int (*creator)(void*, struct afb_api_x3*), + void *closure) { - struct afb_export *export = create(apiset, apiname, Api_Version_1); + struct afb_export *export = create(declare_set, call_set, path, Api_Version_None); + if (export) { + afb_export_logmask_set(export, logmask); + afb_export_update_hooks(export); + if (creator && creator(closure, to_api_x3(export)) < 0) { + afb_export_unref(export); + export = NULL; + } + } + return export; +} + +#if defined(WITH_LEGACY_BINDING_V1) +struct afb_export *afb_export_create_v1( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + int (*init)(struct afb_service_x1), + void (*onevent)(const char*, struct json_object*)) +{ + struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_1); if (export) { export->init.v1 = init; - export->on_event.v12 = onevent; + export->on_any_event_v12 = onevent; export->export.v1.mode = AFB_MODE_LOCAL; - export->export.v1.daemon.closure = export; - afb_export_verbosity_set(export, verbosity); - afb_export_update_hook(export); + export->export.v1.daemon.closure = to_api_x3(export); + afb_export_logmask_set(export, logmask); + afb_export_update_hooks(export); } return export; } +#endif -struct afb_export *afb_export_create_v2(struct afb_apiset *apiset, const char *apiname, struct afb_binding_data_v2 *data, int (*init)(), void (*onevent)(const char*, struct json_object*)) +struct afb_export *afb_export_create_v2( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + const struct afb_binding_v2 *binding, + struct afb_binding_data_v2 *data, + int (*init)(), + void (*onevent)(const char*, struct json_object*)) { - struct afb_export *export = create(apiset, apiname, Api_Version_2); + struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_2); if (export) { export->init.v2 = init; - export->on_event.v12 = onevent; + export->on_any_event_v12 = onevent; + export->desc.v2 = binding; export->export.v2 = data; - data->daemon.closure = export; - data->service.closure = export; - afb_export_verbosity_set(export, verbosity); - afb_export_update_hook(export); + data->daemon.closure = to_api_x3(export); + data->service.closure = to_api_x3(export); + afb_export_logmask_set(export, logmask); + afb_export_update_hooks(export); } return export; } -struct afb_export *afb_export_create_vdyn(struct afb_apiset *apiset, const char *apiname, struct afb_api_dyn *apidyn) +struct afb_export *afb_export_create_v3(struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + struct afb_api_v3 *apiv3) { - struct afb_export *export = create(apiset, apiname, Api_Version_Dyn); + struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_3); if (export) { - export->apidyn = apidyn; - afb_export_verbosity_set(export, verbosity); - afb_export_update_hook(export); + export->unsealed = 1; + export->desc.v3 = apiv3; + afb_export_logmask_set(export, logmask); + afb_export_update_hooks(export); } return export; } -void afb_export_rename(struct afb_export *export, const char *apiname) +int afb_export_add_alias(struct afb_export *export, const char *apiname, const char *aliasname) +{ + return afb_apiset_add_alias(export->declare_set, apiname ?: export->api.apiname, aliasname); +} + +int afb_export_rename(struct afb_export *export, const char *apiname) { - free(export->apiname); - export->apiname = strdup(apiname); - export->dynapi.apiname = export->apiname; - afb_export_update_hook(export); + char *name; + + if (export->declared) { + errno = EBUSY; + return -1; + } + + /* copy the name locally */ + name = strdup(apiname); + if (!name) { + errno = ENOMEM; + return -1; + } + + if (export->api.apiname != export->name) + free((void*)export->api.apiname); + export->api.apiname = name; + + afb_export_update_hooks(export); + return 0; } const char *afb_export_apiname(const struct afb_export *export) { - return export->apiname; + return export->api.apiname; } -void afb_export_update_hook(struct afb_export *export) +void afb_export_update_hooks(struct afb_export *export) { - export->hookditf = afb_hook_flags_ditf(export->apiname); - export->hooksvc = afb_hook_flags_svc(export->apiname); - export->dynapi.itf = export->hookditf|export->hooksvc ? &hooked_dynapi_itf : &dynapi_itf; + export->hookditf = afb_hook_flags_api(export->api.apiname); + export->hooksvc = afb_hook_flags_api(export->api.apiname); + export->api.itf = export->hookditf|export->hooksvc ? &hooked_api_x3_itf : &api_x3_itf; switch (export->version) { +#if defined(WITH_LEGACY_BINDING_V1) case Api_Version_1: export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf; break; +#endif case Api_Version_2: export->export.v2->daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf; export->export.v2->service.itf = export->hooksvc ? &hooked_service_itf : &service_itf; @@ -1164,11 +1397,6 @@ void afb_export_update_hook(struct afb_export *export) } } -struct afb_binding_interface_v1 *afb_export_get_interface_v1(struct afb_export *export) -{ - return export->version == Api_Version_1 ? &export->export.v1 : NULL; -} - int afb_export_unshare_session(struct afb_export *export) { if (export->session == common_session) { @@ -1183,126 +1411,107 @@ int afb_export_unshare_session(struct afb_export *export) return 0; } -void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset) -{ - struct afb_apiset *prvset = export->apiset; - export->apiset = afb_apiset_addref(apiset); - afb_apiset_unref(prvset); -} - -struct afb_apiset *afb_export_get_apiset(struct afb_export *export) -{ - return export->apiset; -} - int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object)) { /* check version */ switch (export->version) { - case Api_Version_1: case Api_Version_2: break; +#if defined(WITH_LEGACY_BINDING_V1) + case Api_Version_1: +#endif + case Api_Version_2: + break; default: - ERROR("invalid version 12 for API %s", export->apiname); + ERROR("invalid version 12 for API %s", export->api.apiname); errno = EINVAL; return -1; } - /* set the event handler */ - if (!on_event) { - if (export->listener) { - afb_evt_listener_unref(export->listener); - export->listener = NULL; - } - export->on_event.v12 = on_event; - } else { - export->on_event.v12 = on_event; - if (!export->listener) { - export->listener = afb_evt_listener_create(&evt_v12_itf, export); - if (export->listener == NULL) - return -1; - } - } - return 0; + export->on_any_event_v12 = on_event; + return ensure_listener(export); } -int afb_export_handle_events_vdyn(struct afb_export *export, void (*on_event)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) +int afb_export_handle_events_v3(struct afb_export *export, void (*on_event)(struct afb_api_x3 *api, const char *event, struct json_object *object)) { /* check version */ switch (export->version) { - case Api_Version_Dyn: break; + case Api_Version_3: break; default: - ERROR("invalid version Dyn for API %s", export->apiname); + ERROR("invalid version Dyn for API %s", export->api.apiname); errno = EINVAL; return -1; } - /* set the event handler */ - if (!on_event) { - if (export->listener) { - afb_evt_listener_unref(export->listener); - export->listener = NULL; - } - export->on_event.vdyn = on_event; - } else { - export->on_event.vdyn = on_event; - if (!export->listener) { - export->listener = afb_evt_listener_create(&evt_vdyn_itf, export); - if (export->listener == NULL) - return -1; - } - } - return 0; + export->on_any_event_v3 = on_event; + return ensure_listener(export); } -int afb_export_handle_init_vdyn(struct afb_export *export, int (*oninit)(struct afb_dynapi *dynapi)) +int afb_export_handle_init_v3(struct afb_export *export, int (*oninit)(struct afb_api_x3 *api)) { if (export->state != Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_dynapi_on_init', must be in PreInit", export->apiname); + ERROR("[API %s] Bad call to 'afb_api_x3_on_init', must be in PreInit", export->api.apiname); errno = EINVAL; return -1; } - export->init.vdyn = oninit; + export->init.v3 = oninit; return 0; } +#if defined(WITH_LEGACY_BINDING_V1) /* * Starts a new service (v1) */ struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*)) { - return regfun(&export->export.v1); + return export->desc.v1 = regfun(&export->export.v1); } +#endif -int afb_export_preinit_vdyn(struct afb_export *export, int (*preinit)(void*, struct afb_dynapi*), void *closure) +int afb_export_preinit_x3( + struct afb_export *export, + int (*preinit)(void*, struct afb_api_x3*), + void *closure) { - return preinit(closure, to_dynapi(export)); + return preinit(closure, to_api_x3(export)); } -int afb_export_verbosity_get(const struct afb_export *export) +int afb_export_logmask_get(const struct afb_export *export) { - return export->dynapi.verbosity; + return export->api.logmask; } -void afb_export_verbosity_set(struct afb_export *export, int level) +void afb_export_logmask_set(struct afb_export *export, int mask) { - export->dynapi.verbosity = level; + export->api.logmask = mask; switch (export->version) { - case Api_Version_1: export->export.v1.verbosity = level; break; - case Api_Version_2: export->export.v2->verbosity = level; break; +#if defined(WITH_LEGACY_BINDING_V1) + case Api_Version_1: export->export.v1.verbosity = verbosity_from_mask(mask); break; +#endif + case Api_Version_2: export->export.v2->verbosity = verbosity_from_mask(mask); break; } } -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +void *afb_export_userdata_get(const struct afb_export *export) +{ + return export->api.userdata; +} + +void afb_export_userdata_set(struct afb_export *export, void *data) +{ + export->api.userdata = data; +} + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** N E W - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ -int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset) +int afb_export_start(struct afb_export *export, int share_session, int onneed) { int rc; @@ -1313,7 +1522,7 @@ int afb_export_start(struct afb_export *export, int share_session, int onneed, s goto done; /* already started: it is an error */ - ERROR("Service of API %s already started", export->apiname); + ERROR("Service of API %s already started", export->api.apiname); return -1; } @@ -1321,49 +1530,59 @@ int afb_export_start(struct afb_export *export, int share_session, int onneed, s if (!share_session) { rc = afb_export_unshare_session(export); if (rc < 0) { - ERROR("Can't unshare the session for %s", export->apiname); + ERROR("Can't unshare the session for %s", export->api.apiname); return -1; } } /* set event handling */ switch (export->version) { +#if defined(WITH_LEGACY_BINDING_V1) case Api_Version_1: +#endif case Api_Version_2: - rc = afb_export_handle_events_v12(export, export->on_event.v12); + if (export->on_any_event_v12) + rc = afb_export_handle_events_v12(export, export->on_any_event_v12); break; default: rc = 0; break; } if (rc < 0) { - ERROR("Can't set event handler for %s", export->apiname); + ERROR("Can't set event handler for %s", export->api.apiname); return -1; } /* Starts the service */ - if (export->hooksvc & afb_hook_flag_svc_start_before) - afb_hook_svc_start_before(export); + if (export->hooksvc & afb_hook_flag_api_start) + afb_hook_api_start_before(export); + export->state = Api_State_Init; switch (export->version) { +#if defined(WITH_LEGACY_BINDING_V1) case Api_Version_1: - rc = export->init.v1 ? export->init.v1((struct afb_service){ .itf = &hooked_service_itf, .closure = export }) : 0; + rc = export->init.v1 ? export->init.v1((struct afb_service_x1){ .itf = &hooked_service_itf, .closure = to_api_x3(export) }) : 0; break; +#endif case Api_Version_2: rc = export->init.v2 ? export->init.v2() : 0; break; - case Api_Version_Dyn: - rc = export->init.vdyn ? export->init.vdyn(to_dynapi(export)) : 0; + case Api_Version_3: + rc = export->init.v3 ? export->init.v3(to_api_x3(export)) : 0; break; default: + errno = EINVAL; + rc = -1; break; } export->state = Api_State_Run; - if (export->hooksvc & afb_hook_flag_svc_start_after) - afb_hook_svc_start_after(export, rc); + + if (export->hooksvc & afb_hook_flag_api_start) + afb_hook_api_start_after(export, rc); + if (rc < 0) { /* initialisation error */ - ERROR("Initialisation of service API %s failed (%d): %m", export->apiname, rc); + ERROR("Initialisation of service API %s failed (%d): %m", export->api.apiname, rc); return rc; } @@ -1371,3 +1590,154 @@ done: return 0; } +static void api_call_cb(void *closure, struct afb_xreq *xreq) +{ + struct afb_export *export = closure; + + xreq->request.api = to_api_x3(export); + + switch (export->version) { +#if defined(WITH_LEGACY_BINDING_V1) + case Api_Version_1: + afb_api_so_v1_process_call(export->desc.v1, xreq); + break; +#endif + case Api_Version_2: + afb_api_so_v2_process_call(export->desc.v2, xreq); + break; + case Api_Version_3: + afb_api_v3_process_call(export->desc.v3, xreq); + break; + default: + afb_xreq_reply(xreq, NULL, "bad-api-type", NULL); + break; + } +} + +static struct json_object *api_describe_cb(void *closure) +{ + struct afb_export *export = closure; + struct json_object *result; + + switch (export->version) { +#if defined(WITH_LEGACY_BINDING_V1) + case Api_Version_1: + result = afb_api_so_v1_make_description_openAPIv3(export->desc.v1, export->api.apiname); + break; +#endif + case Api_Version_2: + result = afb_api_so_v2_make_description_openAPIv3(export->desc.v2, export->api.apiname); + break; + case Api_Version_3: + result = afb_api_v3_make_description_openAPIv3(export->desc.v3, export->api.apiname); + break; + default: + result = NULL; + break; + } + return result; +} + +static int api_service_start_cb(void *closure, int share_session, int onneed) +{ + struct afb_export *export = closure; + + return afb_export_start(export, share_session, onneed); +} + +static void api_update_hooks_cb(void *closure) +{ + struct afb_export *export = closure; + + afb_export_update_hooks(export); +} + +static int api_get_logmask_cb(void *closure) +{ + struct afb_export *export = closure; + + return afb_export_logmask_get(export); +} + +static void api_set_logmask_cb(void *closure, int level) +{ + struct afb_export *export = closure; + + afb_export_logmask_set(export, level); +} + +static void api_unref_cb(void *closure) +{ + struct afb_export *export = closure; + + afb_export_unref(export); +} + +static struct afb_api_itf export_api_itf = +{ + .call = api_call_cb, + .service_start = api_service_start_cb, + .update_hooks = api_update_hooks_cb, + .get_logmask = api_get_logmask_cb, + .set_logmask = api_set_logmask_cb, + .describe = api_describe_cb, + .unref = api_unref_cb +}; + +int afb_export_declare(struct afb_export *export, + int noconcurrency) +{ + int rc; + struct afb_api_item afb_api; + + if (export->declared) + rc = 0; + else { + /* init the record structure */ + afb_api.closure = afb_export_addref(export); + afb_api.itf = &export_api_itf; + afb_api.group = noconcurrency ? export : NULL; + + /* records the binding */ + rc = afb_apiset_add(export->declare_set, export->api.apiname, afb_api); + if (rc >= 0) + export->declared = 1; + else { + ERROR("can't declare export %s to set %s, ABORTING it!", + export->api.apiname, + afb_apiset_name(export->declare_set)); + afb_export_addref(export); + } + } + + return rc; +} + +void afb_export_undeclare(struct afb_export *export) +{ + if (export->declared) { + export->declared = 0; + afb_apiset_del(export->declare_set, export->api.apiname); + } +} + +int afb_export_subscribe(struct afb_export *export, struct afb_event_x2 *event) +{ + return afb_evt_event_x2_add_watch(export->listener, event); +} + +int afb_export_unsubscribe(struct afb_export *export, struct afb_event_x2 *event) +{ + return afb_evt_event_x2_remove_watch(export->listener, event); +} + +void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq) +{ + afb_xreq_process(xreq, export->call_set); +} + +void afb_export_context_init(struct afb_export *export, struct afb_context *context) +{ + afb_context_init(context, export->session, NULL); +} + diff --git a/src/afb-export.h b/src/afb-export.h index 5acca207..c9046be8 100644 --- a/src/afb-export.h +++ b/src/afb-export.h @@ -21,36 +21,111 @@ struct json_object; struct afb_export; struct afb_apiset; -struct afb_api_dyn; +struct afb_context; +struct afb_xreq; -struct afb_service; +struct afb_binding_v2; struct afb_binding_data_v2; -struct afb_binding_interface_v1; -struct afb_dynapi; +struct afb_api_v3; +struct afb_api_x3; +struct afb_event_x2; + +extern struct afb_export *afb_export_create_none_for_path( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *path, + int (*creator)(void*, struct afb_api_x3*), + void *closure); + +extern struct afb_export *afb_export_create_v2( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + const struct afb_binding_v2 *binding, + struct afb_binding_data_v2 *data, + int (*init)(), + void (*onevent)(const char*, struct json_object*)); -extern struct afb_export *afb_export_create_v1(struct afb_apiset *apiset, const char *apiname, int (*init)(struct afb_service), void (*onevent)(const char*, struct json_object*)); -extern struct afb_export *afb_export_create_v2(struct afb_apiset *apiset, const char *apiname, struct afb_binding_data_v2 *data, int (*init)(), void (*onevent)(const char*, struct json_object*)); -extern struct afb_export *afb_export_create_vdyn(struct afb_apiset *apiset, const char *apiname, struct afb_api_dyn *dynapi); +extern struct afb_export *afb_export_create_v3(struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + struct afb_api_v3 *api); + +extern struct afb_export *afb_export_addref(struct afb_export *export); +extern void afb_export_unref(struct afb_export *export); extern void afb_export_destroy(struct afb_export *export); +extern int afb_export_declare(struct afb_export *export, int noconcurrency); +extern void afb_export_undeclare(struct afb_export *export); + extern const char *afb_export_apiname(const struct afb_export *export); -extern void afb_export_rename(struct afb_export *export, const char *apiname); -extern void afb_export_update_hook(struct afb_export *export); +extern int afb_export_add_alias(struct afb_export *export, const char *apiname, const char *aliasname); +extern int afb_export_rename(struct afb_export *export, const char *apiname); +extern void afb_export_update_hooks(struct afb_export *export); extern int afb_export_unshare_session(struct afb_export *export); -extern void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset); -extern struct afb_apiset *afb_export_get_apiset(struct afb_export *export); - -extern struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*)); -extern int afb_export_preinit_vdyn(struct afb_export *export, int (*preinit)(void*, struct afb_dynapi*), void *closure); -extern int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object)); -extern int afb_export_handle_events_vdyn(struct afb_export *export, void (*on_event)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)); -extern int afb_export_handle_init_vdyn(struct afb_export *export, int (*oninit)(struct afb_dynapi *dynapi)); +extern int afb_export_preinit_x3( + struct afb_export *export, + int (*preinit)(void *,struct afb_api_x3*), + void *closure); + +extern int afb_export_handle_events_v12( + struct afb_export *export, + void (*on_event)(const char *event, struct json_object *object)); + + +extern int afb_export_handle_events_v3( + struct afb_export *export, + void (*on_event)(struct afb_api_x3 *api, const char *event, struct json_object *object)); + + +extern int afb_export_handle_init_v3( + struct afb_export *export, + int (*oninit)(struct afb_api_x3 *api)); + +extern int afb_export_start(struct afb_export *export, int share_session, int onneed); + +extern int afb_export_logmask_get(const struct afb_export *export); +extern void afb_export_logmask_set(struct afb_export *export, int mask); + +extern void *afb_export_userdata_get(const struct afb_export *export); +extern void afb_export_userdata_set(struct afb_export *export, void *data); + +extern int afb_export_event_handler_add( + struct afb_export *export, + const char *pattern, + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*), + void *closure); + +extern int afb_export_event_handler_del( + struct afb_export *export, + const char *pattern, + void **closure); + +extern int afb_export_subscribe(struct afb_export *export, struct afb_event_x2 *event); +extern int afb_export_unsubscribe(struct afb_export *export, struct afb_event_x2 *event); +extern void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq); +extern void afb_export_context_init(struct afb_export *export, struct afb_context *context); +extern struct afb_export *afb_export_from_api_x3(struct afb_api_x3 *api); +extern struct afb_api_x3 *afb_export_to_api_x3(struct afb_export *export); + +#if defined(WITH_LEGACY_BINDING_V1) + +struct afb_service_x1; +struct afb_binding_interface_v1; + +extern struct afb_export *afb_export_create_v1( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + int (*init)(struct afb_service_x1), + void (*onevent)(const char*, struct json_object*)); -extern int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset); +extern struct afb_binding_v1 *afb_export_register_v1( + struct afb_export *export, + struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*)); -extern int afb_export_verbosity_get(const struct afb_export *export); -extern void afb_export_verbosity_set(struct afb_export *export, int level); +#endif diff --git a/src/afb-hook.c b/src/afb-hook.c index f5868b18..75e8a691 100644 --- a/src/afb-hook.c +++ b/src/afb-hook.c @@ -27,8 +27,8 @@ #include <json-c/json.h> -#include <afb/afb-req.h> -#include <afb/afb-event.h> +#include <afb/afb-req-x1.h> +#include <afb/afb-event-x2.h> #include "afb-context.h" #include "afb-hook.h" @@ -38,10 +38,19 @@ #include "afb-export.h" #include "afb-evt.h" #include "afb-api.h" +#include "afb-msg-json.h" #include "verbose.h" #include <fnmatch.h> -#define MATCH(pattern,string) (!fnmatch((pattern),(string),FNM_CASEFOLD|FNM_EXTMATCH)) +#define MATCH(pattern,string) (\ + pattern \ + ? !fnmatch((pattern),(string),FNM_CASEFOLD|FNM_EXTMATCH|FNM_PERIOD) \ + : (string)[0] != '.') + +#define MATCH_API(pattern,string) MATCH(pattern,string) +#define MATCH_VERB(pattern,string) MATCH(pattern,string) +#define MATCH_EVENT(pattern,string) MATCH(pattern,string) +#define MATCH_SESSION(pattern,string) MATCH(pattern,string) /** * Definition of a hook for xreq @@ -60,24 +69,12 @@ struct afb_hook_xreq { /** * Definition of a hook for export */ -struct afb_hook_ditf { - struct afb_hook_ditf *next; /**< next hook */ +struct afb_hook_api { + struct afb_hook_api *next; /**< next hook */ unsigned refcount; /**< reference count */ unsigned flags; /**< hook flags */ char *api; /**< api hooked or NULL for any */ - struct afb_hook_ditf_itf *itf; /**< interface of hook */ - void *closure; /**< closure for callbacks */ -}; - -/** - * Definition of a hook for export - */ -struct afb_hook_svc { - struct afb_hook_svc *next; /**< next hook */ - unsigned refcount; /**< reference count */ - unsigned flags; /**< hook flags */ - char *api; /**< api hooked or NULL for any */ - struct afb_hook_svc_itf *itf; /**< interface of hook */ + struct afb_hook_api_itf *itf; /**< interface of hook */ void *closure; /**< closure for callbacks */ }; @@ -123,10 +120,7 @@ static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; static struct afb_hook_xreq *list_of_xreq_hooks = NULL; /* list of hooks for export */ -static struct afb_hook_ditf *list_of_ditf_hooks = NULL; - -/* list of hooks for export */ -static struct afb_hook_svc *list_of_svc_hooks = NULL; +static struct afb_hook_api *list_of_api_hooks = NULL; /* list of hooks for evt */ static struct afb_hook_evt *list_of_evt_hooks = NULL; @@ -225,11 +219,11 @@ static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...) { va_list ap; va_start(ap, format); - _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->request.api, xreq->request.verb); + _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->request.called_api, xreq->request.called_verb); va_end(ap); } -static void hook_xreq_begin_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_begin_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { if (!xreq->cred) _hook_xreq_(xreq, "BEGIN"); @@ -244,92 +238,87 @@ static void hook_xreq_begin_default_cb(void *closure, const struct afb_hookid *h ); } -static void hook_xreq_end_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_end_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { _hook_xreq_(xreq, "END"); } -static void hook_xreq_json_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj) +static void hook_xreq_json_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj) { _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj)); } -static void hook_xreq_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg) +static void hook_xreq_get_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg) { _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path); } -static void hook_xreq_success_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info) -{ - _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info); -} - -static void hook_xreq_fail_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info) +static void hook_xreq_reply_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { - _hook_xreq_(xreq, "fail(%s, %s)", status, info); + _hook_xreq_(xreq, "reply[%s](%s, %s)", error?:"success", json_object_to_json_string(obj), info); } -static void hook_xreq_context_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value) +static void hook_xreq_legacy_context_get_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value) { _hook_xreq_(xreq, "context_get() -> %p", value); } -static void hook_xreq_context_set_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*)) +static void hook_xreq_legacy_context_set_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*)) { _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value); } -static void hook_xreq_addref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_addref_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { _hook_xreq_(xreq, "addref()"); } -static void hook_xreq_unref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_unref_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { _hook_xreq_(xreq, "unref()"); } -static void hook_xreq_session_close_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_session_close_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { _hook_xreq_(xreq, "session_close()"); } -static void hook_xreq_session_set_LOA_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result) +static void hook_xreq_session_set_LOA_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result) { _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result); } -static void hook_xreq_subscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +static void hook_xreq_subscribe_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result) { - _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), result); + _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_event_x2_fullname(event_x2), afb_evt_event_x2_id(event_x2), result); } -static void hook_xreq_unsubscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +static void hook_xreq_unsubscribe_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result) { - _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), result); + _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_event_x2_fullname(event_x2), afb_evt_event_x2_id(event_x2), result); } -static void hook_xreq_subcall_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) +static void hook_xreq_subcall_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) { _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); } -static void hook_xreq_subcall_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) +static void hook_xreq_subcall_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { - _hook_xreq_(xreq, " ...subcall... -> %d: %s", status, json_object_to_json_string(result)); + _hook_xreq_(xreq, " ...subcall... [%s] -> %s (%s)", error?:"success", json_object_to_json_string(object), info?:""); } -static void hook_xreq_subcallsync_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) +static void hook_xreq_subcallsync_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) { _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); } -static void hook_xreq_subcallsync_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) +static void hook_xreq_subcallsync_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info) { - _hook_xreq_(xreq, " ...subcallsync... -> %d: %s", status, json_object_to_json_string(result)); + _hook_xreq_(xreq, " ...subcallsync... %d [%s] -> %s (%s)", status, error?:"success", json_object_to_json_string(object), info?:""); } -static void hook_xreq_vverbose_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args) +static void hook_xreq_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args) { int len; char *msg; @@ -340,105 +329,99 @@ static void hook_xreq_vverbose_default_cb(void *closure, const struct afb_hookid va_end(ap); if (len < 0) - _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt); + _hook_xreq_(xreq, "vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, func, fmt); else { - _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg); + _hook_xreq_(xreq, "vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, func, msg); free(msg); } } -static void hook_xreq_store_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq) +static void hook_xreq_legacy_store_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq) { _hook_xreq_(xreq, "store() -> %p", sreq); } -static void hook_xreq_unstore_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_legacy_unstore_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { _hook_xreq_(xreq, "unstore()"); } -static void hook_xreq_subcall_req_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) -{ - _hook_xreq_(xreq, "subcall_req(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); -} - -static void hook_xreq_subcall_req_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) -{ - _hook_xreq_(xreq, " ...subcall_req... -> %d: %s", status, json_object_to_json_string(result)); -} - -static void hook_xreq_has_permission_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result) +static void hook_xreq_has_permission_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result) { _hook_xreq_(xreq, "has_permission(%s) -> %d", permission, result); } -static void hook_xreq_get_application_id_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result) +static void hook_xreq_get_application_id_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result) { _hook_xreq_(xreq, "get_application_id() -> %s", result); } -static void hook_xreq_context_make_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result) +static void hook_xreq_context_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result) { _hook_xreq_(xreq, "context_make(replace=%s, %p, %p, %p) -> %p", replace?"yes":"no", create_value, free_value, create_closure, result); } -static void hook_xreq_get_uid_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result) +static void hook_xreq_get_uid_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result) { _hook_xreq_(xreq, "get_uid() -> %d", result); } +static void hook_xreq_get_client_info_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *result) +{ + _hook_xreq_(xreq, "get_client_info() -> %s", json_object_to_json_string(result)); +} + static struct afb_hook_xreq_itf hook_xreq_default_itf = { - .hook_xreq_begin = hook_xreq_begin_default_cb, - .hook_xreq_end = hook_xreq_end_default_cb, - .hook_xreq_json = hook_xreq_json_default_cb, - .hook_xreq_get = hook_xreq_get_default_cb, - .hook_xreq_success = hook_xreq_success_default_cb, - .hook_xreq_fail = hook_xreq_fail_default_cb, - .hook_xreq_context_get = hook_xreq_context_get_default_cb, - .hook_xreq_context_set = hook_xreq_context_set_default_cb, - .hook_xreq_addref = hook_xreq_addref_default_cb, - .hook_xreq_unref = hook_xreq_unref_default_cb, - .hook_xreq_session_close = hook_xreq_session_close_default_cb, - .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_default_cb, - .hook_xreq_subscribe = hook_xreq_subscribe_default_cb, - .hook_xreq_unsubscribe = hook_xreq_unsubscribe_default_cb, - .hook_xreq_subcall = hook_xreq_subcall_default_cb, - .hook_xreq_subcall_result = hook_xreq_subcall_result_default_cb, - .hook_xreq_subcallsync = hook_xreq_subcallsync_default_cb, - .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb, - .hook_xreq_vverbose = hook_xreq_vverbose_default_cb, - .hook_xreq_store = hook_xreq_store_default_cb, - .hook_xreq_unstore = hook_xreq_unstore_default_cb, - .hook_xreq_subcall_req = hook_xreq_subcall_req_default_cb, - .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result_default_cb, - .hook_xreq_has_permission = hook_xreq_has_permission_default_cb, - .hook_xreq_get_application_id = hook_xreq_get_application_id_default_cb, - .hook_xreq_context_make = hook_xreq_context_make_default_cb, - .hook_xreq_get_uid = hook_xreq_get_uid_default_cb, + .hook_xreq_begin = hook_xreq_begin_cb, + .hook_xreq_end = hook_xreq_end_cb, + .hook_xreq_json = hook_xreq_json_cb, + .hook_xreq_get = hook_xreq_get_cb, + .hook_xreq_reply = hook_xreq_reply_cb, + .hook_xreq_legacy_context_get = hook_xreq_legacy_context_get_cb, + .hook_xreq_legacy_context_set = hook_xreq_legacy_context_set_cb, + .hook_xreq_addref = hook_xreq_addref_cb, + .hook_xreq_unref = hook_xreq_unref_cb, + .hook_xreq_session_close = hook_xreq_session_close_cb, + .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_cb, + .hook_xreq_subscribe = hook_xreq_subscribe_cb, + .hook_xreq_unsubscribe = hook_xreq_unsubscribe_cb, + .hook_xreq_subcall = hook_xreq_subcall_cb, + .hook_xreq_subcall_result = hook_xreq_subcall_result_cb, + .hook_xreq_subcallsync = hook_xreq_subcallsync_cb, + .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_cb, + .hook_xreq_vverbose = hook_xreq_vverbose_cb, + .hook_xreq_legacy_store = hook_xreq_legacy_store_cb, + .hook_xreq_legacy_unstore = hook_xreq_legacy_unstore_cb, + .hook_xreq_has_permission = hook_xreq_has_permission_cb, + .hook_xreq_get_application_id = hook_xreq_get_application_id_cb, + .hook_xreq_context_make = hook_xreq_context_make_cb, + .hook_xreq_get_uid = hook_xreq_get_uid_cb, + .hook_xreq_get_client_info = hook_xreq_get_client_info_cb, }; /****************************************************************************** * section: hooks for tracing requests *****************************************************************************/ -#define _HOOK_XREQ_(what,...) \ +#define _HOOK_XREQ_2_(flag,func,...) \ struct afb_hook_xreq *hook; \ struct afb_hookid hookid; \ pthread_rwlock_rdlock(&rwlock); \ init_hookid(&hookid); \ hook = list_of_xreq_hooks; \ while (hook) { \ - if (hook->itf->hook_xreq_##what \ - && (hook->flags & afb_hook_flag_req_##what) != 0 \ + if (hook->itf->hook_xreq_##func \ + && (hook->flags & afb_hook_flag_req_##flag) != 0 \ && (!hook->session || hook->session == xreq->context.session) \ - && (!hook->api || !strcasecmp(hook->api, xreq->request.api)) \ - && (!hook->verb || !strcasecmp(hook->verb, xreq->request.verb))) { \ - hook->itf->hook_xreq_##what(hook->closure, &hookid, __VA_ARGS__); \ + && MATCH_API(hook->api, xreq->request.called_api) \ + && MATCH_VERB(hook->verb, xreq->request.called_verb)) { \ + hook->itf->hook_xreq_##func(hook->closure, &hookid, __VA_ARGS__); \ } \ hook = hook->next; \ } \ pthread_rwlock_unlock(&rwlock); +#define _HOOK_XREQ_(what,...) _HOOK_XREQ_2_(what,what,__VA_ARGS__) void afb_hook_xreq_begin(const struct afb_xreq *xreq) { @@ -462,25 +445,20 @@ struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, return arg; } -void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info) +void afb_hook_xreq_reply(const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { - _HOOK_XREQ_(success, xreq, obj, info); + _HOOK_XREQ_(reply, xreq, obj, error, info); } -void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info) +void *afb_hook_xreq_legacy_context_get(const struct afb_xreq *xreq, void *value) { - _HOOK_XREQ_(fail, xreq, status, info); -} - -void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value) -{ - _HOOK_XREQ_(context_get, xreq, value); + _HOOK_XREQ_(legacy_context_get, xreq, value); return value; } -void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*)) +void afb_hook_xreq_legacy_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*)) { - _HOOK_XREQ_(context_set, xreq, value, free_value); + _HOOK_XREQ_(legacy_context_set, xreq, value, free_value); } void afb_hook_xreq_addref(const struct afb_xreq *xreq) @@ -504,36 +482,36 @@ int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, i return result; } -int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result) { - _HOOK_XREQ_(subscribe, xreq, eventid, result); + _HOOK_XREQ_(subscribe, xreq, event_x2, result); return result; } -int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result) { - _HOOK_XREQ_(unsubscribe, xreq, eventid, result); + _HOOK_XREQ_(unsubscribe, xreq, event_x2, result); return result; } -void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) +void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags) { _HOOK_XREQ_(subcall, xreq, api, verb, args); } -void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result) +void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { - _HOOK_XREQ_(subcall_result, xreq, status, result); + _HOOK_XREQ_(subcall_result, xreq, object, error, info); } -void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) +void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags) { _HOOK_XREQ_(subcallsync, xreq, api, verb, args); } -int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result) +int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info) { - _HOOK_XREQ_(subcallsync_result, xreq, status, result); + _HOOK_XREQ_(subcallsync_result, xreq, status, object, error, info); return status; } @@ -542,24 +520,14 @@ void afb_hook_xreq_vverbose(const struct afb_xreq *xreq, int level, const char * _HOOK_XREQ_(vverbose, xreq, level, file ?: "?", line, func ?: "?", fmt, args); } -void afb_hook_xreq_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq) -{ - _HOOK_XREQ_(store, xreq, sreq); -} - -void afb_hook_xreq_unstore(const struct afb_xreq *xreq) -{ - _HOOK_XREQ_(unstore, xreq); -} - -void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) +void afb_hook_xreq_legacy_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq) { - _HOOK_XREQ_(subcall_req, xreq, api, verb, args); + _HOOK_XREQ_(legacy_store, xreq, sreq); } -void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result) +void afb_hook_xreq_legacy_unstore(const struct afb_xreq *xreq) { - _HOOK_XREQ_(subcall_req_result, xreq, status, result); + _HOOK_XREQ_(legacy_unstore, xreq); } int afb_hook_xreq_has_permission(const struct afb_xreq *xreq, const char *permission, int result) @@ -586,6 +554,12 @@ int afb_hook_xreq_get_uid(const struct afb_xreq *xreq, int result) return result; } +struct json_object *afb_hook_xreq_get_client_info(const struct afb_xreq *xreq, struct json_object *result) +{ + _HOOK_XREQ_(get_client_info, xreq, result); + return result; +} + /****************************************************************************** * section: hooking xreqs *****************************************************************************/ @@ -600,21 +574,19 @@ void afb_hook_init_xreq(struct afb_xreq *xreq) /* scan hook list to get the expected flags */ flags = 0; - if (afb_api_is_hookable(xreq->request.api)) { - pthread_rwlock_rdlock(&rwlock); - hook = list_of_xreq_hooks; - while (hook) { - f = hook->flags & afb_hook_flags_req_all; - add = f != 0 - && (!hook->session || hook->session == xreq->context.session) - && (!hook->api || !strcasecmp(hook->api, xreq->request.api)) - && (!hook->verb || !strcasecmp(hook->verb, xreq->request.verb)); - if (add) - flags |= f; - hook = hook->next; - } - pthread_rwlock_unlock(&rwlock); + pthread_rwlock_rdlock(&rwlock); + hook = list_of_xreq_hooks; + while (hook) { + f = hook->flags & afb_hook_flags_req_all; + add = f != 0 + && (!hook->session || hook->session == xreq->context.session) + && MATCH_API(hook->api, xreq->request.called_api) + && MATCH_VERB(hook->verb, xreq->request.called_verb); + if (add) + flags |= f; + hook = hook->next; } + pthread_rwlock_unlock(&rwlock); /* store the hooking data */ xreq->hookflags = flags; @@ -705,40 +677,40 @@ void afb_hook_unref_xreq(struct afb_hook_xreq *hook) * section: default callbacks for tracing daemon interface *****************************************************************************/ -static void _hook_ditf_(const struct afb_export *export, const char *format, ...) +static void _hook_api_(const struct afb_export *export, const char *format, ...) { va_list ap; va_start(ap, format); - _hook_("export-%s", format, ap, afb_export_apiname(export)); + _hook_("api-%s", format, ap, afb_export_apiname(export)); va_end(ap); } -static void hook_ditf_event_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object) +static void hook_api_event_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object) { - _hook_ditf_(export, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object)); + _hook_api_(export, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object)); } -static void hook_ditf_event_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result) +static void hook_api_event_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result) { - _hook_ditf_(export, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result); + _hook_api_(export, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result); } -static void hook_ditf_get_event_loop_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result) +static void hook_api_get_event_loop_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result) { - _hook_ditf_(export, "get_event_loop() -> %p", result); + _hook_api_(export, "get_event_loop() -> %p", result); } -static void hook_ditf_get_user_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) +static void hook_api_get_user_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) { - _hook_ditf_(export, "get_user_bus() -> %p", result); + _hook_api_(export, "get_user_bus() -> %p", result); } -static void hook_ditf_get_system_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) +static void hook_api_get_system_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) { - _hook_ditf_(export, "get_system_bus() -> %p", result); + _hook_api_(export, "get_system_bus() -> %p", result); } -static void hook_ditf_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void hook_api_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { int len; char *msg; @@ -749,427 +721,489 @@ static void hook_ditf_vverbose_cb(void *closure, const struct afb_hookid *hookid va_end(ap); if (len < 0) - _hook_ditf_(export, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, function, fmt); + _hook_api_(export, "vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, function, fmt); else { - _hook_ditf_(export, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, function, msg); + _hook_api_(export, "vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, function, msg); free(msg); } } -static void hook_ditf_event_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_eventid *result) +static void hook_api_event_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_event_x2 *result) { - _hook_ditf_(export, "event_make(%s) -> %s:%d", name, afb_evt_eventid_fullname(result), afb_evt_eventid_id(result)); + _hook_api_(export, "event_make(%s) -> %s:%d", name, afb_evt_event_x2_fullname(result), afb_evt_event_x2_id(result)); } -static void hook_ditf_rootdir_get_fd_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +static void hook_api_rootdir_get_fd_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) { char path[PATH_MAX]; if (result < 0) - _hook_ditf_(export, "rootdir_get_fd() -> %d, %m", result); + _hook_api_(export, "rootdir_get_fd() -> %d, %m", result); else { sprintf(path, "/proc/self/fd/%d", result); readlink(path, path, sizeof path); - _hook_ditf_(export, "rootdir_get_fd() -> %d = %s", result, path); + _hook_api_(export, "rootdir_get_fd() -> %d = %s", result, path); } } -static void hook_ditf_rootdir_open_locale_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result) +static void hook_api_rootdir_open_locale_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result) { char path[PATH_MAX]; if (!locale) locale = "(null)"; if (result < 0) - _hook_ditf_(export, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result); + _hook_api_(export, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result); else { sprintf(path, "/proc/self/fd/%d", result); readlink(path, path, sizeof path); - _hook_ditf_(export, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path); + _hook_api_(export, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path); } } -static void hook_ditf_queue_job_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) +static void hook_api_queue_job_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) +{ + _hook_api_(export, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result); +} + +static void hook_api_unstore_req_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq) +{ + _hook_api_(export, "unstore_req(%p)", sreq); +} + +static void hook_api_require_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized) +{ + _hook_api_(export, "require_api(%s, %d)...", name, initialized); +} + +static void hook_api_require_api_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result) +{ + _hook_api_(export, "...require_api(%s, %d) -> %d", name, initialized, result); +} + +static void hook_api_add_alias_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *alias, int result) +{ + _hook_api_(export, "add_alias(%s -> %s) -> %d", api, alias?:"<null>", result); +} + +static void hook_api_start_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +{ + _hook_api_(export, "start.before"); +} + +static void hook_api_start_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status) +{ + _hook_api_(export, "start.after -> %d", status); +} + +static void hook_api_on_event_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object) +{ + _hook_api_(export, "on_event.before(%s, %d, %s)", event, event_x2, json_object_to_json_string(object)); +} + +static void hook_api_on_event_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object) +{ + _hook_api_(export, "on_event.after(%s, %d, %s)", event, event_x2, json_object_to_json_string(object)); +} + +static void hook_api_call_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +{ + _hook_api_(export, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); +} + +static void hook_api_call_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object, const char *error, const char *info) +{ + _hook_api_(export, " ...call... [%s] -> %s (%s)", error?:"success", json_object_to_json_string(object), info?:""); +} + +static void hook_api_callsync_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +{ + _hook_api_(export, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); +} + +static void hook_api_callsync_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info) +{ + _hook_api_(export, " ...callsync... %d [%s] -> %s (%s)", status, error?:"success", json_object_to_json_string(object), info?:""); +} + +static void hook_api_new_api_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *info, int noconcurrency) +{ + _hook_api_(export, "new_api.before %s (%s)%s ...", api, info?:"", noconcurrency?" no-concurrency" : ""); +} + +static void hook_api_new_api_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *api) +{ + _hook_api_(export, "... new_api.after %s -> %s (%d)", api, result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_set_verbs_v2_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v2 *verbs) +{ + _hook_api_(export, "set_verbs_v2 -> %s (%d)", result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_set_verbs_v3_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v3 *verbs) +{ + _hook_api_(export, "set_verbs_v3 -> %s (%d)", result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_add_verb_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb, const char *info, int glob) +{ + _hook_api_(export, "add_verb(%s%s [%s]) -> %s (%d)", verb, glob?" (GLOB)":"", info?:"", result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_del_verb_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb) +{ + _hook_api_(export, "del_verb(%s) -> %s (%d)", verb, result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_set_on_event_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +{ + _hook_api_(export, "set_on_event -> %s (%d)", result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_set_on_init_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +{ + _hook_api_(export, "set_on_init -> %s (%d)", result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_seal_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +{ + _hook_api_(export, "seal"); +} + +static void hook_api_event_handler_add_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern) +{ + _hook_api_(export, "event_handler_add(%s) -> %s (%d)", pattern, result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_event_handler_del_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern) +{ + _hook_api_(export, "event_handler_del(%s) -> %s (%d)", pattern, result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_class_provide_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name) { - _hook_ditf_(export, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result); + _hook_api_(export, "class_provide(%s) -> %s (%d)", name, result >= 0 ? "OK" : "ERROR", result); } -static void hook_ditf_unstore_req_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq) +static void hook_api_class_require_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name) { - _hook_ditf_(export, "unstore_req(%p)", sreq); + _hook_api_(export, "class_require(%s) -> %s (%d)", name, result >= 0 ? "OK" : "ERROR", result); } -static void hook_ditf_require_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized) +static void hook_api_delete_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) { - _hook_ditf_(export, "require_api(%s, %d)...", name, initialized); + _hook_api_(export, "delete_api -> %s (%d)", result >= 0 ? "OK" : "ERROR", result); } -static void hook_ditf_require_api_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result) +static void hook_api_on_event_handler_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern) { - _hook_ditf_(export, "...require_api(%s, %d) -> %d", name, initialized, result); + _hook_api_(export, "on_event_handler[%s].before(%s, %d, %s)", pattern, event, event_x2, json_object_to_json_string(object)); } -static void hook_ditf_rename_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *oldname, const char *newname, int result) +static void hook_api_on_event_handler_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern) { - _hook_ditf_(export, "rename_api(%s -> %s) -> %d", oldname, newname, result); + _hook_api_(export, "on_event_handler[%s].after(%s, %d, %s)", pattern, event, event_x2, json_object_to_json_string(object)); } -static struct afb_hook_ditf_itf hook_ditf_default_itf = { - .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before_cb, - .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after_cb, - .hook_ditf_get_event_loop = hook_ditf_get_event_loop_cb, - .hook_ditf_get_user_bus = hook_ditf_get_user_bus_cb, - .hook_ditf_get_system_bus = hook_ditf_get_system_bus_cb, - .hook_ditf_vverbose = hook_ditf_vverbose_cb, - .hook_ditf_event_make = hook_ditf_event_make_cb, - .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd_cb, - .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale_cb, - .hook_ditf_queue_job = hook_ditf_queue_job_cb, - .hook_ditf_unstore_req = hook_ditf_unstore_req_cb, - .hook_ditf_require_api = hook_ditf_require_api_cb, - .hook_ditf_require_api_result = hook_ditf_require_api_result_cb, - .hook_ditf_rename_api = hook_ditf_rename_api_cb +static struct afb_hook_api_itf hook_api_default_itf = { + .hook_api_event_broadcast_before = hook_api_event_broadcast_before_cb, + .hook_api_event_broadcast_after = hook_api_event_broadcast_after_cb, + .hook_api_get_event_loop = hook_api_get_event_loop_cb, + .hook_api_get_user_bus = hook_api_get_user_bus_cb, + .hook_api_get_system_bus = hook_api_get_system_bus_cb, + .hook_api_vverbose = hook_api_vverbose_cb, + .hook_api_event_make = hook_api_event_make_cb, + .hook_api_rootdir_get_fd = hook_api_rootdir_get_fd_cb, + .hook_api_rootdir_open_locale = hook_api_rootdir_open_locale_cb, + .hook_api_queue_job = hook_api_queue_job_cb, + .hook_api_legacy_unstore_req = hook_api_unstore_req_cb, + .hook_api_require_api = hook_api_require_api_cb, + .hook_api_require_api_result = hook_api_require_api_result_cb, + .hook_api_add_alias = hook_api_add_alias_cb, + .hook_api_start_before = hook_api_start_before_cb, + .hook_api_start_after = hook_api_start_after_cb, + .hook_api_on_event_before = hook_api_on_event_before_cb, + .hook_api_on_event_after = hook_api_on_event_after_cb, + .hook_api_call = hook_api_call_cb, + .hook_api_call_result = hook_api_call_result_cb, + .hook_api_callsync = hook_api_callsync_cb, + .hook_api_callsync_result = hook_api_callsync_result_cb, + .hook_api_new_api_before = hook_api_new_api_before_cb, + .hook_api_new_api_after = hook_api_new_api_after_cb, + .hook_api_api_set_verbs_v2 = hook_api_api_set_verbs_v2_cb, + .hook_api_api_set_verbs_v3 = hook_api_api_set_verbs_v3_cb, + .hook_api_api_add_verb = hook_api_api_add_verb_cb, + .hook_api_api_del_verb = hook_api_api_del_verb_cb, + .hook_api_api_set_on_event = hook_api_api_set_on_event_cb, + .hook_api_api_set_on_init = hook_api_api_set_on_init_cb, + .hook_api_api_seal = hook_api_api_seal_cb, + .hook_api_event_handler_add = hook_api_event_handler_add_cb, + .hook_api_event_handler_del = hook_api_event_handler_del_cb, + .hook_api_class_provide = hook_api_class_provide_cb, + .hook_api_class_require = hook_api_class_require_cb, + .hook_api_delete_api = hook_api_delete_api_cb, + .hook_api_on_event_handler_before = hook_api_on_event_handler_before_cb, + .hook_api_on_event_handler_after = hook_api_on_event_handler_after_cb, }; /****************************************************************************** * section: hooks for tracing daemon interface (export) *****************************************************************************/ -#define _HOOK_DITF_(what,...) \ - struct afb_hook_ditf *hook; \ +#define _HOOK_API_2_(flag,func,...) \ + struct afb_hook_api *hook; \ struct afb_hookid hookid; \ const char *apiname = afb_export_apiname(export); \ pthread_rwlock_rdlock(&rwlock); \ init_hookid(&hookid); \ - hook = list_of_ditf_hooks; \ + hook = list_of_api_hooks; \ while (hook) { \ - if (hook->itf->hook_ditf_##what \ - && (hook->flags & afb_hook_flag_ditf_##what) != 0 \ - && (!hook->api || !strcasecmp(hook->api, apiname))) { \ - hook->itf->hook_ditf_##what(hook->closure, &hookid, __VA_ARGS__); \ + if (hook->itf->hook_api_##func \ + && (hook->flags & afb_hook_flag_api_##flag) != 0 \ + && MATCH_API(hook->api, apiname)) { \ + hook->itf->hook_api_##func(hook->closure, &hookid, __VA_ARGS__); \ } \ hook = hook->next; \ } \ pthread_rwlock_unlock(&rwlock); -void afb_hook_ditf_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object) +#define _HOOK_API_(what,...) _HOOK_API_2_(what,what,__VA_ARGS__) + +void afb_hook_api_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object) { - _HOOK_DITF_(event_broadcast_before, export, name, object); + _HOOK_API_2_(event_broadcast, event_broadcast_before, export, name, object); } -int afb_hook_ditf_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result) +int afb_hook_api_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result) { - _HOOK_DITF_(event_broadcast_after, export, name, object, result); + _HOOK_API_2_(event_broadcast, event_broadcast_after, export, name, object, result); return result; } -struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_export *export, struct sd_event *result) +struct sd_event *afb_hook_api_get_event_loop(const struct afb_export *export, struct sd_event *result) { - _HOOK_DITF_(get_event_loop, export, result); + _HOOK_API_(get_event_loop, export, result); return result; } -struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_export *export, struct sd_bus *result) +struct sd_bus *afb_hook_api_get_user_bus(const struct afb_export *export, struct sd_bus *result) { - _HOOK_DITF_(get_user_bus, export, result); + _HOOK_API_(get_user_bus, export, result); return result; } -struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_export *export, struct sd_bus *result) +struct sd_bus *afb_hook_api_get_system_bus(const struct afb_export *export, struct sd_bus *result) { - _HOOK_DITF_(get_system_bus, export, result); + _HOOK_API_(get_system_bus, export, result); return result; } -void afb_hook_ditf_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +void afb_hook_api_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { - _HOOK_DITF_(vverbose, export, level, file, line, function, fmt, args); + _HOOK_API_(vverbose, export, level, file, line, function, fmt, args); } -struct afb_eventid *afb_hook_ditf_event_make(const struct afb_export *export, const char *name, struct afb_eventid *result) +struct afb_event_x2 *afb_hook_api_event_make(const struct afb_export *export, const char *name, struct afb_event_x2 *result) { - _HOOK_DITF_(event_make, export, name, result); + _HOOK_API_(event_make, export, name, result); return result; } -int afb_hook_ditf_rootdir_get_fd(const struct afb_export *export, int result) +int afb_hook_api_rootdir_get_fd(const struct afb_export *export, int result) { - _HOOK_DITF_(rootdir_get_fd, export, result); + _HOOK_API_(rootdir_get_fd, export, result); return result; } -int afb_hook_ditf_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result) +int afb_hook_api_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result) { - _HOOK_DITF_(rootdir_open_locale, export, filename, flags, locale, result); + _HOOK_API_(rootdir_open_locale, export, filename, flags, locale, result); return result; } -int afb_hook_ditf_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) +int afb_hook_api_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) { - _HOOK_DITF_(queue_job, export, callback, argument, group, timeout, result); + _HOOK_API_(queue_job, export, callback, argument, group, timeout, result); return result; } -void afb_hook_ditf_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq) +void afb_hook_api_legacy_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq) { - _HOOK_DITF_(unstore_req, export, sreq); + _HOOK_API_(legacy_unstore_req, export, sreq); } -void afb_hook_ditf_require_api(const struct afb_export *export, const char *name, int initialized) +void afb_hook_api_require_api(const struct afb_export *export, const char *name, int initialized) { - _HOOK_DITF_(require_api, export, name, initialized); + _HOOK_API_(require_api, export, name, initialized); } -int afb_hook_ditf_require_api_result(const struct afb_export *export, const char *name, int initialized, int result) +int afb_hook_api_require_api_result(const struct afb_export *export, const char *name, int initialized, int result) { - _HOOK_DITF_(require_api_result, export, name, initialized, result); + _HOOK_API_2_(require_api, require_api_result, export, name, initialized, result); return result; } -int afb_hook_ditf_rename_api(const struct afb_export *export, const char *oldname, const char *newname, int result) +int afb_hook_api_add_alias(const struct afb_export *export, const char *api, const char *alias, int result) { - _HOOK_DITF_(rename_api, export, oldname, newname, result); + _HOOK_API_(add_alias, export, api, alias, result); return result; } -/****************************************************************************** - * section: hooking export - *****************************************************************************/ - -int afb_hook_flags_ditf(const char *api) +void afb_hook_api_start_before(const struct afb_export *export) { - int flags; - struct afb_hook_ditf *hook; - - flags = 0; - if (!api || afb_api_is_hookable(api)) { - pthread_rwlock_rdlock(&rwlock); - hook = list_of_ditf_hooks; - while (hook) { - if (!api || !hook->api || !strcasecmp(hook->api, api)) - flags |= hook->flags; - hook = hook->next; - } - pthread_rwlock_unlock(&rwlock); - } - return flags; + _HOOK_API_2_(start, start_before, export); } -struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure) +int afb_hook_api_start_after(const struct afb_export *export, int status) { - struct afb_hook_ditf *hook; - - /* alloc the result */ - hook = calloc(1, sizeof *hook); - if (hook == NULL) - return NULL; - - /* get a copy of the names */ - hook->api = api ? strdup(api) : NULL; - if (api && !hook->api) { - free(hook); - return NULL; - } - - /* initialise the rest */ - hook->refcount = 1; - hook->flags = flags; - hook->itf = itf ? itf : &hook_ditf_default_itf; - hook->closure = closure; + _HOOK_API_2_(start, start_after, export, status); + return status; +} - /* record the hook */ - pthread_rwlock_wrlock(&rwlock); - hook->next = list_of_ditf_hooks; - list_of_ditf_hooks = hook; - pthread_rwlock_unlock(&rwlock); +void afb_hook_api_on_event_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object) +{ + _HOOK_API_2_(on_event, on_event_before, export, event, event_x2, object); +} - /* returns it */ - return hook; +void afb_hook_api_on_event_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object) +{ + _HOOK_API_2_(on_event, on_event_after, export, event, event_x2, object); } -struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook) +void afb_hook_api_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args) { - pthread_rwlock_wrlock(&rwlock); - hook->refcount++; - pthread_rwlock_unlock(&rwlock); - return hook; + _HOOK_API_(call, export, api, verb, args); } -void afb_hook_unref_ditf(struct afb_hook_ditf *hook) +void afb_hook_api_call_result(const struct afb_export *export, struct json_object *object, const char*error, const char *info) { - struct afb_hook_ditf **prv; + _HOOK_API_2_(call, call_result, export, object, error, info); - if (hook) { - pthread_rwlock_wrlock(&rwlock); - if (--hook->refcount) - hook = NULL; - else { - /* unlink */ - prv = &list_of_ditf_hooks; - while (*prv && *prv != hook) - prv = &(*prv)->next; - if(*prv) - *prv = hook->next; - } - pthread_rwlock_unlock(&rwlock); - if (hook) { - /* free */ - free(hook->api); - free(hook); - } - } } -/****************************************************************************** - * section: default callbacks for tracing service interface (export) - *****************************************************************************/ - -static void _hook_svc_(const struct afb_export *export, const char *format, ...) +void afb_hook_api_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args) { - va_list ap; - va_start(ap, format); - _hook_("export-%s", format, ap, afb_export_apiname(export)); - va_end(ap); + _HOOK_API_(callsync, export, api, verb, args); } -static void hook_svc_start_before_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +int afb_hook_api_callsync_result(const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info) { - _hook_svc_(export, "start.before"); + _HOOK_API_2_(callsync, callsync_result, export, status, object, error, info); + return status; } -static void hook_svc_start_after_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status) +void afb_hook_api_new_api_before(const struct afb_export *export, const char *api, const char *info, int noconcurrency) { - _hook_svc_(export, "start.after -> %d", status); + _HOOK_API_2_(new_api, new_api_before, export, api, info, noconcurrency); } -static void hook_svc_on_event_before_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object) +int afb_hook_api_new_api_after(const struct afb_export *export, int result, const char *api) { - _hook_svc_(export, "on_event.before(%s, %d, %s)", event, eventid, json_object_to_json_string(object)); + _HOOK_API_2_(new_api, new_api_after, export, result, api); + return result; } -static void hook_svc_on_event_after_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object) +int afb_hook_api_api_set_verbs_v2(const struct afb_export *export, int result, const struct afb_verb_v2 *verbs) { - _hook_svc_(export, "on_event.after(%s, %d, %s)", event, eventid, json_object_to_json_string(object)); + _HOOK_API_2_(api_set_verbs, api_set_verbs_v2, export, result, verbs); + return result; } -static void hook_svc_call_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +int afb_hook_api_api_set_verbs_v3(const struct afb_export *export, int result, const struct afb_verb_v3 *verbs) { - _hook_svc_(export, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); + _HOOK_API_2_(api_set_verbs, api_set_verbs_v3, export, result, verbs); + return result; } -static void hook_svc_call_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result) +int afb_hook_api_api_add_verb(const struct afb_export *export, int result, const char *verb, const char *info, int glob) { - _hook_svc_(export, " ...call... -> %d: %s", status, json_object_to_json_string(result)); + _HOOK_API_(api_add_verb, export, result, verb, info, glob); + return result; } -static void hook_svc_callsync_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +int afb_hook_api_api_del_verb(const struct afb_export *export, int result, const char *verb) { - _hook_svc_(export, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); + _HOOK_API_(api_del_verb, export, result, verb); + return result; } -static void hook_svc_callsync_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result) +int afb_hook_api_api_set_on_event(const struct afb_export *export, int result) { - _hook_svc_(export, " ...callsync... -> %d: %s", status, json_object_to_json_string(result)); + _HOOK_API_(api_set_on_event, export, result); + return result; } -static struct afb_hook_svc_itf hook_svc_default_itf = { - .hook_svc_start_before = hook_svc_start_before_default_cb, - .hook_svc_start_after = hook_svc_start_after_default_cb, - .hook_svc_on_event_before = hook_svc_on_event_before_default_cb, - .hook_svc_on_event_after = hook_svc_on_event_after_default_cb, - .hook_svc_call = hook_svc_call_default_cb, - .hook_svc_call_result = hook_svc_call_result_default_cb, - .hook_svc_callsync = hook_svc_callsync_default_cb, - .hook_svc_callsync_result = hook_svc_callsync_result_default_cb -}; - -/****************************************************************************** - * section: hooks for tracing service interface (export) - *****************************************************************************/ - -#define _HOOK_SVC_(what,...) \ - struct afb_hook_svc *hook; \ - struct afb_hookid hookid; \ - const char *apiname = afb_export_apiname(export); \ - pthread_rwlock_rdlock(&rwlock); \ - init_hookid(&hookid); \ - hook = list_of_svc_hooks; \ - while (hook) { \ - if (hook->itf->hook_svc_##what \ - && (hook->flags & afb_hook_flag_svc_##what) != 0 \ - && (!hook->api || !strcasecmp(hook->api, apiname))) { \ - hook->itf->hook_svc_##what(hook->closure, &hookid, __VA_ARGS__); \ - } \ - hook = hook->next; \ - } \ - pthread_rwlock_unlock(&rwlock); - -void afb_hook_svc_start_before(const struct afb_export *export) +int afb_hook_api_api_set_on_init(const struct afb_export *export, int result) { - _HOOK_SVC_(start_before, export); + _HOOK_API_(api_set_on_init, export, result); + return result; } -int afb_hook_svc_start_after(const struct afb_export *export, int status) +void afb_hook_api_api_seal(const struct afb_export *export) { - _HOOK_SVC_(start_after, export, status); - return status; + _HOOK_API_(api_seal, export); } -void afb_hook_svc_on_event_before(const struct afb_export *export, const char *event, int eventid, struct json_object *object) +int afb_hook_api_event_handler_add(const struct afb_export *export, int result, const char *pattern) { - _HOOK_SVC_(on_event_before, export, event, eventid, object); + _HOOK_API_(event_handler_add, export, result, pattern); + return result; } - -void afb_hook_svc_on_event_after(const struct afb_export *export, const char *event, int eventid, struct json_object *object) +int afb_hook_api_event_handler_del(const struct afb_export *export, int result, const char *pattern) { - _HOOK_SVC_(on_event_after, export, event, eventid, object); + _HOOK_API_(event_handler_del, export, result, pattern); + return result; } - -void afb_hook_svc_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +int afb_hook_api_class_provide(const struct afb_export *export, int result, const char *name) { - _HOOK_SVC_(call, export, api, verb, args); + _HOOK_API_(class_provide, export, result, name); + return result; +} +int afb_hook_api_class_require(const struct afb_export *export, int result, const char *name) +{ + _HOOK_API_(class_require, export, result, name); + return result; } -void afb_hook_svc_call_result(const struct afb_export *export, int status, struct json_object *result) +int afb_hook_api_delete_api(const struct afb_export *export, int result) { - _HOOK_SVC_(call_result, export, status, result); + _HOOK_API_(delete_api, export, result); + return result; } -void afb_hook_svc_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +void afb_hook_api_on_event_handler_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern) { - _HOOK_SVC_(callsync, export, api, verb, args); + _HOOK_API_2_(on_event_handler, on_event_handler_before, export, event, event_x2, object, pattern); } -int afb_hook_svc_callsync_result(const struct afb_export *export, int status, struct json_object *result) +void afb_hook_api_on_event_handler_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern) { - _HOOK_SVC_(callsync_result, export, status, result); - return status; + _HOOK_API_2_(on_event_handler, on_event_handler_after, export, event, event_x2, object, pattern); } /****************************************************************************** - * section: hooking services (export) + * section: hooking export *****************************************************************************/ -int afb_hook_flags_svc(const char *api) +int afb_hook_flags_api(const char *api) { int flags; - struct afb_hook_svc *hook; + struct afb_hook_api *hook; flags = 0; - if (!api || afb_api_is_hookable(api)) { - pthread_rwlock_rdlock(&rwlock); - hook = list_of_svc_hooks; - while (hook) { - if (!api || !hook->api || !strcasecmp(hook->api, api)) - flags |= hook->flags; - hook = hook->next; - } - pthread_rwlock_unlock(&rwlock); + pthread_rwlock_rdlock(&rwlock); + hook = list_of_api_hooks; + while (hook) { + if (!api || MATCH_API(hook->api, api)) + flags |= hook->flags; + hook = hook->next; } + pthread_rwlock_unlock(&rwlock); return flags; } -struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_hook_svc_itf *itf, void *closure) +struct afb_hook_api *afb_hook_create_api(const char *api, int flags, struct afb_hook_api_itf *itf, void *closure) { - struct afb_hook_svc *hook; + struct afb_hook_api *hook; /* alloc the result */ hook = calloc(1, sizeof *hook); @@ -1186,20 +1220,20 @@ struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_ /* initialise the rest */ hook->refcount = 1; hook->flags = flags; - hook->itf = itf ? itf : &hook_svc_default_itf; + hook->itf = itf ? itf : &hook_api_default_itf; hook->closure = closure; /* record the hook */ pthread_rwlock_wrlock(&rwlock); - hook->next = list_of_svc_hooks; - list_of_svc_hooks = hook; + hook->next = list_of_api_hooks; + list_of_api_hooks = hook; pthread_rwlock_unlock(&rwlock); /* returns it */ return hook; } -struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook) +struct afb_hook_api *afb_hook_addref_api(struct afb_hook_api *hook) { pthread_rwlock_wrlock(&rwlock); hook->refcount++; @@ -1207,9 +1241,9 @@ struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook) return hook; } -void afb_hook_unref_svc(struct afb_hook_svc *hook) +void afb_hook_unref_api(struct afb_hook_api *hook) { - struct afb_hook_svc **prv; + struct afb_hook_api **prv; if (hook) { pthread_rwlock_wrlock(&rwlock); @@ -1217,7 +1251,7 @@ void afb_hook_unref_svc(struct afb_hook_svc *hook) hook = NULL; else { /* unlink */ - prv = &list_of_svc_hooks; + prv = &list_of_api_hooks; while (*prv && *prv != hook) prv = &(*prv)->next; if(*prv) @@ -1244,56 +1278,56 @@ static void _hook_evt_(const char *evt, int id, const char *format, ...) va_end(ap); } -static void hook_evt_create_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) +static void hook_evt_create_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) { _hook_evt_(evt, id, "create"); } -static void hook_evt_push_before_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj) +static void hook_evt_push_before_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj) { _hook_evt_(evt, id, "push.before(%s)", json_object_to_json_string(obj)); } -static void hook_evt_push_after_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result) +static void hook_evt_push_after_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result) { _hook_evt_(evt, id, "push.after(%s) -> %d", json_object_to_json_string(obj), result); } -static void hook_evt_broadcast_before_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj) +static void hook_evt_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj) { _hook_evt_(evt, id, "broadcast.before(%s)", json_object_to_json_string(obj)); } -static void hook_evt_broadcast_after_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result) +static void hook_evt_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result) { _hook_evt_(evt, id, "broadcast.after(%s) -> %d", json_object_to_json_string(obj), result); } -static void hook_evt_name_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, const char *result) +static void hook_evt_name_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, const char *result) { _hook_evt_(evt, id, "name -> %s", result); } -static void hook_evt_addref_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) +static void hook_evt_addref_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) { _hook_evt_(evt, id, "addref"); } -static void hook_evt_unref_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) +static void hook_evt_unref_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) { _hook_evt_(evt, id, "unref"); } static struct afb_hook_evt_itf hook_evt_default_itf = { - .hook_evt_create = hook_evt_create_default_cb, - .hook_evt_push_before = hook_evt_push_before_default_cb, - .hook_evt_push_after = hook_evt_push_after_default_cb, - .hook_evt_broadcast_before = hook_evt_broadcast_before_default_cb, - .hook_evt_broadcast_after = hook_evt_broadcast_after_default_cb, - .hook_evt_name = hook_evt_name_default_cb, - .hook_evt_addref = hook_evt_addref_default_cb, - .hook_evt_unref = hook_evt_unref_default_cb + .hook_evt_create = hook_evt_create_cb, + .hook_evt_push_before = hook_evt_push_before_cb, + .hook_evt_push_after = hook_evt_push_after_cb, + .hook_evt_broadcast_before = hook_evt_broadcast_before_cb, + .hook_evt_broadcast_after = hook_evt_broadcast_after_cb, + .hook_evt_name = hook_evt_name_cb, + .hook_evt_addref = hook_evt_addref_cb, + .hook_evt_unref = hook_evt_unref_cb }; /****************************************************************************** @@ -1309,7 +1343,7 @@ static struct afb_hook_evt_itf hook_evt_default_itf = { while (hook) { \ if (hook->itf->hook_evt_##what \ && (hook->flags & afb_hook_flag_evt_##what) != 0 \ - && (!hook->pattern || MATCH(hook->pattern, evt))) { \ + && MATCH_EVENT(hook->pattern, evt)) { \ hook->itf->hook_evt_##what(hook->closure, &hookid, __VA_ARGS__); \ } \ hook = hook->next; \ @@ -1368,16 +1402,14 @@ int afb_hook_flags_evt(const char *name) struct afb_hook_evt *hook; flags = 0; - if (!name || afb_api_is_hookable(name)) { - pthread_rwlock_rdlock(&rwlock); - hook = list_of_evt_hooks; - while (hook) { - if (!name || !hook->pattern || MATCH(hook->pattern, name)) - flags |= hook->flags; - hook = hook->next; - } - pthread_rwlock_unlock(&rwlock); + pthread_rwlock_rdlock(&rwlock); + hook = list_of_evt_hooks; + while (hook) { + if (!name || MATCH_EVENT(hook->pattern, name)) + flags |= hook->flags; + hook = hook->next; } + pthread_rwlock_unlock(&rwlock); return flags; } @@ -1458,43 +1490,43 @@ static void _hook_session_(struct afb_session *session, const char *format, ...) va_end(ap); } -static void hook_session_create_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_create_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "create -> token=%s", afb_session_token(session)); } -static void hook_session_close_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_close_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "close"); } -static void hook_session_destroy_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_destroy_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "destroy"); } -static void hook_session_renew_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_renew_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "renew -> token=%s", afb_session_token(session)); } -static void hook_session_addref_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_addref_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "addref"); } -static void hook_session_unref_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_unref_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "unref"); } static struct afb_hook_session_itf hook_session_default_itf = { - .hook_session_create = hook_session_create_default_cb, - .hook_session_close = hook_session_close_default_cb, - .hook_session_destroy = hook_session_destroy_default_cb, - .hook_session_renew = hook_session_renew_default_cb, - .hook_session_addref = hook_session_addref_default_cb, - .hook_session_unref = hook_session_unref_default_cb + .hook_session_create = hook_session_create_cb, + .hook_session_close = hook_session_close_cb, + .hook_session_destroy = hook_session_destroy_cb, + .hook_session_renew = hook_session_renew_cb, + .hook_session_addref = hook_session_addref_cb, + .hook_session_unref = hook_session_unref_cb }; /****************************************************************************** @@ -1511,7 +1543,7 @@ static struct afb_hook_session_itf hook_session_default_itf = { while (hook) { \ if (hook->itf->hook_session_##what \ && (hook->flags & afb_hook_flag_session_##what) != 0 \ - && (!hook->pattern || MATCH(hook->pattern, (sessid?:(sessid=afb_session_uuid(session)))))) { \ + && MATCH_SESSION(hook->pattern, (sessid?:(sessid=afb_session_uuid(session))))) { \ hook->itf->hook_session_##what(hook->closure, &hookid, __VA_ARGS__); \ } \ hook = hook->next; \ @@ -1630,7 +1662,7 @@ static void _hook_global_(const char *format, ...) va_end(ap); } -static void hook_global_vverbose_default_cb(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *func, const char *fmt, va_list args) +static void hook_global_vverbose_cb(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *func, const char *fmt, va_list args) { int len; char *msg; @@ -1641,15 +1673,15 @@ static void hook_global_vverbose_default_cb(void *closure, const struct afb_hook va_end(ap); if (len < 0) - _hook_global_("vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt); + _hook_global_("vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, func, fmt); else { - _hook_global_("vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg); + _hook_global_("vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, func, msg); free(msg); } } static struct afb_hook_global_itf hook_global_default_itf = { - .hook_global_vverbose = hook_global_vverbose_default_cb + .hook_global_vverbose = hook_global_vverbose_cb }; /****************************************************************************** diff --git a/src/afb-hook.h b/src/afb-hook.h index 52d83355..f315cc08 100644 --- a/src/afb-hook.h +++ b/src/afb-hook.h @@ -24,7 +24,9 @@ struct req; struct afb_context; struct json_object; struct afb_arg; -struct afb_eventid; +struct afb_event_x2; +struct afb_verb_v2; +struct afb_verb_v3; struct afb_session; struct afb_xreq; struct afb_export; @@ -32,8 +34,7 @@ struct afb_stored_req; struct sd_bus; struct sd_event; struct afb_hook_xreq; -struct afb_hook_ditf; -struct afb_hook_svc; +struct afb_hook_api; struct afb_hook_evt; struct afb_hook_session; struct afb_hook_global; @@ -56,10 +57,10 @@ struct afb_hookid #define afb_hook_flag_req_end 0x00000002 #define afb_hook_flag_req_json 0x00000004 #define afb_hook_flag_req_get 0x00000008 -#define afb_hook_flag_req_success 0x00000010 -#define afb_hook_flag_req_fail 0x00000020 -#define afb_hook_flag_req_context_get 0x00000040 -#define afb_hook_flag_req_context_set 0x00000080 +#define afb_hook_flag_req_reply 0x00000010 +#define afb_hook_flag_req_get_client_info 0x00000020 +#define afb_hook_flag_req_legacy_context_get 0x00000040 +#define afb_hook_flag_req_legacy_context_set 0x00000080 #define afb_hook_flag_req_addref 0x00000100 #define afb_hook_flag_req_unref 0x00000200 #define afb_hook_flag_req_session_close 0x00000400 @@ -71,35 +72,31 @@ struct afb_hookid #define afb_hook_flag_req_subcallsync 0x00010000 #define afb_hook_flag_req_subcallsync_result 0x00020000 #define afb_hook_flag_req_vverbose 0x00040000 -#define afb_hook_flag_req_store 0x00080000 -#define afb_hook_flag_req_unstore 0x00100000 -#define afb_hook_flag_req_subcall_req 0x00200000 -#define afb_hook_flag_req_subcall_req_result 0x00400000 -#define afb_hook_flag_req_has_permission 0x00800000 -#define afb_hook_flag_req_get_application_id 0x01000000 -#define afb_hook_flag_req_context_make 0x02000000 -#define afb_hook_flag_req_get_uid 0x04000000 +#define afb_hook_flag_req_legacy_store 0x00080000 +#define afb_hook_flag_req_legacy_unstore 0x00100000 +#define afb_hook_flag_req_has_permission 0x00200000 +#define afb_hook_flag_req_get_application_id 0x00400000 +#define afb_hook_flag_req_context_make 0x00800000 +#define afb_hook_flag_req_get_uid 0x01000000 /* common flags */ #define afb_hook_flags_req_life (afb_hook_flag_req_begin|afb_hook_flag_req_end) #define afb_hook_flags_req_args (afb_hook_flag_req_json|afb_hook_flag_req_get) -#define afb_hook_flags_req_result (afb_hook_flag_req_success|afb_hook_flag_req_fail) #define afb_hook_flags_req_session (afb_hook_flag_req_session_close|afb_hook_flag_req_session_set_LOA) #define afb_hook_flags_req_event (afb_hook_flag_req_subscribe|afb_hook_flag_req_unsubscribe) #define afb_hook_flags_req_subcalls (afb_hook_flag_req_subcall|afb_hook_flag_req_subcall_result\ - |afb_hook_flag_req_subcall_req|afb_hook_flag_req_subcall_req_result\ |afb_hook_flag_req_subcallsync|afb_hook_flag_req_subcallsync_result) #define afb_hook_flags_req_security (afb_hook_flag_req_has_permission|afb_hook_flag_req_get_application_id\ - |afb_hook_flag_req_get_uid) + |afb_hook_flag_req_get_uid|afb_hook_flag_req_get_client_info) /* extra flags */ #define afb_hook_flags_req_ref (afb_hook_flag_req_addref|afb_hook_flag_req_unref) -#define afb_hook_flags_req_context (afb_hook_flag_req_context_get|afb_hook_flag_req_context_set\ +#define afb_hook_flags_req_context (afb_hook_flag_req_legacy_context_get|afb_hook_flag_req_legacy_context_set\ |afb_hook_flag_req_context_make) -#define afb_hook_flags_req_stores (afb_hook_flag_req_store|afb_hook_flag_req_unstore) +#define afb_hook_flags_req_stores (afb_hook_flag_req_legacy_store|afb_hook_flag_req_legacy_unstore) /* predefined groups */ -#define afb_hook_flags_req_common (afb_hook_flags_req_life|afb_hook_flags_req_args|afb_hook_flags_req_result\ +#define afb_hook_flags_req_common (afb_hook_flags_req_life|afb_hook_flags_req_args|afb_hook_flag_req_reply\ |afb_hook_flags_req_session|afb_hook_flags_req_event|afb_hook_flags_req_subcalls\ |afb_hook_flag_req_vverbose|afb_hook_flags_req_security) #define afb_hook_flags_req_extra (afb_hook_flags_req_common|afb_hook_flags_req_ref|afb_hook_flags_req_context\ @@ -111,29 +108,27 @@ struct afb_hook_xreq_itf { void (*hook_xreq_end)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); void (*hook_xreq_json)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj); void (*hook_xreq_get)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg); - void (*hook_xreq_success)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info); - void (*hook_xreq_fail)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info); - void (*hook_xreq_context_get)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value); - void (*hook_xreq_context_set)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*)); + void (*hook_xreq_reply)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info); + void (*hook_xreq_legacy_context_get)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value); + void (*hook_xreq_legacy_context_set)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*)); void (*hook_xreq_addref)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); void (*hook_xreq_unref)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); void (*hook_xreq_session_close)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); void (*hook_xreq_session_set_LOA)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result); - void (*hook_xreq_subscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result); - void (*hook_xreq_unsubscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result); + void (*hook_xreq_subscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result); + void (*hook_xreq_unsubscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result); void (*hook_xreq_subcall)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); - void (*hook_xreq_subcall_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result); + void (*hook_xreq_subcall_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info); void (*hook_xreq_subcallsync)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); - void (*hook_xreq_subcallsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result); + void (*hook_xreq_subcallsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info); void (*hook_xreq_vverbose)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args); - void (*hook_xreq_store)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq); - void (*hook_xreq_unstore)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); - void (*hook_xreq_subcall_req)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); - void (*hook_xreq_subcall_req_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result); + void (*hook_xreq_legacy_store)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq); + void (*hook_xreq_legacy_unstore)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); void (*hook_xreq_has_permission)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result); void (*hook_xreq_get_application_id)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result); void (*hook_xreq_context_make)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result); void (*hook_xreq_get_uid)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result); + void (*hook_xreq_get_client_info)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *result); }; extern void afb_hook_init_xreq(struct afb_xreq *xreq); @@ -147,145 +142,220 @@ extern void afb_hook_xreq_begin(const struct afb_xreq *xreq); extern void afb_hook_xreq_end(const struct afb_xreq *xreq); extern struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj); extern struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg); -extern void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info); -extern void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info); -extern void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value); -extern void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*)); +extern void afb_hook_xreq_reply(const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info); +extern void *afb_hook_xreq_legacy_context_get(const struct afb_xreq *xreq, void *value); +extern void afb_hook_xreq_legacy_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*)); extern void afb_hook_xreq_addref(const struct afb_xreq *xreq); extern void afb_hook_xreq_unref(const struct afb_xreq *xreq); extern void afb_hook_xreq_session_close(const struct afb_xreq *xreq); extern int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result); -extern int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result); -extern int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result); -extern void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); -extern void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result); -extern void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); -extern int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result); +extern int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result); +extern int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result); +extern void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags); +extern void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info); +extern void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags); +extern int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info); extern void afb_hook_xreq_vverbose(const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args); -extern void afb_hook_xreq_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq); -extern void afb_hook_xreq_unstore(const struct afb_xreq *xreq); -extern void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); -extern void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result); +extern void afb_hook_xreq_legacy_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq); +extern void afb_hook_xreq_legacy_unstore(const struct afb_xreq *xreq); extern int afb_hook_xreq_has_permission(const struct afb_xreq *xreq, const char *permission, int result); extern char *afb_hook_xreq_get_application_id(const struct afb_xreq *xreq, char *result); extern void *afb_hook_xreq_context_make(const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result); extern int afb_hook_xreq_get_uid(const struct afb_xreq *xreq, int result); +extern struct json_object *afb_hook_xreq_get_client_info(const struct afb_xreq *xreq, struct json_object *result); /********************************************************* -* section hooking export (daemon interface) +* section hooking apis *********************************************************/ -#define afb_hook_flag_ditf_vverbose 0x000001 -#define afb_hook_flag_ditf_event_make 0x000002 -#define afb_hook_flag_ditf_event_broadcast_before 0x000004 -#define afb_hook_flag_ditf_event_broadcast_after 0x000008 -#define afb_hook_flag_ditf_get_event_loop 0x000010 -#define afb_hook_flag_ditf_get_user_bus 0x000020 -#define afb_hook_flag_ditf_get_system_bus 0x000040 -#define afb_hook_flag_ditf_rootdir_get_fd 0x000080 -#define afb_hook_flag_ditf_rootdir_open_locale 0x000100 -#define afb_hook_flag_ditf_queue_job 0x000200 -#define afb_hook_flag_ditf_unstore_req 0x000400 -#define afb_hook_flag_ditf_require_api 0x000800 -#define afb_hook_flag_ditf_require_api_result 0x001000 -#define afb_hook_flag_ditf_rename_api 0x002000 - -#define afb_hook_flags_ditf_common (afb_hook_flag_ditf_vverbose\ - |afb_hook_flag_ditf_event_make\ - |afb_hook_flag_ditf_event_broadcast_before\ - |afb_hook_flag_ditf_event_broadcast_after\ - |afb_hook_flag_ditf_rename_api) -#define afb_hook_flags_ditf_extra (afb_hook_flag_ditf_get_event_loop\ - |afb_hook_flag_ditf_get_user_bus\ - |afb_hook_flag_ditf_get_system_bus\ - |afb_hook_flag_ditf_rootdir_get_fd\ - |afb_hook_flag_ditf_rootdir_open_locale\ - |afb_hook_flag_ditf_queue_job\ - |afb_hook_flag_ditf_unstore_req\ - |afb_hook_flag_ditf_require_api\ - |afb_hook_flag_ditf_require_api_result) - -#define afb_hook_flags_ditf_all (afb_hook_flags_ditf_common|afb_hook_flags_ditf_extra) - -struct afb_hook_ditf_itf { - void (*hook_ditf_event_broadcast_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object); - void (*hook_ditf_event_broadcast_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result); - void (*hook_ditf_get_event_loop)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result); - void (*hook_ditf_get_user_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result); - void (*hook_ditf_get_system_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result); - void (*hook_ditf_vverbose)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args); - void (*hook_ditf_event_make)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_eventid *result); - void (*hook_ditf_rootdir_get_fd)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result); - void (*hook_ditf_rootdir_open_locale)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result); - void (*hook_ditf_queue_job)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result); - void (*hook_ditf_unstore_req)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq); - void (*hook_ditf_require_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized); - void (*hook_ditf_require_api_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result); - void (*hook_ditf_rename_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *oldname, const char *newname, int result); -}; +#define afb_hook_flag_api_vverbose 0x00000001 +#define afb_hook_flag_api_get_event_loop 0x00000002 +#define afb_hook_flag_api_get_user_bus 0x00000004 +#define afb_hook_flag_api_get_system_bus 0x00000008 +#define afb_hook_flag_api_rootdir_get_fd 0x00000010 +#define afb_hook_flag_api_rootdir_open_locale 0x00000020 +#define afb_hook_flag_api_queue_job 0x00000040 +#define afb_hook_flag_api_require_api 0x00000080 +#define afb_hook_flag_api_add_alias 0x00000100 +#define afb_hook_flag_api_event_broadcast 0x00000200 +#define afb_hook_flag_api_event_make 0x00000400 +#define afb_hook_flag_api_new_api 0x00000800 +#define afb_hook_flag_api_api_set_verbs 0x00001000 +#define afb_hook_flag_api_api_add_verb 0x00002000 +#define afb_hook_flag_api_api_del_verb 0x00004000 +#define afb_hook_flag_api_api_set_on_event 0x00008000 +#define afb_hook_flag_api_api_set_on_init 0x00010000 +#define afb_hook_flag_api_api_seal 0x00020000 +#define afb_hook_flag_api_event_handler_add 0x00040000 +#define afb_hook_flag_api_event_handler_del 0x00080000 +#define afb_hook_flag_api_call 0x00100000 +#define afb_hook_flag_api_callsync 0x00200000 +#define afb_hook_flag_api_class_provide 0x00400000 +#define afb_hook_flag_api_class_require 0x00800000 +#define afb_hook_flag_api_delete_api 0x01000000 +#define afb_hook_flag_api_start 0x02000000 +#define afb_hook_flag_api_on_event 0x04000000 +#define afb_hook_flag_api_legacy_unstore_req 0x08000000 +#define afb_hook_flag_api_on_event_handler 0x10000000 + +/* common flags */ +/* extra flags */ +/* predefined groups */ -extern void afb_hook_ditf_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object); -extern int afb_hook_ditf_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result); -extern struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_export *export, struct sd_event *result); -extern struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_export *export, struct sd_bus *result); -extern struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_export *export, struct sd_bus *result); -extern void afb_hook_ditf_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args); -extern struct afb_eventid *afb_hook_ditf_event_make(const struct afb_export *export, const char *name, struct afb_eventid *result); -extern int afb_hook_ditf_rootdir_get_fd(const struct afb_export *export, int result); -extern int afb_hook_ditf_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result); -extern int afb_hook_ditf_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result); -extern void afb_hook_ditf_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq); -extern void afb_hook_ditf_require_api(const struct afb_export *export, const char *name, int initialized); -extern int afb_hook_ditf_require_api_result(const struct afb_export *export, const char *name, int initialized, int result); -extern int afb_hook_ditf_rename_api(const struct afb_export *export, const char *oldname, const char *newname, int result); - -extern int afb_hook_flags_ditf(const char *api); -extern struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure); -extern struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook); -extern void afb_hook_unref_ditf(struct afb_hook_ditf *hook); +#define afb_hook_flags_api_common (afb_hook_flag_api_vverbose\ + |afb_hook_flag_api_event_broadcast\ + |afb_hook_flag_api_event_make\ + |afb_hook_flag_api_call\ + |afb_hook_flag_api_callsync\ + |afb_hook_flag_api_start\ + |afb_hook_flag_api_queue_job) + + +#define afb_hook_flags_api_extra (afb_hook_flag_api_get_event_loop\ + |afb_hook_flag_api_get_user_bus\ + |afb_hook_flag_api_get_system_bus\ + |afb_hook_flag_api_rootdir_get_fd\ + |afb_hook_flag_api_rootdir_open_locale\ + |afb_hook_flag_api_legacy_unstore_req) + + +#define afb_hook_flags_api_api (afb_hook_flag_api_new_api\ + |afb_hook_flag_api_api_set_verbs\ + |afb_hook_flag_api_api_add_verb\ + |afb_hook_flag_api_api_del_verb\ + |afb_hook_flag_api_api_set_on_event\ + |afb_hook_flag_api_api_set_on_init\ + |afb_hook_flag_api_api_seal\ + |afb_hook_flag_api_class_provide\ + |afb_hook_flag_api_class_require\ + |afb_hook_flag_api_require_api\ + |afb_hook_flag_api_add_alias\ + |afb_hook_flag_api_delete_api) + +#define afb_hook_flags_api_event (afb_hook_flag_api_event_broadcast\ + |afb_hook_flag_api_event_make\ + |afb_hook_flag_api_event_handler_add\ + |afb_hook_flag_api_event_handler_del\ + |afb_hook_flag_api_on_event\ + |afb_hook_flag_api_on_event_handler) + +#define afb_hook_flags_api_all (afb_hook_flags_api_common\ + |afb_hook_flags_api_extra\ + |afb_hook_flags_api_api\ + |afb_hook_flags_api_event) /********************************************************* -* section hooking export (service interface) +*********************************************************/ +#define afb_hook_flags_api_svc_all (afb_hook_flag_api_start|afb_hook_flag_api_start\ + |afb_hook_flag_api_on_event|afb_hook_flag_api_on_event\ + |afb_hook_flag_api_call|afb_hook_flag_api_call\ + |afb_hook_flag_api_callsync|afb_hook_flag_api_callsync) + +#define afb_hook_flags_api_ditf_common (afb_hook_flag_api_vverbose\ + |afb_hook_flag_api_event_make\ + |afb_hook_flag_api_event_broadcast\ + |afb_hook_flag_api_event_broadcast\ + |afb_hook_flag_api_add_alias) + +#define afb_hook_flags_api_ditf_extra (afb_hook_flag_api_get_event_loop\ + |afb_hook_flag_api_get_user_bus\ + |afb_hook_flag_api_get_system_bus\ + |afb_hook_flag_api_rootdir_get_fd\ + |afb_hook_flag_api_rootdir_open_locale\ + |afb_hook_flag_api_queue_job\ + |afb_hook_flag_api_legacy_unstore_req\ + |afb_hook_flag_api_require_api\ + |afb_hook_flag_api_require_api) + +#define afb_hook_flags_api_ditf_all (afb_hook_flags_api_ditf_common|afb_hook_flags_api_ditf_extra) +/********************************************************* *********************************************************/ -#define afb_hook_flag_svc_start_before 0x000001 -#define afb_hook_flag_svc_start_after 0x000002 -#define afb_hook_flag_svc_on_event_before 0x000004 -#define afb_hook_flag_svc_on_event_after 0x000008 -#define afb_hook_flag_svc_call 0x000010 -#define afb_hook_flag_svc_call_result 0x000020 -#define afb_hook_flag_svc_callsync 0x000040 -#define afb_hook_flag_svc_callsync_result 0x000080 - -#define afb_hook_flags_svc_all (afb_hook_flag_svc_start_before|afb_hook_flag_svc_start_after\ - |afb_hook_flag_svc_on_event_before|afb_hook_flag_svc_on_event_after\ - |afb_hook_flag_svc_call|afb_hook_flag_svc_call_result\ - |afb_hook_flag_svc_callsync|afb_hook_flag_svc_callsync_result) - -struct afb_hook_svc_itf { - void (*hook_svc_start_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export); - void (*hook_svc_start_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status); - void (*hook_svc_on_event_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object); - void (*hook_svc_on_event_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object); - void (*hook_svc_call)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args); - void (*hook_svc_call_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result); - void (*hook_svc_callsync)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args); - void (*hook_svc_callsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result); -}; -extern void afb_hook_svc_start_before(const struct afb_export *export); -extern int afb_hook_svc_start_after(const struct afb_export *export, int status); -extern void afb_hook_svc_on_event_before(const struct afb_export *export, const char *event, int eventid, struct json_object *object); -extern void afb_hook_svc_on_event_after(const struct afb_export *export, const char *event, int eventid, struct json_object *object); -extern void afb_hook_svc_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args); -extern void afb_hook_svc_call_result(const struct afb_export *export, int status, struct json_object *result); -extern void afb_hook_svc_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args); -extern int afb_hook_svc_callsync_result(const struct afb_export *export, int status, struct json_object *result); +struct afb_hook_api_itf { + void (*hook_api_event_broadcast_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object); + void (*hook_api_event_broadcast_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result); + void (*hook_api_get_event_loop)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result); + void (*hook_api_get_user_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result); + void (*hook_api_get_system_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result); + void (*hook_api_vverbose)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args); + void (*hook_api_event_make)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_event_x2 *result); + void (*hook_api_rootdir_get_fd)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result); + void (*hook_api_rootdir_open_locale)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result); + void (*hook_api_queue_job)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result); + void (*hook_api_legacy_unstore_req)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq); + void (*hook_api_require_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized); + void (*hook_api_require_api_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result); + void (*hook_api_add_alias)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *oldname, const char *newname, int result); + void (*hook_api_start_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export); + void (*hook_api_start_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status); + void (*hook_api_on_event_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object); + void (*hook_api_on_event_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object); + void (*hook_api_call)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args); + void (*hook_api_call_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object, const char *error, const char *info); + void (*hook_api_callsync)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args); + void (*hook_api_callsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, struct json_object *object, const char *error, const char *info); + void (*hook_api_new_api_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *info, int noconcurrency); + void (*hook_api_new_api_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *api); + void (*hook_api_api_set_verbs_v2)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v2 *verbs); + void (*hook_api_api_set_verbs_v3)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v3 *verbs); + void (*hook_api_api_add_verb)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb, const char *info, int glob); + void (*hook_api_api_del_verb)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb); + void (*hook_api_api_set_on_event)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result); + void (*hook_api_api_set_on_init)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result); + void (*hook_api_api_seal)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export); + void (*hook_api_event_handler_add)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern); + void (*hook_api_event_handler_del)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern); + void (*hook_api_class_provide)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name); + void (*hook_api_class_require)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name); + void (*hook_api_delete_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result); + void (*hook_api_on_event_handler_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern); + void (*hook_api_on_event_handler_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern); +}; -extern int afb_hook_flags_svc(const char *api); -extern struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_hook_svc_itf *itf, void *closure); -extern struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook); -extern void afb_hook_unref_svc(struct afb_hook_svc *hook); +extern void afb_hook_api_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object); +extern int afb_hook_api_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result); +extern struct sd_event *afb_hook_api_get_event_loop(const struct afb_export *export, struct sd_event *result); +extern struct sd_bus *afb_hook_api_get_user_bus(const struct afb_export *export, struct sd_bus *result); +extern struct sd_bus *afb_hook_api_get_system_bus(const struct afb_export *export, struct sd_bus *result); +extern void afb_hook_api_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args); +extern struct afb_event_x2 *afb_hook_api_event_make(const struct afb_export *export, const char *name, struct afb_event_x2 *result); +extern int afb_hook_api_rootdir_get_fd(const struct afb_export *export, int result); +extern int afb_hook_api_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result); +extern int afb_hook_api_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result); +extern void afb_hook_api_legacy_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq); +extern void afb_hook_api_require_api(const struct afb_export *export, const char *name, int initialized); +extern int afb_hook_api_require_api_result(const struct afb_export *export, const char *name, int initialized, int result); +extern int afb_hook_api_add_alias(const struct afb_export *export, const char *api, const char *alias, int result); +extern void afb_hook_api_start_before(const struct afb_export *export); +extern int afb_hook_api_start_after(const struct afb_export *export, int status); +extern void afb_hook_api_on_event_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object); +extern void afb_hook_api_on_event_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object); +extern void afb_hook_api_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args); +extern void afb_hook_api_call_result(const struct afb_export *export, struct json_object *object, const char *error, const char *info); +extern void afb_hook_api_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args); +extern int afb_hook_api_callsync_result(const struct afb_export *export, int result, struct json_object *object, const char *error, const char *info); +extern void afb_hook_api_new_api_before(const struct afb_export *export, const char *api, const char *info, int noconcurrency); +extern int afb_hook_api_new_api_after(const struct afb_export *export, int result, const char *api); +extern int afb_hook_api_api_set_verbs_v2(const struct afb_export *export, int result, const struct afb_verb_v2 *verbs); +extern int afb_hook_api_api_set_verbs_v3(const struct afb_export *export, int result, const struct afb_verb_v3 *verbs); +extern int afb_hook_api_api_add_verb(const struct afb_export *export, int result, const char *verb, const char *info, int glob); +extern int afb_hook_api_api_del_verb(const struct afb_export *export, int result, const char *verb); +extern int afb_hook_api_api_set_on_event(const struct afb_export *export, int result); +extern int afb_hook_api_api_set_on_init(const struct afb_export *export, int result); +extern void afb_hook_api_api_seal(const struct afb_export *export); +extern int afb_hook_api_event_handler_add(const struct afb_export *export, int result, const char *pattern); +extern int afb_hook_api_event_handler_del(const struct afb_export *export, int result, const char *pattern); +extern int afb_hook_api_class_provide(const struct afb_export *export, int result, const char *name); +extern int afb_hook_api_class_require(const struct afb_export *export, int result, const char *name); +extern int afb_hook_api_delete_api(const struct afb_export *export, int result); +extern void afb_hook_api_on_event_handler_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern); +extern void afb_hook_api_on_event_handler_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern); + +extern int afb_hook_flags_api(const char *api); +extern struct afb_hook_api *afb_hook_create_api(const char *api, int flags, struct afb_hook_api_itf *itf, void *closure); +extern struct afb_hook_api *afb_hook_addref_api(struct afb_hook_api *hook); +extern void afb_hook_unref_api(struct afb_hook_api *hook); /********************************************************* * section hooking evt (event interface) @@ -384,3 +454,4 @@ extern struct afb_hook_global *afb_hook_create_global(int flags, struct afb_hook extern struct afb_hook_global *afb_hook_addref_global(struct afb_hook_global *hook); extern void afb_hook_unref_global(struct afb_hook_global *hook); + diff --git a/src/afb-hreq.c b/src/afb-hreq.c index 012debbd..e5dcf642 100644 --- a/src/afb-hreq.c +++ b/src/afb-hreq.c @@ -73,15 +73,13 @@ struct hreq_data { static struct json_object *req_json(struct afb_xreq *xreq); static struct afb_arg req_get(struct afb_xreq *xreq, const char *name); -static void req_fail(struct afb_xreq *xreq, const char *status, const char *info); -static void req_success(struct afb_xreq *xreq, json_object *obj, const char *info); +static void req_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info); static void req_destroy(struct afb_xreq *xreq); const struct afb_xreq_query_itf afb_hreq_xreq_query_itf = { .json = req_json, .get = req_get, - .success = req_success, - .fail = req_fail, + .reply = req_reply, .unref = req_destroy }; @@ -332,8 +330,8 @@ static void req_destroy(struct afb_xreq *xreq) } afb_context_disconnect(&hreq->xreq.context); json_object_put(hreq->json); - free((char*)hreq->xreq.request.api); - free((char*)hreq->xreq.request.verb); + free((char*)hreq->xreq.request.called_api); + free((char*)hreq->xreq.request.called_verb); afb_cred_unref(hreq->xreq.cred); free(hreq); } @@ -900,39 +898,32 @@ static ssize_t send_json_cb(json_object *obj, uint64_t pos, char *buf, size_t ma return len ? : (ssize_t)MHD_CONTENT_READER_END_OF_STREAM; } -static void req_reply(struct afb_hreq *hreq, unsigned retcode, const char *status, const char *info, json_object *resp) +static void req_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { - struct json_object *reply; + struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq); + struct json_object *sub, *reply; const char *reqid; struct MHD_Response *response; + /* create the reply */ + reply = afb_msg_json_reply(object, error, info, &xreq->context); + + /* append the req id on need */ reqid = afb_hreq_get_argument(hreq, long_key_for_reqid); if (reqid == NULL) reqid = afb_hreq_get_argument(hreq, short_key_for_reqid); - - reply = afb_msg_json_reply(status, info, resp, &hreq->xreq.context, reqid); + if (reqid != NULL && json_object_object_get_ex(reply, "request", &sub)) + json_object_object_add(sub, "reqid", json_object_new_string(reqid)); response = MHD_create_response_from_callback((uint64_t)strlen(json_object_to_json_string_ext(reply, JSON_C_TO_STRING_PLAIN)), SIZE_RESPONSE_BUFFER, (void*)send_json_cb, reply, (void*)json_object_put); - afb_hreq_reply(hreq, retcode, response, NULL); -} - -static void req_fail(struct afb_xreq *xreq, const char *status, const char *info) -{ - struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq); - req_reply(hreq, MHD_HTTP_OK, status, info, NULL); -} - -static void req_success(struct afb_xreq *xreq, json_object *obj, const char *info) -{ - struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq); - req_reply(hreq, MHD_HTTP_OK, "success", info, obj); + afb_hreq_reply(hreq, MHD_HTTP_OK, response, NULL); } void afb_hreq_call(struct afb_hreq *hreq, struct afb_apiset *apiset, const char *api, size_t lenapi, const char *verb, size_t lenverb) { - hreq->xreq.request.api = strndup(api, lenapi); - hreq->xreq.request.verb = strndup(verb, lenverb); - if (hreq->xreq.request.api == NULL || hreq->xreq.request.verb == NULL) { + hreq->xreq.request.called_api = strndup(api, lenapi); + hreq->xreq.request.called_verb = strndup(verb, lenverb); + if (hreq->xreq.request.called_api == NULL || hreq->xreq.request.called_verb == NULL) { ERROR("Out of memory"); afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR); } else if (afb_hreq_init_context(hreq) < 0) { diff --git a/src/afb-monitor.c b/src/afb-monitor.c index 18ea606b..a50e2c65 100644 --- a/src/afb-monitor.c +++ b/src/afb-monitor.c @@ -21,12 +21,12 @@ #include <json-c/json.h> -#define AFB_BINDING_VERSION 0 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> #include "afb-api.h" #include "afb-apiset.h" -#include "afb-api-so-v2.h" +#include "afb-api-v3.h" #include "afb-evt.h" #include "afb-xreq.h" #include "afb-trace.h" @@ -36,13 +36,12 @@ #include "monitor-api.inc" -extern struct afb_apiset *main_apiset; +static struct afb_apiset *target_set; -static struct afb_binding_data_v2 datav2; - -int afb_monitor_init() +int afb_monitor_init(struct afb_apiset *declare_set, struct afb_apiset *call_set) { - return afb_api_so_v2_add_binding(&_afb_binding_v2_monitor, NULL, main_apiset, &datav2); + target_set = call_set; + return -!afb_api_v3_from_binding(&_afb_binding_monitor, declare_set, call_set); } /****************************************************************************** @@ -66,28 +65,28 @@ static int decode_verbosity(struct json_object *v) int level = -1; if (!wrap_json_unpack(v, "i", &level)) { - level = level < Verbosity_Level_Error ? Verbosity_Level_Error : level > Verbosity_Level_Debug ? Verbosity_Level_Debug : level; + level = level < _VERBOSITY_(Log_Level_Error) ? _VERBOSITY_(Log_Level_Error) : level > _VERBOSITY_(Log_Level_Debug) ? _VERBOSITY_(Log_Level_Debug) : level; } else if (!wrap_json_unpack(v, "s", &s)) { switch(*s&~' ') { case 'D': if (!strcasecmp(s, _debug_)) - level = Verbosity_Level_Debug; + level = _VERBOSITY_(Log_Level_Debug); break; case 'I': if (!strcasecmp(s, _info_)) - level = Verbosity_Level_Info; + level = _VERBOSITY_(Log_Level_Info); break; case 'N': if (!strcasecmp(s, _notice_)) - level = Verbosity_Level_Notice; + level = _VERBOSITY_(Log_Level_Notice); break; case 'W': if (!strcasecmp(s, _warning_)) - level = Verbosity_Level_Warning; + level = _VERBOSITY_(Log_Level_Warning); break; case 'E': if (!strcasecmp(s, _error_)) - level = Verbosity_Level_Error; + level = _VERBOSITY_(Log_Level_Error); break; } } @@ -100,9 +99,10 @@ static int decode_verbosity(struct json_object *v) * @param the name of the api to set * @param closure the verbosity to set as an integer casted to a pointer */ -static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, void *closure) +static void set_verbosity_to_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias) { - afb_apiset_set_verbosity(set, name, (int)(intptr_t)closure); + if (!isalias) + afb_apiset_set_logmask(set, name, (int)(intptr_t)closure); } /** @@ -112,12 +112,13 @@ static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, vo */ static void set_verbosity_to(const char *name, int level) { + int mask = verbosity_to_mask(level); if (!name || !name[0]) - verbosity = level; + verbosity_set(level); else if (name[0] == '*' && !name[1]) - afb_apiset_enum(main_apiset, 1, set_verbosity_to_all_cb, (void*)(intptr_t)level); + afb_apiset_enum(target_set, 1, set_verbosity_to_all_cb, (void*)(intptr_t)mask); else - afb_apiset_set_verbosity(main_apiset, name, level); + afb_apiset_set_logmask(target_set, name, mask); } /** @@ -154,12 +155,12 @@ static void set_verbosity(struct json_object *spec) */ static struct json_object *encode_verbosity(int level) { - switch(level) { - case Verbosity_Level_Error: return json_object_new_string(_error_); - case Verbosity_Level_Warning: return json_object_new_string(_warning_); - case Verbosity_Level_Notice: return json_object_new_string(_notice_); - case Verbosity_Level_Info: return json_object_new_string(_info_); - case Verbosity_Level_Debug: return json_object_new_string(_debug_); + switch(_DEVERBOSITY_(level)) { + case Log_Level_Error: return json_object_new_string(_error_); + case Log_Level_Warning: return json_object_new_string(_warning_); + case Log_Level_Notice: return json_object_new_string(_notice_); + case Log_Level_Info: return json_object_new_string(_info_); + case Log_Level_Debug: return json_object_new_string(_debug_); default: return json_object_new_int(level); } } @@ -170,12 +171,12 @@ static struct json_object *encode_verbosity(int level) * @param the name of the api to set * @param closure the json object to build */ -static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, void *closure) +static void get_verbosity_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias) { struct json_object *resu = closure; - int l = afb_apiset_get_verbosity(set, name); - if (l >= 0) - json_object_object_add(resu, name, encode_verbosity(l)); + int m = afb_apiset_get_logmask(set, name); + if (m >= 0) + json_object_object_add(resu, name, encode_verbosity(verbosity_from_mask(m))); } /** @@ -185,15 +186,15 @@ static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, vo */ static void get_verbosity_of(struct json_object *resu, const char *name) { - int l; + int m; if (!name || !name[0]) - json_object_object_add(resu, "", encode_verbosity(verbosity)); + json_object_object_add(resu, "", encode_verbosity(verbosity_get())); else if (name[0] == '*' && !name[1]) - afb_apiset_enum(main_apiset, 1, get_verbosity_of_all_cb, resu); + afb_apiset_enum(target_set, 1, get_verbosity_of_all_cb, resu); else { - l = afb_apiset_get_verbosity(main_apiset, name); - if (l >= 0) - json_object_object_add(resu, name, encode_verbosity(l)); + m = afb_apiset_get_logmask(target_set, name); + if (m >= 0) + json_object_object_add(resu, name, encode_verbosity(verbosity_from_mask(m))); } } @@ -242,8 +243,8 @@ static void get_one_api(struct json_object *resu, const char *name, struct json_ { struct json_object *o; - o = afb_apiset_describe(main_apiset, name); - if (o || afb_apiset_lookup(main_apiset, name, 1)) + o = afb_apiset_describe(target_set, name); + if (o || afb_apiset_lookup(target_set, name, 1)) json_object_object_add(resu, name, o); } @@ -253,7 +254,7 @@ static void get_one_api(struct json_object *resu, const char *name, struct json_ * @param the name of the api to set * @param closure the json object to build */ -static void get_apis_of_all_cb(struct afb_apiset *set, const char *name, void *closure) +static void get_apis_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias) { struct json_object *resu = closure; get_one_api(resu, name, NULL); @@ -285,7 +286,7 @@ static struct json_object *get_apis(struct json_object *spec) } else if (json_object_is_type(spec, json_type_string)) { get_one_api(resu, json_object_get_string(spec), NULL); } else if (json_object_get_boolean(spec)) { - afb_apiset_enum(main_apiset, 1, get_apis_of_all_cb, resu); + afb_apiset_enum(target_set, 1, get_apis_of_all_cb, resu); } return resu; } @@ -298,7 +299,7 @@ static const char _verbosity_[] = "verbosity"; static const char _apis_[] = "apis"; static const char _refresh_token_[] = "refresh-token"; -static void f_get(struct afb_req req) +static void f_get(afb_req_t req) { struct json_object *r; struct json_object *apis = NULL; @@ -314,7 +315,7 @@ static void f_get(struct afb_req req) afb_req_success(req, r, NULL); } -static void f_set(struct afb_req req) +static void f_set(afb_req_t req) { struct json_object *verbosity = NULL; @@ -325,9 +326,9 @@ static void f_set(struct afb_req req) afb_req_success(req, NULL, NULL); } -static void *context_create() +static void *context_create(void *closure) { - return afb_trace_create(_afb_binding_v2_monitor.api, NULL); + return afb_trace_create(_afb_binding_monitor.api, NULL); } static void context_destroy(void *pointer) @@ -336,14 +337,14 @@ static void context_destroy(void *pointer) afb_trace_unref(trace); } -static void f_trace(struct afb_req req) +static void f_trace(afb_req_t req) { int rc; struct json_object *add = NULL; struct json_object *drop = NULL; struct afb_trace *trace; - trace = afb_req_context(req, context_create, context_destroy); + trace = afb_req_context(req, 0, context_create, context_destroy, NULL); wrap_json_unpack(afb_req_json(req), "{s?o s?o}", "add", &add, "drop", &drop); if (add) { rc = afb_trace_add(req, add, trace); @@ -357,15 +358,15 @@ static void f_trace(struct afb_req req) } afb_req_success(req, NULL, NULL); end: - afb_apiset_update_hooks(main_apiset, NULL); + afb_apiset_update_hooks(target_set, NULL); afb_evt_update_hooks(); } -static void f_session(struct afb_req req) +static void f_session(afb_req_t req) { struct json_object *r = NULL; int refresh = 0; - struct afb_xreq *xreq = xreq_from_request(req.closure); + struct afb_xreq *xreq = xreq_from_req_x2(req); /* check right to call it */ if (xreq->context.super) { @@ -387,4 +388,3 @@ static void f_session(struct afb_req req) afb_req_success(req, r, NULL); } - diff --git a/src/afb-monitor.h b/src/afb-monitor.h index 1f3c1446..407116d2 100644 --- a/src/afb-monitor.h +++ b/src/afb-monitor.h @@ -18,4 +18,6 @@ #pragma once -extern int afb_monitor_init(); +struct afb_apiset; + +extern int afb_monitor_init(struct afb_apiset *declare_set, struct afb_apiset *call_set); diff --git a/src/afb-msg-json.c b/src/afb-msg-json.c index 7597f80f..ceeee1a4 100644 --- a/src/afb-msg-json.c +++ b/src/afb-msg-json.c @@ -22,7 +22,9 @@ #include "afb-msg-json.h" #include "afb-context.h" -struct json_object *afb_msg_json_reply(const char *status, const char *info, struct json_object *resp, struct afb_context *context, const char *reqid) +static const char _success_[] = "success"; + +struct json_object *afb_msg_json_reply(struct json_object *resp, const char *error, const char *info, struct afb_context *context) { json_object *msg, *request; const char *token, *uuid; @@ -37,14 +39,11 @@ struct json_object *afb_msg_json_reply(const char *status, const char *info, str request = json_object_new_object(); json_object_object_add(msg, "request", request); - json_object_object_add(request, "status", json_object_new_string(status)); + json_object_object_add(request, "status", json_object_new_string(error ?: _success_)); if (info != NULL) json_object_object_add(request, "info", json_object_new_string(info)); - if (reqid != NULL) - json_object_object_add(request, "reqid", json_object_new_string(reqid)); - if (context != NULL) { token = afb_context_sent_token(context); if (token != NULL) @@ -58,16 +57,6 @@ struct json_object *afb_msg_json_reply(const char *status, const char *info, str return msg; } -struct json_object *afb_msg_json_reply_ok(const char *info, struct json_object *resp, struct afb_context *context, const char *reqid) -{ - return afb_msg_json_reply("success", info, resp, context, reqid); -} - -struct json_object *afb_msg_json_reply_error(const char *status, const char *info, struct afb_context *context, const char *reqid) -{ - return afb_msg_json_reply(status, info, NULL, context, reqid); -} - struct json_object *afb_msg_json_event(const char *event, struct json_object *object) { json_object *msg; @@ -88,7 +77,7 @@ struct json_object *afb_msg_json_event(const char *event, struct json_object *ob struct json_object *afb_msg_json_internal_error() { - return afb_msg_json_reply_error("failed", "internal error", NULL, NULL); + return afb_msg_json_reply(NULL, "failed", "internal error", NULL); } diff --git a/src/afb-msg-json.h b/src/afb-msg-json.h index e18ca0a9..ee3ed20c 100644 --- a/src/afb-msg-json.h +++ b/src/afb-msg-json.h @@ -21,9 +21,7 @@ struct json_object; struct afb_context; struct afb_arg; -extern struct json_object *afb_msg_json_reply(const char *status, const char *info, struct json_object *resp, struct afb_context *context, const char *reqid); -extern struct json_object *afb_msg_json_reply_ok(const char *info, struct json_object *resp, struct afb_context *context, const char *reqid); -extern struct json_object *afb_msg_json_reply_error(const char *status, const char *info, struct afb_context *context, const char *reqid); +extern struct json_object *afb_msg_json_reply(struct json_object *resp, const char *status, const char *info, struct afb_context *context); extern struct json_object *afb_msg_json_event(const char *event, struct json_object *object); diff --git a/src/afb-proto-ws.c b/src/afb-proto-ws.c index e1993abe..f9313545 100644 --- a/src/afb-proto-ws.c +++ b/src/afb-proto-ws.c @@ -61,8 +61,6 @@ The server must reply to the previous actions by The server can also within the context of a call - - make a subcall - - subscribe or unsubscribe an event For the purpose of handling events the server can: @@ -75,42 +73,17 @@ For the purpose of handling events the server can: /************** constants for protocol definition *************************/ #define CHAR_FOR_CALL 'C' -#define CHAR_FOR_ANSWER_SUCCESS 'T' -#define CHAR_FOR_ANSWER_FAIL 'F' +#define CHAR_FOR_REPLY 'Y' #define CHAR_FOR_EVT_BROADCAST '*' #define CHAR_FOR_EVT_ADD '+' #define CHAR_FOR_EVT_DEL '-' #define CHAR_FOR_EVT_PUSH '!' #define CHAR_FOR_EVT_SUBSCRIBE 'S' #define CHAR_FOR_EVT_UNSUBSCRIBE 'U' -#define CHAR_FOR_SUBCALL_CALL 'B' -#define CHAR_FOR_SUBCALL_REPLY 'R' #define CHAR_FOR_DESCRIBE 'D' #define CHAR_FOR_DESCRIPTION 'd' -/******************* handling subcalls *****************************/ - -/** - * Structure on server side for recording pending - * subcalls. - */ -struct server_subcall -{ - struct server_subcall *next; /**< next subcall for the client */ - uint32_t subcallid; /**< the subcallid */ - void (*callback)(void*, int, struct json_object*); /**< callback on completion */ - void *closure; /**< closure of the callback */ -}; - -/** - * Structure for sending back replies on client side - */ -struct afb_proto_ws_subcall -{ - struct afb_proto_ws *protows; /**< proto descriptor */ - void *buffer; - uint32_t subcallid; /**< subcallid for the reply */ -}; +/******************* handling calls *****************************/ /* * structure for recording calls on client side @@ -182,9 +155,6 @@ struct afb_proto_ws /* emitted calls (client side) */ struct client_call *calls; - /* pending subcalls (server side) */ - struct server_subcall *subcalls; - /* pending description (client side) */ struct client_describe *describes; @@ -237,6 +207,7 @@ static char *readbuf_get(struct readbuf *rb, uint32_t length) return before; } +__attribute__((unused)) static int readbuf_char(struct readbuf *rb, char *value) { if (rb->head >= rb->end) @@ -256,16 +227,35 @@ static int readbuf_uint32(struct readbuf *rb, uint32_t *value) return 1; } -static int readbuf_string(struct readbuf *rb, const char **value, size_t *length) +static int _readbuf_string_(struct readbuf *rb, const char **value, size_t *length, int nulok) { uint32_t len; - if (!readbuf_uint32(rb, &len) || !len) + if (!readbuf_uint32(rb, &len)) return 0; + if (!len) { + if (!nulok) + return 0; + *value = NULL; + if (length) + *length = 0; + return 1; + } if (length) *length = (size_t)(len - 1); return (*value = readbuf_get(rb, len)) != NULL && rb->head[-1] == 0; } + +static int readbuf_string(struct readbuf *rb, const char **value, size_t *length) +{ + return _readbuf_string_(rb, value, length, 0); +} + +static int readbuf_nullstring(struct readbuf *rb, const char **value, size_t *length) +{ + return _readbuf_string_(rb, value, length, 1); +} + static int readbuf_object(struct readbuf *rb, struct json_object **object) { const char *string; @@ -326,6 +316,11 @@ static int writebuf_string(struct writebuf *wb, const char *value) return writebuf_string_length(wb, value, strlen(value)); } +static int writebuf_nullstring(struct writebuf *wb, const char *value) +{ + return value ? writebuf_string_length(wb, value, strlen(value)) : writebuf_uint32(wb, 0); +} + static int writebuf_object(struct writebuf *wb, struct json_object *object) { const char *string = json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN); @@ -349,15 +344,16 @@ void afb_proto_ws_call_unref(struct afb_proto_ws_call *call) free(call); } -int afb_proto_ws_call_success(struct afb_proto_ws_call *call, struct json_object *obj, const char *info) +int afb_proto_ws_call_reply(struct afb_proto_ws_call *call, struct json_object *obj, const char *error, const char *info) { int rc = -1; struct writebuf wb = { .count = 0 }; struct afb_proto_ws *protows = call->protows; - if (writebuf_char(&wb, CHAR_FOR_ANSWER_SUCCESS) + if (writebuf_char(&wb, CHAR_FOR_REPLY) && writebuf_uint32(&wb, call->callid) - && writebuf_string(&wb, info ?: "") + && writebuf_nullstring(&wb, error) + && writebuf_nullstring(&wb, info) && writebuf_object(&wb, obj)) { pthread_mutex_lock(&protows->mutex); rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count); @@ -371,73 +367,6 @@ success: return rc; } -int afb_proto_ws_call_fail(struct afb_proto_ws_call *call, const char *status, const char *info) -{ - int rc = -1; - struct writebuf wb = { .count = 0 }; - struct afb_proto_ws *protows = call->protows; - - if (writebuf_char(&wb, CHAR_FOR_ANSWER_FAIL) - && writebuf_uint32(&wb, call->callid) - && writebuf_string(&wb, status) - && writebuf_string(&wb, info ? : "")) { - pthread_mutex_lock(&protows->mutex); - rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count); - pthread_mutex_unlock(&protows->mutex); - if (rc >= 0) { - rc = 0; - goto success; - } - } -success: - return rc; -} - -int afb_proto_ws_call_subcall(struct afb_proto_ws_call *call, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure) -{ - int rc = -1; - struct writebuf wb = { .count = 0 }; - struct server_subcall *sc, *osc; - struct afb_proto_ws *protows = call->protows; - - sc = malloc(sizeof *sc); - if (!sc) - errno = ENOMEM; - else { - sc->callback = callback; - sc->closure = cb_closure; - - pthread_mutex_lock(&protows->mutex); - sc->subcallid = ptr2id(sc); - do { - sc->subcallid++; - osc = protows->subcalls; - while(osc && osc->subcallid != sc->subcallid) - osc = osc->next; - } while (osc); - sc->next = protows->subcalls; - protows->subcalls = sc; - pthread_mutex_unlock(&protows->mutex); - - if (writebuf_char(&wb, CHAR_FOR_SUBCALL_CALL) - && writebuf_uint32(&wb, sc->subcallid) - && writebuf_uint32(&wb, call->callid) - && writebuf_string(&wb, api) - && writebuf_string(&wb, verb) - && writebuf_object(&wb, args)) { - pthread_mutex_lock(&protows->mutex); - rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count); - pthread_mutex_unlock(&protows->mutex); - if (rc >= 0) { - rc = 0; - goto success; - } - } - } -success: - return rc; -} - int afb_proto_ws_call_subscribe(struct afb_proto_ws_call *call, const char *event_name, int event_id) { int rc = -1; @@ -613,113 +542,23 @@ static void client_on_event_push(struct afb_proto_ws *protows, struct readbuf *r protows->client_itf->on_event_push(protows->closure, event_name, (int)event_id, object); } -static void client_on_reply_success(struct afb_proto_ws *protows, struct readbuf *rb) +static void client_on_reply(struct afb_proto_ws *protows, struct readbuf *rb) { struct client_call *call; struct json_object *object; - const char *info; - - if (!client_msg_call_get(protows, rb, &call)) - return; - - if (readbuf_string(rb, &info, NULL) && readbuf_object(rb, &object)) { - protows->client_itf->on_reply_success(protows->closure, call->request, object, info); - } else { - protows->client_itf->on_reply_fail(protows->closure, call->request, "proto-error", "can't process success"); - } - client_call_destroy(call); -} - -static void client_on_reply_fail(struct afb_proto_ws *protows, struct readbuf *rb) -{ - struct client_call *call; - const char *info, *status; + const char *error, *info; if (!client_msg_call_get(protows, rb, &call)) return; - - if (readbuf_string(rb, &status, NULL) && readbuf_string(rb, &info, NULL)) { - protows->client_itf->on_reply_fail(protows->closure, call->request, status, info); + if (readbuf_nullstring(rb, &error, NULL) && readbuf_nullstring(rb, &info, NULL) && readbuf_object(rb, &object)) { + protows->client_itf->on_reply(protows->closure, call->request, object, error, info); } else { - protows->client_itf->on_reply_fail(protows->closure, call->request, "proto-error", "can't process fail"); + protows->client_itf->on_reply(protows->closure, call->request, NULL, "proto-error", "can't process success"); } client_call_destroy(call); } -/* send a subcall reply */ -static int client_send_subcall_reply(struct afb_proto_ws *protows, uint32_t subcallid, int status, json_object *object) -{ - struct writebuf wb = { .count = 0 }; - char ie = status < 0; - int rc; - - if (writebuf_char(&wb, CHAR_FOR_SUBCALL_REPLY) - && writebuf_uint32(&wb, subcallid) - && writebuf_char(&wb, ie) - && writebuf_object(&wb, object)) { - pthread_mutex_lock(&protows->mutex); - rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count); - pthread_mutex_unlock(&protows->mutex); - if (rc >= 0) - return 0; - } - return -1; -} - -/* callback for subcall reply */ -int afb_proto_ws_subcall_reply(struct afb_proto_ws_subcall *subcall, int status, struct json_object *result) -{ - int rc = client_send_subcall_reply(subcall->protows, subcall->subcallid, status, result); - afb_proto_ws_unref(subcall->protows); - free(subcall->buffer); - free(subcall); - return rc; -} - -/* received a subcall request */ -static void client_on_subcall(struct afb_proto_ws *protows, struct readbuf *rb) -{ - struct afb_proto_ws_subcall *subcall; - struct client_call *call; - const char *api, *verb; - uint32_t subcallid; - struct json_object *object; - - /* get the subcallid */ - if (!readbuf_uint32(rb, &subcallid)) - return; - - /* if not expected drop it */ - if (!protows->client_itf->on_subcall) - goto error; - - /* retrieve the message data */ - if (!client_msg_call_get(protows, rb, &call)) - goto error; - - /* allocation of the subcall */ - subcall = malloc(sizeof *subcall); - if (!subcall) - goto error; - - /* make the call */ - if (readbuf_string(rb, &api, NULL) - && readbuf_string(rb, &verb, NULL) - && readbuf_object(rb, &object)) { - afb_proto_ws_addref(protows); - subcall->protows = protows; - subcall->subcallid = subcallid; - subcall->buffer = rb->base; - rb->base = NULL; - protows->client_itf->on_subcall(protows->closure, subcall, call->request, api, verb, object); - return; - } - free(subcall); -error: - client_send_subcall_reply(protows, subcallid, 1, NULL); -} - static void client_on_description(struct afb_proto_ws *protows, struct readbuf *rb) { uint32_t descid; @@ -751,11 +590,8 @@ static void client_on_binary_job(int sig, void *closure) if (!sig) { switch (*binary->rb.head++) { - case CHAR_FOR_ANSWER_SUCCESS: /* success */ - client_on_reply_success(binary->protows, &binary->rb); - break; - case CHAR_FOR_ANSWER_FAIL: /* fail */ - client_on_reply_fail(binary->protows, &binary->rb); + case CHAR_FOR_REPLY: /* reply */ + client_on_reply(binary->protows, &binary->rb); break; case CHAR_FOR_EVT_BROADCAST: /* broadcast */ client_on_event_broadcast(binary->protows, &binary->rb); @@ -775,9 +611,6 @@ static void client_on_binary_job(int sig, void *closure) case CHAR_FOR_EVT_UNSUBSCRIBE: /* unsubscribe event for a request */ client_on_event_unsubscribe(binary->protows, &binary->rb); break; - case CHAR_FOR_SUBCALL_CALL: /* subcall */ - client_on_subcall(binary->protows, &binary->rb); - break; case CHAR_FOR_DESCRIPTION: /* description */ client_on_description(binary->protows, &binary->rb); break; @@ -819,7 +652,8 @@ int afb_proto_ws_client_call( const char *verb, struct json_object *args, const char *sessionid, - void *request + void *request, + const char *user_creds ) { int rc = -1; @@ -849,7 +683,8 @@ int afb_proto_ws_client_call( || !writebuf_uint32(&wb, call->callid) || !writebuf_string(&wb, verb) || !writebuf_string(&wb, sessionid) - || !writebuf_object(&wb, args)) { + || !writebuf_object(&wb, args) + || !writebuf_nullstring(&wb, user_creds)) { errno = EINVAL; goto clean; } @@ -929,7 +764,7 @@ error: static void server_on_call(struct afb_proto_ws *protows, struct readbuf *rb) { struct afb_proto_ws_call *call; - const char *uuid, *verb; + const char *uuid, *verb, *user_creds; uint32_t callid; size_t lenverb; struct json_object *object; @@ -940,7 +775,8 @@ static void server_on_call(struct afb_proto_ws *protows, struct readbuf *rb) if (!readbuf_uint32(rb, &callid) || !readbuf_string(rb, &verb, &lenverb) || !readbuf_string(rb, &uuid, NULL) - || !readbuf_object(rb, &object)) + || !readbuf_object(rb, &object) + || !readbuf_nullstring(rb, &user_creds, NULL)) goto overflow; /* create the request */ @@ -954,7 +790,7 @@ static void server_on_call(struct afb_proto_ws *protows, struct readbuf *rb) call->buffer = rb->base; rb->base = NULL; /* don't free the buffer */ - protows->server_itf->on_call(protows->closure, call, verb, object, uuid); + protows->server_itf->on_call(protows->closure, call, verb, object, uuid, user_creds); return; out_of_memory: @@ -964,39 +800,6 @@ overflow: afb_proto_ws_unref(protows); } -/* on subcall reply */ -static void server_on_subcall_reply(struct afb_proto_ws *protows, struct readbuf *rb) -{ - char ie; - uint32_t subcallid; - struct json_object *object; - struct server_subcall *sc, **psc; - - /* reads the call message data */ - if (!readbuf_uint32(rb, &subcallid) - || !readbuf_char(rb, &ie) - || !readbuf_object(rb, &object)) { - /* TODO bad protocol */ - return; - } - - /* search the subcall and unlink it */ - pthread_mutex_lock(&protows->mutex); - psc = &protows->subcalls; - while ((sc = *psc) && sc->subcallid != subcallid) - psc = &sc->next; - if (!sc) { - pthread_mutex_unlock(&protows->mutex); - json_object_put(object); - /* TODO subcall not found */ - } else { - *psc = sc->next; - pthread_mutex_unlock(&protows->mutex); - sc->callback(sc->closure, -(int)ie, object); - free(sc); - } -} - static int server_send_description(struct afb_proto_ws *protows, uint32_t descid, struct json_object *descobj) { int rc; @@ -1055,9 +858,6 @@ static void server_on_binary_job(int sig, void *closure) case CHAR_FOR_CALL: server_on_call(binary->protows, &binary->rb); break; - case CHAR_FOR_SUBCALL_REPLY: - server_on_subcall_reply(binary->protows, &binary->rb); - break; case CHAR_FOR_DESCRIBE: server_on_describe(binary->protows, &binary->rb); break; @@ -1139,17 +939,8 @@ int afb_proto_ws_server_event_broadcast(struct afb_proto_ws *protows, const char static void on_hangup(void *closure) { struct afb_proto_ws *protows = closure; - struct server_subcall *sc, *nsc; struct client_describe *cd, *ncd; - nsc = protows->subcalls; - while (nsc) { - sc= nsc; - nsc = sc->next; - sc->callback(sc->closure, 1, NULL); - free(sc); - } - ncd = protows->describes; while (ncd) { cd= ncd; @@ -1202,7 +993,6 @@ static struct afb_proto_ws *afb_proto_ws_create(struct fdev *fdev, const struct if (protows->ws != NULL) { protows->fdev = fdev; protows->refcount = 1; - protows->subcalls = NULL; protows->closure = closure; protows->server_itf = itfs; protows->client_itf = itfc; diff --git a/src/afb-proto-ws.h b/src/afb-proto-ws.h index d674af3d..342313e7 100644 --- a/src/afb-proto-ws.h +++ b/src/afb-proto-ws.h @@ -18,17 +18,21 @@ #pragma once +/* + * Defined since version 3, the value AFB_PROTO_WS_VERSION can be used to + * track versions of afb-proto-ws. + */ +#define AFB_PROTO_WS_VERSION 3 + struct fdev; struct afb_proto_ws; struct afb_proto_ws_call; -struct afb_proto_ws_subcall; struct afb_proto_ws_describe; struct afb_proto_ws_client_itf { /* can't be NULL */ - void (*on_reply_success)(void *closure, void *request, struct json_object *result, const char *info); - void (*on_reply_fail)(void *closure, void *request, const char *status, const char *info); + void (*on_reply)(void *closure, void *request, struct json_object *obj, const char *error, const char *info); /* can be NULL */ void (*on_event_create)(void *closure, const char *event_name, int event_id); @@ -37,13 +41,11 @@ struct afb_proto_ws_client_itf void (*on_event_unsubscribe)(void *closure, void *request, const char *event_name, int event_id); void (*on_event_push)(void *closure, const char *event_name, int event_id, struct json_object *data); void (*on_event_broadcast)(void *closure, const char *event_name, struct json_object *data); - - void (*on_subcall)(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args); }; struct afb_proto_ws_server_itf { - void (*on_call)(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid); + void (*on_call)(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid, const char *user_creds); void (*on_describe)(void *closure, struct afb_proto_ws_describe *describe); }; @@ -61,7 +63,7 @@ extern void afb_proto_ws_on_hangup(struct afb_proto_ws *protows, void (*on_hangu -extern int afb_proto_ws_client_call(struct afb_proto_ws *protows, const char *verb, struct json_object *args, const char *sessionid, void *request); +extern int afb_proto_ws_client_call(struct afb_proto_ws *protows, const char *verb, struct json_object *args, const char *sessionid, void *request, const char *user_creds); extern int afb_proto_ws_client_describe(struct afb_proto_ws *protows, void (*callback)(void*, struct json_object*), void *closure); extern int afb_proto_ws_server_event_create(struct afb_proto_ws *protows, const char *event_name, int event_id); @@ -72,14 +74,9 @@ extern int afb_proto_ws_server_event_broadcast(struct afb_proto_ws *protows, con extern void afb_proto_ws_call_addref(struct afb_proto_ws_call *call); extern void afb_proto_ws_call_unref(struct afb_proto_ws_call *call); -extern int afb_proto_ws_call_success(struct afb_proto_ws_call *call, struct json_object *obj, const char *info); -extern int afb_proto_ws_call_fail(struct afb_proto_ws_call *call, const char *status, const char *info); +extern int afb_proto_ws_call_reply(struct afb_proto_ws_call *call, struct json_object *obj, const char *error, const char *info); -extern int afb_proto_ws_call_subcall(struct afb_proto_ws_call *call, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure); extern int afb_proto_ws_call_subscribe(struct afb_proto_ws_call *call, const char *event_name, int event_id); extern int afb_proto_ws_call_unsubscribe(struct afb_proto_ws_call *call, const char *event_name, int event_id); -extern int afb_proto_ws_subcall_reply(struct afb_proto_ws_subcall *subcall, int status, struct json_object *result); - extern int afb_proto_ws_describe_put(struct afb_proto_ws_describe *describe, struct json_object *description); - diff --git a/src/afb-session.c b/src/afb-session.c index 8c0f77b8..16fc69bb 100644 --- a/src/afb-session.c +++ b/src/afb-session.c @@ -27,11 +27,10 @@ #include <uuid/uuid.h> #include <errno.h> -#include <json-c/json.h> - #include "afb-session.h" #include "afb-hook.h" #include "verbose.h" +#include "pearson.h" #define SIZEUUID 37 #define HEADCOUNT 16 @@ -43,41 +42,45 @@ #define MAX_EXPIRATION (_MAXEXP_ >= 0 ? _MAXEXP_ : _MAXEXP2_) #define NOW (time_now()) -/* structure for a cookie added to sessions */ +/** + * structure for a cookie added to sessions + */ struct cookie { - struct cookie *next; /* link to next cookie */ - const void *key; /* pointer key */ - void *value; /* value */ - void (*freecb)(void*); /* function to call when session is closed */ + struct cookie *next; /**< link to next cookie */ + const void *key; /**< pointer key */ + void *value; /**< value */ + void (*freecb)(void*); /**< function to call when session is closed */ }; -/* +/** * structure for session */ struct afb_session { - struct afb_session *next; /* link to the next */ - unsigned refcount; /* external reference count of the session */ - int timeout; /* timeout of the session */ - time_t expiration; /* expiration time of the token */ - pthread_mutex_t mutex; /* mutex of the session */ - struct cookie *cookies[COOKIECOUNT]; /* cookies of the session */ - uint8_t closed: 1; /* is the session closed ? */ - uint8_t autoclose: 1; /* close the session when unreferenced */ - uint8_t notinset: 1; /* session removed from the set of sessions */ - char uuid[SIZEUUID]; /* long term authentication of remote client */ - char token[SIZEUUID]; /* short term authentication of remote client */ + struct afb_session *next; /**< link to the next */ + unsigned refcount; /**< external reference count of the session */ + int timeout; /**< timeout of the session */ + time_t expiration; /**< expiration time of the token */ + pthread_mutex_t mutex; /**< mutex of the session */ + struct cookie *cookies[COOKIECOUNT]; /**< cookies of the session */ + uint8_t closed: 1; /**< is the session closed ? */ + uint8_t autoclose: 1; /**< close the session when unreferenced */ + uint8_t notinset: 1; /**< session removed from the set of sessions */ + char uuid[SIZEUUID]; /**< long term authentication of remote client */ + char token[SIZEUUID]; /**< short term authentication of remote client */ }; -/* Session UUID are store in a simple array [for 10 sessions this should be enough] */ +/** + * structure for managing sessions + */ static struct { - int count; /* current number of sessions */ - int max; /* maximum count of sessions */ - int timeout; /* common initial timeout */ - struct afb_session *heads[HEADCOUNT]; /* sessions */ - char initok[SIZEUUID]; /* common initial token */ - pthread_mutex_t mutex; /* declare a mutex to protect hash table */ + int count; /**< current number of sessions */ + int max; /**< maximum count of sessions */ + int timeout; /**< common initial timeout */ + struct afb_session *heads[HEADCOUNT]; /**< sessions */ + char initok[SIZEUUID]; /**< common initial token */ + pthread_mutex_t mutex; /**< declare a mutex to protect hash table */ } sessions = { .count = 0, .max = 10, @@ -87,7 +90,9 @@ static struct { .mutex = PTHREAD_MUTEX_INITIALIZER }; -/* Get the actual raw time */ +/** + * Get the actual raw time + */ static inline time_t time_now() { struct timespec ts; @@ -95,7 +100,9 @@ static inline time_t time_now() return ts.tv_sec; } -/* generate a new fresh 'uuid' */ +/** + * generate a new fresh 'uuid' + */ static void new_uuid(char uuid[SIZEUUID]) { uuid_t newuuid; @@ -103,26 +110,6 @@ static void new_uuid(char uuid[SIZEUUID]) uuid_unparse_lower(newuuid, uuid); } -/* - * Returns a tiny hash value for the 'text'. - * - * Tiny hash function inspired from pearson - */ -static uint8_t pearson4(const char *text) -{ - static uint8_t T[16] = { - 4, 1, 6, 0, 9, 14, 11, 5, - 2, 3, 12, 15, 10, 7, 8, 13 - }; - uint8_t r, c; - - for (r = 0; (c = (uint8_t)*text) ; text++) { - r = T[r ^ (15 & c)]; - r = T[r ^ (c >> 4)]; - } - return r; // % HEADCOUNT; -} - /* lock the set of sessions for exclusive access */ static inline void sessionset_lock() { @@ -155,7 +142,7 @@ static struct afb_session *sessionset_search(const char *uuid, uint8_t hashidx) static int sessionset_add(struct afb_session *session, uint8_t hashidx) { /* check availability */ - if (sessions.count >= sessions.max) { + if (sessions.max && sessions.count >= sessions.max) { errno = EBUSY; return -1; } @@ -321,7 +308,7 @@ static time_t sessionset_cleanup (int force) * @param max_session_count maximum allowed session count in the same time * @param timeout the initial default timeout of sessions * @param initok the initial default token of sessions - * + * */ int afb_session_init (int max_session_count, int timeout, const char *initok) { @@ -513,7 +500,7 @@ void afb_session_close (struct afb_session *session) * Set the 'autoclose' flag of the 'session' * * A session whose autoclose flag is true will close as - * soon as it is no more referenced. + * soon as it is no more referenced. * * @param session the session to set * @param autoclose the value to set @@ -694,8 +681,7 @@ void *afb_session_get_cookie(struct afb_session *session, const void *key) * @param value the value to store at key * @param freecb a function to use when the cookie value is to remove (or null) * - * @return the data staored for the key or NULL if the key isn't found - * + * @return 0 in case of success or -1 in case of error */ int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*)) { diff --git a/src/afb-stub-ws.c b/src/afb-stub-ws.c index e725d5ad..68bc8c7c 100644 --- a/src/afb-stub-ws.c +++ b/src/afb-stub-ws.c @@ -34,7 +34,7 @@ #include <json-c/json.h> -#include <afb/afb-event.h> +#include <afb/afb-event-x2.h> #include "afb-session.h" #include "afb-cred.h" @@ -52,29 +52,6 @@ struct afb_stub_ws; -/******************* handling subcalls *****************************/ - -/** - * Structure on server side for recording pending - * subcalls. - */ -struct server_subcall -{ - struct server_subcall *next; /**< next subcall for the client */ - uint32_t subcallid; /**< the subcallid */ - void (*callback)(void*, int, struct json_object*); /**< callback on completion */ - void *closure; /**< closure of the callback */ -}; - -/** - * Structure for sending back replies on client side - */ -struct client_subcall -{ - struct afb_stub_ws *stubws; /**< stub descriptor */ - uint32_t subcallid; /**< subcallid for the reply */ -}; - /* * structure for recording calls on client side */ @@ -100,7 +77,7 @@ struct server_req { struct client_event { struct client_event *next; - struct afb_eventid *eventid; + struct afb_event_x2 *event; int id; int refcount; }; @@ -152,7 +129,7 @@ struct afb_stub_ws /* event replica (client side) */ struct client_event *events; - /* credentials (server side) */ + /* credentials of the client (server side) */ struct afb_cred *cred; /* sessions (server side) */ @@ -183,57 +160,37 @@ static void server_req_destroy_cb(struct afb_xreq *xreq) free(wreq); } -static void server_req_success_cb(struct afb_xreq *xreq, struct json_object *obj, const char *info) +static void server_req_reply_cb(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { int rc; struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq); - rc = afb_proto_ws_call_success(wreq->call, obj, info); + rc = afb_proto_ws_call_reply(wreq->call, obj, error, info); if (rc < 0) - ERROR("error while sending success"); + ERROR("error while sending reply"); json_object_put(obj); } -static void server_req_fail_cb(struct afb_xreq *xreq, const char *status, const char *info) +static int server_req_subscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event) { int rc; struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq); - rc = afb_proto_ws_call_fail(wreq->call, status, info); - if (rc < 0) - ERROR("error while sending fail"); -} - -static void server_req_subcall_cb(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure) -{ - int rc; - struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq); - - rc = afb_proto_ws_call_subcall(wreq->call, api, verb, args, callback, cb_closure); - if (rc < 0) - ERROR("error while sending subcall"); -} - -static int server_req_subscribe_cb(struct afb_xreq *xreq, struct afb_eventid *event) -{ - int rc; - struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq); - - rc = afb_evt_eventid_add_watch(wreq->stubws->listener, event); + rc = afb_evt_event_x2_add_watch(wreq->stubws->listener, event); if (rc >= 0) - rc = afb_proto_ws_call_subscribe(wreq->call, afb_evt_eventid_fullname(event), afb_evt_eventid_id(event)); + rc = afb_proto_ws_call_subscribe(wreq->call, afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event)); if (rc < 0) ERROR("error while subscribing event"); return rc; } -static int server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_eventid *event) +static int server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event) { int rc, rc2; struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq); - rc = afb_proto_ws_call_unsubscribe(wreq->call, afb_evt_eventid_fullname(event), afb_evt_eventid_id(event)); - rc2 = afb_evt_eventid_remove_watch(wreq->stubws->listener, event); + rc = afb_proto_ws_call_unsubscribe(wreq->call, afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event)); + rc2 = afb_evt_event_x2_remove_watch(wreq->stubws->listener, event); if (rc >= 0 && rc2 < 0) rc = rc2; if (rc < 0) @@ -242,10 +199,8 @@ static int server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_eventid * } static const struct afb_xreq_query_itf server_req_xreq_itf = { - .success = server_req_success_cb, - .fail = server_req_fail_cb, + .reply = server_req_reply_cb, .unref = server_req_destroy_cb, - .subcall = server_req_subcall_cb, .subscribe = server_req_subscribe_cb, .unsubscribe = server_req_unsubscribe_cb }; @@ -258,7 +213,7 @@ static struct client_event *client_event_search(struct afb_stub_ws *stubws, uint struct client_event *ev; ev = stubws->events; - while (ev != NULL && (ev->id != eventid || 0 != strcmp(afb_evt_eventid_fullname(ev->eventid), name))) + while (ev != NULL && (ev->id != eventid || 0 != strcmp(afb_evt_event_x2_fullname(ev->event), name))) ev = ev->next; return ev; @@ -269,7 +224,13 @@ static void client_call_cb(void * closure, struct afb_xreq *xreq) { struct afb_stub_ws *stubws = closure; - afb_proto_ws_client_call(stubws->proto, xreq->request.verb, afb_xreq_json(xreq), afb_session_uuid(xreq->context.session), xreq); + afb_proto_ws_client_call( + stubws->proto, + xreq->request.called_verb, + afb_xreq_json(xreq), + afb_session_uuid(xreq->context.session), + xreq, + xreq_on_behalf_cred_export(xreq)); afb_xreq_unhooked_addref(xreq); } @@ -339,19 +300,11 @@ static void server_event_broadcast(void *closure, const char *event, int eventid /*****************************************************/ -static void on_reply_success(void *closure, void *request, struct json_object *result, const char *info) -{ - struct afb_xreq *xreq = request; - - afb_xreq_success(xreq, result, *info ? info : NULL); - afb_xreq_unhooked_unref(xreq); -} - -static void on_reply_fail(void *closure, void *request, const char *status, const char *info) +static void on_reply(void *closure, void *request, struct json_object *object, const char *error, const char *info) { struct afb_xreq *xreq = request; - afb_xreq_fail(xreq, status, *info ? info : NULL); + afb_xreq_reply(xreq, object, error, info); afb_xreq_unhooked_unref(xreq); } @@ -370,8 +323,8 @@ static void on_event_create(void *closure, const char *event_name, int event_id) /* no conflict, try to add it */ ev = malloc(sizeof *ev); if (ev != NULL) { - ev->eventid = afb_evt_eventid_create(event_name); - if (ev->eventid != NULL) { + ev->event = afb_evt_event_x2_create(event_name); + if (ev->event != NULL) { ev->refcount = 1; ev->id = event_id; ev->next = stubws->events; @@ -404,7 +357,7 @@ static void on_event_remove(void *closure, const char *event_name, int event_id) *prv = ev->next; /* destroys the event */ - afb_evt_eventid_unref(ev->eventid); + afb_evt_event_x2_unref(ev->event); free(ev); } @@ -419,7 +372,7 @@ static void on_event_subscribe(void *closure, void *request, const char *event_n if (ev == NULL) return; - if (afb_xreq_subscribe(xreq, ev->eventid) < 0) + if (afb_xreq_subscribe(xreq, ev->event) < 0) ERROR("can't subscribe: %m"); } @@ -434,7 +387,7 @@ static void on_event_unsubscribe(void *closure, void *request, const char *event if (ev == NULL) return; - if (afb_xreq_unsubscribe(xreq, ev->eventid) < 0) + if (afb_xreq_unsubscribe(xreq, ev->event) < 0) ERROR("can't unsubscribe: %m"); } @@ -446,7 +399,7 @@ static void on_event_push(void *closure, const char *event_name, int event_id, s /* check conflicts */ ev = client_event_search(stubws, event_id, event_name); if (ev) - afb_evt_eventid_push(ev->eventid, data); + afb_evt_event_x2_push(ev->event, data); else ERROR("unreadable push event"); } @@ -456,19 +409,6 @@ static void on_event_broadcast(void *closure, const char *event_name, struct jso afb_evt_broadcast(event_name, data); } -static void client_subcall_reply_cb(void *closure, int status, json_object *object, struct afb_request *request) -{ - struct afb_proto_ws_subcall *subcall = closure; - afb_proto_ws_subcall_reply(subcall, status, object); -} - -static void on_subcall(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args) -{ - struct afb_xreq *xreq = request; - - afb_xreq_subcall(xreq, api, verb, args, client_subcall_reply_cb, subcall); -} - /*****************************************************/ static void record_session(struct afb_stub_ws *stubws, struct afb_session *session) @@ -514,7 +454,7 @@ static void release_all_sessions(struct afb_stub_ws *stubws) /*****************************************************/ -static void on_call(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid) +static void on_call(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid, const char *user_creds) { struct afb_stub_ws *stubws = closure; struct server_req *wreq; @@ -539,9 +479,9 @@ static void on_call(void *closure, struct afb_proto_ws_call *call, const char *v afb_session_set_autoclose(wreq->xreq.context.session, 1); /* makes the call */ - wreq->xreq.cred = afb_cred_addref(stubws->cred); - wreq->xreq.request.api = stubws->apiname; - wreq->xreq.request.verb = verb; + wreq->xreq.cred = afb_cred_mixed_on_behalf_import(stubws->cred, sessionid, user_creds); + wreq->xreq.request.called_api = stubws->apiname; + wreq->xreq.request.called_verb = verb; wreq->xreq.json = args; afb_xreq_process(&wreq->xreq, stubws->apiset); return; @@ -551,7 +491,7 @@ unconnected: out_of_memory: json_object_put(args); afb_stub_ws_unref(stubws); - afb_proto_ws_call_fail(call, "internal-error", NULL); + afb_proto_ws_call_reply(call, NULL, "internal-error", NULL); afb_proto_ws_call_unref(call); } @@ -601,15 +541,13 @@ static void on_describe(void *closure, struct afb_proto_ws_describe *describe) static const struct afb_proto_ws_client_itf client_itf = { - .on_reply_success = on_reply_success, - .on_reply_fail = on_reply_fail, + .on_reply = on_reply, .on_event_create = on_event_create, .on_event_remove = on_event_remove, .on_event_subscribe = on_event_subscribe, .on_event_unsubscribe = on_event_unsubscribe, .on_event_push = on_event_push, .on_event_broadcast = on_event_broadcast, - .on_subcall = on_subcall }; static const struct afb_proto_ws_server_itf server_itf = @@ -642,7 +580,7 @@ static void drop_all_events(struct afb_stub_ws *stubws) while (ev) { nxt = ev->next; - afb_evt_eventid_unref(ev->eventid); + afb_evt_event_x2_unref(ev->event); free(ev); ev = nxt; } @@ -738,9 +676,9 @@ const char *afb_stub_ws_name(struct afb_stub_ws *stubws) return stubws->apiname; } -struct afb_api afb_stub_ws_client_api(struct afb_stub_ws *stubws) +struct afb_api_item afb_stub_ws_client_api(struct afb_stub_ws *stubws) { - struct afb_api api; + struct afb_api_item api; assert(!stubws->listener); /* check client */ api.closure = stubws; diff --git a/src/afb-stub-ws.h b/src/afb-stub-ws.h index aa643363..e14eac17 100644 --- a/src/afb-stub-ws.h +++ b/src/afb-stub-ws.h @@ -21,7 +21,7 @@ struct fdev; struct afb_stub_ws; struct afb_apiset; -struct afb_api; +struct afb_api_item; extern struct afb_stub_ws *afb_stub_ws_create_client(struct fdev *fdev, const char *apiname, struct afb_apiset *apiset); @@ -35,7 +35,7 @@ extern void afb_stub_ws_on_hangup(struct afb_stub_ws *stubws, void (*on_hangup)( extern const char *afb_stub_ws_name(struct afb_stub_ws *stubws); -extern struct afb_api afb_stub_ws_client_api(struct afb_stub_ws *stubws); +extern struct afb_api_item afb_stub_ws_client_api(struct afb_stub_ws *stubws); extern int afb_stub_ws_client_add(struct afb_stub_ws *stubws, struct afb_apiset *apiset); diff --git a/src/afb-supervision.c b/src/afb-supervision.c index f1024c3c..79a9d3fd 100644 --- a/src/afb-supervision.c +++ b/src/afb-supervision.c @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #define _GNU_SOURCE #define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO @@ -29,7 +28,9 @@ #include <sys/un.h> #include <json-c/json.h> -#include <afb/afb-binding-v2.h> + +#define AFB_BINDING_VERSION 3 +#include <afb/afb-binding.h> #include "afb-cred.h" #include "afb-api.h" @@ -252,7 +253,7 @@ int afb_supervision_init() /* init the apiset */ rc = afb_apiset_add(supervision_apiset, supervision_apiname, - (struct afb_api){ .itf = &supervision_api_itf, .closure = NULL}); + (struct afb_api_item){ .itf = &supervision_api_itf, .closure = NULL}); if (rc < 0) { ERROR("Can't create supervision's apiset: %m"); afb_apiset_unref(supervision_apiset); @@ -298,14 +299,14 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq) struct json_object *args, *drop, *add, *sub, *list; const char *api, *verb, *uuid; struct afb_session *session; - const struct afb_api *xapi; - struct afb_req req; + const struct afb_api_item *xapi; + afb_req_t req; /* search the verb */ i = (int)(sizeof verbs / sizeof *verbs); - while(--i >= 0 && strcasecmp(verbs[i], xreq->request.verb)); + while(--i >= 0 && strcasecmp(verbs[i], xreq->request.called_verb)); if (i < 0) { - afb_xreq_fail_unknown_verb(xreq); + afb_xreq_reply_unknown_verb(xreq); return; } @@ -324,32 +325,32 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq) if (wrap_json_unpack(args, "s", &uuid)) wrap_json_unpack(args, "{ss}", "uuid", &uuid); if (!uuid) - afb_xreq_fail(xreq, "invalid", NULL); + afb_xreq_reply(xreq, NULL, "invalid", NULL); else { session = afb_session_search(uuid); if (!session) - afb_xreq_fail(xreq, "not-found", NULL); + afb_xreq_reply(xreq, NULL, "not-found", NULL); else { afb_session_close(session); afb_session_unref(session); afb_session_purge(); - afb_xreq_success(xreq, NULL, NULL); + afb_xreq_reply(xreq, NULL, NULL, NULL); } } break; case Slist: list = json_object_new_object(); afb_session_foreach(slist, list); - afb_xreq_success(xreq, list, NULL); + afb_xreq_reply(xreq, list, NULL, NULL); break; case Config: - afb_xreq_success(xreq, afb_config_json(main_config), NULL); + afb_xreq_reply(xreq, afb_config_json(main_config), NULL, NULL); break; case Trace: if (!trace) trace = afb_trace_create(supervisor_apiname, NULL /* not bound to any session */); - req = xreq_to_req(xreq); + req = xreq_to_req_x2(xreq); add = drop = NULL; wrap_json_unpack(args, "{s?o s?o}", "add", &add, "drop", &drop); if (add) { @@ -367,16 +368,16 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq) case Do: sub = NULL; if (wrap_json_unpack(args, "{ss ss s?o*}", "api", &api, "verb", &verb, "args", &sub)) - afb_xreq_fail(xreq, "error", "bad request"); + afb_xreq_reply(xreq, NULL, "error", "bad request"); else { xapi = afb_apiset_lookup_started(main_apiset, api, 1); if (!xapi) - afb_xreq_fail_unknown_api(xreq); + afb_xreq_reply_unknown_api(xreq); else { afb_cred_unref(xreq->cred); xreq->cred = NULL; - xreq->request.api = api; - xreq->request.verb = verb; + xreq->request.called_api = api; + xreq->request.called_verb = verb; xreq->json = json_object_get(sub); xapi->itf->call(xapi->closure, xreq); json_object_put(args); @@ -384,11 +385,11 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq) } break; case Wait: - afb_req_success(req, NULL, NULL); + afb_xreq_reply(xreq, NULL, NULL, NULL); afb_debug_wait("supervisor"); break; case Break: - afb_req_success(req, NULL, NULL); + afb_xreq_reply(xreq, NULL, NULL, NULL); afb_debug_break("supervisor"); break; } diff --git a/src/afb-trace.c b/src/afb-trace.c index 5404a5af..a603951c 100644 --- a/src/afb-trace.c +++ b/src/afb-trace.c @@ -28,7 +28,7 @@ #include <json-c/json.h> -#define AFB_BINDING_VERSION 0 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> #include "afb-hook.h" @@ -74,7 +74,7 @@ struct tag { /* struct for events */ struct event { struct event *next; /* link to the next event */ - struct afb_evtid *evtid; /* the event */ + struct afb_evtid *evtid; /* the event */ }; /* struct for sessions */ @@ -95,13 +95,16 @@ struct hook { /* types of hooks */ enum trace_type { - Trace_Type_Xreq, /* xreq hooks */ - Trace_Type_Ditf, /* export hooks */ - Trace_Type_Svc, /* export hooks */ - Trace_Type_Evt, /* evt hooks */ - Trace_Type_Session, /* session hooks */ - Trace_Type_Global, /* global hooks */ - Trace_Type_Count /* count of types of hooks */ + Trace_Type_Xreq, /* xreq hooks */ + Trace_Type_Api, /* api hooks */ + Trace_Type_Evt, /* evt hooks */ + Trace_Type_Session, /* session hooks */ + Trace_Type_Global, /* global hooks */ +#if !defined(REMOVE_LEGACY_TRACE) + Trace_Legacy_Type_Ditf, /* export hooks */ + Trace_Legacy_Type_Svc, /* export hooks */ +#endif + Trace_Type_Count, /* count of types of hooks */ }; /* client data */ @@ -168,8 +171,15 @@ static struct json_object *timestamp(const struct afb_hookid *hookid) { char ts[50]; - snprintf(ts, sizeof ts, "%llu.%06lu", (long long unsigned)hookid->time.tv_sec, (long unsigned)(hookid->time.tv_nsec / 1000)); + snprintf(ts, sizeof ts, "%llu.%06lu", + (long long unsigned)hookid->time.tv_sec, + (long unsigned)((hookid->time.tv_nsec + 500) / 1000)); + + return json_object_new_double_s(0.0f, ts); /* the real value isn't used */ +#if 0 return json_object_new_string(ts); + return json_object_new_double_s(0f, ts); /* the real value isn't used */ +#endif } /* verbosity level name or NULL */ @@ -222,38 +232,35 @@ static struct flag xreq_flags[] = { /* must be sorted by names */ { "begin", afb_hook_flag_req_begin }, { "common", afb_hook_flags_req_common }, { "context", afb_hook_flags_req_context }, - { "context_get", afb_hook_flag_req_context_get }, + { "context_get", afb_hook_flag_req_legacy_context_get }, { "context_make", afb_hook_flag_req_context_make }, - { "context_set", afb_hook_flag_req_context_set }, + { "context_set", afb_hook_flag_req_legacy_context_set }, { "end", afb_hook_flag_req_end }, { "event", afb_hook_flags_req_event }, { "extra", afb_hook_flags_req_extra }, - { "fail", afb_hook_flag_req_fail }, { "get", afb_hook_flag_req_get }, { "get_application_id", afb_hook_flag_req_get_application_id }, + { "get_client_info", afb_hook_flag_req_get_client_info }, { "get_uid", afb_hook_flag_req_get_uid }, { "has_permission", afb_hook_flag_req_has_permission }, { "json", afb_hook_flag_req_json }, { "life", afb_hook_flags_req_life }, { "ref", afb_hook_flags_req_ref }, - { "result", afb_hook_flags_req_result }, + { "reply", afb_hook_flag_req_reply }, { "security", afb_hook_flags_req_security }, { "session", afb_hook_flags_req_session }, { "session_close", afb_hook_flag_req_session_close }, { "session_set_LOA", afb_hook_flag_req_session_set_LOA }, - { "store", afb_hook_flag_req_store }, + { "store", afb_hook_flag_req_legacy_store }, { "stores", afb_hook_flags_req_stores }, { "subcall", afb_hook_flag_req_subcall }, - { "subcall_req", afb_hook_flag_req_subcall_req }, - { "subcall_req_result", afb_hook_flag_req_subcall_req_result }, { "subcall_result", afb_hook_flag_req_subcall_result }, { "subcalls", afb_hook_flags_req_subcalls }, { "subcallsync", afb_hook_flag_req_subcallsync }, { "subcallsync_result", afb_hook_flag_req_subcallsync_result }, { "subscribe", afb_hook_flag_req_subscribe }, - { "success", afb_hook_flag_req_success }, { "unref", afb_hook_flag_req_unref }, - { "unstore", afb_hook_flag_req_unstore }, + { "unstore", afb_hook_flag_req_legacy_unstore }, { "unsubscribe", afb_hook_flag_req_unsubscribe }, { "vverbose", afb_hook_flag_req_vverbose }, }; @@ -285,8 +292,8 @@ static void hook_xreq(void *closure, const struct afb_hookid *hookid, const stru va_start(ap, format); emit(closure, hookid, "request", "{si ss ss ss so* ss*}", format, ap, "index", xreq->hookindex, - "api", xreq->request.api, - "verb", xreq->request.verb, + "api", xreq->request.called_api, + "verb", xreq->request.called_verb, "action", action, "credentials", cred, "session", session); @@ -295,7 +302,8 @@ static void hook_xreq(void *closure, const struct afb_hookid *hookid, const stru static void hook_xreq_begin(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { - hook_xreq(closure, hookid, xreq, "begin", NULL); + hook_xreq(closure, hookid, xreq, "begin", "{sO?}", + "json", afb_xreq_unhooked_json((struct afb_xreq*)xreq)); } static void hook_xreq_end(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) @@ -318,17 +326,11 @@ static void hook_xreq_get(void *closure, const struct afb_hookid *hookid, const "path", arg.path); } -static void hook_xreq_success(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info) +static void hook_xreq_reply(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { - hook_xreq(closure, hookid, xreq, "success", "{sO? ss?}", + hook_xreq(closure, hookid, xreq, "reply", "{sO? ss? ss?}", "result", obj, - "info", info); -} - -static void hook_xreq_fail(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info) -{ - hook_xreq(closure, hookid, xreq, "fail", "{ss? ss?}", - "status", status, + "error", error, "info", info); } @@ -364,21 +366,21 @@ static void hook_xreq_session_set_LOA(void *closure, const struct afb_hookid *ho "result", result); } -static void hook_xreq_subscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +static void hook_xreq_subscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event, int result) { hook_xreq(closure, hookid, xreq, "subscribe", "{s{ss si} si}", "event", - "name", afb_evt_eventid_fullname(eventid), - "id", afb_evt_eventid_id(eventid), + "name", afb_evt_event_x2_fullname(event), + "id", afb_evt_event_x2_id(event), "result", result); } -static void hook_xreq_unsubscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +static void hook_xreq_unsubscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event, int result) { hook_xreq(closure, hookid, xreq, "unsubscribe", "{s{ss? si} si}", "event", - "name", afb_evt_eventid_fullname(eventid), - "id", afb_evt_eventid_id(eventid), + "name", afb_evt_event_x2_fullname(event), + "id", afb_evt_event_x2_id(event), "result", result); } @@ -390,11 +392,12 @@ static void hook_xreq_subcall(void *closure, const struct afb_hookid *hookid, co "args", args); } -static void hook_xreq_subcall_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) +static void hook_xreq_subcall_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { - hook_xreq(closure, hookid, xreq, "subcall_result", "{si sO?}", - "status", status, - "result", result); + hook_xreq(closure, hookid, xreq, "subcall_result", "{sO? ss? ss?}", + "object", object, + "error", error, + "info", info); } static void hook_xreq_subcallsync(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) @@ -405,11 +408,13 @@ static void hook_xreq_subcallsync(void *closure, const struct afb_hookid *hookid "args", args); } -static void hook_xreq_subcallsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) +static void hook_xreq_subcallsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info) { - hook_xreq(closure, hookid, xreq, "subcallsync_result", "{si sO?}", + hook_xreq(closure, hookid, xreq, "subcallsync_result", "{si sO? ss? ss?}", "status", status, - "result", result); + "object", object, + "error", error, + "info", info); } static void hook_xreq_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args) @@ -448,21 +453,6 @@ static void hook_xreq_unstore(void *closure, const struct afb_hookid *hookid, co hook_xreq(closure, hookid, xreq, "unstore", NULL); } -static void hook_xreq_subcall_req(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) -{ - hook_xreq(closure, hookid, xreq, "subcall_req", "{ss? ss? sO?}", - "api", api, - "verb", verb, - "args", args); -} - -static void hook_xreq_subcall_req_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) -{ - hook_xreq(closure, hookid, xreq, "subcall_req_result", "{si sO?}", - "status", status, - "result", result); -} - static void hook_xreq_has_permission(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result) { hook_xreq(closure, hookid, xreq, "has_permission", "{ss sb}", @@ -497,15 +487,20 @@ static void hook_xreq_get_uid(void *closure, const struct afb_hookid *hookid, co "result", result); } +static void hook_xreq_get_client_info(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *result) +{ + hook_xreq(closure, hookid, xreq, "get_client_info", "{so}", + "result", result); +} + static struct afb_hook_xreq_itf hook_xreq_itf = { .hook_xreq_begin = hook_xreq_begin, .hook_xreq_end = hook_xreq_end, .hook_xreq_json = hook_xreq_json, .hook_xreq_get = hook_xreq_get, - .hook_xreq_success = hook_xreq_success, - .hook_xreq_fail = hook_xreq_fail, - .hook_xreq_context_get = hook_xreq_context_get, - .hook_xreq_context_set = hook_xreq_context_set, + .hook_xreq_reply = hook_xreq_reply, + .hook_xreq_legacy_context_get = hook_xreq_context_get, + .hook_xreq_legacy_context_set = hook_xreq_context_set, .hook_xreq_addref = hook_xreq_addref, .hook_xreq_unref = hook_xreq_unref, .hook_xreq_session_close = hook_xreq_session_close, @@ -517,85 +512,146 @@ static struct afb_hook_xreq_itf hook_xreq_itf = { .hook_xreq_subcallsync = hook_xreq_subcallsync, .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result, .hook_xreq_vverbose = hook_xreq_vverbose, - .hook_xreq_store = hook_xreq_store, - .hook_xreq_unstore = hook_xreq_unstore, - .hook_xreq_subcall_req = hook_xreq_subcall_req, - .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result, + .hook_xreq_legacy_store = hook_xreq_store, + .hook_xreq_legacy_unstore = hook_xreq_unstore, .hook_xreq_has_permission = hook_xreq_has_permission, .hook_xreq_get_application_id = hook_xreq_get_application_id, .hook_xreq_context_make = hook_xreq_context_make, .hook_xreq_get_uid = hook_xreq_get_uid, + .hook_xreq_get_client_info = hook_xreq_get_client_info, }; /*******************************************************************************/ -/***** trace the daemon interface *****/ +/***** trace the api interface *****/ /*******************************************************************************/ -static struct flag ditf_flags[] = { /* must be sorted by names */ - { "all", afb_hook_flags_ditf_all }, - { "common", afb_hook_flags_ditf_common }, - { "event_broadcast_after", afb_hook_flag_ditf_event_broadcast_after }, - { "event_broadcast_before", afb_hook_flag_ditf_event_broadcast_before }, - { "event_make", afb_hook_flag_ditf_event_make }, - { "extra", afb_hook_flags_ditf_extra }, - { "get_event_loop", afb_hook_flag_ditf_get_event_loop }, - { "get_system_bus", afb_hook_flag_ditf_get_system_bus }, - { "get_user_bus", afb_hook_flag_ditf_get_user_bus }, - { "queue_job", afb_hook_flag_ditf_queue_job }, - { "require_api", afb_hook_flag_ditf_require_api }, - { "require_api_result", afb_hook_flag_ditf_require_api_result }, - { "rootdir_get_fd", afb_hook_flag_ditf_rootdir_get_fd }, - { "rootdir_open_locale", afb_hook_flag_ditf_rootdir_open_locale }, - { "unstore_req", afb_hook_flag_ditf_unstore_req }, - { "vverbose", afb_hook_flag_ditf_vverbose }, +#if !defined(REMOVE_LEGACY_TRACE) +static struct flag legacy_ditf_flags[] = { /* must be sorted by names */ + { "all", afb_hook_flags_api_ditf_all }, + { "common", afb_hook_flags_api_ditf_common }, + { "event_broadcast_after", afb_hook_flag_api_event_broadcast }, + { "event_broadcast_before", afb_hook_flag_api_event_broadcast }, + { "event_make", afb_hook_flag_api_event_make }, + { "extra", afb_hook_flags_api_ditf_extra }, + { "get_event_loop", afb_hook_flag_api_get_event_loop }, + { "get_system_bus", afb_hook_flag_api_get_system_bus }, + { "get_user_bus", afb_hook_flag_api_get_user_bus }, + { "queue_job", afb_hook_flag_api_queue_job }, + { "require_api", afb_hook_flag_api_require_api }, + { "require_api_result", afb_hook_flag_api_require_api }, + { "rootdir_get_fd", afb_hook_flag_api_rootdir_get_fd }, + { "rootdir_open_locale", afb_hook_flag_api_rootdir_open_locale }, + { "unstore_req", afb_hook_flag_api_legacy_unstore_req }, + { "vverbose", afb_hook_flag_api_vverbose }, }; +static struct flag legacy_svc_flags[] = { /* must be sorted by names */ + { "all", afb_hook_flags_api_svc_all }, + { "call", afb_hook_flag_api_call }, + { "call_result", afb_hook_flag_api_call }, + { "callsync", afb_hook_flag_api_callsync }, + { "callsync_result", afb_hook_flag_api_callsync }, + { "on_event_after", afb_hook_flag_api_on_event }, + { "on_event_before", afb_hook_flag_api_on_event }, + { "start_after", afb_hook_flag_api_start }, + { "start_before", afb_hook_flag_api_start }, +}; + +/* get the export value for flag of 'name' */ +static int get_legacy_ditf_flag(const char *name) +{ + return get_flag(name, legacy_ditf_flags, (int)(sizeof legacy_ditf_flags / sizeof *legacy_ditf_flags)); +} + /* get the export value for flag of 'name' */ -static int get_ditf_flag(const char *name) +static int get_legacy_svc_flag(const char *name) { - return get_flag(name, ditf_flags, (int)(sizeof ditf_flags / sizeof *ditf_flags)); + return get_flag(name, legacy_svc_flags, (int)(sizeof legacy_svc_flags / sizeof *legacy_svc_flags)); } +#endif + +static struct flag api_flags[] = { /* must be sorted by names */ + { "add_alias", afb_hook_flag_api_add_alias }, + { "all", afb_hook_flags_api_all }, + { "api_add_verb", afb_hook_flag_api_api_add_verb }, + { "api", afb_hook_flags_api_api }, + { "api_del_verb", afb_hook_flag_api_api_del_verb }, + { "api_seal", afb_hook_flag_api_api_seal }, + { "api_set_on_event", afb_hook_flag_api_api_set_on_event }, + { "api_set_on_init", afb_hook_flag_api_api_set_on_init }, + { "api_set_verbs", afb_hook_flag_api_api_set_verbs }, + { "call", afb_hook_flag_api_call }, + { "callsync", afb_hook_flag_api_callsync }, + { "class_provide", afb_hook_flag_api_class_provide }, + { "class_require", afb_hook_flag_api_class_require }, + { "common", afb_hook_flags_api_common }, + { "delete_api", afb_hook_flag_api_delete_api }, + { "event", afb_hook_flags_api_event }, + { "event_broadcast", afb_hook_flag_api_event_broadcast }, + { "event_handler_add", afb_hook_flag_api_event_handler_add }, + { "event_handler_del", afb_hook_flag_api_event_handler_del }, + { "event_make", afb_hook_flag_api_event_make }, + { "extra", afb_hook_flags_api_extra }, + { "get_event_loop", afb_hook_flag_api_get_event_loop }, + { "get_system_bus", afb_hook_flag_api_get_system_bus }, + { "get_user_bus", afb_hook_flag_api_get_user_bus }, + { "legacy_unstore_req", afb_hook_flag_api_legacy_unstore_req }, + { "new_api", afb_hook_flag_api_new_api }, + { "on_event", afb_hook_flag_api_on_event }, + { "on_event_handler", afb_hook_flag_api_on_event_handler }, + { "queue_job", afb_hook_flag_api_queue_job }, + { "require_api", afb_hook_flag_api_require_api }, + { "rootdir_get_fd", afb_hook_flag_api_rootdir_get_fd }, + { "rootdir_open_locale",afb_hook_flag_api_rootdir_open_locale }, + { "start", afb_hook_flag_api_start }, + { "vverbose", afb_hook_flag_api_vverbose }, +}; +/* get the export value for flag of 'name' */ +static int get_api_flag(const char *name) +{ + return get_flag(name, api_flags, (int)(sizeof api_flags / sizeof *api_flags)); +} -static void hook_ditf(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...) +static void hook_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...) { va_list ap; va_start(ap, format); - emit(closure, hookid, "daemon", "{ss ss}", format, ap, + emit(closure, hookid, "api", "{ss ss}", format, ap, "api", afb_export_apiname(export), "action", action); va_end(ap); } -static void hook_ditf_event_broadcast_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object) +static void hook_api_event_broadcast_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object) { - hook_ditf(closure, hookid, export, "event_broadcast_before", "{ss sO*}", + hook_api(closure, hookid, export, "event_broadcast_before", "{ss sO?}", "name", name, "data", object); } -static void hook_ditf_event_broadcast_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result) +static void hook_api_event_broadcast_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result) { - hook_ditf(closure, hookid, export, "event_broadcast_after", "{ss sO* si}", + hook_api(closure, hookid, export, "event_broadcast_after", "{ss sO? si}", "name", name, "data", object, "result", result); } -static void hook_ditf_get_event_loop(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result) +static void hook_api_get_event_loop(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result) { - hook_ditf(closure, hookid, export, "get_event_loop", NULL); + hook_api(closure, hookid, export, "get_event_loop", NULL); } -static void hook_ditf_get_user_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) +static void hook_api_get_user_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) { - hook_ditf(closure, hookid, export, "get_user_bus", NULL); + hook_api(closure, hookid, export, "get_user_bus", NULL); } -static void hook_ditf_get_system_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) +static void hook_api_get_system_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) { - hook_ditf(closure, hookid, export, "get_system_bus", NULL); + hook_api(closure, hookid, export, "get_system_bus", NULL); } -static void hook_ditf_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void hook_api_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { struct json_object *pos; int len; @@ -612,7 +668,7 @@ static void hook_ditf_vverbose(void *closure, const struct afb_hookid *hookid, c if (file) wrap_json_pack(&pos, "{ss si ss*}", "file", file, "line", line, "function", function); - hook_ditf(closure, hookid, export, "vverbose", "{si ss* ss? so*}", + hook_api(closure, hookid, export, "vverbose", "{si ss* ss? so*}", "level", level, "type", verbosity_level_name(level), len < 0 ? "format" : "message", len < 0 ? fmt : msg, @@ -621,13 +677,13 @@ static void hook_ditf_vverbose(void *closure, const struct afb_hookid *hookid, c free(msg); } -static void hook_ditf_event_make(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_eventid *result) +static void hook_api_event_make(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_event_x2 *result) { - hook_ditf(closure, hookid, export, "event_make", "{ss ss si}", - "name", name, "event", afb_evt_eventid_fullname(result), "id", afb_evt_eventid_id(result)); + hook_api(closure, hookid, export, "event_make", "{ss ss si}", + "name", name, "event", afb_evt_event_x2_fullname(result), "id", afb_evt_event_x2_id(result)); } -static void hook_ditf_rootdir_get_fd(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +static void hook_api_rootdir_get_fd(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) { char path[PATH_MAX]; @@ -636,12 +692,12 @@ static void hook_ditf_rootdir_get_fd(void *closure, const struct afb_hookid *hoo readlink(path, path, sizeof path); } - hook_ditf(closure, hookid, export, "rootdir_get_fd", "{ss}", + hook_api(closure, hookid, export, "rootdir_get_fd", "{ss}", result < 0 ? "path" : "error", result < 0 ? strerror(errno) : path); } -static void hook_ditf_rootdir_open_locale(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result) +static void hook_api_rootdir_open_locale(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result) { char path[PATH_MAX]; @@ -650,7 +706,7 @@ static void hook_ditf_rootdir_open_locale(void *closure, const struct afb_hookid readlink(path, path, sizeof path); } - hook_ditf(closure, hookid, export, "rootdir_open_locale", "{ss si ss* ss}", + hook_api(closure, hookid, export, "rootdir_open_locale", "{ss si ss* ss}", "file", filename, "flags", flags, "locale", locale, @@ -658,130 +714,187 @@ static void hook_ditf_rootdir_open_locale(void *closure, const struct afb_hookid result < 0 ? strerror(errno) : path); } -static void hook_ditf_queue_job(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) +static void hook_api_queue_job(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) { - hook_ditf(closure, hookid, export, "queue_job", "{ss}", "result", result); + hook_api(closure, hookid, export, "queue_job", "{ss}", "result", result); } -static void hook_ditf_unstore_req(void * closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq) +static void hook_api_unstore_req(void * closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq) { - hook_ditf(closure, hookid, export, "unstore_req", NULL); + hook_api(closure, hookid, export, "unstore_req", NULL); } -static void hook_ditf_require_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized) +static void hook_api_require_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized) { - hook_ditf(closure, hookid, export, "require_api", "{ss sb}", "name", name, "initialized", initialized); + hook_api(closure, hookid, export, "require_api", "{ss sb}", "name", name, "initialized", initialized); } -static void hook_ditf_require_api_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result) +static void hook_api_require_api_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result) { - hook_ditf(closure, hookid, export, "require_api_result", "{ss sb si}", "name", name, "initialized", initialized, "result", result); + hook_api(closure, hookid, export, "require_api_result", "{ss sb si}", "name", name, "initialized", initialized, "result", result); } -static struct afb_hook_ditf_itf hook_ditf_itf = { - .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before, - .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after, - .hook_ditf_get_event_loop = hook_ditf_get_event_loop, - .hook_ditf_get_user_bus = hook_ditf_get_user_bus, - .hook_ditf_get_system_bus = hook_ditf_get_system_bus, - .hook_ditf_vverbose = hook_ditf_vverbose, - .hook_ditf_event_make = hook_ditf_event_make, - .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd, - .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale, - .hook_ditf_queue_job = hook_ditf_queue_job, - .hook_ditf_unstore_req = hook_ditf_unstore_req, - .hook_ditf_require_api = hook_ditf_require_api, - .hook_ditf_require_api_result = hook_ditf_require_api_result -}; +static void hook_api_add_alias_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *alias, int result) +{ + hook_api(closure, hookid, export, "add_alias", "{si ss? ss}", "status", result, "api", api, "alias", alias); +} -/*******************************************************************************/ -/***** trace the services *****/ -/*******************************************************************************/ +static void hook_api_start_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +{ + hook_api(closure, hookid, export, "start_before", NULL); +} -static struct flag svc_flags[] = { /* must be sorted by names */ - { "all", afb_hook_flags_svc_all }, - { "call", afb_hook_flag_svc_call }, - { "call_result", afb_hook_flag_svc_call_result }, - { "callsync", afb_hook_flag_svc_callsync }, - { "callsync_result", afb_hook_flag_svc_callsync_result }, - { "on_event_after", afb_hook_flag_svc_on_event_after }, - { "on_event_before", afb_hook_flag_svc_on_event_before }, - { "start_after", afb_hook_flag_svc_start_after }, - { "start_before", afb_hook_flag_svc_start_before }, -}; +static void hook_api_start_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status) +{ + hook_api(closure, hookid, export, "start_after", "{si}", "result", status); +} -/* get the export value for flag of 'name' */ -static int get_svc_flag(const char *name) +static void hook_api_on_event_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object) { - return get_flag(name, svc_flags, (int)(sizeof svc_flags / sizeof *svc_flags)); + hook_api(closure, hookid, export, "on_event_before", "{ss si sO*}", + "event", event, "id", evtid, "data", object); } -static void hook_svc(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...) +static void hook_api_on_event_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object) { - va_list ap; + hook_api(closure, hookid, export, "on_event_after", "{ss si sO?}", + "event", event, "id", evtid, "data", object); +} - va_start(ap, format); - emit(closure, hookid, "service", "{ss ss}", format, ap, - "api", afb_export_apiname(export), - "action", action); - va_end(ap); +static void hook_api_call(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +{ + hook_api(closure, hookid, export, "call", "{ss ss sO?}", + "api", api, "verb", verb, "args", args); } -static void hook_svc_start_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +static void hook_api_call_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object, const char *error, const char *info) { - hook_svc(closure, hookid, export, "start_before", NULL); + hook_api(closure, hookid, export, "call_result", "{sO? ss? ss?}", + "object", object, "error", error, "info", info); } -static void hook_svc_start_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status) +static void hook_api_callsync(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) { - hook_svc(closure, hookid, export, "start_after", "{si}", "result", status); + hook_api(closure, hookid, export, "callsync", "{ss ss sO?}", + "api", api, "verb", verb, "args", args); } -static void hook_svc_on_event_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object) +static void hook_api_callsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info) { - hook_svc(closure, hookid, export, "on_event_before", "{ss si sO*}", - "event", event, "id", evtid, "data", object); + hook_api(closure, hookid, export, "callsync_result", "{si sO? ss? ss?}", + "status", status, "object", object, "error", error, "info", info); } -static void hook_svc_on_event_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object) +static void hook_api_new_api_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *info, int noconcurrency) { - hook_svc(closure, hookid, export, "on_event_after", "{ss si sO*}", - "event", event, "id", evtid, "data", object); + hook_api(closure, hookid, export, "new_api.before", "{ss ss? sb}", + "api", api, "info", info, "noconcurrency", noconcurrency); } -static void hook_svc_call(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +static void hook_api_new_api_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *api) { - hook_svc(closure, hookid, export, "call", "{ss ss sO*}", - "api", api, "verb", verb, "args", args); + hook_api(closure, hookid, export, "new_api.after", "{si ss}", + "status", result, "api", api); } -static void hook_svc_call_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result) +static void hook_api_api_set_verbs_v2(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v2 *verbs) { - hook_svc(closure, hookid, export, "call_result", "{si sO*}", - "status", status, "result", result); + hook_api(closure, hookid, export, "set_verbs_v2", "{si}", "status", result); } -static void hook_svc_callsync(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +static void hook_api_api_set_verbs_v3(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v3 *verbs) { - hook_svc(closure, hookid, export, "callsync", "{ss ss sO*}", - "api", api, "verb", verb, "args", args); + hook_api(closure, hookid, export, "set_verbs_v3", "{si}", "status", result); +} + + +static void hook_api_api_add_verb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb, const char *info, int glob) +{ + hook_api(closure, hookid, export, "add_verb", "{si ss ss? sb}", "status", result, "verb", verb, "info", info, "glob", glob); +} + +static void hook_api_api_del_verb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb) +{ + hook_api(closure, hookid, export, "del_verb", "{si ss}", "status", result, "verb", verb); +} + +static void hook_api_api_set_on_event(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +{ + hook_api(closure, hookid, export, "set_on_event", "{si}", "status", result); } -static void hook_svc_callsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result) +static void hook_api_api_set_on_init(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) { - hook_svc(closure, hookid, export, "callsync_result", "{si sO*}", - "status", status, "result", result); + hook_api(closure, hookid, export, "set_on_init", "{si}", "status", result); } -static struct afb_hook_svc_itf hook_svc_itf = { - .hook_svc_start_before = hook_svc_start_before, - .hook_svc_start_after = hook_svc_start_after, - .hook_svc_on_event_before = hook_svc_on_event_before, - .hook_svc_on_event_after = hook_svc_on_event_after, - .hook_svc_call = hook_svc_call, - .hook_svc_call_result = hook_svc_call_result, - .hook_svc_callsync = hook_svc_callsync, - .hook_svc_callsync_result = hook_svc_callsync_result +static void hook_api_api_seal(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +{ + hook_api(closure, hookid, export, "seal", NULL); +} + +static void hook_api_event_handler_add(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern) +{ + hook_api(closure, hookid, export, "event_handler_add", "{si ss?}", "status", result, "pattern", pattern); +} + +static void hook_api_event_handler_del(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern) +{ + hook_api(closure, hookid, export, "event_handler_del", "{si ss?}", "status", result, "pattern", pattern); +} + +static void hook_api_class_provide(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name) +{ + hook_api(closure, hookid, export, "class_provide", "{si ss?}", "status", result, "name", name); +} + +static void hook_api_class_require(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name) +{ + hook_api(closure, hookid, export, "class_require", "{si ss?}", "status", result, "name", name); +} + +static void hook_api_delete_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +{ + hook_api(closure, hookid, export, "delete_api", "{si}", "status", result); +} + +static struct afb_hook_api_itf hook_api_itf = { + .hook_api_event_broadcast_before = hook_api_event_broadcast_before, + .hook_api_event_broadcast_after = hook_api_event_broadcast_after, + .hook_api_get_event_loop = hook_api_get_event_loop, + .hook_api_get_user_bus = hook_api_get_user_bus, + .hook_api_get_system_bus = hook_api_get_system_bus, + .hook_api_vverbose = hook_api_vverbose, + .hook_api_event_make = hook_api_event_make, + .hook_api_rootdir_get_fd = hook_api_rootdir_get_fd, + .hook_api_rootdir_open_locale = hook_api_rootdir_open_locale, + .hook_api_queue_job = hook_api_queue_job, + .hook_api_legacy_unstore_req = hook_api_unstore_req, + .hook_api_require_api = hook_api_require_api, + .hook_api_require_api_result = hook_api_require_api_result, + .hook_api_add_alias = hook_api_add_alias_cb, + .hook_api_start_before = hook_api_start_before, + .hook_api_start_after = hook_api_start_after, + .hook_api_on_event_before = hook_api_on_event_before, + .hook_api_on_event_after = hook_api_on_event_after, + .hook_api_call = hook_api_call, + .hook_api_call_result = hook_api_call_result, + .hook_api_callsync = hook_api_callsync, + .hook_api_callsync_result = hook_api_callsync_result, + .hook_api_new_api_before = hook_api_new_api_before, + .hook_api_new_api_after = hook_api_new_api_after, + .hook_api_api_set_verbs_v2 = hook_api_api_set_verbs_v2, + .hook_api_api_set_verbs_v3 = hook_api_api_set_verbs_v3, + .hook_api_api_add_verb = hook_api_api_add_verb, + .hook_api_api_del_verb = hook_api_api_del_verb, + .hook_api_api_set_on_event = hook_api_api_set_on_event, + .hook_api_api_set_on_init = hook_api_api_set_on_init, + .hook_api_api_seal = hook_api_api_seal, + .hook_api_event_handler_add = hook_api_event_handler_add, + .hook_api_event_handler_del = hook_api_event_handler_del, + .hook_api_class_provide = hook_api_class_provide, + .hook_api_class_require = hook_api_class_require, + .hook_api_delete_api = hook_api_delete_api, }; /*******************************************************************************/ @@ -1016,17 +1129,11 @@ abstracting[Trace_Type_Count] = .unref = (void(*)(void*))afb_hook_unref_xreq, .get_flag = get_xreq_flag }, - [Trace_Type_Ditf] = - { - .name = "daemon", - .unref = (void(*)(void*))afb_hook_unref_ditf, - .get_flag = get_ditf_flag - }, - [Trace_Type_Svc] = + [Trace_Type_Api] = { - .name = "service", - .unref = (void(*)(void*))afb_hook_unref_svc, - .get_flag = get_svc_flag + .name = "api", + .unref = (void(*)(void*))afb_hook_unref_api, + .get_flag = get_api_flag }, [Trace_Type_Evt] = { @@ -1046,6 +1153,20 @@ abstracting[Trace_Type_Count] = .unref = (void(*)(void*))afb_hook_unref_global, .get_flag = get_global_flag }, +#if !defined(REMOVE_LEGACY_TRACE) + [Trace_Legacy_Type_Ditf] = + { + .name = "daemon", + .unref = (void(*)(void*))afb_hook_unref_api, + .get_flag = get_legacy_ditf_flag + }, + [Trace_Legacy_Type_Svc] = + { + .name = "service", + .unref = (void(*)(void*))afb_hook_unref_api, + .get_flag = get_legacy_svc_flag + }, +#endif }; /*******************************************************************************/ @@ -1242,7 +1363,7 @@ static void trace_attach_hook(struct afb_trace *trace, struct hook *hook, enum t struct context { struct afb_trace *trace; - struct afb_req req; + afb_req_t req; char *errors; }; @@ -1252,13 +1373,12 @@ struct desc const char *name; const char *tag; const char *uuid; - const char *api; - const char *verb; + const char *apiname; + const char *verbname; const char *pattern; int flags[Trace_Type_Count]; }; - static void addhook(struct desc *desc, enum trace_type type) { struct hook *hook; @@ -1299,15 +1419,12 @@ static void addhook(struct desc *desc, enum trace_type type) return; } } - hook->handler = afb_hook_create_xreq(desc->api, desc->verb, session, + hook->handler = afb_hook_create_xreq(desc->apiname, desc->verbname, session, desc->flags[type], &hook_xreq_itf, hook); afb_session_unref(session); break; - case Trace_Type_Ditf: - hook->handler = afb_hook_create_ditf(desc->api, desc->flags[type], &hook_ditf_itf, hook); - break; - case Trace_Type_Svc: - hook->handler = afb_hook_create_svc(desc->api, desc->flags[type], &hook_svc_itf, hook); + case Trace_Type_Api: + hook->handler = afb_hook_create_api(desc->apiname, desc->flags[type], &hook_api_itf, hook); break; case Trace_Type_Evt: hook->handler = afb_hook_create_evt(desc->pattern, desc->flags[type], &hook_evt_itf, hook); @@ -1328,7 +1445,7 @@ static void addhook(struct desc *desc, enum trace_type type) } /* attach and activate the hook */ - afb_req_subscribe(desc->context->req, afb_evt_event_from_evtid(hook->event->evtid)); + afb_req_subscribe(desc->context->req, afb_evt_event_x2_from_evtid(hook->event->evtid)); trace_attach_hook(trace, hook, type); } @@ -1336,6 +1453,11 @@ static void addhooks(struct desc *desc) { int i; +#if !defined(REMOVE_LEGACY_TRACE) + desc->flags[Trace_Type_Api] |= desc->flags[Trace_Legacy_Type_Ditf] | desc->flags[Trace_Legacy_Type_Svc]; + desc->flags[Trace_Legacy_Type_Ditf] = desc->flags[Trace_Legacy_Type_Svc] = 0; +#endif + for (i = 0 ; i < Trace_Type_Count ; i++) { if (desc->flags[i]) addhook(desc, i); @@ -1368,14 +1490,21 @@ static void add_xreq_flags(void *closure, struct json_object *object) add_flags(closure, object, Trace_Type_Xreq); } -static void add_ditf_flags(void *closure, struct json_object *object) +#if !defined(REMOVE_LEGACY_TRACE) +static void legacy_add_ditf_flags(void *closure, struct json_object *object) +{ + add_flags(closure, object, Trace_Legacy_Type_Ditf); +} + +static void legacy_add_svc_flags(void *closure, struct json_object *object) { - add_flags(closure, object, Trace_Type_Ditf); + add_flags(closure, object, Trace_Legacy_Type_Svc); } +#endif -static void add_svc_flags(void *closure, struct json_object *object) +static void add_api_flags(void *closure, struct json_object *object) { - add_flags(closure, object, Trace_Type_Svc); + add_flags(closure, object, Trace_Type_Api); } static void add_evt_flags(void *closure, struct json_object *object) @@ -1398,21 +1527,30 @@ static void add(void *closure, struct json_object *object) { int rc; struct desc desc; - struct json_object *request, *event, *daemon, *service, *sub, *global, *session; + struct json_object *request, *event, *sub, *global, *session, *api; +#if !defined(REMOVE_LEGACY_TRACE) + struct json_object *daemon, *service; +#endif memcpy (&desc, closure, sizeof desc); - request = event = daemon = service = sub = global = session = NULL; + request = event = sub = global = session = api = NULL; +#if !defined(REMOVE_LEGACY_TRACE) + daemon = service = NULL; +#endif - rc = wrap_json_unpack(object, "{s?s s?s s?s s?s s?s s?s s?o s?o s?o s?o s?o s?o}", + rc = wrap_json_unpack(object, "{s?s s?s s?s s?s s?s s?s s?o s?o s?o s?o s?o s?o s?o}", "name", &desc.name, "tag", &desc.tag, - "api", &desc.api, - "verb", &desc.verb, + "apiname", &desc.apiname, + "verbname", &desc.verbname, "uuid", &desc.uuid, "pattern", &desc.pattern, + "api", &api, "request", &request, +#if !defined(REMOVE_LEGACY_TRACE) "daemon", &daemon, "service", &service, +#endif "event", &event, "session", &session, "global", &global, @@ -1420,11 +1558,11 @@ static void add(void *closure, struct json_object *object) if (!rc) { /* replace stars */ - if (desc.api && desc.api[0] == '*' && !desc.api[1]) - desc.api = NULL; + if (desc.apiname && desc.apiname[0] == '*' && !desc.apiname[1]) + desc.apiname = NULL; - if (desc.verb && desc.verb[0] == '*' && !desc.verb[1]) - desc.verb = NULL; + if (desc.verbname && desc.verbname[0] == '*' && !desc.verbname[1]) + desc.verbname = NULL; if (desc.uuid && desc.uuid[0] == '*' && !desc.uuid[1]) desc.uuid = NULL; @@ -1433,11 +1571,16 @@ static void add(void *closure, struct json_object *object) if (request) wrap_json_optarray_for_all(request, add_xreq_flags, &desc); + if (api) + wrap_json_optarray_for_all(api, add_api_flags, &desc); + +#if !defined(REMOVE_LEGACY_TRACE) if (daemon) - wrap_json_optarray_for_all(daemon, add_ditf_flags, &desc); + wrap_json_optarray_for_all(daemon, legacy_add_ditf_flags, &desc); if (service) - wrap_json_optarray_for_all(service, add_svc_flags, &desc); + wrap_json_optarray_for_all(service, legacy_add_svc_flags, &desc); +#endif if (event) wrap_json_optarray_for_all(event, add_evt_flags, &desc); @@ -1562,7 +1705,7 @@ void afb_trace_unref(struct afb_trace *trace) } /* add traces */ -int afb_trace_add(struct afb_req req, struct json_object *args, struct afb_trace *trace) +int afb_trace_add(afb_req_t req, struct json_object *args, struct afb_trace *trace) { struct context context; struct desc desc; @@ -1587,7 +1730,7 @@ int afb_trace_add(struct afb_req req, struct json_object *args, struct afb_trace } /* drop traces */ -extern int afb_trace_drop(struct afb_req req, struct json_object *args, struct afb_trace *trace) +extern int afb_trace_drop(afb_req_t req, struct json_object *args, struct afb_trace *trace) { int rc; struct context context; diff --git a/src/afb-trace.h b/src/afb-trace.h index 5056fb25..0371546f 100644 --- a/src/afb-trace.h +++ b/src/afb-trace.h @@ -25,7 +25,7 @@ extern struct afb_trace *afb_trace_create(const char *api, struct afb_session *b extern void afb_trace_addref(struct afb_trace *trace); extern void afb_trace_unref(struct afb_trace *trace); -extern int afb_trace_add(struct afb_req req, struct json_object *args, struct afb_trace *trace); -extern int afb_trace_drop(struct afb_req req, struct json_object *args, struct afb_trace *trace); +extern int afb_trace_add(afb_req_t req, struct json_object *args, struct afb_trace *trace); +extern int afb_trace_drop(afb_req_t req, struct json_object *args, struct afb_trace *trace); diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c index 315bee8e..95167b5f 100644 --- a/src/afb-ws-json1.c +++ b/src/afb-ws-json1.c @@ -49,7 +49,7 @@ static void aws_on_event(struct afb_ws_json1 *ws, const char *event, int eventid /* predeclaration of wsreq callbacks */ static void wsreq_destroy(struct afb_xreq *xreq); -static void wsreq_reply(struct afb_xreq *xreq, int status, json_object *obj); +static void wsreq_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info); /* declaration of websocket structure */ struct afb_ws_json1 @@ -194,8 +194,8 @@ static void aws_on_call(struct afb_ws_json1 *ws, const char *api, const char *ve afb_wsj1_msg_addref(msg); wsreq->msgj1 = msg; wsreq->xreq.cred = afb_cred_addref(ws->cred); - wsreq->xreq.request.api = api; - wsreq->xreq.request.verb = verb; + wsreq->xreq.request.called_api = api; + wsreq->xreq.request.called_verb = verb; wsreq->xreq.json = afb_wsj1_msg_object_j(wsreq->msgj1); wsreq->aws = afb_ws_json1_addref(ws); wsreq->xreq.listener = wsreq->aws->listener; @@ -228,13 +228,17 @@ static void wsreq_destroy(struct afb_xreq *xreq) free(wsreq); } -static void wsreq_reply(struct afb_xreq *xreq, int status, json_object *obj) +static void wsreq_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { struct afb_wsreq *wsreq = CONTAINER_OF_XREQ(struct afb_wsreq, xreq); int rc; + struct json_object *reply; - rc = (status < 0 ? afb_wsj1_reply_error_j : afb_wsj1_reply_ok_j)( - wsreq->msgj1, obj, afb_context_sent_token(&wsreq->xreq.context)); + /* create the reply */ + reply = afb_msg_json_reply(object, error, info, &xreq->context); + + rc = (error ? afb_wsj1_reply_error_j : afb_wsj1_reply_ok_j)( + wsreq->msgj1, reply, afb_context_sent_token(&wsreq->xreq.context)); if (rc) ERROR("Can't send reply: %m"); } diff --git a/src/afb-xreq.c b/src/afb-xreq.c index 582e9b72..8f246b3c 100644 --- a/src/afb-xreq.c +++ b/src/afb-xreq.c @@ -21,22 +21,26 @@ #include <stdio.h> #include <string.h> #include <errno.h> +#include <stdarg.h> #include <json-c/json.h> + #include <afb/afb-binding-v1.h> #include <afb/afb-binding-v2.h> -#include <afb/afb-request.h> +#include <afb/afb-binding-v3.h> +#include <afb/afb-req-x2.h> +#include "afb-api.h" +#include "afb-apiset.h" +#include "afb-auth.h" +#include "afb-calls.h" #include "afb-context.h" -#include "afb-xreq.h" #include "afb-evt.h" -#include "afb-msg-json.h" #include "afb-cred.h" #include "afb-hook.h" -#include "afb-api.h" -#include "afb-api-dyn.h" -#include "afb-apiset.h" -#include "afb-auth.h" +#include "afb-msg-json.h" +#include "afb-xreq.h" + #include "jobs.h" #include "verbose.h" @@ -45,7 +49,7 @@ static void xreq_finalize(struct afb_xreq *xreq) { if (!xreq->replied) - afb_xreq_fail(xreq, "error", "no reply"); + afb_xreq_reply(xreq, NULL, "error", "no reply"); if (xreq->hookflags) afb_hook_xreq_end(xreq); if (xreq->caller) @@ -66,274 +70,22 @@ inline void afb_xreq_unhooked_unref(struct afb_xreq *xreq) /******************************************************************************/ -struct subcall -{ - struct afb_xreq xreq; - - void (*completion)(struct subcall*, int, struct json_object*); - - union { - struct { - struct jobloop *jobloop; - struct json_object *result; - int status; - }; - struct { - union { - void (*callback)(void*, int, struct json_object*); - void (*callback_req)(void*, int, struct json_object*, struct afb_req); - void (*callback_request)(void*, int, struct json_object*, struct afb_request*); - }; - void *closure; - }; - }; -}; - -static int subcall_subscribe_cb(struct afb_xreq *xreq, struct afb_eventid *eventid) -{ - struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - - return afb_xreq_subscribe(subcall->xreq.caller, eventid); -} - -static int subcall_unsubscribe_cb(struct afb_xreq *xreq, struct afb_eventid *eventid) -{ - struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - - return afb_xreq_unsubscribe(subcall->xreq.caller, eventid); -} - -static void subcall_reply_cb(struct afb_xreq *xreq, int status, struct json_object *result) -{ - struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - - subcall->completion(subcall, status, result); - json_object_put(result); - afb_xreq_unhooked_unref(&subcall->xreq); -} - -static void subcall_destroy_cb(struct afb_xreq *xreq) -{ - struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - - json_object_put(subcall->xreq.json); - afb_cred_unref(subcall->xreq.cred); - free(subcall); -} - -const struct afb_xreq_query_itf afb_xreq_subcall_itf = { - .reply = subcall_reply_cb, - .unref = subcall_destroy_cb, - .subscribe = subcall_subscribe_cb, - .unsubscribe = subcall_unsubscribe_cb -}; - -static struct subcall *subcall_alloc( - struct afb_xreq *caller, - const char *api, - const char *verb, - struct json_object *args -) -{ - struct subcall *subcall; - size_t lenapi, lenverb; - char *copy; - - lenapi = 1 + strlen(api); - lenverb = 1 + strlen(verb); - subcall = malloc(lenapi + lenverb + sizeof *subcall); - if (!subcall) - ERROR("out of memory"); - else { - copy = (char*)&subcall[1]; - memcpy(copy, api, lenapi); - api = copy; - copy = ©[lenapi]; - memcpy(copy, verb, lenverb); - verb = copy; - - afb_xreq_init(&subcall->xreq, &afb_xreq_subcall_itf); - afb_context_subinit(&subcall->xreq.context, &caller->context); - subcall->xreq.cred = afb_cred_addref(caller->cred); - subcall->xreq.json = args; - subcall->xreq.request.api = api; - subcall->xreq.request.verb = verb; - subcall->xreq.caller = caller; - afb_xreq_unhooked_addref(caller); - } - return subcall; -} - - -static void subcall_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - subcall->callback(subcall->closure, status, result); -} - -static void subcall_req_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - subcall->callback_req(subcall->closure, status, result, xreq_to_req(subcall->xreq.caller)); -} - -static void subcall_request_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - subcall->callback_request(subcall->closure, status, result, xreq_to_request(subcall->xreq.caller)); -} - -static void subcall_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - afb_hook_xreq_subcall_result(subcall->xreq.caller, status, result); - subcall_on_reply(subcall, status, result); -} - -static void subcall_req_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - afb_hook_xreq_subcall_req_result(subcall->xreq.caller, status, result); - subcall_req_on_reply(subcall, status, result); -} - -static void subcall_request_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - afb_hook_xreq_subcall_result(subcall->xreq.caller, status, result); - subcall_request_on_reply(subcall, status, result); -} - -static void subcall_reply_direct_cb(void *closure, int status, struct json_object *result) +struct json_object *afb_xreq_unhooked_json(struct afb_xreq *xreq) { - struct afb_xreq *xreq = closure; - - if (xreq->replied) { - ERROR("subcall replied more than one time!!"); - json_object_put(result); - } else { - xreq->replied = 1; - subcall_reply_cb(xreq, status, result); - } -} - -static void subcall_process(struct subcall *subcall, void (*completion)(struct subcall*, int, struct json_object*)) -{ - subcall->completion = completion; - if (subcall->xreq.caller->queryitf->subcall) { - subcall->xreq.caller->queryitf->subcall( - subcall->xreq.caller, subcall->xreq.request.api, subcall->xreq.request.verb, - subcall->xreq.json, subcall_reply_direct_cb, &subcall->xreq); - } else { - afb_xreq_unhooked_addref(&subcall->xreq); - afb_xreq_process(&subcall->xreq, subcall->xreq.caller->apiset); - } -} - -static void subcall(struct subcall *subcall, void (*callback)(void*, int, struct json_object*), void *cb_closure) -{ - subcall->callback = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_on_reply); -} - -static void subcall_req(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) -{ - subcall->callback_req = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_req_on_reply); -} - -static void subcall_request(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure) -{ - subcall->callback_request = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_request_on_reply); -} - -static void subcall_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*), void *cb_closure) -{ - subcall->callback = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_hooked_on_reply); -} - -static void subcall_req_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) -{ - subcall->callback_req = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_req_hooked_on_reply); -} - -static void subcall_request_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure) -{ - subcall->callback_request = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_request_hooked_on_reply); -} - -static void subcall_sync_leave(struct subcall *subcall) -{ - struct jobloop *jobloop = __atomic_exchange_n(&subcall->jobloop, NULL, __ATOMIC_RELAXED); - if (jobloop) - jobs_leave(jobloop); -} - -static void subcall_sync_reply(struct subcall *subcall, int status, struct json_object *result) -{ - subcall->status = status; - subcall->result = json_object_get(result); - subcall_sync_leave(subcall); -} - -static void subcall_sync_enter(int signum, void *closure, struct jobloop *jobloop) -{ - struct subcall *subcall = closure; - - if (!signum) { - subcall->jobloop = jobloop; - subcall->result = NULL; - subcall->status = 0; - subcall_process(subcall, subcall_sync_reply); - } else { - subcall->status = -1; - subcall_sync_leave(subcall); - } -} - -static int subcallsync(struct subcall *subcall, struct json_object **result) -{ - int rc; - - afb_xreq_unhooked_addref(&subcall->xreq); - rc = jobs_enter(NULL, 0, subcall_sync_enter, subcall); - *result = subcall->result; - if (rc < 0 || subcall->status < 0) { - *result = *result ?: afb_msg_json_internal_error(); - rc = -1; - } - afb_xreq_unhooked_unref(&subcall->xreq); - return rc; -} - -/******************************************************************************/ - -static void vinfo(void *first, void *second, const char *fmt, va_list args, void (*fun)(void*,void*,const char*)) -{ - char *info; - if (fmt == NULL || vasprintf(&info, fmt, args) < 0) - info = NULL; - fun(first, second, info); - free(info); -} - -/******************************************************************************/ - -static struct json_object *xreq_json_cb(struct afb_request *closure) -{ - struct afb_xreq *xreq = xreq_from_request(closure); if (!xreq->json && xreq->queryitf->json) xreq->json = xreq->queryitf->json(xreq); return xreq->json; } -static struct afb_arg xreq_get_cb(struct afb_request *closure, const char *name) +static struct json_object *xreq_json_cb(struct afb_req_x2 *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_xreq_unhooked_json(xreq); +} + +static struct afb_arg xreq_get_cb(struct afb_req_x2 *closure, const char *name) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); struct afb_arg arg; struct json_object *object, *value; @@ -353,409 +105,388 @@ static struct afb_arg xreq_get_cb(struct afb_request *closure, const char *name) return arg; } -static void xreq_success_cb(struct afb_request *closure, struct json_object *obj, const char *info) +static void xreq_reply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *info) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); if (xreq->replied) { ERROR("reply called more than one time!!"); json_object_put(obj); } else { xreq->replied = 1; - if (xreq->queryitf->success) - xreq->queryitf->success(xreq, obj, info); - else - xreq->queryitf->reply(xreq, 0, afb_msg_json_reply_ok(info, obj, &xreq->context, NULL)); + xreq->queryitf->reply(xreq, obj, error, info); } } -static void xreq_fail_cb(struct afb_request *closure, const char *status, const char *info) +static void xreq_vreply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *fmt, va_list args) { - struct afb_xreq *xreq = xreq_from_request(closure); + char *info; + if (fmt == NULL || vasprintf(&info, fmt, args) < 0) + info = NULL; + xreq_reply_cb(closure, obj, error, info); + free(info); +} - if (xreq->replied) { - ERROR("reply called more than one time!!"); - } else { - xreq->replied = 1; - if (xreq->queryitf->fail) - xreq->queryitf->fail(xreq, status, info); - else - xreq->queryitf->reply(xreq, -1, afb_msg_json_reply_error(status, info, &xreq->context, NULL)); - } +static void xreq_legacy_success_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *info) +{ + xreq_reply_cb(closure, obj, NULL, info); } -static void xreq_vsuccess_cb(struct afb_request *closure, struct json_object *obj, const char *fmt, va_list args) +static void xreq_legacy_fail_cb(struct afb_req_x2 *closure, const char *status, const char *info) { - vinfo(closure, obj, fmt, args, (void*)xreq_success_cb); + xreq_reply_cb(closure, NULL, status, info); } -static void xreq_vfail_cb(struct afb_request *closure, const char *status, const char *fmt, va_list args) +static void xreq_legacy_vsuccess_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *fmt, va_list args) { - vinfo(closure, (void*)status, fmt, args, (void*)xreq_fail_cb); + xreq_vreply_cb(closure, obj, NULL, fmt, args); } -static void *xreq_context_get_cb(struct afb_request *closure) +static void xreq_legacy_vfail_cb(struct afb_req_x2 *closure, const char *status, const char *fmt, va_list args) { - struct afb_xreq *xreq = xreq_from_request(closure); + xreq_vreply_cb(closure, NULL, status, fmt, args); +} + +static void *xreq_legacy_context_get_cb(struct afb_req_x2 *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_context_get(&xreq->context); } -static void xreq_context_set_cb(struct afb_request *closure, void *value, void (*free_value)(void*)) +static void xreq_legacy_context_set_cb(struct afb_req_x2 *closure, void *value, void (*free_value)(void*)) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_context_set(&xreq->context, value, free_value); } -static struct afb_request *xreq_addref_cb(struct afb_request *closure) +static struct afb_req_x2 *xreq_addref_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_xreq_unhooked_addref(xreq); return closure; } -static void xreq_unref_cb(struct afb_request *closure) +static void xreq_unref_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_xreq_unhooked_unref(xreq); } -static void xreq_session_close_cb(struct afb_request *closure) +static void xreq_session_close_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_context_close(&xreq->context); } -static int xreq_session_set_LOA_cb(struct afb_request *closure, unsigned level) +static int xreq_session_set_LOA_cb(struct afb_req_x2 *closure, unsigned level) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_context_change_loa(&xreq->context, level); } -static int xreq_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid); -static int xreq_subscribe_cb(struct afb_request *closure, struct afb_event event) +static int xreq_subscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event) { - return xreq_subscribe_eventid_cb(closure, afb_event_to_eventid(event)); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_xreq_subscribe(xreq, event); } -static int xreq_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid) +static int xreq_legacy_subscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event) { - struct afb_xreq *xreq = xreq_from_request(closure); - return afb_xreq_subscribe(xreq, eventid); + return xreq_subscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event)); } -int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid) +int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event) { if (xreq->listener) - return afb_evt_eventid_add_watch(xreq->listener, eventid); + return afb_evt_event_x2_add_watch(xreq->listener, event); if (xreq->queryitf->subscribe) - return xreq->queryitf->subscribe(xreq, eventid); + return xreq->queryitf->subscribe(xreq, event); ERROR("no event listener, subscription impossible"); errno = EINVAL; return -1; } -static int xreq_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid); -static int xreq_unsubscribe_cb(struct afb_request *closure, struct afb_event event) +static int xreq_unsubscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event) { - return xreq_unsubscribe_eventid_cb(closure, afb_event_to_eventid(event)); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_xreq_unsubscribe(xreq, event); } -static int xreq_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid) +static int xreq_legacy_unsubscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event) { - struct afb_xreq *xreq = xreq_from_request(closure); - return afb_xreq_unsubscribe(xreq, eventid); + return xreq_unsubscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event)); } -int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid) +int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event) { if (xreq->listener) - return afb_evt_eventid_remove_watch(xreq->listener, eventid); + return afb_evt_event_x2_remove_watch(xreq->listener, event); if (xreq->queryitf->unsubscribe) - return xreq->queryitf->unsubscribe(xreq, eventid); + return xreq->queryitf->unsubscribe(xreq, event); ERROR("no event listener, unsubscription impossible"); errno = EINVAL; return -1; } -static void xreq_subcall_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure) +static void xreq_legacy_subcall_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error()); - json_object_put(args); - } else { - subcall(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_legacy_subcall_v1(xreq, api, verb, args, callback, closure); } -static void xreq_subcall_req_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) +static void xreq_legacy_subcall_req_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x1), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_req(xreq)); - json_object_put(args); - } else { - subcall_req(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_legacy_subcall_v2(xreq, api, verb, args, callback, closure); } -static void xreq_subcall_request_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure) +static void xreq_legacy_subcall_request_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2*), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_request(xreq)); - json_object_put(args); - } else { - subcall_request(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_legacy_subcall_v3(xreq, api, verb, args, callback, closure); } -static int xreq_subcallsync_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result) +static int xreq_legacy_subcallsync_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - int rc; - struct subcall *sc; - struct afb_xreq *xreq = xreq_from_request(closure); - struct json_object *resu; - - sc = subcall_alloc(xreq, api, verb, args); - if (!sc) { - rc = -1; - resu = afb_msg_json_internal_error(); - json_object_put(args); - } else { - rc = subcallsync(sc, &resu); - } - if (result) - *result = resu; - else - json_object_put(resu); - return rc; + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_legacy_subcall_sync(xreq, api, verb, args, result); } -static void xreq_vverbose_cb(struct afb_request *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args) +static void xreq_vverbose_cb(struct afb_req_x2 *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args) { char *p; - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); if (!fmt || vasprintf(&p, fmt, args) < 0) vverbose(level, file, line, func, fmt, args); else { - verbose(level, file, line, func, "[REQ/API %s] %s", xreq->request.api, p); + verbose(level, file, line, func, "[REQ/API %s] %s", xreq->request.called_api, p); free(p); } } -static struct afb_stored_req *xreq_store_cb(struct afb_request *closure) +static struct afb_stored_req *xreq_legacy_store_cb(struct afb_req_x2 *closure) { xreq_addref_cb(closure); return (struct afb_stored_req*)closure; } -static int xreq_has_permission_cb(struct afb_request *closure, const char *permission) +static int xreq_has_permission_cb(struct afb_req_x2 *closure, const char *permission) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_auth_has_permission(xreq, permission); } -static char *xreq_get_application_id_cb(struct afb_request *closure) +static char *xreq_get_application_id_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return xreq->cred && xreq->cred->id ? strdup(xreq->cred->id) : NULL; } -static void *xreq_context_make_cb(struct afb_request *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure) +static void *xreq_context_make_cb(struct afb_req_x2 *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_context_make(&xreq->context, replace, create_value, free_value, create_closure); } -static int xreq_get_uid_cb(struct afb_request *closure) +static int xreq_get_uid_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return xreq->cred && xreq->cred->id ? (int)xreq->cred->uid : -1; } +static struct json_object *xreq_get_client_info_cb(struct afb_req_x2 *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(closure); + struct json_object *r = json_object_new_object(); + if (xreq->cred && xreq->cred->id) { + json_object_object_add(r, "uid", json_object_new_int(xreq->cred->uid)); + json_object_object_add(r, "gid", json_object_new_int(xreq->cred->gid)); + json_object_object_add(r, "pid", json_object_new_int(xreq->cred->pid)); + json_object_object_add(r, "user", json_object_new_string(xreq->cred->user)); + json_object_object_add(r, "label", json_object_new_string(xreq->cred->label)); + json_object_object_add(r, "id", json_object_new_string(xreq->cred->id)); + } + if (xreq->context.session) { + json_object_object_add(r, "uuid", json_object_new_string(afb_context_uuid(&xreq->context))); + json_object_object_add(r, "LOA", json_object_new_int(afb_context_get_loa(&xreq->context))); + } + return r; +} + +static void xreq_subcall_cb( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(req); + afb_calls_subcall(xreq, api, verb, args, flags, callback, closure); +} + +static int xreq_subcallsync_cb( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info) +{ + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_subcall_sync(xreq, api, verb, args, flags, object, error, info); +} + /******************************************************************************/ -static struct json_object *xreq_hooked_json_cb(struct afb_request *closure) +static struct json_object *xreq_hooked_json_cb(struct afb_req_x2 *closure) { struct json_object *r = xreq_json_cb(closure); - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_hook_xreq_json(xreq, r); } -static struct afb_arg xreq_hooked_get_cb(struct afb_request *closure, const char *name) +static struct afb_arg xreq_hooked_get_cb(struct afb_req_x2 *closure, const char *name) { struct afb_arg r = xreq_get_cb(closure, name); - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_hook_xreq_get(xreq, name, r); } -static void xreq_hooked_success_cb(struct afb_request *closure, struct json_object *obj, const char *info) +static void xreq_hooked_reply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *info) +{ + struct afb_xreq *xreq = xreq_from_req_x2(closure); + afb_hook_xreq_reply(xreq, obj, error, info); + xreq_reply_cb(closure, obj, error, info); +} + +static void xreq_hooked_vreply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *fmt, va_list args) +{ + char *info; + if (fmt == NULL || vasprintf(&info, fmt, args) < 0) + info = NULL; + xreq_hooked_reply_cb(closure, obj, error, info); + free(info); +} + +static void xreq_hooked_legacy_success_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *info) { - struct afb_xreq *xreq = xreq_from_request(closure); - afb_hook_xreq_success(xreq, obj, info); - xreq_success_cb(closure, obj, info); + xreq_hooked_reply_cb(closure, obj, NULL, info); } -static void xreq_hooked_fail_cb(struct afb_request *closure, const char *status, const char *info) +static void xreq_hooked_legacy_fail_cb(struct afb_req_x2 *closure, const char *status, const char *info) { - struct afb_xreq *xreq = xreq_from_request(closure); - afb_hook_xreq_fail(xreq, status, info); - xreq_fail_cb(closure, status, info); + xreq_hooked_reply_cb(closure, NULL, status, info); } -static void xreq_hooked_vsuccess_cb(struct afb_request *closure, struct json_object *obj, const char *fmt, va_list args) +static void xreq_hooked_legacy_vsuccess_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *fmt, va_list args) { - vinfo(closure, obj, fmt, args, (void*)xreq_hooked_success_cb); + xreq_hooked_vreply_cb(closure, obj, NULL, fmt, args); } -static void xreq_hooked_vfail_cb(struct afb_request *closure, const char *status, const char *fmt, va_list args) +static void xreq_hooked_legacy_vfail_cb(struct afb_req_x2 *closure, const char *status, const char *fmt, va_list args) { - vinfo(closure, (void*)status, fmt, args, (void*)xreq_hooked_fail_cb); + xreq_hooked_vreply_cb(closure, NULL, status, fmt, args); } -static void *xreq_hooked_context_get_cb(struct afb_request *closure) +static void *xreq_hooked_legacy_context_get_cb(struct afb_req_x2 *closure) { - void *r = xreq_context_get_cb(closure); - struct afb_xreq *xreq = xreq_from_request(closure); - return afb_hook_xreq_context_get(xreq, r); + void *r = xreq_legacy_context_get_cb(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_hook_xreq_legacy_context_get(xreq, r); } -static void xreq_hooked_context_set_cb(struct afb_request *closure, void *value, void (*free_value)(void*)) +static void xreq_hooked_legacy_context_set_cb(struct afb_req_x2 *closure, void *value, void (*free_value)(void*)) { - struct afb_xreq *xreq = xreq_from_request(closure); - afb_hook_xreq_context_set(xreq, value, free_value); - xreq_context_set_cb(closure, value, free_value); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + afb_hook_xreq_legacy_context_set(xreq, value, free_value); + xreq_legacy_context_set_cb(closure, value, free_value); } -static struct afb_request *xreq_hooked_addref_cb(struct afb_request *closure) +static struct afb_req_x2 *xreq_hooked_addref_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_hook_xreq_addref(xreq); return xreq_addref_cb(closure); } -static void xreq_hooked_unref_cb(struct afb_request *closure) +static void xreq_hooked_unref_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_hook_xreq_unref(xreq); xreq_unref_cb(closure); } -static void xreq_hooked_session_close_cb(struct afb_request *closure) +static void xreq_hooked_session_close_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_hook_xreq_session_close(xreq); xreq_session_close_cb(closure); } -static int xreq_hooked_session_set_LOA_cb(struct afb_request *closure, unsigned level) +static int xreq_hooked_session_set_LOA_cb(struct afb_req_x2 *closure, unsigned level) { int r = xreq_session_set_LOA_cb(closure, level); - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_hook_xreq_session_set_LOA(xreq, level, r); } -static int xreq_hooked_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid); -static int xreq_hooked_subscribe_cb(struct afb_request *closure, struct afb_event event) +static int xreq_hooked_subscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event) { - return xreq_hooked_subscribe_eventid_cb(closure, afb_event_to_eventid(event)); + int r = xreq_subscribe_event_x2_cb(closure, event); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_hook_xreq_subscribe(xreq, event, r); } -static int xreq_hooked_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid) +static int xreq_hooked_legacy_subscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event) { - int r = xreq_subscribe_eventid_cb(closure, eventid); - struct afb_xreq *xreq = xreq_from_request(closure); - return afb_hook_xreq_subscribe(xreq, eventid, r); + return xreq_hooked_subscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event)); } -static int xreq_hooked_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid); -static int xreq_hooked_unsubscribe_cb(struct afb_request *closure, struct afb_event event) +static int xreq_hooked_unsubscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event) { - return xreq_hooked_unsubscribe_eventid_cb(closure, afb_event_to_eventid(event)); + int r = xreq_unsubscribe_event_x2_cb(closure, event); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_hook_xreq_unsubscribe(xreq, event, r); } -static int xreq_hooked_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid) +static int xreq_hooked_legacy_unsubscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event) { - int r = xreq_unsubscribe_eventid_cb(closure, eventid); - struct afb_xreq *xreq = xreq_from_request(closure); - return afb_hook_xreq_unsubscribe(xreq, eventid, r); + return xreq_hooked_unsubscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event)); } -static void xreq_hooked_subcall_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure) +static void xreq_hooked_legacy_subcall_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - afb_hook_xreq_subcall(xreq, api, verb, args); - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error()); - json_object_put(args); - } else { - subcall_hooked(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + afb_calls_legacy_hooked_subcall_v1(xreq, api, verb, args, callback, closure); } -static void xreq_hooked_subcall_req_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) +static void xreq_hooked_legacy_subcall_req_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x1), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - afb_hook_xreq_subcall_req(xreq, api, verb, args); - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_req(xreq)); - json_object_put(args); - } else { - subcall_req_hooked(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + afb_calls_legacy_hooked_subcall_v2(xreq, api, verb, args, callback, closure); } -static void xreq_hooked_subcall_request_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure) +static void xreq_hooked_legacy_subcall_request_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - afb_hook_xreq_subcall(xreq, api, verb, args); - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_request(xreq)); - json_object_put(args); - } else { - subcall_request_hooked(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + afb_calls_legacy_hooked_subcall_v3(xreq, api, verb, args, callback, closure); } -static int xreq_hooked_subcallsync_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result) +static int xreq_hooked_legacy_subcallsync_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - int r; - struct afb_xreq *xreq = xreq_from_request(closure); - afb_hook_xreq_subcallsync(xreq, api, verb, args); - r = xreq_subcallsync_cb(closure, api, verb, args, result); - return afb_hook_xreq_subcallsync_result(xreq, r, *result); + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_legacy_hooked_subcall_sync(xreq, api, verb, args, result); } -static void xreq_hooked_vverbose_cb(struct afb_request *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args) +static void xreq_hooked_vverbose_cb(struct afb_req_x2 *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); va_list ap; va_copy(ap, args); xreq_vverbose_cb(closure, level, file, line, func, fmt, args); @@ -763,149 +494,178 @@ static void xreq_hooked_vverbose_cb(struct afb_request *closure, int level, cons va_end(ap); } -static struct afb_stored_req *xreq_hooked_store_cb(struct afb_request *closure) +static struct afb_stored_req *xreq_hooked_legacy_store_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct afb_stored_req *r = xreq_store_cb(closure); - afb_hook_xreq_store(xreq, r); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + struct afb_stored_req *r = xreq_legacy_store_cb(closure); + afb_hook_xreq_legacy_store(xreq, r); return r; } -static int xreq_hooked_has_permission_cb(struct afb_request *closure, const char *permission) +static int xreq_hooked_has_permission_cb(struct afb_req_x2 *closure, const char *permission) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); int r = xreq_has_permission_cb(closure, permission); return afb_hook_xreq_has_permission(xreq, permission, r); } -static char *xreq_hooked_get_application_id_cb(struct afb_request *closure) +static char *xreq_hooked_get_application_id_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); char *r = xreq_get_application_id_cb(closure); return afb_hook_xreq_get_application_id(xreq, r); } -static void *xreq_hooked_context_make_cb(struct afb_request *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure) +static void *xreq_hooked_context_make_cb(struct afb_req_x2 *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); void *result = xreq_context_make_cb(closure, replace, create_value, free_value, create_closure); return afb_hook_xreq_context_make(xreq, replace, create_value, free_value, create_closure, result); } -static int xreq_hooked_get_uid_cb(struct afb_request *closure) +static int xreq_hooked_get_uid_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); int r = xreq_get_uid_cb(closure); return afb_hook_xreq_get_uid(xreq, r); } +static struct json_object *xreq_hooked_get_client_info_cb(struct afb_req_x2 *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(closure); + struct json_object *r = xreq_get_client_info_cb(closure); + return afb_hook_xreq_get_client_info(xreq, r); +} + +static void xreq_hooked_subcall_cb( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(req); + afb_calls_hooked_subcall(xreq, api, verb, args, flags, callback, closure); +} + +static int xreq_hooked_subcallsync_cb( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info) +{ + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_hooked_subcall_sync(xreq, api, verb, args, flags, object, error, info); +} + /******************************************************************************/ -const struct afb_request_itf xreq_itf = { +const struct afb_req_x2_itf xreq_itf = { .json = xreq_json_cb, .get = xreq_get_cb, - .success = xreq_success_cb, - .fail = xreq_fail_cb, - .vsuccess = xreq_vsuccess_cb, - .vfail = xreq_vfail_cb, - .context_get = xreq_context_get_cb, - .context_set = xreq_context_set_cb, + .legacy_success = xreq_legacy_success_cb, + .legacy_fail = xreq_legacy_fail_cb, + .legacy_vsuccess = xreq_legacy_vsuccess_cb, + .legacy_vfail = xreq_legacy_vfail_cb, + .legacy_context_get = xreq_legacy_context_get_cb, + .legacy_context_set = xreq_legacy_context_set_cb, .addref = xreq_addref_cb, .unref = xreq_unref_cb, .session_close = xreq_session_close_cb, .session_set_LOA = xreq_session_set_LOA_cb, - .subscribe = xreq_subscribe_cb, - .unsubscribe = xreq_unsubscribe_cb, - .subcall = xreq_subcall_cb, - .subcallsync = xreq_subcallsync_cb, + .legacy_subscribe_event_x1 = xreq_legacy_subscribe_event_x1_cb, + .legacy_unsubscribe_event_x1 = xreq_legacy_unsubscribe_event_x1_cb, + .legacy_subcall = xreq_legacy_subcall_cb, + .legacy_subcallsync = xreq_legacy_subcallsync_cb, .vverbose = xreq_vverbose_cb, - .store = xreq_store_cb, - .subcall_req = xreq_subcall_req_cb, + .legacy_store_req = xreq_legacy_store_cb, + .legacy_subcall_req = xreq_legacy_subcall_req_cb, .has_permission = xreq_has_permission_cb, .get_application_id = xreq_get_application_id_cb, .context_make = xreq_context_make_cb, - .subscribe_eventid = xreq_subscribe_eventid_cb, - .unsubscribe_eventid = xreq_unsubscribe_eventid_cb, - .subcall_request = xreq_subcall_request_cb, + .subscribe_event_x2 = xreq_subscribe_event_x2_cb, + .unsubscribe_event_x2 = xreq_unsubscribe_event_x2_cb, + .legacy_subcall_request = xreq_legacy_subcall_request_cb, .get_uid = xreq_get_uid_cb, + .reply = xreq_reply_cb, + .vreply = xreq_vreply_cb, + .get_client_info = xreq_get_client_info_cb, + .subcall = xreq_subcall_cb, + .subcallsync = xreq_subcallsync_cb, }; -const struct afb_request_itf xreq_hooked_itf = { +const struct afb_req_x2_itf xreq_hooked_itf = { .json = xreq_hooked_json_cb, .get = xreq_hooked_get_cb, - .success = xreq_hooked_success_cb, - .fail = xreq_hooked_fail_cb, - .vsuccess = xreq_hooked_vsuccess_cb, - .vfail = xreq_hooked_vfail_cb, - .context_get = xreq_hooked_context_get_cb, - .context_set = xreq_hooked_context_set_cb, + .legacy_success = xreq_hooked_legacy_success_cb, + .legacy_fail = xreq_hooked_legacy_fail_cb, + .legacy_vsuccess = xreq_hooked_legacy_vsuccess_cb, + .legacy_vfail = xreq_hooked_legacy_vfail_cb, + .legacy_context_get = xreq_hooked_legacy_context_get_cb, + .legacy_context_set = xreq_hooked_legacy_context_set_cb, .addref = xreq_hooked_addref_cb, .unref = xreq_hooked_unref_cb, .session_close = xreq_hooked_session_close_cb, .session_set_LOA = xreq_hooked_session_set_LOA_cb, - .subscribe = xreq_hooked_subscribe_cb, - .unsubscribe = xreq_hooked_unsubscribe_cb, - .subcall = xreq_hooked_subcall_cb, - .subcallsync = xreq_hooked_subcallsync_cb, + .legacy_subscribe_event_x1 = xreq_hooked_legacy_subscribe_event_x1_cb, + .legacy_unsubscribe_event_x1 = xreq_hooked_legacy_unsubscribe_event_x1_cb, + .legacy_subcall = xreq_hooked_legacy_subcall_cb, + .legacy_subcallsync = xreq_hooked_legacy_subcallsync_cb, .vverbose = xreq_hooked_vverbose_cb, - .store = xreq_hooked_store_cb, - .subcall_req = xreq_hooked_subcall_req_cb, + .legacy_store_req = xreq_hooked_legacy_store_cb, + .legacy_subcall_req = xreq_hooked_legacy_subcall_req_cb, .has_permission = xreq_hooked_has_permission_cb, .get_application_id = xreq_hooked_get_application_id_cb, .context_make = xreq_hooked_context_make_cb, - .subscribe_eventid = xreq_hooked_subscribe_eventid_cb, - .unsubscribe_eventid = xreq_hooked_unsubscribe_eventid_cb, - .subcall_request = xreq_hooked_subcall_request_cb, + .subscribe_event_x2 = xreq_hooked_subscribe_event_x2_cb, + .unsubscribe_event_x2 = xreq_hooked_unsubscribe_event_x2_cb, + .legacy_subcall_request = xreq_hooked_legacy_subcall_request_cb, .get_uid = xreq_hooked_get_uid_cb, + .reply = xreq_hooked_reply_cb, + .vreply = xreq_hooked_vreply_cb, + .get_client_info = xreq_hooked_get_client_info_cb, + .subcall = xreq_hooked_subcall_cb, + .subcallsync = xreq_hooked_subcallsync_cb, }; /******************************************************************************/ -struct afb_req afb_xreq_unstore(struct afb_stored_req *sreq) +struct afb_req_x1 afb_xreq_unstore(struct afb_stored_req *sreq) { struct afb_xreq *xreq = (struct afb_xreq *)sreq; if (xreq->hookflags) - afb_hook_xreq_unstore(xreq); - return xreq_to_req(xreq); + afb_hook_xreq_legacy_unstore(xreq); + return xreq_to_req_x1(xreq); } struct json_object *afb_xreq_json(struct afb_xreq *xreq) { - return afb_request_json(xreq_to_request(xreq)); + return afb_req_x2_json(xreq_to_req_x2(xreq)); } -void afb_xreq_success(struct afb_xreq *xreq, struct json_object *obj, const char *info) +void afb_xreq_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { - afb_request_success(xreq_to_request(xreq), obj, info); + afb_req_x2_reply(xreq_to_req_x2(xreq), obj, error, info); } -void afb_xreq_success_f(struct afb_xreq *xreq, struct json_object *obj, const char *info, ...) +void afb_xreq_reply_f(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info, ...) { va_list args; va_start(args, info); - afb_request_success_v(xreq_to_request(xreq), obj, info, args); + afb_req_x2_reply_v(xreq_to_req_x2(xreq), obj, error, info, args); va_end(args); } -void afb_xreq_fail(struct afb_xreq *xreq, const char *status, const char *info) -{ - afb_request_fail(xreq_to_request(xreq), status, info); -} - -void afb_xreq_fail_f(struct afb_xreq *xreq, const char *status, const char *info, ...) -{ - va_list args; - - va_start(args, info); - afb_request_fail_v(xreq_to_request(xreq), status, info, args); - va_end(args); - -} - const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size) { - struct json_object *obj = xreq_json_cb(xreq_to_request(xreq)); + struct json_object *obj = xreq_json_cb(xreq_to_req_x2(xreq)); const char *result = json_object_to_json_string(obj); if (size != NULL) *size = strlen(result); @@ -914,69 +674,79 @@ const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size) void afb_xreq_addref(struct afb_xreq *xreq) { - afb_request_addref(xreq_to_request(xreq)); + afb_req_x2_addref(xreq_to_req_x2(xreq)); } void afb_xreq_unref(struct afb_xreq *xreq) { - afb_request_unref(xreq_to_request(xreq)); + afb_req_x2_unref(xreq_to_req_x2(xreq)); +} + +void afb_xreq_unhooked_legacy_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *cb_closure) +{ + xreq_legacy_subcall_request_cb(xreq_to_req_x2(xreq), api, verb, args, callback, cb_closure); +} + +void afb_xreq_legacy_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *cb_closure) +{ + afb_req_x2_subcall_legacy(xreq_to_req_x2(xreq), api, verb, args, callback, cb_closure); } -void afb_xreq_unhooked_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure) +void afb_xreq_unhooked_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags, void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *), void *closure) { - xreq_subcall_request_cb(xreq_to_request(xreq), api, verb, args, callback, cb_closure); + xreq_subcall_cb(xreq_to_req_x2(xreq), api, verb, args, flags, callback, closure); } -void afb_xreq_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure) +void afb_xreq_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags, void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *), void *closure) { - afb_request_subcall(xreq_to_request(xreq), api, verb, args, callback, cb_closure); + afb_req_x2_subcall(xreq_to_req_x2(xreq), api, verb, args, flags, callback, closure); } -int afb_xreq_unhooked_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result) +int afb_xreq_unhooked_legacy_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - return xreq_subcallsync_cb(xreq_to_request(xreq), api, verb, args, result); + return xreq_legacy_subcallsync_cb(xreq_to_req_x2(xreq), api, verb, args, result); } -int afb_xreq_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result) +int afb_xreq_legacy_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - return afb_request_subcall_sync(xreq_to_request(xreq), api, verb, args, result); + return afb_req_x2_subcall_sync_legacy(xreq_to_req_x2(xreq), api, verb, args, result); } static int xreq_session_check_apply_v1(struct afb_xreq *xreq, int sessionflags) { int loa; - if ((sessionflags & (AFB_SESSION_CLOSE_V1|AFB_SESSION_RENEW_V1|AFB_SESSION_CHECK_V1|AFB_SESSION_LOA_EQ_V1)) != 0) { + if ((sessionflags & (AFB_SESSION_CLOSE_X1|AFB_SESSION_RENEW_X1|AFB_SESSION_CHECK_X1|AFB_SESSION_LOA_EQ_X1)) != 0) { if (!afb_context_check(&xreq->context)) { afb_context_close(&xreq->context); - afb_xreq_fail_f(xreq, "denied", "invalid token's identity"); + afb_xreq_reply_f(xreq, NULL, "denied", "invalid token's identity"); errno = EINVAL; return -1; } } - if ((sessionflags & AFB_SESSION_LOA_GE_V1) != 0) { - loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1; + if ((sessionflags & AFB_SESSION_LOA_GE_X1) != 0) { + loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1; if (!afb_context_check_loa(&xreq->context, loa)) { - afb_xreq_fail_f(xreq, "denied", "invalid LOA"); + afb_xreq_reply_f(xreq, NULL, "denied", "invalid LOA"); errno = EPERM; return -1; } } - if ((sessionflags & AFB_SESSION_LOA_LE_V1) != 0) { - loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1; + if ((sessionflags & AFB_SESSION_LOA_LE_X1) != 0) { + loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1; if (afb_context_check_loa(&xreq->context, loa + 1)) { - afb_xreq_fail_f(xreq, "denied", "invalid LOA"); + afb_xreq_reply_f(xreq, NULL, "denied", "invalid LOA"); errno = EPERM; return -1; } } - if ((sessionflags & AFB_SESSION_RENEW_V1) != 0) { + if ((sessionflags & AFB_SESSION_RENEW_X1) != 0) { afb_context_refresh(&xreq->context); } - if ((sessionflags & AFB_SESSION_CLOSE_V1) != 0) { + if ((sessionflags & AFB_SESSION_CLOSE_X1) != 0) { afb_context_change_loa(&xreq->context, 0); afb_context_close(&xreq->context); } @@ -991,29 +761,29 @@ static int xreq_session_check_apply_v2(struct afb_xreq *xreq, uint32_t sessionfl if (sessionflags != 0) { if (!afb_context_check(&xreq->context)) { afb_context_close(&xreq->context); - afb_xreq_fail_f(xreq, "denied", "invalid token's identity"); + afb_xreq_reply_f(xreq, NULL, "denied", "invalid token's identity"); errno = EINVAL; return -1; } } - loa = (int)(sessionflags & AFB_SESSION_LOA_MASK_V2); + loa = (int)(sessionflags & AFB_SESSION_LOA_MASK_X2); if (loa && !afb_context_check_loa(&xreq->context, loa)) { - afb_xreq_fail_f(xreq, "denied", "invalid LOA"); + afb_xreq_reply_f(xreq, NULL, "denied", "invalid LOA"); errno = EPERM; return -1; } if (auth && !afb_auth_check(xreq, auth)) { - afb_xreq_fail_f(xreq, "denied", "authorisation refused"); + afb_xreq_reply_f(xreq, NULL, "denied", "authorisation refused"); errno = EPERM; return -1; } - if ((sessionflags & AFB_SESSION_REFRESH_V2) != 0) { + if ((sessionflags & AFB_SESSION_REFRESH_X2) != 0) { afb_context_refresh(&xreq->context); } - if ((sessionflags & AFB_SESSION_CLOSE_V2) != 0) { + if ((sessionflags & AFB_SESSION_CLOSE_X2) != 0) { afb_context_close(&xreq->context); } @@ -1023,55 +793,55 @@ static int xreq_session_check_apply_v2(struct afb_xreq *xreq, uint32_t sessionfl void afb_xreq_call_verb_v1(struct afb_xreq *xreq, const struct afb_verb_desc_v1 *verb) { if (!verb) - afb_xreq_fail_unknown_verb(xreq); + afb_xreq_reply_unknown_verb(xreq); else if (!xreq_session_check_apply_v1(xreq, verb->session)) - verb->callback(xreq_to_req(xreq)); + verb->callback(xreq_to_req_x1(xreq)); } void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb) { if (!verb) - afb_xreq_fail_unknown_verb(xreq); + afb_xreq_reply_unknown_verb(xreq); else if (!xreq_session_check_apply_v2(xreq, verb->session, verb->auth)) - verb->callback(xreq_to_req(xreq)); + verb->callback(xreq_to_req_x1(xreq)); } -void afb_xreq_call_verb_vdyn(struct afb_xreq *xreq, const struct afb_api_dyn_verb *verb) +void afb_xreq_call_verb_v3(struct afb_xreq *xreq, const struct afb_verb_v3 *verb) { if (!verb) - afb_xreq_fail_unknown_verb(xreq); + afb_xreq_reply_unknown_verb(xreq); else if (xreq_session_check_apply_v2(xreq, verb->session, verb->auth) >= 0) - verb->callback(xreq_to_request(xreq)); + verb->callback(xreq_to_req_x2(xreq)); } void afb_xreq_init(struct afb_xreq *xreq, const struct afb_xreq_query_itf *queryitf) { memset(xreq, 0, sizeof *xreq); - xreq->request.itf = &xreq_hooked_itf; /* hook by default */ + xreq->request.itf = &xreq_itf; /* no hook by default */ xreq->refcount = 1; xreq->queryitf = queryitf; } -void afb_xreq_fail_unknown_api(struct afb_xreq *xreq) +void afb_xreq_reply_unknown_api(struct afb_xreq *xreq) { - afb_xreq_fail_f(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->request.api, xreq->request.verb); + afb_xreq_reply_f(xreq, NULL, "unknown-api", "api %s not found (for verb %s)", xreq->request.called_api, xreq->request.called_verb); } -void afb_xreq_fail_unknown_verb(struct afb_xreq *xreq) +void afb_xreq_reply_unknown_verb(struct afb_xreq *xreq) { - afb_xreq_fail_f(xreq, "unknown-verb", "verb %s unknown within api %s", xreq->request.verb, xreq->request.api); + afb_xreq_reply_f(xreq, NULL, "unknown-verb", "verb %s unknown within api %s", xreq->request.called_verb, xreq->request.called_api); } static void init_hooking(struct afb_xreq *xreq) { afb_hook_init_xreq(xreq); - if (xreq->hookflags) + if (xreq->hookflags) { + xreq->request.itf = &xreq_hooked_itf; /* unhook the interface */ afb_hook_xreq_begin(xreq); - else - xreq->request.itf = &xreq_itf; /* unhook the interface */ + } } /** @@ -1080,16 +850,16 @@ static void init_hooking(struct afb_xreq *xreq) static void process_async(int signum, void *arg) { struct afb_xreq *xreq = arg; - const struct afb_api *api; + const struct afb_api_item *api; if (signum != 0) { /* emit the error (assumes that hooking is initialised) */ - afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum); + afb_xreq_reply_f(xreq, NULL, "aborted", "signal %s(%d) caught", strsignal(signum), signum); } else { /* init hooking */ init_hooking(xreq); - /* invoke api call method to process the reqiest */ - api = (const struct afb_api*)xreq->context.api_key; + /* invoke api call method to process the request */ + api = (const struct afb_api_item*)xreq->context.api_key; api->itf->call(api->closure, xreq); } /* release the request */ @@ -1111,7 +881,7 @@ static void early_failure(struct afb_xreq *xreq, const char *status, const char /* send error */ va_start(args, info); - afb_request_fail_v(xreq_to_request(xreq), status, info, args); + afb_req_x2_reply_v(xreq_to_req_x2(xreq), NULL, status, info, args); va_end(args); } @@ -1121,17 +891,17 @@ static void early_failure(struct afb_xreq *xreq, const char *status, const char */ void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset) { - const struct afb_api *api; + const struct afb_api_item *api; struct afb_xreq *caller; /* lookup at the api */ xreq->apiset = apiset; - api = afb_apiset_lookup_started(apiset, xreq->request.api, 1); + api = afb_apiset_lookup_started(apiset, xreq->request.called_api, 1); if (!api) { if (errno == ENOENT) - early_failure(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->request.api, xreq->request.verb); + early_failure(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->request.called_api, xreq->request.called_verb); else - early_failure(xreq, "bad-api-state", "api %s not started correctly: %m", xreq->request.api); + early_failure(xreq, "bad-api-state", "api %s not started correctly: %m", xreq->request.called_api); goto end; } xreq->context.api_key = api; @@ -1140,10 +910,10 @@ void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset) if (api->group) { caller = xreq->caller; while (caller) { - if (((const struct afb_api *)caller->context.api_key)->group == api->group) { + if (((const struct afb_api_item*)caller->context.api_key)->group == api->group) { /* noconcurrency lock detected */ - ERROR("self-lock detected in call stack for API %s", xreq->request.api); - early_failure(xreq, "self-locked", "recursive self lock, API %s", xreq->request.api); + ERROR("self-lock detected in call stack for API %s", xreq->request.called_api); + early_failure(xreq, "self-locked", "recursive self lock, API %s", xreq->request.called_api); goto end; } caller = caller->caller; @@ -1162,3 +932,8 @@ end: afb_xreq_unhooked_unref(xreq); } +const char *xreq_on_behalf_cred_export(struct afb_xreq *xreq) +{ + return xreq->caller ? afb_cred_export(xreq->cred) : NULL; +} + diff --git a/src/afb-xreq.h b/src/afb-xreq.h index ae1419fb..5c748d6f 100644 --- a/src/afb-xreq.h +++ b/src/afb-xreq.h @@ -17,8 +17,9 @@ #pragma once -#include <afb/afb-request-itf.h> -#include <afb/afb-req-itf.h> +#include <stdarg.h> +#include <afb/afb-req-x1-itf.h> +#include <afb/afb-req-x2-itf.h> #include "afb-context.h" struct json_object; @@ -26,29 +27,20 @@ struct afb_evt_listener; struct afb_xreq; struct afb_cred; struct afb_apiset; -struct afb_api_dyn_verb; -struct afb_eventid; +struct afb_event_x2; struct afb_verb_desc_v1; struct afb_verb_v2; -struct afb_req; +struct afb_verb_v3; +struct afb_req_x1; struct afb_stored_req; struct afb_xreq_query_itf { struct json_object *(*json)(struct afb_xreq *xreq); struct afb_arg (*get)(struct afb_xreq *xreq, const char *name); - void (*success)(struct afb_xreq *xreq, struct json_object *obj, const char *info); - void (*fail)(struct afb_xreq *xreq, const char *status, const char *info); - void (*reply)(struct afb_xreq *xreq, int status, struct json_object *obj); + void (*reply)(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info); void (*unref)(struct afb_xreq *xreq); - int (*subscribe)(struct afb_xreq *xreq, struct afb_eventid *eventid); - int (*unsubscribe)(struct afb_xreq *xreq, struct afb_eventid *eventid); - void (*subcall)( - struct afb_xreq *xreq, - const char *api, - const char *verb, - struct json_object *args, - void (*callback)(void*, int, struct json_object*), - void *cb_closure); + int (*subscribe)(struct afb_xreq *xreq, struct afb_event_x2 *event); + int (*unsubscribe)(struct afb_xreq *xreq, struct afb_event_x2 *event); }; /** @@ -56,7 +48,7 @@ struct afb_xreq_query_itf { */ struct afb_xreq { - struct afb_request request; /**< exported request */ + struct afb_req_x2 request; /**< exported request */ struct afb_context context; /**< context of the request */ struct afb_apiset *apiset; /**< apiset of the xreq */ struct json_object *json; /**< the json object (or NULL) */ @@ -90,49 +82,65 @@ struct afb_xreq #define CONTAINER_OF_XREQ(type,x) CONTAINER_OF(type,xreq,x) /* req wrappers for xreq */ -extern struct afb_req afb_xreq_unstore(struct afb_stored_req *sreq); +extern struct afb_req_x1 afb_xreq_unstore(struct afb_stored_req *sreq); extern void afb_xreq_addref(struct afb_xreq *xreq); extern void afb_xreq_unref(struct afb_xreq *xreq); extern void afb_xreq_unhooked_addref(struct afb_xreq *xreq); extern void afb_xreq_unhooked_unref(struct afb_xreq *xreq); +extern struct json_object *afb_xreq_unhooked_json(struct afb_xreq *xreq); extern struct json_object *afb_xreq_json(struct afb_xreq *xreq); -extern void afb_xreq_success(struct afb_xreq *xreq, struct json_object *obj, const char *info); -extern void afb_xreq_success_f(struct afb_xreq *xreq, struct json_object *obj, const char *info, ...); +extern void afb_xreq_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info); +extern void afb_xreq_reply_f(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info, ...); -extern void afb_xreq_fail(struct afb_xreq *xreq, const char *status, const char *info); -extern void afb_xreq_fail_f(struct afb_xreq *xreq, const char *status, const char *info, ...); -extern void afb_xreq_fail_unknown_api(struct afb_xreq *xreq); -extern void afb_xreq_fail_unknown_verb(struct afb_xreq *xreq); +extern void afb_xreq_reply_unknown_api(struct afb_xreq *xreq); +extern void afb_xreq_reply_unknown_verb(struct afb_xreq *xreq); extern const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size); -extern int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid); -extern int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid); +extern int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event); +extern int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event); -extern void afb_xreq_subcall( +extern void afb_xreq_legacy_subcall( struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_request *), + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *cb_closure); -extern void afb_xreq_unhooked_subcall( +extern void afb_xreq_unhooked_legacy_subcall( struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_request *), + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *cb_closure); -extern int afb_xreq_unhooked_subcall_sync( +extern void afb_xreq_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *), + void *closure); +extern void afb_xreq_unhooked_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *), + void *closure); + +extern int afb_xreq_unhooked_legacy_subcall_sync( struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result); -extern int afb_xreq_subcall_sync( +extern int afb_xreq_legacy_subcall_sync( struct afb_xreq *xreq, const char *api, const char *verb, @@ -146,23 +154,24 @@ extern void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset); extern void afb_xreq_call_verb_v1(struct afb_xreq *xreq, const struct afb_verb_desc_v1 *verb); extern void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb); -extern void afb_xreq_call_verb_vdyn(struct afb_xreq *xreq, const struct afb_api_dyn_verb *verb); +extern void afb_xreq_call_verb_v3(struct afb_xreq *xreq, const struct afb_verb_v3 *verb); + +extern const char *xreq_on_behalf_cred_export(struct afb_xreq *xreq); /******************************************************************************/ -static inline struct afb_req xreq_to_req(struct afb_xreq *xreq) +static inline struct afb_req_x1 xreq_to_req_x1(struct afb_xreq *xreq) { - return (struct afb_req){ .itf = xreq->request.itf, .closure = &xreq->request }; + return (struct afb_req_x1){ .itf = xreq->request.itf, .closure = &xreq->request }; } -static inline struct afb_request *xreq_to_request(struct afb_xreq *xreq) +static inline struct afb_req_x2 *xreq_to_req_x2(struct afb_xreq *xreq) { return &xreq->request; } -static inline struct afb_xreq *xreq_from_request(struct afb_request *request) +static inline struct afb_xreq *xreq_from_req_x2(struct afb_req_x2 *req) { - return CONTAINER_OF(struct afb_xreq, request, request); + return CONTAINER_OF(struct afb_xreq, request, req); } - diff --git a/src/afs-config.c b/src/afs-config.c index 78fee7dc..70a6d475 100644 --- a/src/afs-config.c +++ b/src/afs-config.c @@ -263,11 +263,11 @@ static void parse_arguments(int argc, char **argv, struct afs_config *config) while ((optc = getopt_long(argc, argv, shortopts, gnuOptions, NULL)) != EOF) { switch (optc) { case SET_VERBOSE: - verbosity++; + verbose_inc(); break; case SET_QUIET: - verbosity--; + verbose_dec(); break; case SET_TCP_PORT: @@ -441,7 +441,7 @@ struct afs_config *afs_config_parse_arguments(int argc, char **argv) parse_environment(result); parse_arguments(argc, argv, result); fulfill_config(result); - if (verbosity >= 3) + if (verbose_wants(Log_Level_Info)) afs_config_dump(result); return result; } diff --git a/src/afs-supervision.h b/src/afs-supervision.h index 2c76f249..25d1b4b1 100644 --- a/src/afs-supervision.h +++ b/src/afs-supervision.h @@ -45,5 +45,5 @@ struct afs_supervision_initiator char extra[27]; /**< zero terminated extra computed here to be 64-37 */ }; -#define AFS_SUPERVISION_APINAME "$" +#define AFS_SUPERVISION_APINAME "." #define AFS_SUPERVISOR_APINAME "supervisor" diff --git a/src/afs-supervisor.c b/src/afs-supervisor.c index 285d82cb..6bd1fc62 100644 --- a/src/afs-supervisor.c +++ b/src/afs-supervisor.c @@ -28,13 +28,15 @@ #include <sys/un.h> #include <json-c/json.h> -#include <afb/afb-binding-v2.h> + +#define AFB_BINDING_VERSION 3 +#include <afb/afb-binding.h> #include "afb-cred.h" #include "afb-stub-ws.h" #include "afb-api.h" #include "afb-xreq.h" -#include "afb-api-so-v2.h" +#include "afb-api-v3.h" #include "afb-apiset.h" #include "afb-fdev.h" @@ -76,6 +78,10 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /* list of supervised daemons */ static struct supervised *superviseds; +/* events */ +static afb_event_t event_add_pid; +static afb_event_t event_del_pid; + /*************************************************************************************/ @@ -155,7 +161,7 @@ static int send_initiator(int fd, const char *command) } /* - * checks whether the incomming supervised represented by its creds + * checks whether the incoming supervised represented by its creds * is to be accepted or not. * return 1 if yes or 0 otherwise. */ @@ -171,11 +177,15 @@ static void on_supervised_hangup(struct afb_stub_ws *stub) ps = &superviseds; while ((s = *ps) && s->stub != stub) ps = &s->next; - if (s) { + if (s) *ps = s->next; - afb_stub_ws_unref(stub); - } pthread_mutex_unlock(&mutex); + afb_stub_ws_unref(stub); + if (s) { + afb_event_push(event_del_pid, json_object_new_int((int)s->cred->pid)); + afb_cred_unref(s->cred); + free(s); + } } /* @@ -246,8 +256,10 @@ static void accept_supervision_link(int sock) rc = send_initiator(fd, NULL); if (!rc) { rc = make_supervised(fd, cred); - if (!rc) + if (!rc) { + afb_event_push(event_add_pid, json_object_new_int((int)cred->pid)); return; + } } } afb_cred_unref(cred); @@ -290,9 +302,27 @@ int afs_supervisor_discover() /*************************************************************************************/ -static struct afb_binding_data_v2 datav2; +static void f_subscribe(afb_req_t req) +{ + struct json_object *args = afb_req_json(req); + int revoke, ok; + + revoke = json_object_is_type(args, json_type_boolean) + && !json_object_get_boolean(args); -static void f_list(struct afb_req req) + ok = 1; + if (!revoke) { + ok = !afb_req_subscribe(req, event_add_pid) + && !afb_req_subscribe(req, event_del_pid); + } + if (revoke || !ok) { + afb_req_unsubscribe(req, event_add_pid); + afb_req_unsubscribe(req, event_del_pid); + } + afb_req_reply(req, NULL, ok ? NULL : "error", NULL); +} + +static void f_list(afb_req_t req) { char pid[50]; struct json_object *resu, *item; @@ -317,82 +347,82 @@ static void f_list(struct afb_req req) afb_req_success(req, resu, NULL); } -static void f_discover(struct afb_req req) +static void f_discover(afb_req_t req) { afs_supervisor_discover(); afb_req_success(req, NULL, NULL); } -static void propagate(struct afb_req req, const char *verb) +static void propagate(afb_req_t req, const char *verb) { struct afb_xreq *xreq; struct json_object *args, *item; struct supervised *s; - struct afb_api api; + struct afb_api_item api; int p; - xreq = xreq_from_request(req.closure); + xreq = xreq_from_req_x2(req); args = afb_xreq_json(xreq); if (!json_object_object_get_ex(args, "pid", &item)) { - afb_xreq_fail(xreq, "no-pid", NULL); + afb_xreq_reply(xreq, NULL, "no-pid", NULL); return; } errno = 0; p = json_object_get_int(item); if (!p && errno) { - afb_xreq_fail(xreq, "bad-pid", NULL); + afb_xreq_reply(xreq, NULL, "bad-pid", NULL); return; } s = supervised_of_pid((pid_t)p); if (!s) { - afb_req_fail(req, "unknown-pid", NULL); + afb_req_reply(req, NULL, "unknown-pid", NULL); return; } json_object_object_del(args, "pid"); if (verb) - xreq->request.verb = verb; + xreq->request.called_verb = verb; api = afb_stub_ws_client_api(s->stub); api.itf->call(api.closure, xreq); } -static void f_do(struct afb_req req) +static void f_do(afb_req_t req) { propagate(req, NULL); } -static void f_config(struct afb_req req) +static void f_config(afb_req_t req) { propagate(req, NULL); } -static void f_trace(struct afb_req req) +static void f_trace(afb_req_t req) { propagate(req, NULL); } -static void f_sessions(struct afb_req req) +static void f_sessions(afb_req_t req) { propagate(req, "slist"); } -static void f_session_close(struct afb_req req) +static void f_session_close(afb_req_t req) { propagate(req, "sclose"); } -static void f_exit(struct afb_req req) +static void f_exit(afb_req_t req) { propagate(req, NULL); afb_req_success(req, NULL, NULL); } -static void f_debug_wait(struct afb_req req) +static void f_debug_wait(afb_req_t req) { propagate(req, "wait"); afb_req_success(req, NULL, NULL); } -static void f_debug_break(struct afb_req req) +static void f_debug_break(afb_req_t req) { propagate(req, "break"); afb_req_success(req, NULL, NULL); @@ -403,10 +433,22 @@ static void f_debug_break(struct afb_req req) /** * initialize the supervisor */ -static int init_supervisor() +static int init_supervisor(afb_api_t api) { int rc, fd; + event_add_pid = afb_api_make_event(api, "add-pid"); + if (!afb_event_is_valid(event_add_pid)) { + ERROR("Can't create added event"); + return -1; + } + + event_del_pid = afb_api_make_event(api, "del-pid"); + if (!afb_event_is_valid(event_del_pid)) { + ERROR("Can't create deleted event"); + return -1; + } + /* create an empty set for superviseds */ empty_apiset = afb_apiset_create(supervision_apiname, 0); if (!empty_apiset) { @@ -448,93 +490,102 @@ static const struct afb_auth _afb_auths_v2_supervisor[] = { } }; -static const struct afb_verb_v2 _afb_verbs_v2_supervisor[] = { +static const struct afb_verb_v3 _afb_verbs_supervisor[] = { + { + .verb = "subscribe", + .callback = f_subscribe, + .auth = &_afb_auths_v2_supervisor[0], + .info = NULL, + .session = AFB_SESSION_CHECK_X2 + }, { .verb = "list", .callback = f_list, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "config", .callback = f_config, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "do", .callback = f_do, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "trace", .callback = f_trace, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "sessions", .callback = f_sessions, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "session-close", .callback = f_session_close, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "exit", .callback = f_exit, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "debug-wait", .callback = f_debug_wait, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "debug-break", .callback = f_debug_break, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "discover", .callback = f_discover, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = NULL } }; -static const struct afb_binding_v2 _afb_binding_v2_supervisor = { +static const struct afb_binding_v3 _afb_binding_supervisor = { .api = supervisor_apiname, .specification = NULL, .info = NULL, - .verbs = _afb_verbs_v2_supervisor, + .verbs = _afb_verbs_supervisor, .preinit = NULL, .init = init_supervisor, .onevent = NULL, .noconcurrency = 0 }; -int afs_supervisor_add(struct afb_apiset *apiset) +int afs_supervisor_add( + struct afb_apiset *declare_set, + struct afb_apiset * call_set) { - return afb_api_so_v2_add_binding(&_afb_binding_v2_supervisor, NULL, apiset, &datav2); + return -!afb_api_v3_from_binding(&_afb_binding_supervisor, declare_set, call_set); } diff --git a/src/afs-supervisor.h b/src/afs-supervisor.h index aeae6c72..08768ae7 100644 --- a/src/afs-supervisor.h +++ b/src/afs-supervisor.h @@ -19,5 +19,6 @@ extern int afs_supervisor_discover(); -extern int afs_supervisor_add(struct afb_apiset *apiset); - +extern int afs_supervisor_add( + struct afb_apiset *declare_set, + struct afb_apiset * call_set); diff --git a/src/devtools/genskel.c b/src/devtools/genskel.c index a0a78815..55dd3c15 100644 --- a/src/devtools/genskel.c +++ b/src/devtools/genskel.c @@ -62,6 +62,7 @@ struct path /** * root of the JSON being parsed */ +int version = 3; struct json_object *root = NULL; struct json_object *d_perms = NULL; struct json_object *a_perms = NULL; @@ -78,8 +79,8 @@ int noconc = -1; int cpp = 0; /** - * Search for a reference of type "#/a/b/c" int the - * parsed JSON object + * Search for a reference of type "#/a/b/c" in the + * parsed JSON object (root) */ struct json_object *search(const char *path) { @@ -170,6 +171,7 @@ struct json_object *expand_$ref(struct path path) return path.object; } +/* create c name by replacing non alpha numeric characters with underscores */ char *cify(const char *str) { char *r = strdup(str); @@ -182,6 +184,7 @@ char *cify(const char *str) return r; } +/* format the specification as a C string */ char *make_info(const char *text, int split) { const char *a, *b; @@ -260,11 +263,13 @@ char *make_info(const char *text, int split) return desc; } +/* make the description of the object */ char *make_desc(struct json_object *o) { - return make_info(json_object_to_json_string_ext(root, 0), 1); + return make_info(json_object_to_json_string_ext(o, 0), 1); } +/* get the permission odescription if set */ struct json_object *permissions_of_verb(struct json_object *obj) { struct json_object *x, *y; @@ -279,6 +284,7 @@ struct json_object *permissions_of_verb(struct json_object *obj) return NULL; } +/* output the array of permissions */ void print_perms() { int i, n; @@ -286,7 +292,7 @@ void print_perms() n = a_perms ? json_object_array_length(a_perms) : 0; if (n) { - printf("static const struct afb_auth _afb_auths_v2_%s[] = {\n" , capi); + printf("static const struct afb_auth _afb_auths_%s[] = {\n" , capi); i = 0; while (i < n) { printf(fmtstr, json_object_get_string(json_object_array_get_idx(a_perms, i))); @@ -296,6 +302,10 @@ void print_perms() } } +/* + * search in the global object 'd_perm' the computed representation + * of the permission described either by 'obj' or 'desc' + */ struct json_object *new_perm(struct json_object *obj, const char *desc) { const char *tag; @@ -304,12 +314,15 @@ struct json_object *new_perm(struct json_object *obj, const char *desc) tag = obj ? json_object_to_json_string_ext(obj, 0) : desc; if (!json_object_object_get_ex(d_perms, tag, &y)) { + + /* creates the d_perms dico and the a_perms array */ if (!d_perms) { d_perms = json_object_new_object(); a_perms = json_object_new_array(); } - asprintf(&b, "&_afb_auths_v2_%s[%d]", capi, json_object_array_length(a_perms)); + /* creates the reference in the structure */ + asprintf(&b, "&_afb_auths_%s[%d]", capi, json_object_array_length(a_perms)); x = json_object_new_string(desc); y = json_object_new_string(b); json_object_array_add(a_perms, x); @@ -323,6 +336,7 @@ struct json_object *decl_perm(struct json_object *obj); enum optype { And, Or }; +/* recursive declare and/or permissions */ struct json_object *decl_perm_a(enum optype op, struct json_object *obj) { int i, n; @@ -354,16 +368,22 @@ struct json_object *decl_perm_a(enum optype op, struct json_object *obj) return x; } +/* declare the permission for obj */ struct json_object *decl_perm(struct json_object *obj) { char *a; + const char *fmt; struct json_object *x, *y; if (json_object_object_get_ex(d_perms, json_object_to_json_string_ext(obj, 0), &x)) return x; if (json_object_object_get_ex(obj, "permission", &x)) { - asprintf(&a, cpp ? "afb::auth_permission(\"%s\")" : ".type = afb_auth_Permission, .text = \"%s\"", json_object_get_string(x)); + if (cpp) + fmt = "afb::auth_permission(\"%s\")"; + else + fmt = ".type = afb_auth_Permission, .text = \"%s\""; + asprintf(&a, fmt, json_object_get_string(x)); y = new_perm(obj, a); free(a); } @@ -375,7 +395,11 @@ struct json_object *decl_perm(struct json_object *obj) } else if (json_object_object_get_ex(obj, "not", &x)) { x = decl_perm(x); - asprintf(&a, cpp ? "afb::auth_not(%s)" : ".type = afb_auth_Not, .first = %s", json_object_get_string(x)); + if (cpp) + fmt = "afb::auth_not(%s)"; + else + fmt = ".type = afb_auth_Not, .first = %s"; + asprintf(&a, fmt, json_object_get_string(x)); y = new_perm(obj, a); free(a); } @@ -477,7 +501,7 @@ void print_session(struct json_object *p) s = p ? get_session(p) : 0; c = 1; if (s & SESSION_CHECK) { - printf("%s", "|AFB_SESSION_CHECK_V2" + c); + printf("%s", "|AFB_SESSION_CHECK" + c); c = 0; } if (s & SESSION_LOA_3 & ~SESSION_LOA_2) @@ -489,19 +513,19 @@ void print_session(struct json_object *p) else l = 0; if (l) { - printf("%s%d_V2", "|AFB_SESSION_LOA_" + c, l); + printf("%s%d", "|AFB_SESSION_LOA_" + c, l); c = 0; } if (s & SESSION_CLOSE) { - printf("%s", "|AFB_SESSION_CLOSE_V2" + c); + printf("%s", "|AFB_SESSION_CLOSE" + c); c = 0; } if (s & SESSION_RENEW) { - printf("%s", "|AFB_SESSION_REFRESH_V2" + c); + printf("%s", "|AFB_SESSION_REFRESH" + c); c = 0; } if (c) - printf("AFB_SESSION_NONE_V2"); + printf("AFB_SESSION_NONE"); } void print_verb(const char *name) @@ -513,7 +537,7 @@ void print_declare_verb(const char *name, struct json_object *obj) { printf("%s void ", scope); print_verb(name); - printf("(struct afb_req req);\n"); + printf("(afb_req req);\n"); } void print_struct_verb(const char *name, struct json_object *obj) @@ -542,6 +566,12 @@ void print_struct_verb(const char *name, struct json_object *obj) , info ? make_info(info, 0) : "NULL" ); print_session(p); + if (version == 3) + printf( + ",\n" + " .vcbdata = NULL,\n" + " .glob = 0" + ); printf( "\n" " },\n" @@ -646,7 +676,7 @@ void process(char *filename) /* get the API name */ printf( "\n" - "static const char _afb_description_v2_%s[] =\n" + "static const char _afb_description_%s[] =\n" "%s" ";\n" "\n" @@ -657,8 +687,8 @@ void process(char *filename) enum_verbs(print_declare_verb); printf( "\n" - "static const struct afb_verb_v2 _afb_verbs_v2_%s[] = {\n" - , capi + "static const struct afb_verb_v%d _afb_verbs_%s[] = {\n" + , version, capi ); enum_verbs(print_struct_verb); printf( @@ -667,25 +697,36 @@ void process(char *filename) " .callback = NULL,\n" " .auth = NULL,\n" " .info = NULL,\n" - " .session = 0\n" + " .session = 0" + ); + if (version == 3) + printf( + ",\n" + " .vcbdata = NULL,\n" + " .glob = 0" + ); + printf( + "\n" " }\n" "};\n" ); printf( "\n" - "%sconst struct afb_binding_v2 %s%s = {\n" + "%sconst struct afb_binding_v%d %s%s = {\n" " .api = \"%s\",\n" - " .specification = _afb_description_v2_%s,\n" + " .specification = _afb_description_%s,\n" " .info = %s,\n" - " .verbs = _afb_verbs_v2_%s,\n" + " .verbs = _afb_verbs_%s,\n" " .preinit = %s,\n" " .init = %s,\n" " .onevent = %s,\n" + "%s" " .noconcurrency = %d\n" "};\n" "\n" , priv ? "static " : "" - , priv ? "_afb_binding_v2_" : "afbBindingV2" + , version + , priv ? "_afb_binding_" : version==3 ? "afbBindingV3" : "afbBindingV2" , priv ? capi : "" , api , capi @@ -694,6 +735,7 @@ void process(char *filename) , preinit ?: "NULL" , init ?: "NULL" , onevent ?: "NULL" + , version==3 ? " .userdata = NULL,\n" : "" , !!noconc ); @@ -705,11 +747,25 @@ void process(char *filename) /** process the list of files or stdin if none */ int main(int ac, char **av) { + int r, w; av++; - if (*av && !(strcmp(*av, "-x") && strcmp(*av, "--cpp"))) { - cpp = 1; - av++; + + r = w = 0; + while (av[r]) { + if (!(strcmp(av[r], "-x") && strcmp(av[r], "--cpp"))) { + cpp = 1; + r++; + } else if (!strcmp(av[r], "-2")) { + version = 2; + r++; + } else if (!strcmp(av[r], "-3")) { + version = 3; + r++; + } else { + av[w++] = av[r++]; + } } + av[w] = NULL; if (!*av) process("-"); else { @@ -718,7 +774,3 @@ int main(int ac, char **av) return 0; } - - - - diff --git a/src/devtools/monitor-api.json b/src/devtools/monitor-api.json index 3c8867cd..ca4a9b37 100644 --- a/src/devtools/monitor-api.json +++ b/src/devtools/monitor-api.json @@ -172,11 +172,11 @@ "end", "event", "extra", - "fail", "get", "json", "life", "ref", + "reply", "result", "session", "session_close", @@ -190,7 +190,6 @@ "subcallsync", "subcallsync_result", "subscribe", - "success", "unref", "unstore", "unsubscribe", @@ -306,8 +305,8 @@ "paths": { "/get": { "description": "Get monitoring data.", + "x-permissions": { "session": "check" }, "get": { - "x-permissions": { "session": "check" }, "parameters": [ { "in": "query", @@ -338,8 +337,8 @@ }, "/set": { "description": "Set monitoring actions.", + "x-permissions": { "session": "check" }, "get": { - "x-permissions": { "session": "check" }, "parameters": [ { "in": "query", @@ -364,8 +363,8 @@ }, "/trace": { "description": "Set monitoring actions.", + "x-permissions": { "session": "check" }, "get": { - "x-permissions": { "session": "check" }, "parameters": [ { "in": "query", @@ -396,8 +395,8 @@ }, "/session": { "description": "describes the session.", + "x-permissions": { "session": "check" }, "get": { - "x-permissions": { "session": "check" }, "parameters": [ { "in": "query", diff --git a/src/jobs-fake.c b/src/jobs-fake.c index d3444e32..d3cd19e1 100644 --- a/src/jobs-fake.c +++ b/src/jobs-fake.c @@ -71,7 +71,7 @@ static int add_job(const void *group, int timeout, void (*callback)(int signum, else first = j; last = j; - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); return 0; } @@ -83,7 +83,7 @@ static void *thrrun(void *arg) j = first; if (j) first = j->next; - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); if (j) { j->callback(0, j->closure); free(j); @@ -716,7 +716,7 @@ static int on_evloop_efd(sd_event_source *s, int fd, uint32_t revents, void *use struct evloop *evloop = userdata; read(evloop->efd, &x, sizeof x); pthread_mutex_lock(&mutex); - pthread_cond_broadcast(&evloop->cond); + pthread_cond_broadcast(&evloop->cond); pthread_mutex_unlock(&mutex); return 1; } diff --git a/src/afb-client-demo.c b/src/main-afb-client-demo.c index 011de2b5..4e865879 100644 --- a/src/afb-client-demo.c +++ b/src/main-afb-client-demo.c @@ -41,15 +41,13 @@ static void on_wsj1_call(void *closure, const char *api, const char *verb, struc static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg *msg); static void on_pws_hangup(void *closure); -static void on_pws_reply_success(void *closure, void *request, struct json_object *result, const char *info); -static void on_pws_reply_fail(void *closure, void *request, const char *status, const char *info); +static void on_pws_reply(void *closure, void *request, struct json_object *result, const char *error, const char *info); static void on_pws_event_create(void *closure, const char *event_name, int event_id); static void on_pws_event_remove(void *closure, const char *event_name, int event_id); static void on_pws_event_subscribe(void *closure, void *request, const char *event_name, int event_id); static void on_pws_event_unsubscribe(void *closure, void *request, const char *event_name, int event_id); static void on_pws_event_push(void *closure, const char *event_name, int event_id, struct json_object *data); static void on_pws_event_broadcast(void *closure, const char *event_name, struct json_object *data); -static void on_pws_subcall(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args); static int io_event_callback(sd_event_source *src, int fd, uint32_t revents, void *closure); @@ -65,15 +63,13 @@ static struct afb_wsj1_itf wsj1_itf = { /* the callback interface for pws */ static struct afb_proto_ws_client_itf pws_itf = { - .on_reply_success = on_pws_reply_success, - .on_reply_fail = on_pws_reply_fail, + .on_reply = on_pws_reply, .on_event_create = on_pws_event_create, .on_event_remove = on_pws_event_remove, .on_event_subscribe = on_pws_event_subscribe, .on_event_unsubscribe = on_pws_event_unsubscribe, .on_event_push = on_pws_event_push, .on_event_broadcast = on_pws_event_broadcast, - .on_subcall = on_pws_subcall, }; /* global variables */ @@ -96,18 +92,18 @@ static void usage(int status, char *arg0) name = name ? name + 1 : arg0; fprintf(status ? stderr : stdout, "usage: %s [-H [-r]] [-b] [-e] uri [api verb [data]]\n", name); fprintf(status ? stderr : stdout, " %s -d [-H [-r]] [-b] [-e] uri [verb [data]]\n", name); - fprintf(status ? stderr : stdout, "\n" \ - "allowed options\n" \ - " --break, -b Break connection just after event/call has been emitted.\n" \ - " --direct, -d Direct api\n" \ - " --echo, -e Echo inputs\n" \ - " --help, -h Display this help\n" \ - " --human, -H Display human readable JSON\n" \ - " --raw, -r Raw output (default)\n" \ - "Example:\n" \ - " %s --human 'localhost:1234/api?token=HELLO&uuid=magic' hello ping\n" - "\n", name - ); + fprintf(status ? stderr : stdout, "\n" + "allowed options\n" + " --break, -b Break connection just after event/call has been emitted.\n" + " --direct, -d Direct api\n" + " --echo, -e Echo inputs\n" + " --help, -h Display this help\n" + " --human, -H Display human readable JSON\n" + " --raw, -r Raw output (default)\n" + "Example:\n" + " %s --human 'localhost:1234/api?token=HELLO&uuid=magic' hello ping\n" + "\n", name + ); exit(status); } @@ -233,7 +229,7 @@ static void on_wsj1_call(void *closure, const char *api, const char *verb, struc { int rc; if (raw) - printf("%s", afb_wsj1_msg_object_s(msg)); + printf("%s\n", afb_wsj1_msg_object_s(msg)); if (human) printf("ON-CALL %s/%s:\n%s\n", api, verb, json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg), @@ -248,7 +244,7 @@ static void on_wsj1_call(void *closure, const char *api, const char *verb, struc static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg *msg) { if (raw) - printf("%s", afb_wsj1_msg_object_s(msg)); + printf("%s\n", afb_wsj1_msg_object_s(msg)); if (human) printf("ON-EVENT %s:\n%s\n", event, json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg), @@ -260,7 +256,7 @@ static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg static void on_wsj1_reply(void *closure, struct afb_wsj1_msg *msg) { if (raw) - printf("%s", afb_wsj1_msg_object_s(msg)); + printf("%s\n", afb_wsj1_msg_object_s(msg)); if (human) printf("ON-REPLY %s: %s\n%s\n", (char*)closure, afb_wsj1_msg_is_reply_ok(msg) ? "OK" : "ERROR", @@ -393,20 +389,25 @@ static int io_event_callback(sd_event_source *src, int fd, uint32_t revents, voi return 1; } -static void on_pws_reply_success(void *closure, void *request, struct json_object *result, const char *info) +static void on_pws_reply(void *closure, void *request, struct json_object *result, const char *error, const char *info) { - if (raw) - printf("%s", json_object_to_json_string(result)); + error = error ?: "success"; + if (raw) { + /* TODO: transitionnal: fake the structured response */ + struct json_object *x = json_object_new_object(), *y = json_object_new_object(); + json_object_object_add(x, "jtype", json_object_new_string("afb-reply")); + json_object_object_add(x, "request", y); + json_object_object_add(y, "status", json_object_new_string(error)); + if (info) + json_object_object_add(y, "info", json_object_new_string(info)); + if (result) + json_object_object_add(x, "response", json_object_get(result)); + + printf("%s\n", json_object_to_json_string(x)); + json_object_put(x); + } if (human) - printf("ON-REPLY-SUCCESS %s: %s\n%s\n", (char*)request, info?:"", json_object_to_json_string_ext(result, JSON_C_TO_STRING_PRETTY)); - fflush(stdout); - free(request); - dec_callcount(); -} - -static void on_pws_reply_fail(void *closure, void *request, const char *status, const char *info) -{ - printf("ON-REPLY-FAIL %s: %s [%s]\n", (char*)request, status?:"?", info?:""); + printf("ON-REPLY %s: %s %s\n%s\n", (char*)request, error, info ?: "", json_object_to_json_string_ext(result, JSON_C_TO_STRING_PRETTY)); fflush(stdout); free(request); dec_callcount(); @@ -439,7 +440,7 @@ static void on_pws_event_unsubscribe(void *closure, void *request, const char *e static void on_pws_event_push(void *closure, const char *event_name, int event_id, struct json_object *data) { if (raw) - printf("%s", json_object_to_json_string(data)); + printf("ON-EVENT-PUSH: [%d:%s]\n%s\n", event_id, event_name, json_object_to_json_string_ext(data, 0)); if (human) printf("ON-EVENT-PUSH: [%d:%s]\n%s\n", event_id, event_name, json_object_to_json_string_ext(data, JSON_C_TO_STRING_PRETTY)); fflush(stdout); @@ -448,22 +449,12 @@ static void on_pws_event_push(void *closure, const char *event_name, int event_i static void on_pws_event_broadcast(void *closure, const char *event_name, struct json_object *data) { if (raw) - printf("%s", json_object_to_json_string(data)); + printf("ON-EVENT-BROADCAST: [%s]\n%s\n", event_name, json_object_to_json_string_ext(data, 0)); if (human) printf("ON-EVENT-BROADCAST: [%s]\n%s\n", event_name, json_object_to_json_string_ext(data, JSON_C_TO_STRING_PRETTY)); fflush(stdout); } -static void on_pws_subcall(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args) -{ - if (raw) - printf("%s", json_object_to_json_string(args)); - if (human) - printf("ON-SUBCALL %s: %s/%s\n%s\n", (char*)request, api, verb, json_object_to_json_string_ext(args, JSON_C_TO_STRING_PRETTY)); - afb_proto_ws_subcall_reply(subcall, 1, NULL); - fflush(stdout); -} - /* makes a call */ static void pws_call(const char *verb, const char *object) { @@ -488,7 +479,7 @@ static void pws_call(const char *verb, const char *object) if (!o) o = json_object_new_string(object); } - rc = afb_proto_ws_client_call(pws, verb, o, sessionid, key); + rc = afb_proto_ws_client_call(pws, verb, o, sessionid, key, NULL); json_object_put(o); if (rc < 0) { fprintf(stderr, "calling %s(%s) failed: %m\n", verb, object?:""); diff --git a/src/main.c b/src/main-afb-daemon.c index 8c243f73..8b1a2b23 100644 --- a/src/main.c +++ b/src/main-afb-daemon.c @@ -39,6 +39,7 @@ #include "afb-config.h" #include "afb-hswitch.h" #include "afb-apiset.h" +#include "afb-autoset.h" #include "afb-api-so.h" #if defined(WITH_DBUS_TRANSPARENCY) # include "afb-api-dbus.h" @@ -90,12 +91,13 @@ static struct afb_config_list *run_for_list(struct afb_config_list *list, static int run_start(void *closure, char *value) { - int (*starter) (const char *value, struct afb_apiset *apiset) = closure; - return starter(value, main_apiset) >= 0; + int (*starter) (const char *value, struct afb_apiset *declare_set, struct afb_apiset *call_set) = closure; + return starter(value, main_apiset, main_apiset) >= 0; } static void apiset_start_list(struct afb_config_list *list, - int (*starter) (const char *value, struct afb_apiset *apiset), const char *message) + int (*starter) (const char *value, struct afb_apiset *declare_set, struct afb_apiset *call_set), + const char *message) { list = run_for_list(list, run_start, starter); if (list) { @@ -263,17 +265,17 @@ static struct afb_hsrv *start_http_server() return NULL; } - if (!afb_hsrv_set_cache_timeout(hsrv, main_config->cacheTimeout) + if (!afb_hsrv_set_cache_timeout(hsrv, main_config->cache_timeout) || !init_http_server(hsrv)) { ERROR("initialisation of httpd failed"); afb_hsrv_put(hsrv); return NULL; } - NOTICE("Waiting port=%d rootdir=%s", main_config->httpdPort, main_config->rootdir); - NOTICE("Browser URL= http://localhost:%d", main_config->httpdPort); + NOTICE("Waiting port=%d rootdir=%s", main_config->http_port, main_config->rootdir); + NOTICE("Browser URL= http://localhost:%d", main_config->http_port); - rc = afb_hsrv_start(hsrv, (uint16_t) main_config->httpdPort, 15); + rc = afb_hsrv_start(hsrv, (uint16_t) main_config->http_port, 15); if (!rc) { ERROR("starting of httpd failed"); afb_hsrv_put(hsrv); @@ -419,8 +421,8 @@ static int execute_command() return 0; /* compute the string for port */ - if (main_config->httpdPort) - rc = snprintf(port, sizeof port, "%d", main_config->httpdPort); + if (main_config->http_port) + rc = snprintf(port, sizeof port, "%d", main_config->http_port); else rc = snprintf(port, sizeof port, "%cp", SUBST_CHAR); if (rc < 0 || rc >= (int)(sizeof port)) { @@ -455,14 +457,16 @@ struct startup_req struct afb_session *session; }; -static void startup_call_reply(struct afb_xreq *xreq, int status, struct json_object *obj) +static void startup_call_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { struct startup_req *sreq = CONTAINER_OF_XREQ(struct startup_req, xreq); - if (status >= 0) - NOTICE("startup call %s returned %s", sreq->current->value, json_object_get_string(obj)); - else { - ERROR("startup call %s ERROR! %s", sreq->current->value, json_object_get_string(obj)); + info = info ?: ""; + if (!error) { + NOTICE("startup call %s returned %s (%s)", sreq->current->value, json_object_get_string(object), info); + json_object_put(object); + } else { + ERROR("startup call %s ERROR! %s (%s)", sreq->current->value, error, info); exit(1); } } @@ -506,8 +510,8 @@ static void startup_call_current(struct startup_req *sreq) sreq->xreq.context.validated = 1; sreq->api = strndup(api, verb - api); sreq->verb = strndup(verb + 1, json - verb - 1); - sreq->xreq.request.api = sreq->api; - sreq->xreq.request.verb = sreq->verb; + sreq->xreq.request.called_api = sreq->api; + sreq->xreq.request.called_verb = sreq->verb; sreq->xreq.json = json_tokener_parse(json + 1); if (sreq->api && sreq->verb && sreq->xreq.json) { afb_xreq_process(&sreq->xreq, main_apiset); @@ -560,16 +564,16 @@ static void start(int signum, void *arg) } /* configure the daemon */ - if (afb_session_init(main_config->nbSessionMax, main_config->cntxTimeout, main_config->token)) { + if (afb_session_init(main_config->max_session_count, main_config->session_timeout, main_config->token)) { ERROR("initialisation of session manager failed"); goto error; } - main_apiset = afb_apiset_create("main", main_config->apiTimeout); + main_apiset = afb_apiset_create("main", main_config->api_timeout); if (!main_apiset) { ERROR("can't create main api set"); goto error; } - if (afb_monitor_init() < 0) { + if (afb_monitor_init(main_apiset, main_apiset) < 0) { ERROR("failed to setup monitor"); goto error; } @@ -581,10 +585,8 @@ static void start(int signum, void *arg) /* install hooks */ if (main_config->tracereq) afb_hook_create_xreq(NULL, NULL, NULL, main_config->tracereq, NULL, NULL); - if (main_config->traceditf) - afb_hook_create_ditf(NULL, main_config->traceditf, NULL, NULL); - if (main_config->tracesvc) - afb_hook_create_svc(NULL, main_config->tracesvc, NULL, NULL); + if (main_config->traceapi) + afb_hook_create_api(NULL, main_config->traceapi, NULL, NULL); if (main_config->traceevt) afb_hook_create_evt(NULL, main_config->traceevt, NULL, NULL); if (main_config->traceses) @@ -599,6 +601,8 @@ static void start(int signum, void *arg) apiset_start_list(main_config->ws_clients, afb_api_ws_add_client_weak, "the afb-websocket client"); apiset_start_list(main_config->ldpaths, afb_api_so_add_pathset_fails, "the binding path set"); apiset_start_list(main_config->weak_ldpaths, afb_api_so_add_pathset_nofails, "the weak binding path set"); + apiset_start_list(main_config->auto_ws, afb_autoset_add_ws, "the automatic afb-websocket path set"); + apiset_start_list(main_config->auto_link, afb_autoset_add_so, "the automatic link binding path set"); #if defined(WITH_DBUS_TRANSPARENCY) apiset_start_list(main_config->dbus_servers, afb_api_dbus_add_server, "the afb-dbus service"); @@ -617,13 +621,13 @@ static void start(int signum, void *arg) /* start the HTTP server */ afb_debug("start-http"); - if (!main_config->noHttpd) { - if (main_config->httpdPort <= 0) { + if (!main_config->no_httpd) { + if (main_config->http_port <= 0) { ERROR("no port is defined"); goto error; } - if (!afb_hreq_init_cookie(main_config->httpdPort, main_config->rootapi, main_config->cntxTimeout)) { + if (!afb_hreq_init_cookie(main_config->http_port, main_config->rootapi, main_config->session_timeout)) { ERROR("initialisation of HTTP cookies failed"); goto error; } diff --git a/src/afs-main.c b/src/main-afs-supervisor.c index 88e4757f..14f1c3b0 100644 --- a/src/afs-main.c +++ b/src/main-afs-supervisor.c @@ -144,7 +144,7 @@ static void start(int signum, void *arg) } /* init the main apiset */ - rc = afs_supervisor_add(main_apiset); + rc = afs_supervisor_add(main_apiset, main_apiset); if (rc < 0) { ERROR("Can't create supervision's apiset: %m"); goto error; @@ -152,7 +152,7 @@ static void start(int signum, void *arg) /* export the service if required */ if (main_config->ws_server) { - rc = afb_api_ws_add_server(main_config->ws_server, main_apiset); + rc = afb_api_ws_add_server(main_config->ws_server, main_apiset, main_apiset); if (rc < 0) { ERROR("Can't export (ws-server) api %s: %m", main_config->ws_server); goto error; diff --git a/src/monitor-api.inc b/src/monitor-api.inc index cbc1187f..e4dc2c92 100644 --- a/src/monitor-api.inc +++ b/src/monitor-api.inc @@ -1,5 +1,5 @@ -static const char _afb_description_v2_monitor[] = +static const char _afb_description_monitor[] = "{\"openapi\":\"3.0.0\",\"info\":{\"description\":\"monitoring of binding" "s and internals\",\"title\":\"monitor\",\"version\":\"1.0\",\"x-binding-" "c-generator\":{\"api\":\"monitor\",\"version\":2,\"prefix\":\"f_\",\"pos" @@ -118,57 +118,68 @@ static const char _afb_description_v2_monitor[] = "}}}}}}}}}" ; -static void f_get(struct afb_req req); -static void f_set(struct afb_req req); -static void f_trace(struct afb_req req); -static void f_session(struct afb_req req); +static void f_get(afb_req_t req); +static void f_set(afb_req_t req); +static void f_trace(afb_req_t req); +static void f_session(afb_req_t req); -static const struct afb_verb_v2 _afb_verbs_v2_monitor[] = { +static const struct afb_verb_v3 _afb_verbs_monitor[] = { { .verb = "get", .callback = f_get, .auth = NULL, .info = "Get monitoring data.", - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK, + .vcbdata = NULL, + .glob = 0 }, { .verb = "set", .callback = f_set, .auth = NULL, .info = "Set monitoring actions.", - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK, + .vcbdata = NULL, + .glob = 0 }, { .verb = "trace", .callback = f_trace, .auth = NULL, .info = "Set monitoring actions.", - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK, + .vcbdata = NULL, + .glob = 0 }, { .verb = "session", .callback = f_session, .auth = NULL, .info = "describes the session.", - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK, + .vcbdata = NULL, + .glob = 0 }, { .verb = NULL, .callback = NULL, .auth = NULL, .info = NULL, - .session = 0 + .session = 0, + .vcbdata = NULL, + .glob = 0 } }; -static const struct afb_binding_v2 _afb_binding_v2_monitor = { +static const struct afb_binding_v3 _afb_binding_monitor = { .api = "monitor", - .specification = _afb_description_v2_monitor, + .specification = _afb_description_monitor, .info = "monitoring of bindings and internals", - .verbs = _afb_verbs_v2_monitor, + .verbs = _afb_verbs_monitor, .preinit = NULL, .init = NULL, .onevent = NULL, + .userdata = NULL, .noconcurrency = 0 }; diff --git a/src/pearson.c b/src/pearson.c new file mode 100644 index 00000000..a39c8952 --- /dev/null +++ b/src/pearson.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> + +/* + * Returns a tiny hash value for the 'text'. + * + * Tiny hash function inspired from pearson + */ +uint8_t pearson4(const char *text) +{ + static uint8_t T[16] = { + 4, 1, 6, 0, 9, 14, 11, 5, + 2, 3, 12, 15, 10, 7, 8, 13 + }; + uint8_t r, c; + + for (r = 0; (c = (uint8_t)*text) ; text++) { + r = T[r ^ (15 & c)]; + r = T[r ^ (c >> 4)]; + } + return r; // % HEADCOUNT; +} + diff --git a/src/pearson.h b/src/pearson.h new file mode 100644 index 00000000..2daa6546 --- /dev/null +++ b/src/pearson.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +extern uint8_t pearson4(const char *text); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index f63f27ae..f0349a68 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -22,6 +22,8 @@ if(check_FOUND) INCLUDE_DIRECTORIES(${INCLUDE_DIRS} ${check_INCLUDE_DIRS}) SET(link_libraries ${link_libraries} ${check_LDFLAGS}) add_subdirectory(session) + add_subdirectory(apiset) + add_subdirectory(apiv3) else(check_FOUND) MESSAGE(WARNING "check not found! no test!") endif(check_FOUND) diff --git a/src/tests/apiset/CMakeLists.txt b/src/tests/apiset/CMakeLists.txt new file mode 100644 index 00000000..180c80b8 --- /dev/null +++ b/src/tests/apiset/CMakeLists.txt @@ -0,0 +1,23 @@ +########################################################################### +# Copyright (C) 2018 "IoT.bzh" +# +# author: José Bollo <jose.bollo@iot.bzh> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +########################################################################### + +add_executable(test-apiset test-apiset.c) +target_include_directories(test-apiset PRIVATE ../..) +target_link_libraries(test-apiset afb-lib ${link_libraries}) +add_test(NAME apiset COMMAND test-apiset) + diff --git a/src/tests/apiset/test-apiset.c b/src/tests/apiset/test-apiset.c new file mode 100644 index 00000000..bdc84137 --- /dev/null +++ b/src/tests/apiset/test-apiset.c @@ -0,0 +1,579 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> + +#include <check.h> +#if !defined(ck_assert_ptr_null) +# define ck_assert_ptr_null(X) ck_assert_ptr_eq(X, NULL) +# define ck_assert_ptr_nonnull(X) ck_assert_ptr_ne(X, NULL) +#endif + +#include "afb-api.h" +#include "afb-apiset.h" + +const char *names[] = { + "Sadie", + "Milford", + "Yvette", + "Carma", + "Cory", + "Clarence", + "Jeffery", + "Molly", + "Sheba", + "Tasha", + "Corey", + "Gerry", + NULL +}; + +const char *aliases[] = { + "Rich", "Molly", + "Alicia", "Carma", + "Drema", "YVETTE", + "Pablo", "Sheba", + "Wendell", "Sadie", + "Cathrine", "CarMa", + "Allen", "Corey", + "Tori", "Drema", + NULL +}; + +const char *extras[] = { + "Meta", + "Delia", + "Pearlie", + "Hank", + "Vena", + "Terrance", + "Gloria", + "Tobi", + "Mack", + "Rosalee", + NULL +}; + +struct afb_api_itf api_itf_null = { + .call = NULL, + .service_start = NULL, + .update_hooks = NULL, + .get_logmask = NULL, + .set_logmask = NULL, + .describe = NULL, + .unref = NULL +}; + + +/*********************************************************************/ +/* check the initialisation */ +START_TEST (check_initialisation) +{ + const char name[] = "name"; + const char noname[] = ""; + int to = 3600; + int noto = -1; + struct afb_apiset *a, *b; + + a = afb_apiset_create(NULL, noto); + ck_assert_ptr_nonnull(a); + ck_assert_str_eq(noname, afb_apiset_name(a)); + ck_assert_int_eq(noto, afb_apiset_timeout_get(a)); + afb_apiset_timeout_set(a, to); + ck_assert_int_eq(to, afb_apiset_timeout_get(a)); + b = afb_apiset_addref(a); + ck_assert_ptr_eq(a, b); + afb_apiset_unref(b); + afb_apiset_unref(a); + + a = afb_apiset_create(name, to); + ck_assert_ptr_nonnull(a); + ck_assert_str_eq(name, afb_apiset_name(a)); + ck_assert_int_eq(to, afb_apiset_timeout_get(a)); + afb_apiset_timeout_set(a, noto); + ck_assert_int_eq(noto, afb_apiset_timeout_get(a)); + b = afb_apiset_addref(a); + ck_assert_ptr_eq(a, b); + afb_apiset_unref(b); + afb_apiset_unref(a); +} +END_TEST + +/*********************************************************************/ +/* check that NULL is a valid value for addref/unref */ +START_TEST (check_sanity) +{ + struct afb_apiset *a; + + a = afb_apiset_addref(NULL); + ck_assert_ptr_null(a); + afb_apiset_unref(NULL); + ck_assert(1); +} +END_TEST + +/*********************************************************************/ +/* check creation and retrieval of apis */ + +START_TEST (check_creation) +{ + int i, j, nn, na; + struct afb_apiset *a; + struct afb_api_item sa; + const char *x, *y, **set; + const struct afb_api_item *pa; + + /* create a apiset */ + a = afb_apiset_create(NULL, 0); + ck_assert_ptr_nonnull(a); + + /* add apis */ + for (i = 0 ; names[i] != NULL ; i++) { + sa.itf = &api_itf_null; + sa.closure = (void*)names[i]; + sa.group = names[i]; + ck_assert_int_eq(0, afb_apiset_add(a, names[i], sa)); + pa = afb_apiset_lookup(a, names[i], 1); + ck_assert_ptr_nonnull(pa); + ck_assert_ptr_eq(sa.itf, pa->itf); + ck_assert_ptr_eq(sa.closure, pa->closure); + ck_assert_ptr_eq(sa.group, pa->group); + ck_assert_int_eq(0, afb_apiset_is_alias(a, names[i])); + ck_assert_str_eq(names[i], afb_apiset_unalias(a, names[i])); + ck_assert_int_eq(-1, afb_apiset_add(a, names[i], sa)); + ck_assert_int_eq(errno, EEXIST); + } + nn = i; + + /* add aliases */ + for (i = 0 ; aliases[i] != NULL ; i += 2) { + ck_assert_int_eq(-1, afb_apiset_add_alias(a, extras[0], aliases[i])); + ck_assert_int_eq(errno, ENOENT); + ck_assert_int_eq(0, afb_apiset_add_alias(a, aliases[i + 1], aliases[i])); + ck_assert_ptr_nonnull(afb_apiset_lookup(a, aliases[i], 1)); + ck_assert_int_eq(1, afb_apiset_is_alias(a, aliases[i])); + x = afb_apiset_unalias(a, aliases[i]); + y = afb_apiset_unalias(a, aliases[i + 1]); + ck_assert_int_eq(0, strcasecmp(x, y)); + ck_assert_int_eq(-1, afb_apiset_add_alias(a, aliases[i + 1], aliases[i])); + ck_assert_int_eq(errno, EEXIST); + } + na = i / 2; + + /* check extras */ + for (i = 0 ; extras[i] != NULL ; i++) { + pa = afb_apiset_lookup(a, extras[i], 1); + ck_assert_ptr_null(pa); + ck_assert_int_eq(errno, ENOENT); + } + + /* get the names */ + set = afb_apiset_get_names(a, 0, 1); + ck_assert_ptr_nonnull(set); + for (i = 0 ; set[i] != NULL ; i++) { + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0)); + ck_assert_int_eq(0, afb_apiset_is_alias(a, set[i])); + if (i) + ck_assert_int_gt(0, strcasecmp(set[i-1], set[i])); + } + ck_assert_int_eq(i, nn); + free(set); + set = afb_apiset_get_names(a, 0, 2); + ck_assert_ptr_nonnull(set); + for (i = 0 ; set[i] != NULL ; i++) { + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0)); + ck_assert_int_eq(1, afb_apiset_is_alias(a, set[i])); + if (i) + ck_assert_int_gt(0, strcasecmp(set[i-1], set[i])); + } + ck_assert_int_eq(i, na); + free(set); + set = afb_apiset_get_names(a, 0, 3); + ck_assert_ptr_nonnull(set); + for (i = 0 ; set[i] != NULL ; i++) { + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0)); + if (i) + ck_assert_int_gt(0, strcasecmp(set[i-1], set[i])); + } + ck_assert_int_eq(i, nn + na); + + /* removes the apis to check deletion */ + for (i = 0 ; i < nn + na ; i++) { + if (!set[i]) + continue; + + /* should be present */ + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0)); + + /* deleting a non aliased api removes the aliases! */ + if (!afb_apiset_is_alias(a, set[i])) { + for (j = i + 1 ; j < nn + na ; j++) { + if (!set[j]) + continue; + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[j], 0)); + if (afb_apiset_is_alias(a, set[j]) + && afb_apiset_lookup(a, set[i], 0) == afb_apiset_lookup(a, set[j], 0)) { + ck_assert(set[j][0] > 0); + ((char*)set[j])[0] = (char)-set[j][0]; + } + } + } + + /* delete now */ + ck_assert_int_eq(0, afb_apiset_del(a, set[i])); + ck_assert_ptr_null(afb_apiset_lookup(a, set[i], 0)); + + /* check other not removed except aliases */ + for (j = i + 1 ; j < nn + na ; j++) { + if (!set[j]) + continue; + if (set[j][0] > 0) + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[j], 0)); + else { + ((char*)set[j])[0] = (char)-set[j][0]; + ck_assert_ptr_null(afb_apiset_lookup(a, set[j], 0)); + set[j] = NULL; + } + } + } + free(set); + + afb_apiset_unref(a); +} +END_TEST + +/*********************************************************************/ +/* check onlack behaviour */ + +int onlackcount; + +static void onlackcleanup(void *closure) +{ + int *count = closure; + ck_assert_ptr_eq(count, &onlackcount); + *count = 0; +} +static int onlack(void *closure, struct afb_apiset *a, const char *name) +{ + int *count = closure; + struct afb_api_item sa; + + ck_assert_ptr_eq(count, &onlackcount); + (*count)++; + + sa.itf = &api_itf_null; + sa.closure = (void*)name; + sa.group = name; + + ck_assert_int_eq(0, afb_apiset_add(a, name, sa)); + return 1; +} + +START_TEST (check_onlack) +{ + int i; + struct afb_apiset *a; + struct afb_api_item sa; + const char *x, *y; + const struct afb_api_item *pa; + + /* create a apiset */ + a = afb_apiset_create(NULL, 0); + ck_assert_ptr_nonnull(a); + + /* add apis */ + for (i = 0 ; names[i] != NULL ; i++) { + sa.itf = &api_itf_null; + sa.closure = (void*)names[i]; + sa.group = names[i]; + ck_assert_int_eq(0, afb_apiset_add(a, names[i], sa)); + pa = afb_apiset_lookup(a, names[i], 1); + ck_assert_ptr_nonnull(pa); + ck_assert_ptr_eq(sa.itf, pa->itf); + ck_assert_ptr_eq(sa.closure, pa->closure); + ck_assert_ptr_eq(sa.group, pa->group); + ck_assert_int_eq(0, afb_apiset_is_alias(a, names[i])); + ck_assert_str_eq(names[i], afb_apiset_unalias(a, names[i])); + ck_assert_int_eq(-1, afb_apiset_add(a, names[i], sa)); + ck_assert_int_eq(errno, EEXIST); + } + + /* add aliases */ + for (i = 0 ; aliases[i] != NULL ; i += 2) { + ck_assert_int_eq(-1, afb_apiset_add_alias(a, extras[0], aliases[i])); + ck_assert_int_eq(errno, ENOENT); + ck_assert_int_eq(0, afb_apiset_add_alias(a, aliases[i + 1], aliases[i])); + ck_assert_ptr_nonnull(afb_apiset_lookup(a, aliases[i], 1)); + ck_assert_int_eq(1, afb_apiset_is_alias(a, aliases[i])); + x = afb_apiset_unalias(a, aliases[i]); + y = afb_apiset_unalias(a, aliases[i + 1]); + ck_assert_int_eq(0, strcasecmp(x, y)); + ck_assert_int_eq(-1, afb_apiset_add_alias(a, aliases[i + 1], aliases[i])); + ck_assert_int_eq(errno, EEXIST); + } + + /* check extras */ + for (i = 0 ; extras[i] != NULL ; i++) { + pa = afb_apiset_lookup(a, extras[i], 1); + ck_assert_ptr_null(pa); + ck_assert_int_eq(errno, ENOENT); + } + + /* put the onlack feature */ + afb_apiset_onlack_set(a, onlack, &onlackcount, onlackcleanup); + + /* check extras */ + onlackcount = 0; + for (i = 0 ; extras[i] != NULL ; i++) { + ck_assert_int_eq(onlackcount, i); + pa = afb_apiset_lookup(a, extras[i], 1); + ck_assert_int_eq(onlackcount, i + 1); + ck_assert_ptr_nonnull(pa); + ck_assert_ptr_eq(&api_itf_null, pa->itf); + ck_assert_ptr_eq(extras[i], pa->closure); + ck_assert_ptr_eq(extras[i], pa->group); + } + + ck_assert_int_eq(onlackcount, i); + afb_apiset_unref(a); + ck_assert_int_eq(onlackcount, 0); +} +END_TEST + +/*********************************************************************/ + +struct set_api { + const char *name; + int init; + int mask; +} set_apis[] = { + { "Sadie", 0, 0 }, + { "Milford", 0, 0 }, + { "Yvette", 0, 0 }, + { "Carma", 0, 0 }, + { "Cory", 0, 0 }, + { "Clarence", 0, 0 }, + { "Jeffery", 0, 0 }, + { "Molly", 0, 0 }, + { "Sheba", 0, 0 }, + { "Tasha", 0, 0 }, + { "Corey", 0, 0 }, + { "Gerry", 0, 0 }, + { NULL, 0, 0 } +}; + +int set_count; +struct set_api *set_last_api; + +void set_cb0(void *closure) +{ + set_last_api = closure; + set_count++; +} + +void set_cb_setmask(void *closure, int mask) +{ + set_cb0(closure); + set_last_api->mask = mask; +} + +int set_cb_getmask(void *closure) +{ + set_cb0(closure); + return set_last_api->mask; +} + +int set_cb_start(void *closure, int share_session, int onneed) +{ + set_cb0(closure); + ck_assert_int_eq(0, set_last_api->init); + set_last_api->init = 1; + return 0; +} + +struct afb_api_itf set_api_itf = { + .call = NULL, + .service_start = set_cb_start, + .update_hooks = set_cb0, + .get_logmask = set_cb_getmask, + .set_logmask = set_cb_setmask, + .describe = NULL, + .unref = set_cb0 +}; + +START_TEST (check_settings) +{ + int i, nn, mask; + struct afb_apiset *a; + struct afb_api_item sa; + + /* create a apiset */ + a = afb_apiset_create(NULL, 0); + ck_assert_ptr_nonnull(a); + + /* add apis */ + for (i = 0 ; set_apis[i].name != NULL ; i++) { + sa.itf = &set_api_itf; + sa.closure = &set_apis[i]; + sa.group = NULL; + ck_assert_int_eq(0, afb_apiset_add(a, set_apis[i].name, sa)); + } + nn = i; + + set_count = 0; + afb_apiset_start_all_services(a, 1); + ck_assert_int_eq(nn, set_count); + + set_count = 0; + afb_apiset_update_hooks(a, NULL); + ck_assert_int_eq(nn, set_count); + + for (mask = 1 ; !(mask >> 10) ; mask <<= 1) { + set_count = 0; + afb_apiset_set_logmask(a, NULL, mask); + ck_assert_int_eq(nn, set_count); + set_count = 0; + for (i = 0 ; set_apis[i].name != NULL ; i++) { + ck_assert_int_eq(mask, afb_apiset_get_logmask(a, set_apis[i].name)); + ck_assert_ptr_eq(set_last_api, &set_apis[i]); + ck_assert_int_eq(i + 1, set_count); + } + } + + set_count = 0; + afb_apiset_unref(a); + ck_assert_int_eq(nn, set_count); +} +END_TEST + +/*********************************************************************/ + +struct clacl { + const char *name; + int count; +} clacl[] = { + { "Sadie", 0 }, + { "Milford", 0 }, + { "Yvette", 0 }, +}; + +struct clapi { + const char *name; + const char *provides; + const char *requires; + const char *apireq; + int init; + int expect; +} clapi[] = { + { "Carma", "", "Sadie", "", 0, 9 }, + { "Cory", "Milford", "", "Clarence", 0, 3 }, + { "Clarence", "Milford", "", "Jeffery", 0, 2 }, + { "Jeffery", "Milford", "", "", 0, 1 }, + { "Molly", "Yvette", "", "Corey", 0, 6 }, + { "Sheba", "Yvette", "Milford", "Molly", 0, 7 }, + { "Tasha", "Sadie", "Yvette", "", 0, 8 }, + { "Corey", "Sadie", "Milford", "Gerry", 0, 5 }, + { "Gerry", "Sadie", "Milford", "", 0, 4 }, + { NULL, NULL, NULL, NULL, 0, 0 } +}; + +int clorder; + +int clacb_start(void *closure, int share_session, int onneed) +{ + struct clapi *a = closure; + int i; + + ck_assert_int_eq(0, a->init); + + for (i = 0 ; clapi[i].name ; i++) { + if (a->requires && a->requires[0] + && clapi[i].provides && clapi[i].provides[0] + && !strcmp(a->requires, clapi[i].provides)) + ck_assert_int_ne(0, clapi[i].init); + if (a->apireq && a->apireq[0] + && !strcmp(a->apireq, clapi[i].name)) + ck_assert_int_ne(0, clapi[i].init); + } + a->init = ++clorder; + ck_assert_int_eq(a->init, a->expect); + + return 0; +} + +struct afb_api_itf clitf = { + .call = NULL, + .service_start = clacb_start, + .update_hooks = NULL, + .get_logmask = NULL, + .set_logmask = NULL, + .describe = NULL, + .unref = NULL +}; + +START_TEST (check_classes) +{ + int i; + struct afb_apiset *a; + struct afb_api_item sa; + + /* create a apiset */ + a = afb_apiset_create(NULL, 0); + ck_assert_ptr_nonnull(a); + + /* add apis */ + for (i = 0 ; clapi[i].name != NULL ; i++) { + sa.itf = &clitf; + sa.closure = &clapi[i]; + sa.group = NULL; + ck_assert_int_eq(0, afb_apiset_add(a, clapi[i].name, sa)); + } + + /* add constraints */ + for (i = 0 ; clapi[i].name != NULL ; i++) { + if (clapi[i].provides && clapi[i].provides[0]) + ck_assert_int_eq(0, afb_apiset_provide_class(a, clapi[i].name, clapi[i].provides)); + if (clapi[i].requires && clapi[i].requires[0]) + ck_assert_int_eq(0, afb_apiset_require_class(a, clapi[i].name, clapi[i].requires)); + if (clapi[i].apireq && clapi[i].apireq[0]) + ck_assert_int_eq(0, afb_apiset_require(a, clapi[i].name, clapi[i].apireq)); + } + + /* start all */ + ck_assert_int_eq(0, afb_apiset_start_all_services(a, 0)); + + afb_apiset_unref(a); +} +END_TEST + +/*********************************************************************/ + +static Suite *suite; +static TCase *tcase; + +void mksuite(const char *name) { suite = suite_create(name); } +void addtcase(const char *name) { tcase = tcase_create(name); suite_add_tcase(suite, tcase); } +void addtest(TFun fun) { tcase_add_test(tcase, fun); } +int srun() +{ + int nerr; + SRunner *srunner = srunner_create(suite); + srunner_run_all(srunner, CK_NORMAL); + nerr = srunner_ntests_failed(srunner); + srunner_free(srunner); + return nerr; +} + +int main(int ac, char **av) +{ + mksuite("apiset"); + addtcase("apiset"); + addtest(check_initialisation); + addtest(check_sanity); + addtest(check_creation); + addtest(check_onlack); + addtest(check_settings); + addtest(check_classes); + return !!srun(); +} diff --git a/src/tests/apiv3/CMakeLists.txt b/src/tests/apiv3/CMakeLists.txt new file mode 100644 index 00000000..dfc44619 --- /dev/null +++ b/src/tests/apiv3/CMakeLists.txt @@ -0,0 +1,24 @@ +########################################################################### +# Copyright (C) 2018 "IoT.bzh" +# +# author: José Bollo <jose.bollo@iot.bzh> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +########################################################################### + +add_executable(test-apiv3 test-apiv3.c) +target_include_directories(test-apiv3 PRIVATE ../..) +target_link_libraries(test-apiv3 afb-lib ${link_libraries}) +add_test(NAME apiv3 COMMAND test-apiv3) + + diff --git a/src/tests/apiv3/test-apiv3.c b/src/tests/apiv3/test-apiv3.c new file mode 100644 index 00000000..dec1af97 --- /dev/null +++ b/src/tests/apiv3/test-apiv3.c @@ -0,0 +1,198 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> + +#include <check.h> + +#if !defined(ck_assert_ptr_null) +# define ck_assert_ptr_null(X) ck_assert_ptr_eq(X, NULL) +# define ck_assert_ptr_nonnull(X) ck_assert_ptr_ne(X, NULL) +#endif + +#define AFB_BINDING_VERSION 0 +#include <afb/afb-binding.h> +#include "afb-api.h" +#include "afb-apiset.h" +#include "afb-api-v3.h" + +struct inapis { + struct afb_binding_v3 desc; + struct afb_api_x3 *api; + int init; +}; + +struct inapis inapis[] = { + { .desc = { + .api = "ezra", + .provide_class = "e", + .require_class = "c", + .require_api = "armel" + }}, + { .desc = { + .api = "clara", + .provide_class = "c", + .require_class = "a" + }}, + { .desc = { + .api = "amelie", + .provide_class = "a", + .require_api = "albert armel" + }}, + { .desc = { + .api = "chloe", + .provide_class = "c a" + }}, + { .desc = { + .api = "albert", + .provide_class = "a" + }}, + { .desc = { + .api = "armel", + .provide_class = "a", + .require_api = "albert" + }}, + { .desc = { .api = NULL }} +}; + +int last_in_init; + +int in_init(struct afb_api_x3 *api) +{ + struct inapis *desc = api->userdata; + + ck_assert_str_eq(api->apiname, desc->desc.api); + ck_assert_int_eq(desc->init, 0); + + desc->init = ++last_in_init; + printf("init %d of %s\n", desc->init, api->apiname); + return 0; +} + +int in_preinit(void *closure, struct afb_api_x3 *api) +{ + int rc; + struct inapis *desc = closure; + + printf("default preinit of %s\n", api->apiname); + + ck_assert_ptr_nonnull(api); + ck_assert_ptr_nonnull(desc); + ck_assert_ptr_nonnull(api->apiname); + ck_assert_ptr_null(api->userdata); + ck_assert_str_eq(api->apiname, desc->desc.api); + ck_assert_ptr_null(desc->api); + ck_assert_int_eq(desc->init, 0); + + rc = afb_api_v3_set_binding_fields(&desc->desc, api); + ck_assert_int_eq(rc, 0); + + api->userdata = desc; + desc->api = api; + + if (desc->desc.preinit) + desc->desc.preinit(api); + + if (!desc->desc.init) { + rc = afb_api_x3_on_init(api, in_init); + ck_assert_int_eq(rc, 0); + } + + return 0; +} + +int out_init(struct afb_api_x3 *api) +{ + return 0; +} + +struct afb_apiset *apiset; +char out_apiname[] = "out"; +struct afb_api_v3 *out_v3; +struct afb_api_x3 *out_api; + +int out_preinit(void *closure, struct afb_api_x3 *api) +{ + int i; + int rc; + struct afb_api_x3 *napi; + + ck_assert_ptr_nonnull(api); + ck_assert_ptr_eq(closure, out_apiname); + ck_assert_ptr_null(api->userdata); + ck_assert_str_eq(api->apiname, out_apiname); + out_api = api; + + for (i = 0 ; inapis[i].desc.api ; i++) { + ck_assert_ptr_null(inapis[i].api); + napi = afb_api_x3_new_api( + api, + inapis[i].desc.api, + NULL, + 0, + in_preinit, + &inapis[i]); + ck_assert_ptr_nonnull(napi); + ck_assert_ptr_nonnull(inapis[i].api); + ck_assert_ptr_eq(inapis[i].api, napi); + } + + rc = afb_api_x3_on_init(api, out_init); + ck_assert_int_eq(rc, 0); + + return 0; +} + +START_TEST (test) +{ + int rc; + + apiset = afb_apiset_create("test-apiv3", 1); + ck_assert_ptr_nonnull(apiset); + + out_v3 = afb_api_v3_create( + apiset, + apiset, + out_apiname, + NULL, + 0, + out_preinit, + out_apiname, + 0 + ); + ck_assert_ptr_nonnull(out_v3); + ck_assert_ptr_nonnull(out_api); + + /* start all services */ + rc = afb_apiset_start_all_services(apiset, 1); + ck_assert_int_eq(rc, 0); +} +END_TEST + + +/*********************************************************************/ + +static Suite *suite; +static TCase *tcase; + +void mksuite(const char *name) { suite = suite_create(name); } +void addtcase(const char *name) { tcase = tcase_create(name); suite_add_tcase(suite, tcase); } +void addtest(TFun fun) { tcase_add_test(tcase, fun); } +int srun() +{ + int nerr; + SRunner *srunner = srunner_create(suite); + srunner_run_all(srunner, CK_NORMAL); + nerr = srunner_ntests_failed(srunner); + srunner_free(srunner); + return nerr; +} + +int main(int ac, char **av) +{ + mksuite("apiv3"); + addtcase("apiv3"); + addtest(test); + return !!srun(); +} diff --git a/src/tests/session/test-session.c b/src/tests/session/test-session.c index 58e57536..637b0a16 100644 --- a/src/tests/session/test-session.c +++ b/src/tests/session/test-session.c @@ -55,7 +55,7 @@ START_TEST (check_creation) ck_assert(afb_session_uuid(s) != NULL); ck_assert(afb_session_token(s) != NULL); ck_assert(!afb_session_is_closed(s)); - + /* token is the initial one */ ck_assert_str_eq(afb_session_token(s), GOOD_UUID); ck_assert(afb_session_check_token(s, GOOD_UUID)); diff --git a/src/verbose.c b/src/verbose.c index 3e266a18..5fd1940c 100644 --- a/src/verbose.c +++ b/src/verbose.c @@ -21,14 +21,44 @@ #include "verbose.h" -#if !defined(DEFAULT_VERBOSITY) -# define DEFAULT_VERBOSITY Verbosity_Level_Warning +#define MASKOF(x) (1 << (x)) + +#if !defined(DEFAULT_LOGLEVEL) +# define DEFAULT_LOGLEVEL Log_Level_Warning +#endif + +#if !defined(DEFAULT_LOGMASK) +# define DEFAULT_LOGMASK (MASKOF((DEFAULT_LOGLEVEL) + 1) - 1) +#endif + +#if !defined(MINIMAL_LOGLEVEL) +# define MINIMAL_LOGLEVEL Log_Level_Error #endif -int verbosity = 1; +#if !defined(MINIMAL_LOGMASK) +# define MINIMAL_LOGMASK (MASKOF((MINIMAL_LOGLEVEL) + 1) - 1) +#endif + +static const char *names[] = { + "emergency", + "alert", + "critical", + "error", + "warning", + "notice", + "info", + "debug" +}; + +static const char asort[] = { 1, 2, 7, 0, 3, 6, 5, 4 }; + +int logmask = DEFAULT_LOGMASK | MINIMAL_LOGMASK; + void (*verbose_observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args); -#define CROP_LOGLEVEL(x) ((x) < Log_Level_Emergency ? Log_Level_Emergency : (x) > Log_Level_Debug ? Log_Level_Debug : (x)) +#define CROP_LOGLEVEL(x) \ + ((x) < Log_Level_Emergency ? Log_Level_Emergency \ + : (x) > Log_Level_Debug ? Log_Level_Debug : (x)) #if defined(VERBOSE_WITH_SYSLOG) @@ -41,7 +71,7 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun if (file == NULL || vasprintf(&p, fmt, args) < 0) vsyslog(loglevel, fmt, args); else { - syslog(CROP_LOGLEVEL(loglevel), "%s [%s:%d, function]", p, file, line, function); + syslog(CROP_LOGLEVEL(loglevel), "%s [%s:%d, %s]", p, file, line, function?:"?"); free(p); } } @@ -115,14 +145,18 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun int saverr, n, rc; struct iovec iov[20]; + /* save errno */ saverr = errno; + /* check if tty (2) or not (1) */ if (!tty) tty = 1 + isatty(STDERR_FILENO); + /* prefix */ iov[0].iov_base = (void*)prefixes[CROP_LOGLEVEL(loglevel)] + (tty - 1 ? 4 : 0); iov[0].iov_len = strlen(iov[0].iov_base); + /* " " */ iov[1].iov_base = (void*)&chars[2]; iov[1].iov_len = 2; @@ -134,31 +168,40 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun if (rc < 0) rc = 0; else if ((size_t)rc > sizeof buffer) { + /* if too long, ellipsis the end with ... */ rc = (int)sizeof buffer; buffer[rc - 1] = buffer[rc - 2] = buffer[rc - 3] = '.'; } iov[n++].iov_len = (size_t)rc; } if (file && (!fmt || tty == 1 || loglevel <= Log_Level_Warning)) { + /* "[" (!fmt) or " [" (fmt) */ iov[n].iov_base = (void*)&chars[3 + !fmt]; iov[n++].iov_len = 2 - !fmt; + /* file */ iov[n].iov_base = (void*)file; iov[n++].iov_len = strlen(file); + /* ":" */ iov[n].iov_base = (void*)&chars[2]; iov[n++].iov_len = 1; if (line) { + /* line number */ iov[n].iov_base = lino; iov[n++].iov_len = snprintf(lino, sizeof lino, "%d", line); } else { + /* "?" */ iov[n].iov_base = (void*)&chars[1]; iov[n++].iov_len = 1; } + /* "," */ iov[n].iov_base = (void*)&chars[5]; iov[n++].iov_len = 1; if (function) { + /* function name */ iov[n].iov_base = (void*)function; iov[n++].iov_len = strlen(function); } else { + /* "?" */ iov[n].iov_base = (void*)&chars[1]; iov[n++].iov_len = 1; } @@ -166,16 +209,20 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun iov[n++].iov_len = 1; } if (n == 2) { + /* "?" */ iov[n].iov_base = (void*)&chars[1]; iov[n++].iov_len = 1; } + /* "\n" */ iov[n].iov_base = (void*)&chars[0]; iov[n++].iov_len = 1; + /* emit the message */ pthread_mutex_lock(&mutex); writev(STDERR_FILENO, iov, n); pthread_mutex_unlock(&mutex); + /* restore errno */ errno = saverr; } @@ -187,15 +234,6 @@ void verbose_set_name(const char *name, int authority) #endif -void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vverbose(loglevel, file, line, function, fmt, ap); - va_end(ap); -} - void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) { void (*observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) = verbose_observer; @@ -211,3 +249,89 @@ void vverbose(int loglevel, const char *file, int line, const char *function, co } } +void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vverbose(loglevel, file, line, function, fmt, ap); + va_end(ap); +} + +void set_logmask(int lvl) +{ + logmask = lvl | MINIMAL_LOGMASK; +} + +void verbose_add(int level) +{ + set_logmask(logmask | MASKOF(level)); +} + +void verbose_sub(int level) +{ + set_logmask(logmask & ~MASKOF(level)); +} + +void verbose_clear() +{ + set_logmask(0); +} + +void verbose_dec() +{ + verbosity_set(verbosity_get() - 1); +} + +void verbose_inc() +{ + verbosity_set(verbosity_get() + 1); +} + +int verbosity_to_mask(int verbo) +{ + int x = verbo + Log_Level_Error; + int l = CROP_LOGLEVEL(x); + return (1 << (l + 1)) - 1; +} + +int verbosity_from_mask(int mask) +{ + int v = 0; + while (mask > verbosity_to_mask(v)) + v++; + return v; +} + +void verbosity_set(int verbo) +{ + set_logmask(verbosity_to_mask(verbo)); +} + +int verbosity_get() +{ + return verbosity_from_mask(logmask); +} + +int verbose_level_of_name(const char *name) +{ + int c, i, r, l = 0, u = sizeof names / sizeof * names; + while (l < u) { + i = (l + u) >> 1; + r = (int)asort[i]; + c = strcasecmp(names[r], name); + if (!c) + return r; + if (c < 0) + l = i + 1; + else + u = i; + } + return -1; +} + +const char *verbose_name_of_level(int level) +{ + return level == CROP_LOGLEVEL(level) ? names[level] : NULL; +} + diff --git a/src/verbose.h b/src/verbose.h index 5cbe2aa6..bd36f97e 100644 --- a/src/verbose.h +++ b/src/verbose.h @@ -32,7 +32,6 @@ 3 : ERROR, WARNING, NOTICE, INFO greater than 3 : ERROR, WARNING, NOTICE, INFO, DEBUG -*/ extern int verbosity; enum verbosity_levels @@ -43,6 +42,7 @@ enum verbosity_levels Verbosity_Level_Info = 3, Verbosity_Level_Debug = 4 }; +*/ extern void verbose_set_name(const char *name, int authority); @@ -58,7 +58,7 @@ extern void verbose_set_name(const char *name, int authority); KERN_DEBUG 7 Debug-level messages */ -enum log_levels +enum { Log_Level_Emergency = 0, Log_Level_Alert = 1, @@ -70,27 +70,53 @@ enum log_levels Log_Level_Debug = 7 }; +extern int logmask; + extern void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf, 5, 6))); extern void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args); #if defined(VERBOSE_NO_DATA) -# define __VERBOSE__(lvl,...) do{if((lvl)<=Log_Level_Error) verbose(lvl, __FILE__, __LINE__, __func__, __VA_ARGS__)\ - else verbose(lvl, __FILE__, __LINE__, __func__, NULL);}while(0) +# define __VERBOSE__(lvl,...) do{if((lvl)<=Log_Level_Error) verbose(lvl, __FILE__, __LINE__, NULL, __VA_ARGS__)\ + else verbose(lvl, __FILE__, __LINE__, NULL, NULL);}while(0) #elif defined(VERBOSE_NO_DETAILS) # define __VERBOSE__(lvl,...) verbose(lvl, NULL, 0, NULL, __VA_ARGS__) #else # define __VERBOSE__(lvl,...) verbose(lvl, __FILE__, __LINE__, __func__, __VA_ARGS__) #endif -# define _VERBOSE_(vlvl,llvl,...) do{ if (verbosity >= vlvl) __VERBOSE__(llvl, __VA_ARGS__); } while(0) +#define _LOGMASK_(lvl) ((lvl) < 0 ? -1 : (1 << (lvl))) +#define _WANTLOG_(lvl) (logmask & _LOGMASK_(lvl)) +#define _VERBOSE_(lvl,...) do{ if (_WANTLOG_(lvl)) __VERBOSE__((lvl), __VA_ARGS__); } while(0) -# define ERROR(...) _VERBOSE_(Verbosity_Level_Error, Log_Level_Error, __VA_ARGS__) -# define WARNING(...) _VERBOSE_(Verbosity_Level_Warning, Log_Level_Warning, __VA_ARGS__) -# define NOTICE(...) _VERBOSE_(Verbosity_Level_Notice, Log_Level_Notice, __VA_ARGS__) -# define INFO(...) _VERBOSE_(Verbosity_Level_Info, Log_Level_Info, __VA_ARGS__) -# define DEBUG(...) _VERBOSE_(Verbosity_Level_Debug, Log_Level_Debug, __VA_ARGS__) +#define EMERGENCY(...) _VERBOSE_(Log_Level_Emergency, __VA_ARGS__) +#define ALERT(...) _VERBOSE_(Log_Level_Alert, __VA_ARGS__) +#define CRITICAL(...) _VERBOSE_(Log_Level_Critical, __VA_ARGS__) +#define ERROR(...) _VERBOSE_(Log_Level_Error, __VA_ARGS__) +#define WARNING(...) _VERBOSE_(Log_Level_Warning, __VA_ARGS__) +#define NOTICE(...) _VERBOSE_(Log_Level_Notice, __VA_ARGS__) +#define INFO(...) _VERBOSE_(Log_Level_Info, __VA_ARGS__) +#define DEBUG(...) _VERBOSE_(Log_Level_Debug, __VA_ARGS__) -# define LOGUSER(app) verbose_set_name(app,0) -# define LOGAUTH(app) verbose_set_name(app,1) +#define LOGUSER(app) verbose_set_name(app,0) +#define LOGAUTH(app) verbose_set_name(app,1) extern void (*verbose_observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args); + +static inline int verbose_wants(int lvl) { return _WANTLOG_(lvl); } + +extern void verbose_dec(); +extern void verbose_inc(); +extern void verbose_clear(); +extern void verbose_add(int level); +extern void verbose_sub(int level); + +extern int verbose_level_of_name(const char *name); +extern const char *verbose_name_of_level(int level); + +#define _DEVERBOSITY_(vlvl) ((vlvl) + Log_Level_Error) +#define _VERBOSITY_(llvl) ((llvl) - Log_Level_Error) +extern int verbosity_get(); +extern void verbosity_set(int verbo); +extern int verbosity_from_mask(int mask); +extern int verbosity_to_mask(int verbo); + diff --git a/src/wrap-json.c b/src/wrap-json.c index b139e7ad..e757c369 100644 --- a/src/wrap-json.c +++ b/src/wrap-json.c @@ -17,6 +17,7 @@ */ #include <string.h> +#include <limits.h> #include "wrap-json.h" @@ -528,7 +529,7 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i int64_t *pI = NULL; size_t *pz = NULL; uint8_t **py = NULL; - struct { struct json_object *parent; const char *acc; size_t index; size_t count; char type; } stack[STACKCOUNT], *top; + struct { struct json_object *parent; const char *acc; int index; int count; char type; } stack[STACKCOUNT], *top; struct json_object *obj; struct json_object **po; @@ -702,7 +703,7 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i if (!ignore) { if (!json_object_is_type(obj, json_type_array)) goto missfit; - top->count = json_object_array_length(obj); + top->count = (int)json_object_array_length(obj); } xacc[0] = ']'; acc = unpack_accept_arr; @@ -752,7 +753,7 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i if (key && key >= unpack_accept_any) { if (top->index >= top->count) goto out_of_range; - obj = json_object_array_get_idx(top->parent, (int)top->index++); + obj = json_object_array_get_idx(top->parent, top->index++); } } break; @@ -863,10 +864,10 @@ static void object_for_all(struct json_object *object, void (*callback)(void*,st static void array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure) { - size_t n = json_object_array_length(object); - size_t i = 0; + int n = (int)json_object_array_length(object); + int i = 0; while(i < n) - callback(closure, json_object_array_get_idx(object, (int)i++)); + callback(closure, json_object_array_get_idx(object, i++)); } void wrap_json_optarray_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure) @@ -906,16 +907,362 @@ void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct else if (!json_object_is_type(object, json_type_array)) callback(closure, object, NULL); else { - size_t n = json_object_array_length(object); - size_t i = 0; + int n = (int)json_object_array_length(object); + int i = 0; while(i < n) - callback(closure, json_object_array_get_idx(object, (int)i++), NULL); + callback(closure, json_object_array_get_idx(object, i++), NULL); } } +/** + * Clones the 'object' for the depth 'subdepth'. The object 'object' is + * duplicated and all its fields are cloned with the depth 'subdepth'. + * + * @param object the object to clone. MUST be an **object**. + * @param subdepth the depth to use when cloning the fields of the object. + * + * @return the cloned object. + */ +static struct json_object *clone_object(struct json_object *object, int subdepth) +{ + struct json_object *r = json_object_new_object(); + struct json_object_iterator it = json_object_iter_begin(object); + struct json_object_iterator end = json_object_iter_end(object); + while (!json_object_iter_equal(&it, &end)) { + json_object_object_add(r, + json_object_iter_peek_name(&it), + wrap_json_clone_depth(json_object_iter_peek_value(&it), subdepth)); + json_object_iter_next(&it); + } + return r; +} + +/** + * Clones the 'array' for the depth 'subdepth'. The array 'array' is + * duplicated and all its fields are cloned with the depth 'subdepth'. + * + * @param array the array to clone. MUST be an **array**. + * @param subdepth the depth to use when cloning the items of the array. + * + * @return the cloned array. + */ +static struct json_object *clone_array(struct json_object *array, int subdepth) +{ + int n = json_object_array_length(array); + struct json_object *r = json_object_new_array(); + while (n) { + n--; + json_object_array_put_idx(r, n, + wrap_json_clone_depth(json_object_array_get_idx(array, n), subdepth)); + } + return r; +} + +/** + * Clones any json 'item' for the depth 'depth'. The item is duplicated + * and if 'depth' is not zero, its contents is recursively cloned with + * the depth 'depth' - 1. + * + * Be aware that this implementation doesn't copies the primitive json + * items (numbers, nulls, booleans, strings) but instead increments their + * use count. This can cause issues with newer versions of libjson-c that + * now unfortunately allows to change their values. + * + * @param item the item to clone. Can be of any kind. + * @param depth the depth to use when cloning composites: object or arrays. + * + * @return the cloned array. + * + * @see wrap_json_clone + * @see wrap_json_clone_deep + */ +struct json_object *wrap_json_clone_depth(struct json_object *item, int depth) +{ + if (depth) { + switch (json_object_get_type(item)) { + case json_type_object: + return clone_object(item, depth - 1); + case json_type_array: + return clone_array(item, depth - 1); + default: + break; + } + } + return json_object_get(item); +} + +/** + * Clones the 'object': returns a copy of it. But doen't clones + * the content. Synonym of wrap_json_clone_depth(object, 1). + * + * @param object the object to clone + * + * @return a copy of the object. + * + * @see wrap_json_clone_depth + * @see wrap_json_clone_deep + */ +struct json_object *wrap_json_clone(struct json_object *object) +{ + return wrap_json_clone_depth(object, 1); +} + +/** + * Clones the 'object': returns a copy of it. Also clones all + * the content recursively. Synonym of wrap_json_clone_depth(object, INT_MAX). + * + * @param object the object to clone + * + * @return a copy of the object. + * + * @see wrap_json_clone_depth + * @see wrap_json_clone + */ +struct json_object *wrap_json_clone_deep(struct json_object *object) +{ + return wrap_json_clone_depth(object, INT_MAX); +} + +/** + * Adds the items of the object 'added' to the object 'dest'. + * + * @param dest the object to complete this object is modified + * @added the object containing fields to add + * + * @return the destination object 'dest' + * + * @example wrap_json_object_add({"a":"a"},{"X":"X"}) -> {"a":"a","X":"X"} + */ +struct json_object *wrap_json_object_add(struct json_object *dest, struct json_object *added) +{ + struct json_object_iterator it, end; + if (json_object_is_type(dest, json_type_object) && json_object_is_type(added, json_type_object)) { + it = json_object_iter_begin(added); + end = json_object_iter_end(added); + while (!json_object_iter_equal(&it, &end)) { + json_object_object_add(dest, + json_object_iter_peek_name(&it), + json_object_get(json_object_iter_peek_value(&it))); + json_object_iter_next(&it); + } + } + return dest; +} + +/** + * Sort the 'array' and returns it. Sorting is done accordingly to the + * order given by the function 'wrap_json_cmp'. If the paramater isn't + * an array, nothing is done and the parameter is returned unchanged. + * + * @param array the array to sort + * + * @returns the array sorted + */ +struct json_object *wrap_json_sort(struct json_object *array) +{ + if (json_object_is_type(array, json_type_array)) + json_object_array_sort(array, (int(*)(const void*, const void*))wrap_json_cmp); + + return array; +} + +/** + * Returns a json array of the sorted keys of 'object' or null if 'object' has no keys. + * + * @param object the object whose keys are to be returned + * + * @return either NULL is 'object' isn't an object or a sorted array of the key's strings. + */ +struct json_object *wrap_json_keys(struct json_object *object) +{ + struct json_object *r; + struct json_object_iterator it, end; + if (!json_object_is_type(object, json_type_object)) + r = NULL; + else { + r = json_object_new_array(); + it = json_object_iter_begin(object); + end = json_object_iter_end(object); + while (!json_object_iter_equal(&it, &end)) { + json_object_array_add(r, json_object_new_string(json_object_iter_peek_name(&it))); + json_object_iter_next(&it); + } + wrap_json_sort(r); + } + return r; +} + +/** + * Internal comparison of 'x' with 'y' + * + * @param x first object to compare + * @param y second object to compare + * @param inc boolean true if should test for inclusion of y in x + * @param sort boolean true if comparison used for sorting + * + * @return an integer indicating the computed result. Refer to + * the table below for meaning of the returned value. + * + * inc | sort | x < y | x == y | x > y | y in x + * ----+------+---------+----------+---------+--------- + * 0 | 0 | != 0 | 0 | != 0 | > 0 + * 0 | 1 | < 0 | 0 | > 0 | > 0 + * 1 | 0 | != 0 | 0 | != 0 | 0 + * 1 | 1 | < 0 | 0 | > 0 | 0 + * + * + * if 'x' is found, respectively, to be less than, to match, + * or be greater than 'y'. This is valid when 'sort' + */ +static int jcmp(struct json_object *x, struct json_object *y, int inc, int sort) +{ + double dx, dy; + int64_t ix, iy; + const char *sx, *sy; + enum json_type tx, ty; + int r, nx, ny, i; + struct json_object_iterator it, end; + struct json_object *jx, *jy; + + /* check equality of pointers */ + if (x == y) + return 0; + + /* get the types */ + tx = json_object_get_type(x); + ty = json_object_get_type(y); + r = (int)tx - (int)ty; + if (r) + return r; + + /* compare following the type */ + switch (tx) { + default: + case json_type_null: + break; + + case json_type_boolean: + r = (int)json_object_get_boolean(x) + - (int)json_object_get_boolean(y); + break; + + case json_type_double: + dx = json_object_get_double(x); + dy = json_object_get_double(y); + r = dx < dy ? -1 : dx > dy; + break; + + case json_type_int: + ix = json_object_get_int64(x); + iy = json_object_get_int64(y); + r = ix < iy ? -1 : ix > iy; + break; + + case json_type_object: + it = json_object_iter_begin(y); + end = json_object_iter_end(y); + nx = json_object_object_length(x); + ny = json_object_object_length(y); + r = nx - ny; + if (r > 0 && inc) + r = 0; + while (!r && !json_object_iter_equal(&it, &end)) { + if (json_object_object_get_ex(x, json_object_iter_peek_name(&it), &jx)) { + jy = json_object_iter_peek_value(&it); + json_object_iter_next(&it); + r = jcmp(jx, jy, inc, sort); + } else if (sort) { + jx = wrap_json_keys(x); + jy = wrap_json_keys(y); + r = wrap_json_cmp(jx, jy); + json_object_put(jx); + json_object_put(jy); + } else + r = 1; + } + break; + + case json_type_array: + nx = json_object_array_length(x); + ny = json_object_array_length(y); + r = nx - ny; + if (r > 0 && inc) + r = 0; + for (i = 0 ; !r && i < ny ; i++) { + jx = json_object_array_get_idx(x, i); + jy = json_object_array_get_idx(y, i); + r = jcmp(jx, jy, inc, sort); + } + break; + + case json_type_string: + sx = json_object_get_string(x); + sy = json_object_get_string(y); + r = strcmp(sx, sy); + break; + } + return r; +} + +/** + * Compares 'x' with 'y' + * + * @param x first object to compare + * @param y second object to compare + * + * @return an integer less than, equal to, or greater than zero + * if 'x' is found, respectively, to be less than, to match, + * or be greater than 'y'. + */ +int wrap_json_cmp(struct json_object *x, struct json_object *y) +{ + return jcmp(x, y, 0, 1); +} + +/** + * Searchs wether 'x' equals 'y' + * + * @param x first object to compare + * @param y second object to compare + * + * @return an integer equal to zero when 'x' != 'y' or 1 when 'x' == 'y'. + */ +int wrap_json_equal(struct json_object *x, struct json_object *y) +{ + return !jcmp(x, y, 0, 0); +} + +/** + * Searchs wether 'x' contains 'y' + * + * @param x first object to compare + * @param y second object to compare + * + * @return an integer equal to 1 when 'y' is a subset of 'x' or zero otherwise + */ +int wrap_json_contains(struct json_object *x, struct json_object *y) +{ + return !jcmp(x, y, 1, 0); +} + #if defined(WRAP_JSON_TEST) #include <stdio.h> +void tclone(struct json_object *object) +{ + struct json_object *o; + + o = wrap_json_clone(object); + if (!wrap_json_equal(object, o)) + printf("ERROR in clone or equal: %s VERSUS %s\n", json_object_to_json_string(object), json_object_to_json_string(o)); + json_object_put(o); + + o = wrap_json_clone_deep(object); + if (!wrap_json_equal(object, o)) + printf("ERROR in clone_deep or equal: %s VERSUS %s\n", json_object_to_json_string(object), json_object_to_json_string(o)); + json_object_put(o); +} + void p(const char *desc, ...) { int rc; @@ -929,6 +1276,7 @@ void p(const char *desc, ...) printf(" SUCCESS %s\n\n", json_object_to_json_string(result)); else printf(" ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc)); + tclone(result); json_object_put(result); } @@ -945,7 +1293,7 @@ void u(const char *value, const char *desc, ...) unsigned m, k; int rc; va_list args; - struct json_object *obj, *o; + struct json_object *object, *o; memset(xs, 0, sizeof xs); memset(xi, 0, sizeof xi); @@ -954,9 +1302,9 @@ void u(const char *value, const char *desc, ...) memset(xo, 0, sizeof xo); memset(xy, 0, sizeof xy); memset(xz, 0, sizeof xz); - obj = json_tokener_parse(value); + object = json_tokener_parse(value); va_start(args, desc); - rc = wrap_json_vunpack(obj, desc, args); + rc = wrap_json_vunpack(object, desc, args); va_end(args); if (rc) printf(" ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc)); @@ -996,7 +1344,30 @@ void u(const char *value, const char *desc, ...) va_end(args); printf("\n\n"); } - json_object_put(obj); + tclone(object); + json_object_put(object); +} + +void c(const char *sx, const char *sy, int e, int c) +{ + int re, rc; + struct json_object *jx, *jy; + + jx = json_tokener_parse(sx); + jy = json_tokener_parse(sy); + + re = wrap_json_cmp(jx, jy); + rc = wrap_json_contains(jx, jy); + + printf("compare(%s)(%s)\n", sx, sy); + printf(" -> %d / %d\n", re, rc); + + if (!re != !!e) + printf(" ERROR should be %s\n", e ? "equal" : "different"); + if (!rc != !c) + printf(" ERROR should %scontain\n", c ? "" : "not "); + + printf("\n"); } #define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0) @@ -1145,6 +1516,41 @@ int main() U("{\"foo\":\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"}", "{s?y}", "foo", &xy[0], &xz[0]); U("{\"foo\":\"\"}", "{s?y}", "foo", &xy[0], &xz[0]); U("{}", "{s?y}", "foo", &xy[0], &xz[0]); + + c("null", "null", 1, 1); + c("true", "true", 1, 1); + c("false", "false", 1, 1); + c("1", "1", 1, 1); + c("1.0", "1.0", 1, 1); + c("\"\"", "\"\"", 1, 1); + c("\"hi\"", "\"hi\"", 1, 1); + c("{}", "{}", 1, 1); + c("{\"a\":true,\"b\":false}", "{\"b\":false,\"a\":true}", 1, 1); + c("[]", "[]", 1, 1); + c("[1,true,null]", "[1,true,null]", 1, 1); + + c("null", "true", 0, 0); + c("null", "false", 0, 0); + c("0", "1", 0, 0); + c("1", "0", 0, 0); + c("0", "true", 0, 0); + c("0", "false", 0, 0); + c("0", "null", 0, 0); + + c("\"hi\"", "\"hello\"", 0, 0); + c("\"hello\"", "\"hi\"", 0, 0); + + c("{}", "null", 0, 0); + c("{}", "true", 0, 0); + c("{}", "1", 0, 0); + c("{}", "1.0", 0, 0); + c("{}", "[]", 0, 0); + c("{}", "\"x\"", 0, 0); + + c("[1,true,null]", "[1,true]", 0, 1); + c("{\"a\":true,\"b\":false}", "{\"a\":true}", 0, 1); + c("{\"a\":true,\"b\":false}", "{\"a\":true,\"c\":false}", 0, 0); + c("{\"a\":true,\"c\":false}", "{\"a\":true,\"b\":false}", 0, 0); return 0; } diff --git a/src/wrap-json.h b/src/wrap-json.h index 56f99198..d75ebc43 100644 --- a/src/wrap-json.h +++ b/src/wrap-json.h @@ -18,6 +18,10 @@ #pragma once +#ifdef __cplusplus + extern "C" { +#endif + #include <stdarg.h> #include <json-c/json.h> @@ -44,3 +48,18 @@ extern void wrap_json_object_for_all(struct json_object *object, void (*callback extern void wrap_json_optobject_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure); extern void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure); +extern struct json_object *wrap_json_clone(struct json_object *object); +extern struct json_object *wrap_json_clone_deep(struct json_object *object); +extern struct json_object *wrap_json_clone_depth(struct json_object *object, int depth); + +extern struct json_object *wrap_json_object_add(struct json_object *dest, struct json_object *added); + +extern struct json_object *wrap_json_sort(struct json_object *array); +extern struct json_object *wrap_json_keys(struct json_object *object); +extern int wrap_json_cmp(struct json_object *x, struct json_object *y); +extern int wrap_json_equal(struct json_object *x, struct json_object *y); +extern int wrap_json_contains(struct json_object *x, struct json_object *y); + +#ifdef __cplusplus + } +#endif diff --git a/test/monitoring/monitor.js b/test/monitoring/monitor.js index ec4821cc..1bdfcb43 100644 --- a/test/monitoring/monitor.js +++ b/test/monitoring/monitor.js @@ -454,12 +454,12 @@ function gottraceevent(obj) { x.className = x.className + " " + type; get(".time", x).textContent = data.time; get(".tag", x).textContent = ({ - request: function(r) { return r.api + "/" + r.verb + " [" + r.index + "] " + r.action; }, + request: function(r,d) { return r.api + "/" + r.verb + " [" + r.index + "] " + r.action + (r.action == 'reply' ? ' '+d.data.error : ''); }, service: function(r) { return r.api + "@" + r.action; }, daemon: function(r) { return r.api + ":" + r.action; }, event: function(r) { return r.name + "!" + r.action; }, global: function(r) { return "$" + r.action; }, - })[type](desc); + })[type](desc,data); var tab = makeobj(desc, 4); if ("data" in data) makeobjitem(tab, 2, "data", data.data); diff --git a/test/tic-tac-toe.html b/test/tic-tac-toe.html new file mode 100644 index 00000000..d9ea664c --- /dev/null +++ b/test/tic-tac-toe.html @@ -0,0 +1,87 @@ +<html> +<head> + <title>tic tac toe</title> + <style> + td { + border: 1px solid black; + width: 3em; + height: 3em; + font-weight: bolder; + text-align: center; + align-content: center; + } + .button { + border: 1px solid black; + border-radius: 5px; + } + .button:hover { + border-width: 2px; + font-weight: bolder; + } + </style> + <script type="text/javascript" src="AFB.js"></script> + <script type="text/javascript"> + var afb = new AFB("api", "HELLO"); + var ws; + + function $(x) { return document.getElementById(x); } + + + function replyok(obj) { + $("id").innerHTML = obj.response.boardid; + var i; + for (var i = 0 ; i < 9 ; i++) + $("cell-" + i).innerHTML = obj.response.board[i]; + } + function replyerr(obj) { + } + function gotevent(obj) { + ws.call("tictactoe/board").then(replyok, replyerr); + } + + function onopen() { + $("main").style.visibility = "visible"; + $("connected").innerHTML = "Connected to WebSocket server"; + ws.onevent("tictactoe/board", gotevent); + ws.call("tictactoe/new").then(gotevent, replyerr); + } + function onabort() { + $("main").style.visibility = "hidden"; + $("connected").innerHTML = "Connected Closed"; + } + + function init() { + ws = new afb.ws(onopen, onabort); + } + + </script> + +<body onload="init();"> + <h1>Tic Tac Toe</h1> + <div id="connected">Not Connected</div> + <div id="main" style="visibility:hidden"> + <div>board id <span id="id"></span></div> + <div> + <table> + <tr> + <td id="cell-0" onclick="javascript: ws.call('tictactoe/move',{'index':0})"> </td> + <td id="cell-1" onclick="javascript: ws.call('tictactoe/move',{'index':1})"> </td> + <td id="cell-2" onclick="javascript: ws.call('tictactoe/move',{'index':2})"> </td> + </tr> + <tr> + <td id="cell-3" onclick="javascript: ws.call('tictactoe/move',{'index':3})"> </td> + <td id="cell-4" onclick="javascript: ws.call('tictactoe/move',{'index':4})"> </td> + <td id="cell-5" onclick="javascript: ws.call('tictactoe/move',{'index':5})"> </td> + </tr> + <tr> + <td id="cell-6" onclick="javascript: ws.call('tictactoe/move',{'index':6})"> </td> + <td id="cell-7" onclick="javascript: ws.call('tictactoe/move',{'index':7})"> </td> + <td id="cell-8" onclick="javascript: ws.call('tictactoe/move',{'index':8})"> </td> + </tr> + </table> + </div> + <div><span class="button" id="play" onclick="javascript: ws.call('tictactoe/play')">play</span></div> + <div><span class="button" id="undo" onclick="javascript: ws.call('tictactoe/undo')">undo</span></div> + <div><span class="button" id="new" onclick="javascript: ws.call('tictactoe/new')">new</span></div> + </div> + |