From a22449d6bcc902aadd3d1f697888f3ed3e485f84 Mon Sep 17 00:00:00 2001 From: Shankho Boron Ghosh Date: Mon, 30 Nov 2020 02:46:36 +0530 Subject: Added Application Framework Binder in Developer Guides Revised and added Application Framework Binder as a part of Developer Guides. v2 : Corrected typo : MACRO -> MACROS Bug-AGL: [SPEC-3633] Signed-off-by: Shankho Boron Ghosh Change-Id: I7a6d6206f69ed44a18011c81f475ce5eac306a33 --- .../2_Application_Framework_Binder/0_Overview.md | 91 + .../1_Binder_daemon_vocabulary.md | 104 + .../2_How_to_write_a_binding.md | 444 ++++ .../3_Binder_References.md | 2524 ++++++++++++++++++++ .../4_Binder_events_guide.md | 291 +++ .../5_Binder_Application_writing_guide.md | 319 +++ .../7_Document_revisions.md | 17 + .../Annexes/1_Migration_to_bindings_v3.md | 199 ++ .../Annexes/2_WebSocket_protocol_x-afb-ws-json1.md | 308 +++ .../3_Installing_the_binder_on_a_desktop.md | 44 + .../Annexes/4_Options_of_afb-daemon.md | 355 +++ .../Annexes/5_Debugging_binder_and_bindings.md | 38 + .../Annexes/6_LEGACY_Migration_from_v1_to_v2.md | 656 +++++ .../Annexes/7_LEGACY_Binding_v2_references.md | 757 ++++++ .../pictures/basis.svg | 356 +++ .../pictures/interconnection.svg | 854 +++++++ .../pictures/signaling-basis.svg | 145 ++ 17 files changed, 7502 insertions(+) create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/0_Overview.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/1_Binder_daemon_vocabulary.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/2_How_to_write_a_binding.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/3_Binder_References.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/4_Binder_events_guide.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/5_Binder_Application_writing_guide.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/7_Document_revisions.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/1_Migration_to_bindings_v3.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/2_WebSocket_protocol_x-afb-ws-json1.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/3_Installing_the_binder_on_a_desktop.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/4_Options_of_afb-daemon.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/5_Debugging_binder_and_bindings.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/6_LEGACY_Migration_from_v1_to_v2.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/7_LEGACY_Binding_v2_references.md create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/basis.svg create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/interconnection.svg create mode 100644 docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/signaling-basis.svg diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/0_Overview.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/0_Overview.md new file mode 100644 index 0000000..1b2163c --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/0_Overview.md @@ -0,0 +1,91 @@ +--- +title: Overview +--- + +The ***binder*** provides the way to connect applications to +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 (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). + +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. +Within AGL, the connection between services and/or applications +is tuned by the AGL framework and the AGL system. + +## The basis of the binder + +The following figure shows main concepts linked to the ***binder***. + +![Figure: binder basis](pictures/basis.svg) + +The shown elements are: + +- The SECURITY CONTEXT + + The primary intention of any ***binder*** is to provide + a secured environment for any application. + On AGL, the **security context** is ensured by [Smack] + , the security context of the application or service. + +- The BINDER + + This is the central element. + It makes possible to run HTML5 applications and provides + the unified access to APIs provided by the ***bindings***. + + Running a pure HTML5 application doesn't require any ***binding***. + In that case , the ***binder*** acts as a simple HTTP server for + the web runtime. + +- The BINDINGs + + A ***binding*** adds one **API** to the ***binder***. + + An **API** is a set of **verbs** that can be called + using either REST over HTTP or a kind of JSON RPC. + + ***bindings*** are either: + + - dynamically loaded libraries in the ***binder*** process + - remote service running on the same host + - remote service running on other hosts + + When acting as an HTTP server, the binder treats the language + settings of the HTTP requests to provide internationalized + content as specified by + [widget + specifications](https://www.w3.org/TR/widgets/#internationalization-and-localization). + +- The APPLICATION + + An ***application*** connects to the binder to get access to + the **API** that it provides or to get its HTTP services to access + resources. + +## Interconnection of binders + +The AGL framework interprets the **widget/application** manifests +to setup the ***bindings*** configuration of the ***binders***. + +The figure below shows that ***binders*** are interconnected. + +![Figure: binder interconnection](pictures/interconnection.svg) + +The figure shows 4 several **application/service**: **A**, **B**, +**C** and **D**. + +The application **A** might use an **API** that is shown as a +local ***binding*** but that in reality runs within the context +of **D**. + +The framework AGL takes care of making the plumbing working. \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/1_Binder_daemon_vocabulary.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/1_Binder_daemon_vocabulary.md new file mode 100644 index 0000000..9839e65 --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/1_Binder_daemon_vocabulary.md @@ -0,0 +1,104 @@ +--- +title: Binder daemon vocabulary +--- + +## Binding + +A shared library object intended to add a functionality to an afb-daemon +instance. +It implements an API and may provide a service. + +Binding made for services can have specific entry points called after +initialization and before serving. + +## Event + +Messages with data propagated from the services to the client and not expecting +any reply. + +The current implementation allows to widely broadcast events to all clients. + +## Level of assurance (LOA) + +This level that can be from 0 to 3 represent the level of +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. + +## Request + +A request is an invocation by a client to a binding method using a message +transferred through some protocol: + +- HTTP +- WebSocket +- ... + +and served by ***afb-daemon*** + +## Reply/Response + +This is a message sent to client as the result of the request. + +## Service + +Service are made of bindings running on a binder +The binder is in charge of connecting services and applications. +A service can serve many clients. + +The framework establishes connection between the services and the clients. +Using sockets currently but other protocols are considered. + +The term of service is tightly bound to the notion of API. + +## Session + +A session is meant to be the unique instance context of a client, +which identify that instance across requests. + +Each session has an identifier. +Session identifier generated by afb-daemon are UUIDs. +A client can present its own session id. + +Internally, afb-daemon offers a mechanism to attach data to sessions. +When a session is closed or disappears, data attached to that session +are freed. + +## Token + +The token is an identifier that the client must give to be authenticated. + +At start, afb-daemon get an initial token. +This initial token must be presented by incoming client to be authenticated. + +A token is valid only for a period. + +The token must be renewed periodically. +When the token is renewed, afb-daemon sends the new token to the client. + +Tokens generated by afb-daemon are UUIDs. + +## UUID + +It stand for Universal Unique IDentifier. + +It is designed to create identifier in a way that avoid has much as possible +conflicts. +It means that if two different instances create an UUID, the +probability that they create the same UUID is very low, near to zero. + +## x-afb-reqid + +Argument name that can be used with HTTP request. +When this argument is given, it is automatically added to the "request" object of the answer. + +## x-afb-token + +Argument name meant to give the token without ambiguity. +You can also use the name **token** but it may conflicts with others arguments. + +## x-afb-uuid + +Argument name for giving explicitly the session identifier without ambiguity. +You can also use the name **uuid** but it may conflicts with others arguments. diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/2_How_to_write_a_binding.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/2_How_to_write_a_binding.md new file mode 100644 index 0000000..d739167 --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/2_How_to_write_a_binding.md @@ -0,0 +1,444 @@ +--- +title: How to write a binding? +--- + +# Overview of the bindings + +The ***binder*** serves files through HTTP protocol and offers developers the capability to offer application API methods through HTTP or +WebSocket protocol. + +The ***bindings*** are used to add **API** to ***binders***. +This part describes how to write a ***binding*** for ***binder*** +or in other words how to add a new **API** to the system. + +This section target developers. + +This section shortly explain how to write a binding +using the C programming language. + +It is convenient to install the ***binder*** on the +desktop used for writing the binding. +It allows for easy debug and test. + +## Nature of a binding + +A ***binding*** is an independent piece of software compiled as a shared +library and dynamically loaded by a ***binder***. +It is intended to provide one **API** (**A**pplication **P**rogramming +**I**nterface). + +The **API** is designated and accessed through its name. +It contains several **verbs** that implement the ***binding*** +functionalities. +Each of these **verbs** is a **method** that +processes requests of applications and sends results. + +The ***binding***'s methods are invoked by HTTP or websocket +requests. + +The **methods** of the ***bindings*** are noted **api/verb** +where **api** is the **API** name of the binding and **verb** is +the **method**'s name within the **API**. +This notation comes from HTTP invocations that rely on URL path terminated +with **api/verb**. + +The name of an **API** can be made of any characters except: + +- the control characters (\u0000 .. \u001f) +- the characters of the set { ' ', '"', '#', '%', '&', + '\'', '/', '?', '`', '\x7f' } + +The names of the **verbs** can be any character. + +The binder makes no distinctions between upper case and lower case +latin letters. +So **API/VERB** matches **Api/Verb** or **api/verb**. + +## 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 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 3. + +## Sample binding: tuto-1 + +This is the code of the binding **tuto-1.c**: + +```C + 1 #define AFB_BINDING_VERSION 3 + 2 #include + 3 + 4 void hello(afb_req_t req) + 5 { + 6 AFB_REQ_DEBUG(req, "hello world"); + 7 afb_req_reply(req, NULL, NULL, "hello world"); + 8 } + 9 + 10 const afb_verb_t verbs[] = { + 11 { .verb="hello", .callback=hello }, + 12 { .verb=NULL } + 13 }; + 14 + 15 const afb_binding_t afbBindingExport = { + 16 .api = "tuto-1", + 17 .verbs = verbs + 18 }; +``` + +Compiling: + +```bash +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 +$ curl http://localhost:3333/api/tuto-1/hello +{"jtype":"afb-reply","request":{"status":"success","info":"hello world","uuid":"1e587b54-900b-49ab-9940-46141bc2e1d6"}} +``` + +Testing using **afb-client-demo** (with option -H for +getting a human readable output): + +```bash +$ afb-client-demo -H ws://localhost:3333/api?token=x tuto-1 hello +ON-REPLY 1:tuto-1/hello: OK +{ + "jtype":"afb-reply", + "request":{ + "status":"success", + "info":"hello world", + "uuid":"03a84ad1-458a-4ace-af74-b1da917391b9" + } +} +``` + +This shows basic things: + +- The include to get for creating a binding +- How to declare the API offered by the binding +- How to handle requests made to the binding + +### Getting declarations for the binding + +The lines 1 and 2 show how to get the include file **afb-binding.h**. + +```C + 1 #define AFB_BINDING_VERSION 3 + 2 #include +``` + +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, 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 +/usr/include/afb directory that is the default). + +Setting the include path is easy using **pkg-config**: + +```bash +pkg-config --cflags-only-I afb-daemon +``` + +> 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**). + + +### Declaring the API of the binding + +Lines 10 to 18 show the declaration of the ***binding***. + +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_t verbs[] = { + 11 { .verb="hello", .callback=hello }, + 12 { .verb=NULL } + 13 }; + 14 + 15 const afb_binding_t afbBindingExport = { + 16 .api = "tuto-1", + 17 .verbs = verbs + 18 }; +``` + +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 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**). + +### 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_t req) + 5 { + 6 AFB_REQ_DEBUG(req, "hello world"); + 7 afb_req_reply(req, NULL, NULL, "hello world"); + 8 } +``` + +When the ***binder*** receives a request for the verb **hello** of +of the api **tuto-1**, it invoke the callback **hello** of the **binding** +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. + +At the line 7, the callback for **tuto-1/hello** replies to the request **req**. +Parameters of the reply are: + + 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. + +The 3 last parameters are sent back to the client as the reply content. + + + +## Sample binding: tuto-2 + +The second tutorial shows many important feature that can +commonly be used when writing a ***binding***: + +- initialization, getting arguments, sending replies, pushing events. + +This is the code of the binding **tuto-2.c**: + +```C + 1 #include + 2 #include + 3 + 4 #define AFB_BINDING_VERSION 3 + 5 #include + 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 + 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_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_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_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_reply(req, NULL, NULL, NULL); + 31 afb_event_push(event_login, json_object_new_string(usr)); + 32 } + 33 } + 34 + 35 void action(afb_req_t req) + 36 { + 37 json_object *args, *val; + 38 char *usr; + 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)); + 43 if (json_object_object_get_ex(args, "subscribe", &val)) { + 44 if (json_object_get_boolean(val)) { + 45 AFB_REQ_NOTICE(req, "user %s subscribes to events", usr); + 46 afb_req_subscribe(req, event_login); + 47 afb_req_subscribe(req, event_logout); + 48 } else { + 49 AFB_REQ_NOTICE(req, "user %s unsubscribes to events", usr); + 50 afb_req_unsubscribe(req, event_login); + 51 afb_req_unsubscribe(req, event_logout); + 52 } + 53 } + 54 afb_req_reply(req, json_object_get(args), NULL, NULL); + 55 } + 56 + 57 void logout(afb_req_t req) + 58 { + 59 char *usr; + 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_reply(req, NULL, NULL, NULL); + 67 } + 68 + 69 int preinit(afb_api_t api) + 70 { + 71 AFB_API_NOTICE(api, "preinit"); + 72 return 0; + 73 } + 74 + 75 int init(afb_api_t api) + 76 { + 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_API_ERROR(api, "Can't create events"); + 83 return -1; + 84 } + 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_t afbBindingExport = { + 94 .api = "tuto-2", + 95 .specification = NULL, + 96 .verbs = verbs, + 97 .preinit = preinit, + 98 .init = init, + 99 .noconcurrency = 0 + 100 }; +``` + +Compiling: + +```bash +gcc -fPIC -shared tuto-2.c -o tuto-2.so $(pkg-config --cflags --libs afb-daemon) +``` + +Running: + +```bash +afb-daemon --binding ./tuto-2.so --port 3333 --token '' +``` + +Testing: + +```bash +$ afb-client-demo -H localhost:3333/api?token=toto +tuto-2 login {"help":true} +ON-REPLY 1:tuto-2/login: ERROR +{ + "jtype":"afb-reply", + "request":{ + "status":"bad-request", + "uuid":"e2b24a13-fc43-487e-a5f4-9266dd1e60a9" + } +} +tuto-2 login {"user":"jose","password":"please"} +ON-REPLY 2:tuto-2/login: OK +{ + "jtype":"afb-reply", + "request":{ + "status":"success" + } +} +tuto-2 login {"user":"jobol","password":"please"} +ON-REPLY 3:tuto-2/login: ERROR +{ + "jtype":"afb-reply", + "request":{ + "status":"bad-state" + } +} +tuto-2 action {"subscribe":true} +ON-REPLY 4:tuto-2/action: OK +{ + "response":{ + "subscribe":true + }, + "jtype":"afb-reply", + "request":{ + "status":"success" + } +} +``` + +In another terminal: + +```bash +$ afb-client-demo -H localhost:3333/api?token=toto +tuto-2 login {"user":"jobol","password":"please"} +ON-REPLY 1:tuto-2/login: OK +{ + "jtype":"afb-reply", + "request":{ + "status":"success", + "uuid":"a09f55ff-0e89-4f4e-8415-c6e0e7f439be" + } +} +tuto-2 logout true +ON-REPLY 2:tuto-2/logout: OK +{ + "jtype":"afb-reply", + "request":{ + "status":"success" + } +} +``` + +It produced in the first terminal: + +```bash +ON-EVENT tuto-2/login: +{ + "event":"tuto-2\/login", + "data":"jobol", + "jtype":"afb-event" +} +ON-EVENT tuto-2/logout: +{ + "event":"tuto-2\/logout", + "data":"jobol", + "jtype":"afb-event" +} +``` diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/3_Binder_References.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/3_Binder_References.md new file mode 100644 index 0000000..fab571b --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/3_Binder_References.md @@ -0,0 +1,2524 @@ +--- +title: Binder References +--- + +i. TYPES AND GLOBALS +====================== + +## The global afbBindingRoot + +The global **afbBindingRoot** of type **afb_api_t** is always implicitly +defined for bindings of version 3 or upper. It records the root api of +the binding. + +When the binding has a defined **afbBindingExport**, the root api +**afbBindingRoot** is the **afb_pi_t** relative to the api created for +this static description. + +When the binding has no defined **afbBindingExport**, the root api is +a virtual api representing the shared object of the binding. In that case +the name of the api is the path of the shared object. Its use is restricted +but allows log messages. + +## The global afbBindingExport + +The global **afbBindingExport** is not mandatory. + +If **afbBindingExport** is defined and exported, it must be of the type +**const afb_binding_t** and must describe the *root* api of the binding. + +## The type afb_api_t + +Bindings now can declare more than one api. The counter part is that +a new handle is needed to manage apis. These handles are of the type +**afb_api_t**. + +It is defined as below. + +```C +typedef struct afb_api_x3 afb_api_t; +``` + +## The type afb_binding_t + +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 +typedef struct afb_binding_v3 afb_binding_t; +``` + +Where: + +```C +/** + * 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; +}; +``` + +## The type afb_verb_t + +Each verb is described with a structure of type **afb_verb_t** +defined below: + +```C +typedef struct afb_verb_v3 afb_verb_t; +``` + +```C +/** + * 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)(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; +}; +``` + +The **session** flags is one of the constant defined below: + +| Name | Description +|:----------------------:|------------------------------------------------------ +| AFB_SESSION_NONE | no flag, synonym to 0 +| AFB_SESSION_LOA_0 | Requires the LOA to be 0 or more, synonym to 0 or AFB_SESSION_NONE +| AFB_SESSION_LOA_1 | Requires the LOA to be 1 or more +| AFB_SESSION_LOA_2 | Requires the LOA to be 2 or more +| 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 closing the session after request processed + +The LOA (Level Of Assurance) is set, by binding api, using the function **afb_req_session_set_LOA**. + +The session can be closed, by binding api, using the function **afb_req_session_close**. + +## The types 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 +{ + /** 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 +typedef enum afb_auth_type afb_auth_type_t; + +/** + * Enumeration for authority (Session/Token/Assurance) definitions. + * + * @see afb_auth + */ +enum afb_auth_type +{ + /** never authorized, no data */ + afb_auth_No = 0, + + /** authorized if token valid, no data */ + afb_auth_Token, + + /** authorized if LOA greater than or equal to 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 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] } +}; +``` + + +## The type afb_req_subcall_flags_t + +This is an enumeration that defines bit's positions for setting behaviour +of subcalls. + +| flag | value | description +|----------------------------|-------|-------------- +| afb_req_subcall_catch_events | 1 | the calling API wants to receive the events from subscription +| afb_req_subcall_pass_events | 2 | the original request will receive the events from subscription +| afb_req_subcall_on_behalf | 4 | the calling API wants to use the credentials of the original request +| afb_req_subcall_api_session | 8 | the calling API wants to use its session instead of the one of the original request + +ii. MACROS FOR LOGGING +================= + +The final behaviour of macros can be tuned using 2 defines that must be defined +before including ****. + +| define | action +|---------------------------------------|-------------------- +| AFB_BINDING_PRAGMA_NO_VERBOSE_DATA | show file and line, remove function and text message +| AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS | show text, remove function, line and file + +## Logging for an api + +The following macros must be used for logging for an **api** of type +**afb_api_t**. + +```C +AFB_API_ERROR(api,fmt,...) +AFB_API_WARNING(api,fmt,...) +AFB_API_NOTICE(api,fmt,...) +AFB_API_INFO(api,fmt,...) +AFB_API_DEBUG(api,fmt,...) +``` + +## Logging for a request + + +The following macros can be used for logging in the context +of a request **req** of type **afb_req_t**: + +```C +AFB_REQ_ERROR(req,fmt,...) +AFB_REQ_WARNING(req,fmt,...) +AFB_REQ_NOTICE(req,fmt,...) +AFB_REQ_INFO(req,fmt,...) +AFB_REQ_DEBUG(req,fmt,...) +``` + +By default, the logging macros add file, line and function +indication. + +## Logging legacy + +The following macros are provided for legacy. + +```C +AFB_ERROR(fmt,...) +AFB_WARNING(fmt,...) +AFB_NOTICE(fmt,...) +AFB_INFO(fmt,...) +AFB_DEBUG(fmt,...) +``` + +iii. FUNCTIONS OF CLASS **afb_api** +============================ + +## General functions + +### afb_api_name + +```C +/** + * 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. + */ +const char *afb_api_name( + afb_api_t api); +``` + +### afb_api_get_userdata + +```C +/** + * 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_set_userdata + */ +void *afb_api_get_userdata( + afb_api_t api); +``` + +### afb_api_set_userdata + +```C +/** + * 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_get_userdata + */ +void afb_api_set_userdata( + afb_api_t api, + void *value); +``` + +### afb_api_require_api + +```C +/** + * Check that it requires the API of 'name'. + * If 'initialized' is not zero it requests the API to be + * initialized, implying its initialization if needed. + * + * 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 required api names + * @param initialized if zero, the api is just required to exist. If not zero, + * the api is required to exist and to be initialized at return of the call + * (initializing it if needed and possible as a side effect of the call). + * + * @return 0 in case of success or -1 in case of error with errno set appropriately. + */ +int afb_api_require_api( + afb_api_t api, + const char *name, + int initialized); +``` + + +## Verbosity functions + +### afb_api_wants_log_level + +```C +/** + * 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 + */ +int afb_api_wants_log_level( + afb_api_t api, + int level); +``` + +### afb_api_vverbose + +```C +/** + * Send to the journal with the logging 'level' a message described + * by 'fmt' applied to the va-list 'args'. + * + * 'file', 'line' and 'func' are indicators of code position 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 + */ +void afb_api_vverbose( + afb_api_t api, + int level, + const char *file, + int line, + const char *func, + const char *fmt, + va_list args); +``` + +### afb_api_verbose + +```C +/** + * 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 + */ +void afb_api_verbose( + afb_api_t api, + int level, + const char *file, + int line, + const char *func, + const char *fmt, + ...); +``` + +## Data retrieval functions + +### afb_api_rootdir_get_fd + +```C +/** + * Get the root directory file descriptor. This file descriptor can + * be used with functions 'openat', 'fstatat', ... + * + * CAUTION, manipulate this descriptor with care, in particular, don't close + * it. + * + * This can be used to get the path of the root directory using: + * + * char buffer[MAX_PATH], proc[100]; + * int dirfd = afb_api_rootdir_get_fd(api); + * snprintf(proc, sizeof proc, "/proc/self/fd/%d", dirfd); + * readlink(proc, 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_rootdir_open_locale + */ +int afb_api_rootdir_get_fd( + afb_api_t api); +``` + +### afb_api_rootdir_open_locale + +```C +/** + * 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_rootdir_get_fd + */ +int afb_api_rootdir_open_locale( + afb_api_t api, + const char *filename, + int flags, + const char *locale); +``` + +### afb_api_settings + +```C +/** + * Settings of the api. + * + * Get the settings of the API. The settings are recorded + * as a JSON object. The returned object should not be modified. + * It MUST NOT be released using json_object_put. + * + * @param api the api whose settings are required + * + * @returns The setting object. + */ +struct json_object *afb_api_settings( + struct afb_api_x3 *api); +``` + +## Calls and job functions + +### afb_api_call + +```C +/** + * Calls the 'verb' of the 'apiname' with the arguments 'args' and 'verb' in the name of the binding 'api'. + * 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 + * + * NOTE: For convenience, *json_object_put* is called on 'object' after the + * callback returns. So, it is wrong to call *json_object_put* in the callback. + * + * @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_call_sync + */ +void afb_api_call( + afb_api_t 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, + afb_api_t api), + void *closure); +``` + +### afb_api_call_sync + +```C +/** + * Calls the 'verb' of the 'apiname' with the arguments 'args' and 'verb' in the name of the binding 'api'. + * '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_call + */ +int afb_api_call_sync( + afb_api_t api, + const char *apiname, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info); +``` + +### afb_api_queue_job + +```C +/** + * 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 implementation of the job callback is: + * + * void my_job_cb(int signum, void *arg) + * { + * struct myarg_t *myarg = arg; + * if (signum) + * AFB_API_ERROR(myarg->api, "job interrupted 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. + */ +int afb_api_queue_job( + afb_api_t api, + void (*callback)(int signum, void *arg), + void *argument, + void *group, + int timeout); +``` + +## Event functions + +### afb_api_broadcast_event + +```C +/** + * 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 0 in case of success or -1 in case of error + */ +int afb_api_broadcast_event( + afb_api_t api, + const char *name, + struct json_object *object); +``` + +### afb_api_make_event + +```C +/** + * 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 + */ +afb_event_t afb_api_make_event( + afb_api_t api, + const char *name); +``` + +### afb_api_event_handler_add + +```C +/** + * 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_on_event + * @see afb_api_event_handler_del + */ +int afb_api_event_handler_add( + afb_api_t api, + const char *pattern, + void (*callback)( + void *, + const char*, + struct json_object*, + afb_api_t), + void *closure); +``` + +### afb_api_event_handler_del + +```C +/** + * 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_on_event + * @see afb_api_event_handler_add + */ +int afb_api_event_handler_del( + afb_api_t api, + const char *pattern, + void **closure); + +``` + +## Systemd functions + +### afb_api_get_event_loop + +```C +/** + * 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_get_user_bus + * @see afb_api_get_system_bus + */ +struct sd_event *afb_api_get_event_loop( + afb_api_t api); +``` + +### afb_api_get_user_bus + +```C +/** + * 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_get_event_loop + * @see afb_api_get_system_bus + */ +struct sd_bus *afb_api_get_user_bus( + afb_api_t api); +``` + +### afb_api_get_system_bus + +```C +/** + * 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_get_event_loop + * @see afb_api_get_user_bus + */ +struct sd_bus *afb_api_get_system_bus( + afb_api_t api); +``` + + +## Dynamic api functions + +### afb_api_new_api + +```C +/** + * 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 preinit + * + * @return the created api in case of success or NULL on error + * + * @see afb_api_delete_api + */ +afb_api_t afb_api_new_api( + afb_api_t api, + const char *apiname, + const char *info, + int noconcurrency, + int (*preinit)(void*, afb_api_t ), + void *closure); +``` + +### afb_api_set_verbs_v2 + +```C +/** + * @deprecated use @ref afb_api_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_add_verb + * @see afb_api_set_verbs_v3 + */ +int afb_api_set_verbs_v2( + afb_api_t api, + const struct afb_verb_v2 *verbs); +``` + +### afb_api_set_verbs_v3 + +```C +/** + * 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_add_verb + * @see afb_api_del_verb + */ +int afb_api_set_verbs_v3( + afb_api_t api, + const struct afb_verb_v3 *verbs); +``` + +### afb_api_add_verb + +```C +/** + * 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_del_verb + * @see afb_api_set_verbs_v3 + * @see fnmatch for matching names using glob + */ +int afb_api_add_verb( + afb_api_t 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); +``` + +### afb_api_del_verb + +```C +/** + * 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_add_verb + */ +int afb_api_del_verb( + afb_api_t api, + const char *verb, + void **vcbdata); +``` + +### afb_api_on_event + +```C +/** + * 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_event_handler_add + * @see afb_api_event_handler_del + */ +int afb_api_on_event( + afb_api_t api, + void (*onevent)( + afb_api_t api, + const char *event, + struct json_object *object)); +``` + +### afb_api_on_init + +```C +/** + * 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 + */ +int afb_api_on_init( + afb_api_t api, + int (*oninit)(afb_api_t api)); +``` + +### afb_api_provide_class + +```C +/** + * 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_require_class + */ +int afb_api_provide_class( + afb_api_t api, + const char *name); +``` + +### afb_api_require_class + +```C +/** + * 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 required classes + * + * @returns 0 in case of success or a negative value in case of error. + * + * @see afb_api_provide_class + */ +int afb_api_require_class( + afb_api_t api, + const char *name); +``` + +### afb_api_seal + +```C +/** + * Seal the api. After a call to this function the api can not be modified + * anymore. + * + * @param api the api to be sealed + */ +void afb_api_seal( + afb_api_t api); +``` + +### afb_api_delete_api + +```C +/** + * 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_new_api + */ +int afb_api_delete_api( + afb_api_t api); +``` + +### afb_api_add_alias + +```C +/** + * 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. + */ +int afb_api_add_alias( + afb_api_t api, + const char *name, + const char *as_name); +``` + + +## Legacy functions + +The function for legacy calls are still provided for some time because +adaptation of existing code to the new call functions require a small amount +of work. + +### afb_api_call_legacy + +```C +/** + * @deprecated try to use @ref afb_api_call instead + * + * Calls the 'verb' of the 'apiname' 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' + */ +void afb_api_call_legacy( + afb_api_t api, + const char *apiname, + const char *verb, + struct json_object *args, + void (*callback)( + void *closure, + int status, + struct json_object *result, + afb_api_t api), + void *closure); +``` + +### afb_api_call_sync_legacy + +```C +/** + * @deprecated try to use @ref afb_api_call_sync instead + * + * Calls the 'verb' of the 'apiname' 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' + */ +int afb_api_call_sync_legacy( + afb_api_t api, + const char *apiname, + const char *verb, + struct json_object *args, + struct json_object **result); +``` + +iv. FUNCTIONS OF CLASS **afb_req** +============================ + +## General function + +### afb_req_is_valid + +```C +/** + * Checks whether the request 'req' is valid or not. + * + * @param req the request to check + * + * @return 0 if not valid or 1 if valid. + */ +int afb_req_is_valid( + afb_req_t req); +``` + +### afb_req_get_api + +```C +/** + * Retrieves the api that serves the request + * + * @param req the request whose serving api is queried + * + * @return the api serving the request + */ +afb_api_t afb_req_get_api( + afb_req_t req); +``` + +### afb_req_get_vcbdata + +```C +/** + * 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 + */ +void *afb_req_get_vcbdata( + afb_req_t req); +``` + +### afb_req_get_called_api + +```C +/** + * Retrieve the name of the called api. + * + * @param req the request + * + * @return the name of the called api + * + * @see afb_api_new_api + * @see afb_api_add_alias + */ +const char *afb_req_get_called_api( + afb_req_t req); +``` + +### afb_req_get_called_verb + +```C +/** + * Retrieve the name of the called verb + * + * @param req the request + * + * @return the name of the called verb + */ +const char *afb_req_get_called_verb( + afb_req_t req); +``` + +### afb_req_addref + +```C +/** + * Increments the count of references of 'req'. + * + * @param req the request + * + * @return returns the request req + */ +afb_req_t *afb_req_addref( + afb_req_t req); +``` + +### afb_req_unref + +```C +/** + * Decrement the count of references of 'req'. + * + * @param req the request + */ +void afb_req_unref( + afb_req_t req); +``` + + +## Logging functions + +### afb_req_wants_log_level + +```C +/** + * 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 + */ +int afb_req_wants_log_level( + afb_req_t req, + int level); +``` + +### afb_req_vverbose + +```C +/** + * Send associated to 'req' a message described by 'fmt' and its 'args' + * 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 args the arguments to the format + * + * @see printf + * @see afb_req_verbose + */ +void afb_req_vverbose( + afb_req_t req, + int level, const char *file, + int line, + const char * func, + const char *fmt, + va_list args); +``` + +### afb_req_verbose + +```C +/** + * 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 format 'fmt' + * + * @see printf + */ +void afb_req_verbose( + afb_req_t req, + int level, const char *file, + int line, + const char * func, + const char *fmt, + ...); +``` + +## Arguments/parameters function + +### afb_req_get + +```C +/** + * 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_value + * @see afb_req_path + */ +struct afb_arg afb_req_get( + afb_req_t req, + const char *name); +``` + +### afb_req_value + +```C +/** + * 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 + * + * @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_get + * @see afb_req_path + */ +const char *afb_req_value( + afb_req_t req, + const char *name); +``` + +### afb_req_path + +```C +/** + * 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 + * + * @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_get + * @see afb_req_value + */ +const char *afb_req_path( + afb_req_t req, + const char *name); +``` + +### afb_req_json + +```C +/** + * 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_get + * @see afb_req_value + * @see afb_req_path + */ +struct json_object *afb_req_json( + afb_req_t req); +``` + +## Reply functions + +The functions **success** and **fail** are still supported. +These functions are now implemented as the following macros: + +```C +#define afb_req_success(r,o,i) afb_req_reply(r,o,NULL,i) +#define afb_req_success_f(r,o,...) afb_req_reply_f(r,o,NULL,__VA_ARGS__) +#define afb_req_success_v(r,o,f,v) afb_req_reply_v(r,o,NULL,f,v) +#define afb_req_fail(r,e,i) afb_req_reply(r,NULL,e,i) +#define afb_req_fail_f(r,e,...) afb_req_reply_f(r,NULL,e,__VA_ARGS__) +#define afb_req_fail_v(r,e,f,v) afb_req_reply_v(r,NULL,e,f,v) +``` + + +### afb_req_reply + +```C +/** + * 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_reply_v + * @see afb_req_reply_f + */ +void afb_req_reply( + afb_req_t req, + struct json_object *obj, + const char *error, + const char *info); +``` + +### afb_req_reply_v + +```C +/** + * Same as 'afb_req_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_reply + * @see afb_req_reply_f + * @see vprintf + */ +void afb_req_reply_v( + afb_req_t req, + struct json_object *obj, + const char *error, + const char *info, + va_list args); +``` + +### afb_req_reply_f + +```C +/** + * Same as 'afb_req_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_reply + * @see afb_req_reply_v + * @see printf + */ +void afb_req_reply_f( + afb_req_t req, + struct json_object *obj, + const char *error, + const char *info, + ...); +``` + +## Subcall functions + + + +### afb_req_subcall + +```C +/** + * 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 + * + * NOTE: For convenience, *json_object_put* is called on 'object' after the + * callback returns. So, it is wrong to call *json_object_put* in the callback. + * + * @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_subcall_flags_t + * @param callback The to call on completion + * @param closure The closure to pass to the callback + * + * The flags are any combination of the following values: + * + * - afb_req_x2_subcall_catch_events = 1 + * + * the calling API wants to receive the events from subscription + * + * - afb_req_x2_subcall_pass_events = 2 + * + * the original request will receive the events from subscription + * + * - afb_req_x2_subcall_on_behalf = 4 + * + * the calling API wants to use the credentials of the original request + * + * - afb_req_x2_subcall_api_session = 8 + * + * the calling API wants to use its session instead of the one of the + * original request + * + * @see also 'afb_req_subcall_sync' + */ +void afb_req_subcall( + afb_req_t 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, + afb_req_t req), + void *closure); +``` + +### afb_req_subcall_sync + +```C +/** + * 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_subcall_req' that is convenient to keep request alive automatically. + * - 'afb_req_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_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 + */ +int afb_req_subcall_sync( + afb_req_t req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info); +``` + +## Event functions + +### afb_req_subscribe + +```C +/** + * Establishes for the client link identified by 'req' a subscription + * to the 'event'. + * + * Establishing subscription MUST be called BEFORE replying to the request. + * + * @param req the request + * @param event the event to subscribe + * + * @return 0 in case of successful subscription or -1 in case of error. + */ +int afb_req_subscribe( + afb_req_t req, + afb_event_t event); +``` + +### afb_req_unsubscribe + +```C +/** + * 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. + * + * Revoking subscription MUST be called BEFORE replying to the request. + * + * @param req the request + * @param event the event to revoke + * + * @return 0 in case of successful subscription or -1 in case of error. + */ +int afb_req_unsubscribe( + afb_req_t req, + afb_event_t event); +``` + +## Session functions + +### afb_req_context + +```C +/** + * 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 + */ +void *afb_req_context( + afb_req_t req, + int replace, + void *(*create_context)(void *closure), + void (*free_context)(void*), + void *closure); +``` + +### afb_req_context_get + +```C +/** + * 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_context(req, 0, NULL, NULL, NULL) + * + * @param req the request + * + * @return the previously stored value + */ +void *afb_req_context_get( + afb_req_t req); +``` + +### afb_req_context_set + +```C +/** + * 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_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) + */ +void afb_req_context_set( + afb_req_t req, + void *context, + void (*free_context)(void*)); +``` + +### afb_req_context_clear + +```C +/** + * 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) + * + * @param req the request + */ +void afb_req_context_clear( + afb_req_t req); +``` + +### afb_req_session_close + +```C +/** + * Closes the session associated with 'req' + * and delete all associated contexts. + * + * @param req the request + */ +void afb_req_session_close( + afb_req_t req); +``` + +### afb_req_session_set_LOA + +```C +/** + * 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. + */ +int afb_req_session_set_LOA( + afb_req_t req, + unsigned level); +``` + +## Credential/client functions + +### afb_req_has_permission + +```C +/** + * 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. + */ +int afb_req_has_permission( + afb_req_t req, + const char *permission); +``` + +### afb_req_get_application_id + +```C +/** + * 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 + */ +char *afb_req_get_application_id( + afb_req_t req); +``` + +### afb_req_get_uid + +```C +/** + * 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. + * + */ +int afb_req_get_uid( + afb_req_t req); +``` + +### afb_req_get_client_info + +```C +/** + * 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 + */ +struct json_object *afb_req_get_client_info( + afb_req_t req); +``` + +## Legacy functions + +### afb_req_subcall_legacy + +```C +/** + * @deprecated use @ref afb_req_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_subcall + * @see afb_req_subcall_sync + */ +void afb_req_subcall_legacy( + 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); +``` + +### afb_req_subcall_sync_legacy + +```C +/** + * @deprecated use @ref afb_req_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 until 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_subcall + * @see afb_req_subcall_sync + */ +int afb_req_subcall_sync_legacy( + afb_req_t req, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); +``` + +v. FUNCTIONS OF CLASS **afb_event** +============================== + +## General functions + +### afb_event_is_valid + +```C +/** + * Checks whether the 'event' is valid or not. + * + * @param event the event to check + * + * @return 0 if not valid or 1 if valid. + */ +int afb_event_is_valid( + afb_event_t event); +``` + +### afb_event_name + +```C +/** + * 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_unref'. + * It shouldn't be freed. + */ +const char *afb_event_name( + afb_event_t event); +``` + +### afb_event_unref + +```C +/** + * 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 + */ +void afb_event_unref( + afb_event_t event); +``` + +### afb_event_addref + +```C +/** + * Increases the count of references to 'event' + * + * @param event the event + * + * @return the event + */ +afb_event_t *afb_event_addref( + afb_event_t event); +``` + +## Pushing functions + +### afb_event_broadcast + +```C +/** + * 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 0 in case of success or -1 in case of error + */ +int afb_event_broadcast( + afb_event_t event, + struct json_object *object); +``` + +### afb_event_push + +```C +/** + * 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 + * * 1 if at least one client listen for the event + * * 0 if no more client listen for the event + * * -1 in case of error (the event can't be delivered) + */ +int afb_event_push( + afb_event_t event, + struct json_object *object); +``` + +vi. FUNCTIONS OF CLASS **afb_daemon** +============================ + +All the functions of the class **afb_daemon** use the default api. +This are internally aliased to the corresponding function of class afb_api_t. + +```C +/** + * 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 + */ +struct sd_bus *afb_daemon_get_user_bus(); + +/** + * Retrieves the common systemd's system d-bus of AFB + */ +struct sd_bus *afb_daemon_get_system_bus(); + +/** + * 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. + */ +int afb_daemon_broadcast_event( + const char *name, + struct json_object *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. + */ +afb_event_t afb_daemon_make_event( + const char *name); + +/** + * @deprecated use bindings version 3 + * + * 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 + */ +void afb_daemon_verbose( + int level, + const char *file, + int line, + const char * func, + const char *fmt, + ...); + +/** + * @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. + */ +int afb_daemon_rootdir_get_fd(); + +/** + * 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. + */ +int afb_daemon_rootdir_open_locale( + const char *filename, + int flags, + const char *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. + */ +int afb_daemon_queue_job( + void (*callback)(int signum, void *arg), + void *argument, + void *group, + int 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. + */ +int afb_daemon_require_api( + const char *name, + int initialized); + +/** + * 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. + */ +int afb_daemon_add_alias(const char *name, const char *as_name); + +/** + * Creates a new api of name 'api' with brief 'info'. + * + * Returns 0 in case of success or -1 in case of error. + */ +int afb_daemon_new_api( + const char *api, + const char *info, + int noconcurrency, + int (*preinit)(void*, struct afb_api_x3 *), + void *closure); +``` + +vii. FUNCTIONS OF CLASS **afb_service** +============================== + +All the functions of the class **afb_service** use the default api. + +All these function are deprecated, try to use functions of class **afb_api** instead. + +## afb_service_call + +```C +/** + * @deprecated try to use @ref afb_api_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 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 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_call_sync + */ +void afb_service_call( + const char *api, + const char *verb, + struct json_object *args, + void (*callback)( + void *closure, + struct json_object *object, + const char *error, + const char * info, + afb_api_t api), + void *closure); +``` + +## afb_service_call_sync + +```C +/** + * @deprecated try to use @ref afb_api_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 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_call + */ +int afb_service_call_sync( + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info); +``` + +## afb_service_call_legacy + +```C +/** + * @deprecated try to use @ref afb_api_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 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' + */ +void afb_service_call_legacy( + const char *api, + const char *verb, + struct json_object *args, + void (*callback)( + void *closure, + int status, + struct json_object *result, + afb_api_t api), + void *closure); +``` + +## afb_service_call_sync_legacy + +```C +/** + * @deprecated try to use @ref afb_api_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 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' + */ +int afb_service_call_sync_legacy( + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); +``` \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/4_Binder_events_guide.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/4_Binder_events_guide.md new file mode 100644 index 0000000..0b91a23 --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/4_Binder_events_guide.md @@ -0,0 +1,291 @@ +--- +title: Binder events guide +--- + +Signaling agents are services that send events to any clients that +are subscribed to receive it. +The sent events carry any data. + +To have a good understanding of how to: + +- write a signaling agent. +- actions of subscribing. +- actions of unsubscribing. +- actions of producing. +- actions of sending and receiving. + +Events must be described and explained. + +## Overview of events + +The basis of a signaling agent is shown in the following figure: + +![scenario of using events](pictures/signaling-basis.svg) + +This figure shows the main role of the signaling framework for the events +propagation. + +For people not familiar with the framework, a signaling agent and +a “binding” are similar. + +### Subscribing and unsubscribing + +- Subscribing is the action that makes a client able to receive + data from a signaling agent. + +Subscription must : + +1. Create resources for generating the data. +2. Deliver the data to the client. + +These two aspects are not handled by the same piece of software. + +1. Generating the data is the responsibility of the developer of the signaling agent +2. Delivering the data is handled by the framework. + +When a client subscribes for data, the agent must: + +1. Check that the subscription request is correct. +2. Establish the computation chain of the required data (if not already done). +3. Create a named event for the computed data (if not already done). +4. Ask the framework to establish the subscription to the event for the request. +5. Optionally give indications about the event in the reply to the client. + +The first two steps do not involve the framework. +They are linked to the business logic of the binding. +The request can be any description of the requested data +and the computing stream can be of any nature, +this is specific to the binding. + +As said before, the framework uses and integrates **libsystemd** and its event +loop. +Within the framework, **libsystemd** is the standard API/library for +bindings expecting to setup and handle I/O, timer or signal events. + +Steps 3 and 4 are bound to the framework. + +The agent must create an object for handling the propagation of produced +data to its clients. +That object is called “event” in the framework. +An event has a name that allows clients to distinguish it from other +events. + +Events are created using the ***afb\_api\_make\_event*** function +that takes the api that creates the event and the name of the event. +Example: + +```C + event = afb_api_make_event(api, name); +``` + +Once created, the event can be used either to push data to its +subscribers or to broadcast data to any listener. + +The event must be used to establish the subscription for the requesting +client. +This is done using the ***afb\_req\_subscribe*** function +that takes the current request object and event and associates them +together. +Example: + +```C + rc = afb_req_subscribe(req, event); +``` + +When successful, this function make the connection between the event and +the client that emitted the request. +The client becomes a subscriber of the event until it unsubscribes or disconnects. +The ***afb\_req\_subscribe*** function will fail: + +- if the client connection is weak. +- if the request comes from a HTTP link. + +To receive signals, the client must be connected. + +The AGL framework allows connections using WebSocket. + +The name of the event is either a well known name or an ad hoc name +forged for the use case. + +Let's see a basic example: + +- client A expects to receive the speed in km/h every second. +- client B expects the speed in mph twice a second. + +In that case, there are two different events because it is not the same +unit and it is not the same frequency. +Having two different events allows to associate clients to the correct event. +But this doesn't tell any word about the name of these events. +The designer of the signaling agent has two options for naming: + +1. names can be the same (“speed” for example) with sent data + self describing itself or having a specific tag (requiring from + clients awareness about requesting both kinds of speed isn't safe). +2. names of the event include the variations (by example: + “speed-km/h-1Hz” and “speed-mph-2Hz”) and, in that case, sent data + can self describe itself or not. + +In both cases, the signaling agent might have to send the name of the +event and/or an associated tag to its client in the reply of the +subscription. +This is part of the step 5 above. + +The framework only uses the event (not its name) for: + +- subscription +- un-subscription +- pushing + +When the requested data is already generated and the event used for +pushing it already exists, the signaling agent must not instantiate a +new processing chain and must not create a new event object for pushing +data. +The signaling agent must reuse the existing chain and event. + +Unsubscribing is made by the signaling agent on a request of its client. +The ***afb\_req\_unsubscribe*** function tells the framework to +remove the requesting client from the event's list of subscribers. +Example: + +```C + afb_req_unsubscribe(req, event); +``` + +Subscription count does not matter to the framework: + +- Subscribing the same client several times has the same effect that subscribing only one time. + +Thus, when unsubscribing is invoked, it becomes immediately effective. + +#### More on naming events + +- Within the AGL framework, a signaling agent is a binding that has an API prefix. + +This prefix is meant to be unique and to identify the binding API. +The names of the events that this signaling agent creates are +automatically prefixed by the framework, using the API prefix of the +binding. + +Thus, if a signaling agent of API prefix ***api*** creates an event +of name ***event*** and pushes data to that event, the subscribers +will receive an event of name ***api/event***. + +### Generating and pushing signals and data + +- This of the responsibility of the designer of the signaling agent to establish the processing chain for generating events. + +In many cases, this can be achieved using I/O or timer or signal events inserted in the main loop. +For this case, the AGL framework uses **libsystemd** and +provide a way to integrates to the main loop of this library using +afb\_api\_get\_event\_loop. +Example: + +```C + sdev = afb_api_get_event_loop(api); + rc = sd_event_add_io(sdev, &source, fd, EPOLLIN, myfunction, NULL); +``` + +In some other cases, the events are coming from D-Bus. +In that case, the framework also uses **libsystemd** internally to access D-Bus. +It provides two methods to get the available D-Bus objects, already existing and +bound to the main **libsystemd** event loop. +Use either ***afb\_api\_get\_system\_bus*** or +***afb\_api\_get\_user\_bus*** to get the required instance. +Then use functions of **libsystemd** to handle D-Bus. + +In some rare cases, the generation of the data requires to start a new +thread. + +When a data is generated and ready to be pushed, the signaling agent +should call the function ***afb\_event\_push***. +Example: + +```C + rc = afb_event_push(event, JSON); + if (rc == 0) { + stop_generating(event); + afb_event_unref(event); + } +``` + +The function ***afb\_event\_push*** pushes json data to all the subscribers. +It then returns the count of subscribers. +When the count is zero, there is no subscriber listening for the event. +The example above shows that in that case, the signaling agent stops to +generate data for the event and tells that it doesn't use it anymore by calling +**afb\_event\_unref**. + +This is one possible option. +Other valuable options are: + +- do nothing and continue to generate and push the event. +- just stop to generate and push the data but keep the event existing. + +### Receiving the signals + +Understanding what a client expects when it receives signals, events or +data shall be the most important topic of the designer of a signaling +agent. +The good point here is that because JSON[^1] is the exchange +format, structured data can be sent in a flexible way. + +The good design is to allow as much as possible the client to describe +what is needed with the goal to optimize the processing to the +requirements only. + +### The exceptional case of wide broadcast + +Some data or events have so much importance that they can be widely +broadcasted to alert any listening client. +Examples of such an alert are: + +- system is entering/leaving “power safe” mode +- system is shutting down +- the car starts/stops moving +- ... + +An event can be broadcasted using one of the two following methods: + +- ***afb\_api\_broadcast\_event*** +- ***afb\_event\_broadcast*** + +Example 1: + +```C +afb_api_broadcast_event(api, name, json); +``` + +Example 2: + +```C +event = afb_api_make_event(api, name); +. . . . +afb_event_broadcast(event, json); +``` + +As for other events, the name of events broadcasted using +***afb\_api\_broadcast\_event*** are automatically prefixed by +the framework with API prefix. + +## Reference of functions + +See the [references for functions of class afb_event](3_Binder_References.md#v-FUNCTIONS-OF-CLASS-afb_event) + +### Function onevent (field of afbBindingExport) + +Binding can designate an event handling function using the field **onevent** +of the structure **afb_binding_t**. + +This function is called when an event is broadcasted or when an event that the +api subscribed to (through call or subcall mechanism) is pushed. +That behavior allows a service to react to an event and do what it is to do if +this is relevant for it. +(ie: car back camera detects imminent collision and broadcast it, then +appropriate service enable parking brake.). + +### Event handlers + +The apis functions allow to declare event handling callbacks. These callbacks are +called on reception of an event matching a pattern and a receive in more that +the event name and its companion JSON data, a user defiend closure and the api +that is used to create it. \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/5_Binder_Application_writing_guide.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/5_Binder_Application_writing_guide.md new file mode 100644 index 0000000..4886e5d --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/5_Binder_Application_writing_guide.md @@ -0,0 +1,319 @@ +--- +title: Binder Application writing guide +--- + +### Writing an HTML5 application + +Developers of HTML5 applications (client side) can easily create +applications for AGL framework using their preferred +HTML5 framework. + +Developers may also take advantage of powerful server side bindings to improve +application behavior. +Server side bindings return an application/json mine-type +and can be accessed though either HTTP or Websockets. + +In a near future, JSON-RPC protocol should be added to complete the current +x-afb-json1 protocol. + +Two examples of HTML5 applications are given: + +- [afb-client](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-demo.git;a=tree;f=afb-client) a simple "hello world" application template + +- [afm-client](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-demo.git;a=tree;f=afm-client) a simple "Home screen" application template + +### Writing a Qt application + +Writing Qt applications is also supported. +Qt offers standard API to send request through HTTP or WebSockets. + +It is also possible to write QML applications. +A sample QML application token-websock is available: + +- [token-websock](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=blob;f=test/token-websock.qml) + +A simple "hello world" application in QML + +### Writing a "C" application + +C applications can use afb-daemon binder through a websocket connection. + +The library **libafbwsc** is provided for C clients that need +to connect with an afb-daemon binder. + +The program **afb-client-demo** is the C example that uses the +**libafbwsc** library. +Source code is available here +[src/afb-client-demo.c](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=blob;f=src/afb-client-demo.c). + +Current implementation relies on libsystemd and file descriptors. +This model may be reviewed in the future to support secure sockets +and get rid of libsystemd dependency. + +### Handling sessions within applications + +Applications should understand sessions and token management when interacting +with afb-daemon binder. + +Applications communicate with their private binder (afb-daemon) using +a network connection or any other potential connection channel. +While the current version does not yet implement Unix socket, +this feature might be added in the near future. +Developers need to be warn that HTTP protocol is a none +connected protocol and that using HTTP socket connection to authenticate +clients is not supported. + +For this reason, the binder should authenticate the application +by using a shared secret. +The secret is named "token" and the identification of client is named "session.” + +The examples **token-websock.qml** and **afb-client** are demonstrating +how authentication and sessions are managed. + +### Handling sessions + +Bindings and other binder features need to keep track of client +instances. +This is especially important for bindings running as services +as they may typically have to keep each client's data separated. + +For HTML5 applications, the web runtime handles the cookie of the session +that the binder afb-daemon automatically sets. + +Session identifier can be set using the parameter **uuid** or **x-afb-uuid** in +URI requests. +Within current version of the framework session UUID is supported +by both HTTP requests and websocket negotiation. + +### Exchanging tokens + +At application start, AGL framework communicates a shared secret to both binder +and client application. +This initial secret is called the "**initial token**". + +For each of its client application, the binder manages a current active +token for session management. +This authentication token can be use to restrict the access to some binding's methods. + +The token must be included in URI request on HTTP or during websockets +connection using parameter **token** or **x-afb-token**. + +To ensure security, tokens must be refreshed periodically. + +### Example of session management + +In following examples, we suppose that **afb-daemon** is launched with something +equivalent to: + +```bash +afb-daemon --port=1234 --token=123456 [...] +``` + +making the expectation that **AuthLogin** binding is requested as default. + +#### Using curl + +First, connects with the initial token, 123456: + +```bash +$ curl http://localhost:1234/api/auth/connect?token=123456 +{ + "jtype": "afb-reply", + "request": { + "status": "success", + "token": "0aef6841-2ddd-436d-b961-ae78da3b5c5f", + "uuid": "850c4594-1be1-4e9b-9fcc-38cc3e6ff015" + }, + "response": {"token": "A New Token and Session Context Was Created"} +} +``` + +It returns an answer containing session UUID, 850c4594-1be1-4e9b-9fcc-38cc3e6ff015, +and a refreshed token, 850c4594-1be1-4e9b-9fcc-38cc3e6ff015. + +Check if session and token is valid: + +```bash +$ curl http://localhost:1234/api/auth/check?token=0aef6841-2ddd-436d-b961-ae78da3b5c5f\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 +{ + "jtype": "afb-reply", + "request": {"status":"success"}, + "response": {"isvalid":true} +} +``` + +Refresh the token: + +```bash +$ curl http://localhost:1234/api/auth/refresh?token=0aef6841-2ddd-436d-b961-ae78da3b5c5f\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 +{ + "jtype": "afb-reply", + "request": { + "status":"success", + "token":"b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9" + }, + "response": {"token":"Token was refreshed"} +} +``` + +Close the session: + +```bash +$ curl http://localhost:1234/api/auth/logout?token=b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 +{ + "jtype": "afb-reply", + "request": {"status": "success"}, + "response": {"info":"Token and all resources are released"} +} +``` + +Checking on closed session for uuid should be refused: + +```bash +$ curl http://localhost:1234/api/auth/check?token=b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 +{ + "jtype": "afb-reply", + "request": { + "status": "failed", + "info": "invalid token's identity" + } +} +``` + +#### Using afb-client-demo + +- The program is packaged within AGL in the rpm **libafbwsc-dev** + +Here is an example of exchange using **afb-client-demo**: + +```bash +$ afb-client-demo ws://localhost:1234/api?token=123456 +auth connect +ON-REPLY 1:auth/connect: {"jtype":"afb-reply","request":{"status":"success", + "token":"63f71a29-8b52-4f9b-829f-b3028ba46b68","uuid":"5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1"}, + "response":{"token":"A New Token and Session Context Was Created"}} +auth check +ON-REPLY 2:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} +auth refresh +ON-REPLY 4:auth/refresh: {"jtype":"afb-reply","request":{"status":"success", + "token":"8b8ba8f4-1b0c-48fa-962d-4a00a8c9157e"},"response":{"token":"Token was refreshed"}} +auth check +ON-REPLY 5:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} +auth refresh +ON-REPLY 6:auth/refresh: {"jtype":"afb-reply","request":{"status":"success", + "token":"e83b36f8-d945-463d-b983-5d8ed73ba529"},"response":{"token":"Token was refreshed"}} +``` + +After closing connection, reconnect as here after: + +```bash +$ afb-client-demo ws://localhost:1234/api?token=e83b36f8-d945-463d-b983-5d8ed73ba529\&uuid=5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1 auth check +ON-REPLY 1:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} +``` + +Same connection check using **curl**: + +```bash +$ curl http://localhost:1234/api/auth/check?token=e83b36f8-d945-463d-b983-5d8ed73ba529\&uuid=5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1 +{"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} +``` + +### Format of replies + +Replies use javascript object returned as serialized JSON. + +This object contains at least 2 mandatory fields of name **jtype** and +**request** and one optional field of name **response**. + +#### Template of replies + +This is a template of replies: + +```json +{ + "jtype": "afb-reply", + "request": { + "status": "success", + "info": "informationnal text", + "token": "e83b36f8-d945-463d-b983-5d8ed73ba52", + "uuid": "5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1", + "reqid": "application-generated-id-23456" + }, + "response": ....any response object.... +} +``` + +#### Field jtype of replies + +The field **jtype** must have a value of type string equal to **"afb-reply"**. + +#### Field request of replies + +The field **request** must have a value of type object. +This request object has at least one field named **status** +and four optional fields named **info**, **token**, **uuid**, **reqid**. + +##### Subfield request.status + +**status** must have a value of type string. This string is equal to **"success"** +only in case of success. + +##### Subfield request.info + +**info** is of type string and represent optional information added to the reply. + +##### Subfield request.token + +**token** is of type string. It is sent either at session creation +or when the token is refreshed. + +##### Subfield request.uuid + +**uuid** is of type string. It is sent at session creation. + +##### Subfield request.reqid + +**reqid** is of type string. It is sent in response to HTTP requests +that added a parameter of name **reqid** or **x-afb-reqid** at request time. +Value returns in the reply has the exact same value as the one received in the +request. + +#### Field response of replies + +This field response optionally contains an object returned when request +succeeded. + +### Format of events + +Events are javascript object serialized as JSON. + +This object contains at least 2 mandatory fields of name **jtype** and **event** +and one optional field of name **data**. + +#### Template of event + +Here is a template of event: + +```json +{ + "jtype": "afb-event", + "event": "sample_api_name/sample_event_name", + "data": ...any event data... +} +``` + +#### Field jtype of event + +The field **jtype** must have a value of type string equal to **"afb-event"**. + +#### Field event of event + +The field **event** carries the event's name. + +The name of the event is made of two parts separated by a slash: +the name of the name of the API that generated the event +and the name of event within the API. + +#### Field data of event + +This field data if present holds the data carried by the event. \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/7_Document_revisions.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/7_Document_revisions.md new file mode 100644 index 0000000..06242ce --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/7_Document_revisions.md @@ -0,0 +1,17 @@ +--- +title: Document revisions +--- + +Document revisions + +| Date | Version | Designation  | Author | +|--------------|:----------:|----------------------------------------------|-------------------------------------------------------| +| 23 May 2016 | 0.9 | Initial release | J. Bollo [ IoT.bzh ]
M. Bachmann [ IoT.bzh ] | +| 30 May 2016 | 1.0 | Master document edition, final review | S. Desneux [ IoT.bzh ]
F. Ar Foll [ IoT.bzh ] | +| 21 Sept 2016 | 2.0 | Updated with new sections (events,widgets) | J. Bollo [ IoT.bzh ]
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 ]
S. Desneux [ IoT.bzh ] | +| 21 Jun 2017 | 4.0 | Update for AGL DD | J. Bollo [ IoT.bzh ]
S. Desneux [ IoT.bzh ] | +| 21 Sep 2017 | 4.99-EERC1 | Update for AGL EE-RC1 | J. Bollo [ IoT.bzh ]
S. Desneux [ IoT.bzh ] | +| 14 Jun 2018 | 5.99-FFRC1 | Update for AGL FF-RC1 | J. Bollo [ IoT.bzh ] | diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/1_Migration_to_bindings_v3.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/1_Migration_to_bindings_v3.md new file mode 100644 index 0000000..bba5354 --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/1_Migration_to_bindings_v3.md @@ -0,0 +1,199 @@ +--- +title: Migration to bindings 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 and 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 in 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 do not exist anymore. If needed you can refer +to the old [guide to migrate bindings from v1 to v2](./6_LEGACY_Migration_from_v1_to_v2.md). + + +Differences between version 2 and version 3 +------------------------------------------- + +** *In v3 all is api.* ** + +The version 3 introduces 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, 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 functions **preinit**, **init** and **onevent** +3. Consider use of the new reply +4. Consider use of the new (sub)call +5. Consider use of event handlers + +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 done using **curl** and applied using **sed** +as below. + +```bash +BASE=https://git.automotivelinux.org/src/app-framework-binder/plain +SED=migration-to-binding-v3.sed +curl -o $SED $BASE/docs/$SED +sed -i -f $SED file1 file2 file3... +``` + +You can also follow +[this link](https://git.automotivelinux.org/src/app-framework-binder/plain/docs/migration-to-binding-v3.sed) +and save the file. + +This automatic action does most of the boring job but not all the job. +The remaining of this guide explains the missing part. + +Adapt the functions preinit, init and onevent +---------------------------------------------- + +The signature of the functions **preinit**, **init** and **onevent** changed +to include the target api. + +The functions of the v2: + +```C +int (*preinit)(); +int (*init)(); +void (*onevent)(const char *event, struct json_object *object); +``` + +Gain a new first argument of type **afb_api_t** as below: + +```C +int (*preinit)(afb_api_t api); +int (*init)(afb_api_t api); +void (*onevent)(afb_api_t api, const char *event, struct json_object *object); +``` + +For the migration, it is enough to just add the new argument without +using it. + +Consider use of the new reply +----------------------------- + +The v3 allows error reply with JSON object. To achieve it, an unified +reply function's family is introduced: + +```C +void afb_req_reply(afb_req_t req, json_object *obj, const char *error, const char *info); +void afb_req_reply_v(afb_req_t req, json_object *obj, const char *error, const char *info, va_list args); +void afb_req_reply_f(afb_req_t req, json_object *obj, const char *error, const char *info, ...); +``` + +The functions **success** and **fail** are still supported. +These functions are now implemented as the following macros: + + +```C +#define afb_req_success(r,o,i) afb_req_reply(r,o,NULL,i) +#define afb_req_success_f(r,o,...) afb_req_reply_f(r,o,NULL,__VA_ARGS__) +#define afb_req_success_v(r,o,f,v) afb_req_reply_v(r,o,NULL,f,v) +#define afb_req_fail(r,e,i) afb_req_reply(r,NULL,e,i) +#define afb_req_fail_f(r,e,...) afb_req_reply_f(r,NULL,e,__VA_ARGS__) +#define afb_req_fail_v(r,e,f,v) afb_req_reply_v(r,NULL,e,f,v) +``` + +This is a decision of the developer to switch to the new family +**afb_req_reply** or to keep the good old functions **afb_req_fail** +adn **afb_req_success**. + +Consider use of the new (sub)call +--------------------------------- + +The new call and subcall (the functions **afb_api_call**, **afb_api_call_sync**, +**afb_req_subcall** and **afb_req_subcall_sync**) functions are redesigned +to better fit the new reply behaviour. In most case the developer will benefit +of the new behavior that directly gives result and error without enforcing +to parse the JSON object result. + +The subcall functions are also fully redesigned to allow precise handling +of the context and event subscriptions. The new design allows you to specify: + + - whether the subcall is made in the session of the caller or in the session + of the service + - whether the credentials to use are those of the caller or those of the + service + - whether the caller or the service or both or none will receive the + eventually events during the subcall. + +See [calls](../3_Binder_References.md#afb_api_call) and +[subcalls](../3_Binder_References.md#subcall-functions). + +The table below list the changes to apply: + +| Name in Version 2 | New name of Version 3 +|:----------------------:|:----------------------------------------------------: +| afb_req_subcall | afb_req_subcall_legacy +| afb_req_subcall_sync | afb_req_subcall_sync_legacy +| afb_service_call | afb_service_call_legacy +| afb_service_call_sync | afb_service_call_sync_legacy +| afb_req_subcall_req | afb_req_subcall_req (same but obsolete) + + +Consider use of event handlers +------------------------------ + +Binding V3 brings new ways of handling event in services. You can register +functions that will handle specific events and that accept closure arguments. + +See [**afb_api_event_handler_add** and **afb_api_event_handler_del**](../3_Binder_References.md#event-functions) \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/2_WebSocket_protocol_x-afb-ws-json1.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/2_WebSocket_protocol_x-afb-ws-json1.md new file mode 100644 index 0000000..7ebf22a --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/2_WebSocket_protocol_x-afb-ws-json1.md @@ -0,0 +1,308 @@ +--- +title: WebSocket protocol x-afb-ws-json1 +--- + +The WebSocket protocol *x-afb-ws-json1* is used to communicate between +an application and a binder. It allows access to all registered apis +of the binder. + +This protocol is inspired from the protocol **OCPP - SRPC** as described for +example here: +[OCPP transport specification - SRPC over WebSocket](http://www.gir.fr/ocppjs/ocpp_srpc_spec.shtml). + +The registration to the IANA is still to be done, see: +[WebSocket Protocol Registries](https://www.iana.org/assignments/websocket/websocket.xml) + +This document gives a short description of the protocol *x-afb-ws-json1*. +A more formal description has to be done. + +## Architecture + +The protocol is intended to be symmetric. It allows: + +- to CALL a remote procedure that returns a result +- to push and receive EVENT + +## Messages + +Valid messages are made of *text* frames that are all valid JSON. + +Valid messages are: + +Calls: + +```txt +[ 2, ID, PROCN, ARGS ] +[ 2, ID, PROCN, ARGS, TOKEN ] +``` + +Replies (3: OK, 4: ERROR): + +```txt +[ 3, ID, RESP ] +[ 4, ID, RESP ] +``` + +Events: + +```txt +[ 5, EVTN, OBJ ] +``` + +Where: + +| Field | Type | Description +|-------|--------|------------------ +| ID | string | A string that identifies the call. A reply to that call use the ID of the CALL. +| PROCN | string | The procedure name to call of the form "api/verb" +| ARGS | any | Any argument to pass to the call (see afb_req_json that returns it) +| RESP | any | The response to the call +| TOKEN | string | The authorisation token +| EVTN | string | Name of the event in the form "api/event" +| OBJ | any | The companion object of the event + +Below, an example of exchange: + +```txt +C->S: [2,"156","hello/ping",null] +S->C: [3,"156",{"response":"Some String","jtype":"afb-reply","request":{"status":"success","info":"Ping Binder Daemon tag=pingSample count=1 query=\"null\"","uuid":"ec30120c-6997-4529-9d63-c0de0cce56c0"}}] +``` + +## History + +### 14 November 2019 + +Removal of token returning. The replies + +```txt +[ 3, ID, RESP, TOKEN ] +[ 4, ID, RESP, TOKEN ] +``` + +are removed from the specification. + +## Future + +Here are the planned extensions: + +- add binary messages with cbor data +- add calls with unstructured replies + +This could be implemented by extending the current protocol or by +allowing the binder to accept either protocol including the new ones. + +## Javascript implementation + +The file **AFB.js** is a javascript implementation of the protocol. + +Here is that code: + +```javascript +/* + * Copyright (C) 2017-2019 "IoT.bzh" + * Author: José Bollo + * + * 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. + */ +AFB = function(base, initialtoken){ + +if (typeof base != "object") + base = { base: base, token: initialtoken }; + +var initial = { + base: base.base || "api", + token: base.token || initialtoken || "HELLO", + host: base.host || window.location.host, + url: base.url || undefined +}; + +var urlws = initial.url || "ws://"+initial.host+"/"+initial.base; + +/*********************************************/ +/**** ****/ +/**** AFB_context ****/ +/**** ****/ +/*********************************************/ +var AFB_context; +{ + var UUID = undefined; + var TOKEN = initial.token; + + var context = function(token, uuid) { + this.token = token; + this.uuid = uuid; + } + + context.prototype = { + get token() {return TOKEN;}, + set token(tok) {if(tok) TOKEN=tok;}, + get uuid() {return UUID;}, + set uuid(id) {if(id) UUID=id;} + }; + + AFB_context = new context(); +} +/*********************************************/ +/**** ****/ +/**** AFB_websocket ****/ +/**** ****/ +/*********************************************/ +var AFB_websocket; +{ + var CALL = 2; + var RETOK = 3; + var RETERR = 4; + var EVENT = 5; + + var PROTO1 = "x-afb-ws-json1"; + + AFB_websocket = function(on_open, on_abort) { + var u = urlws; + if (AFB_context.token) { + u = u + '?x-afb-token=' + AFB_context.token; + if (AFB_context.uuid) + u = u + '&x-afb-uuid=' + AFB_context.uuid; + } + this.ws = new WebSocket(u, [ PROTO1 ]); + this.url = u; + this.pendings = {}; + this.awaitens = {}; + this.counter = 0; + this.ws.onopen = onopen.bind(this); + this.ws.onerror = onerror.bind(this); + this.ws.onclose = onclose.bind(this); + this.ws.onmessage = onmessage.bind(this); + this.onopen = on_open; + this.onabort = on_abort; + } + + function onerror(event) { + var f = this.onabort; + if (f) { + delete this.onopen; + delete this.onabort; + f && f(this); + } + this.onerror && this.onerror(this); + } + + function onopen(event) { + var f = this.onopen; + delete this.onopen; + delete this.onabort; + f && f(this); + } + + function onclose(event) { + for (var id in this.pendings) { + try { this.pendings[id][1](); } catch (x) {/*TODO?*/} + } + this.pendings = {}; + this.onclose && this.onclose(); + } + + function fire(awaitens, name, data) { + var a = awaitens[name]; + if (a) + a.forEach(function(handler){handler(data);}); + var i = name.indexOf("/"); + if (i >= 0) { + a = awaitens[name.substring(0,i)]; + if (a) + a.forEach(function(handler){handler(data);}); + } + a = awaitens["*"]; + if (a) + a.forEach(function(handler){handler(data);}); + } + + function reply(pendings, id, ans, offset) { + if (id in pendings) { + var p = pendings[id]; + delete pendings[id]; + try { p[offset](ans); } catch (x) {/*TODO?*/} + } + } + + function onmessage(event) { + var obj = JSON.parse(event.data); + var code = obj[0]; + var id = obj[1]; + var ans = obj[2]; + AFB_context.token = obj[3]; + switch (code) { + case RETOK: + reply(this.pendings, id, ans, 0); + break; + case RETERR: + reply(this.pendings, id, ans, 1); + break; + case EVENT: + default: + fire(this.awaitens, id, ans); + break; + } + } + + function close() { + this.ws.close(); + this.ws.onopen = + this.ws.onerror = + this.ws.onclose = + this.ws.onmessage = + this.onopen = + this.onabort = function(){}; + } + + function call(method, request, callid) { + return new Promise((function(resolve, reject){ + var id, arr; + if (callid) { + id = String(callid); + if (id in this.pendings) + throw new Error("pending callid("+id+") exists"); + } else { + do { + id = String(this.counter = 4095 & (this.counter + 1)); + } while (id in this.pendings); + } + this.pendings[id] = [ resolve, reject ]; + arr = [CALL, id, method, request ]; + if (AFB_context.token) arr.push(AFB_context.token); + this.ws.send(JSON.stringify(arr)); + }).bind(this)); + } + + function onevent(name, handler) { + var id = name; + var list = this.awaitens[id] || (this.awaitens[id] = []); + list.push(handler); + } + + AFB_websocket.prototype = { + close: close, + call: call, + onevent: onevent + }; +} +/*********************************************/ +/**** ****/ +/**** ****/ +/**** ****/ +/*********************************************/ +return { + context: AFB_context, + ws: AFB_websocket +}; +}; +``` diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/3_Installing_the_binder_on_a_desktop.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/3_Installing_the_binder_on_a_desktop.md new file mode 100644 index 0000000..8874bde --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/3_Installing_the_binder_on_a_desktop.md @@ -0,0 +1,44 @@ +--- +title: Installing the binder on a desktop +--- + +Packages of the ***binder*** (afb-daemon)exist +for common desktop linux distributions. + +- Fedora +- Ubuntu +- Debian +- Suse + +Installing the development package of the ***binder*** +allows to write ***bindings*** that runs on the desktop +computer of the developer. + +It is very convenient to quickly write and debug a binding. + +## Retrieving compiling option with pkg-config + +The ***binder*** afb-daemon provides a configuration +file for **pkg-config**. +Typing the command + +```bash +pkg-config --cflags afb-daemon +``` + +Print flags use for compilation: + +```bash +$ pkg-config --cflags afb-daemon +-I/opt/local/include -I/usr/include/json-c +``` + +For linking, you should use + +```bash +$ pkg-config --libs afb-daemon +-ljson-c +``` + +It automatically includes the dependency to json-c. +This is activated through **Requires** keyword in pkg-config. diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/4_Options_of_afb-daemon.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/4_Options_of_afb-daemon.md new file mode 100644 index 0000000..0b58eec --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/4_Options_of_afb-daemon.md @@ -0,0 +1,355 @@ +--- +title: Options of afb-daemon +--- + +The launch options for binder **afb-daemon** are: + +``` + -v, --verbose Verbose Mode, repeat to increase verbosity + -c, --color Colorize the ouput + -q, --quiet Quiet Mode, repeat to decrease verbosity + -l, --log=xxxx Tune log level + --foreground Get all in foreground mode + --background Get all in background mode + -D, --daemon Get all in background mode + -n, --name=xxxx Set the visible name + -p, --port=xxxx HTTP listening TCP port [default 1234] + --roothttp=xxxx HTTP Root Directory [default no root http (files not served but apis still available)] + --rootbase=xxxx Angular Base Root URL [default /opa] + --rootapi=xxxx HTML Root API URL [default /api] + --alias=xxxx Multiple url map outside of rootdir [eg: --alias=/icons:/usr/share/icons] + --apitimeout=xxxx Binding API timeout in seconds [default 20] + --cntxtimeout=xxxx Client Session Context Timeout [default 32000000] + --cache-eol=xxxx Client cache end of live [default 100000] + -w, --workdir=xxxx Set the working directory [default: $PWD or current working directory] + -u, --uploaddir=xxxx Directory for uploading files [default: workdir] relative to workdir + --rootdir=xxxx Root Directory of the application [default: workdir] relative to workdir + --ldpaths=xxxx Load bindings from dir1:dir2:... [default: path of afb-dbus-binding.so] + -b, --binding=xxxx Load the binding of path + --weak-ldpaths=xxxx Same as --ldpaths but ignore errors + --no-ldpaths Discard default ldpaths loading + -t, --token=xxxx Initial Secret [default=random, use --token= to allow any token] + -r, --random-token Enforce a random token + -V, --version Display version and copyright + -h, --help Display this help + --ws-client=xxxx Bind to an afb service through websocket + --ws-server=xxxx Provide an afb service through websockets + -A, --auto-api=xxxx Automatic load of api of the given directory + --session-max=xxxx Max count of session simultaneously [default 200] + --tracereq=xxxx Log the requests: no, common, extra, all + --traceevt=xxxx Log the events: no, common, extra, all + --traceses=xxxx Log the sessions: no, all + --traceapi=xxxx Log the apis: no, common, api, event, all + --traceglob=xxxx Log the globals: none, all + --traceditf=xxxx Log the daemons: no, common, all + --tracesvc=xxxx Log the services: no, all + --call=xxxx call at start, format of val: API/VERB:json-args + --no-httpd Forbid HTTP service + -e, --exec Execute the remaining arguments + -M, --monitoring Enable HTTP monitoring at /monitoring/ + -C, --config=xxxx Load options from the given config file + -Z, --dump-config Dump the config to stdout and exit + -s, --set=xxxx Set parameters ([API]/[KEY]:JSON or {"API":{"KEY":JSON}} + -o, --output=xxxx Redirect stdout and stderr to output file (when --daemon) + --trap-faults=xxxx Trap faults: on, off, yes, no, true, false, 1, 0 (default: true) +``` + +## help + +Prints help with available options + +## version + +Display version and copyright + +## verbose + +Increases the verbosity, can be repeated + +## color + +Add basic colorization to the ouput. + +## quiet + +Decreases the verbosity, can be repeated + +## log=xxxx + +Tune the log level mask. The levels are: + + - error + - warning + - notice + - info + - debug + +The level can be set using + or -. + +| Examples | descritpion +|-----------------|------------------- +| error,warning | selects only the levels error and warning +| +debug | adds level debug to the current verbosity +| -warning | remove the level warning from the current verbosity +| +warning-debug,info | Adds error and remove errors and warnings + +## port=xxxx + +HTTP listening TCP port [default 1234] + +## workdir=xxxx + +Directory where the daemon must run [default: $PWD if defined +or the current working directory] + +## uploaddir=xxxx + +Directory where uploaded files are temporarily stored [default: workdir] + +## rootdir=xxxx + +Root directory of the application to serve [default: workdir] + +## roothttp=xxxx + +Directory of HTTP served files. If not set, files are not served +but apis are still accessible. + +## rootbase=xxxx + +Angular Base Root URL [default /opa] + +This is used for any application of kind OPA (one page application). +When set, any missing document whose url has the form /opa/zzz +is translated to /opa/#!zzz + +## rootapi=xxxx + +HTML Root API URL [default /api] + +The bindings are available within that url. + +## alias=xxxx + +Maps a path located anywhere in the file system to the +a subdirectory. The syntax for mapping a PATH to the +subdirectory NAME is: --alias=/NAME:PATH. + +Example: --alias=/icons:/usr/share/icons maps the +content of /usr/share/icons within the subpath /icons. + +This option can be repeated. + +## apitimeout=xxxx + +binding API timeout in seconds [default 20] + +Defines how many seconds maximum a method is allowed to run. +0 means no limit. + +## cntxtimeout=xxxx + +Client Session Timeout in seconds [default 32000000 that is 1 year] + +## cache-eol=xxxx + +Client cache end of live [default 100000 that is 27,7 hours] + +## session-max=xxxx + +Maximum count of simultaneous sessions [default 200] + +## ldpaths=xxxx + +Load bindings from given paths separated by colons +as for dir1:dir2:binding1.so:... [default = $libdir/afb] + +You can mix path to directories and to bindings. +The sub-directories of the given directories are searched +recursively. + +The bindings are the files terminated by '.so' (the extension +so denotes shared object) that contain the public entry symbol. + +## weak-ldpaths=xxxx + +Same as --ldpaths but instead of stopping on error, ignore errors and continue. + +## binding=xxxx + +Load the binding of given path. + +## token=xxxx + +Initial Secret token to authenticate. + +If not set, no client can authenticate. + +If set to the empty string, then any initial token is accepted. + +## random-token + +Generate a random starting token. See option --exec. + +## ws-client=xxxx + +Transparent binding to a binder afb-daemon service through a WebSocket. + +The value of xxxx is either a unix naming socket, of the form "unix:path/api", +or an internet socket, of the form "host:port/api". + +## ws-server=xxxx + +Provides a binder afb-daemon service through WebSocket. + +The value of xxxx is either a unix naming socket, of the form "unix:path/api", +or an internet socket, of the form "host:port/api". + +## foreground + +Get all in foreground mode (default) + +## daemon + +Get all in background mode + +## no-httpd + +Forbids HTTP serve + +## exec + +Must be the last option for afb-daemon. The remaining +arguments define a command that afb-daemon will launch. +The sequences @p, @t and @@ of the arguments are replaced +with the port, the token and @. + +## tracereq=xxxx + +Trace the processing of requests in the log file. + +Valid values are 'no' (default), 'common', 'extra' or 'all'. + +## traceapi=xxxx + +Trace the accesses to functions of class api. + +Valid values are 'no' (default), 'common', 'api', 'event' or 'all'. + +## traceevt=xxxx + +Trace the accesses to functions of class event. + +Valid values are 'no' (default), 'common', 'extra' or 'all'. + +## call=xxx + +Call a binding at start (can be be repeated). +The values are given in the form API/VERB:json-args. + +Example: --call 'monitor/set:{"verbosity":{"api":"debug"}}' + +## monitoring + +Enable HTTP monitoring at /monitoring/ + +## name=xxxx + +Set the visible name + +## auto-api=xxxx + +Automatic activation of api of the given directory when the api is missing. + +## config=xxxx + +Load options from the given config file + +This can be used instead of arguments on the command line. + +Example: + + afb-daemon \ + --no-ldpaths \ + --binding /home/15646/bindings/binding45.so \ + --binding /home/15646/bindings/binding3.so \ + --tracereq common \ + --port 5555 \ + --token SPYER \ + --set api45/key:54027a5e3c6cb2ca5ddb97679ce32f185b067b0a557d16a8333758910bc25a72 \ + --exec /home/15646/bin/test654 @p @t + +is equivalent to: + + afb-daemon --config /home/15646/config1 + +when the file **/home/15646/config1** is: + + { + "no-ldpaths": true, + "binding": [ + "\/home\/15646\/bindings\/binding45.so", + "\/home\/15646\/bindings\/binding3.so" + ], + "tracereq": "common", + "port": 5555, + "token": "SPYER", + "set" : { + "api45": { + "key": "54027a5e3c6cb2ca5ddb97679ce32f185b067b0a557d16a8333758910bc25a72" + } + }, + "exec": [ + "\/home\/15646\/bin\/test654", + "@p", + "@t" + ] + } + +The options are the keys of the config object. + +See option --dump-config + +## dump-config + +Output a JSON representation of the configuration resulting from +environment and options. + +## output=xxxx + +Redirect stdout and stderr to output file + +## set=xxxx + +Set values that can be retrieved by bindings. + +The set value can have different formats. + +The most generic format is **{"API1":{"KEY1":VALUE,"KEY2":VALUE2,...},"API2":...}** + +This example set 2 keys for the api *chook*: + + afb-daemon -Z --set '{"chook":{"account":"urn:chook:b2ca5ddb97679","delay":500}}' + { + "set": { + "chook": { + "account": "urn:chook:b2ca5ddb97679", + "delay": 500 + } + } + } + +An other format is: **[API]/[KEY]:VALUE**. +When API is omitted, it take the value " * ". +When KEY is ommitted, it take the value of " * ". + +The settings for the API \* are globals and apply to all bindings. + +The settings for the KEY \* are mixing the value for the API. + +The following examples are all setting the same values: + + afb-daemon --set '{"chook":{"account":"urn:chook:b2ca5ddb97679","delay":500}}' + afb-daemon --set 'chook/*:{"account":"urn:chook:b2ca5ddb97679","delay":500}' + afb-daemon --set 'chook/:{"account":"urn:chook:b2ca5ddb97679","delay":500}' + afb-daemon --set 'chook/account:"urn:chook:b2ca5ddb97679"' --set chook/delay:500 \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/5_Debugging_binder_and_bindings.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/5_Debugging_binder_and_bindings.md new file mode 100644 index 0000000..dbb9bdd --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/5_Debugging_binder_and_bindings.md @@ -0,0 +1,38 @@ +--- +title: Debugging binder and bindings +--- + +When compiled with the symbol AGL_DEVEL defined, the ***binder*** +understands the 2 configuration variables: + + - AFB_DEBUG_BREAK: to emit interrupts + - AFB_DEBUG_WAIT: to wait interrupts + +To use these variables, assign it the list of break or wait points +to reach. + +Example: + +```bash +$ AFB_DEBUG_BREAK=main-entry AFB_DEBUG_WAIT=start-load,start-exec afb-daemon .... +``` + +This tells to ***afb-daemon*** to break at the point **main-entry** and to +wait at the points **start-load** and **start-exec**. + +The items of the list can be separated using comma, space, tab or new-line. + +The break/wait points are, in the order of their occurrence: + +- main-entry: before decode arguments +- main-args: before daemon setup +- main-start: before starting jobs +- start-entry: before initialisation of sessions and hooks +- start-load: before load and pre-init of bindings +- start-start: before init of bindings +- start-http: before start of http server +- start-call: before execution of requests of the command line (option --call) +- start-exec: before execution of child preocees + +Note also that a call to 'personality' is inserted just after +the point start-start. \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/6_LEGACY_Migration_from_v1_to_v2.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/6_LEGACY_Migration_from_v1_to_v2.md new file mode 100644 index 0000000..6004aec --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/6_LEGACY_Migration_from_v1_to_v2.md @@ -0,0 +1,656 @@ +--- +title: LEGACY Migration from v1 to 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: + +- 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 and/or v2 in any combination. +Thus moving from v1 to v2 is not enforced, there is no real need. + +More, it is possible to write a dual ***binding***: + +- a ***binding*** that implements the version 1 and the version 2. + +However, IT IS HIGHLY RECOMMENDED TO SWITCH TO ONLY VERSION 2: + +- any new development SHOULD start using ***binding*** V2 +- existing ***bindings*** SHOULD migrate to the version 2 + +This guide covers the migration of bindings from version 1 to version 2. + +It also explains some of the rationale taken when migrating from version 1 to version 2. + +In the future, if ***binding*** api evolves to fresh versions (3, 4, ...) +it might be necessarily to write bindings implementing more than +just one version. +For example: + +- a ***binding*** being v2 AND v3 will resolve the issue of running on older and newer version of AGL. + +This should always be possible even if more complicated. + +Important things to known when migrating +---------------------------------------- + +One of the most important change when migrating from v1 to v2 is +that many functions use an hidden *common* variable. +This affects the functions of the following classes: + +- functions of class **daemon**: + - functions starting with **afb_daemon_...** + - functions for logging: **ERROR**, **WARNING**, **NOTICE**, **INFO**, **DEBUG** +- functions of class **service**: + - functions starting with **afb_service_...** +- callback functions: + - the register function (that is removed) + - the service init function + - the onevent function + +For these functions, the first parameter is now implicit. + +Let takes an example. +For ***binding*** v1 you had to write: + +```C + afb_daemon_broadcast_event(afbitf->daemon, reason, description); +``` + +For ***binding*** v2, you simply write: + +```C + afb_daemon_broadcast_event(reason, description); +``` + +This simplification is possible because the header files included for the bindings +now provide a common variable for storing the **daemon** and **service** data. + +As a programmer, you shouldn't care much about that hidden variable. +It simplifies the job, that's all and that is the reason of the change. + +An other important difference is between the version 1 and the version 2 is +on how the ***binding***'s **API** is documented. +The version 2 emphasis the **OpenAPI v3** description of the **API**. +For this reason, to avoid duplication of descriptions, only one description is expected: + +- The **OpenAPI** one. + +Task list for the migration +--------------------------- + +This task list is: + +1. Enforce use of binding v2 by setting **AFB_BINDING_VERSION** +2. Rewrite the main structure and the list of exported verbs +3. Adapt the init and callback functions +4. Removes the first parameter of functions of classes **daemon** and **service** +5. Consider where to emit logs for requests +6. Take care of store/unstore changes +7. Consider use of synchronous (sub)call requests +8. Optionally, removes explicit struct + +The remaining chapters explain these task with more details. + +Enforce use of binding v2 by setting AFB_BINDING_VERSION +-------------------------------------------------------- + +By defining **AFB_BINDING_VERSION** to **2** you switch to version 2. +This is done as below. + +```C +#define AFB_BINDING_VERSION 2 +#include +``` + +After that you will get many errors when compiling. + +Rewrite the main structures and the list of exported verbs +--------------------------------------------------------- + +The structures describing the ***binding** changed from version 1 to version 2. + +The structure for describing verbs changed to include security +requirements. + +In version 1 it was: + +```C +struct afb_verb_desc_v1 +{ + const char *name; /* name of the verb */ + enum afb_session_flags_v1 session; /* authorization 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 */ +}; +``` + +In version 2 it becomes: + +```C +struct afb_verb_v2 +{ + 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 */ + uint32_t session; /* authorization and session requirements of the verb */ +}; + +``` + +The migration of instances of that structure requires the following actions: + +- rename field **name** to **verb** +- remove field **info** +- adapt field **session** if needed +- set field **auth** to NULL + +Example: + +```C + { .name= "new", .session= AFB_SESSION_NONE, .callback= new, .info= "Starts a new game" } +``` + +Becomes + +```C + { .verb = "new", .session = AFB_SESSION_NONE, .callback = new, .auth = NULL } +``` + +The field **auth** can be set to a value describing the requested +authorization. + +The main describing structure also changed. + +In version 1 it was: + +```C +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 */ +}; +``` + +In version 2 it becomes: + +```C +struct afb_binding_v2 +{ + const char *api; /* api name for the binding */ + const char *specification; /* textual specification of the binding */ + 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 */ +}; +``` + +The migration of instances of that structure requires the following actions: + +- declare, explore, name the structure as ```const struct afb_binding_v2 afbBindingV2``` +- rename the field **prefix** to **api** +- remove the field **info** +- setup the fields **preinit**, **init**, **onevent** according to the next section +- set the field **noconcurrency** to the right value: + - to 1 if you want to avoid concurrent calls to verbs. + - to 0 if you allow concurrent calls to verbs. + +Example: + +```C +static const struct afb_binding plugin_desc = { + .type = AFB_BINDING_VERSION_1, + .v1 = { + .info = "Minimal Hello World Sample", + .prefix = "hello", + .verbs = verbs + } +``` + +Becomes: + +```C +const struct afb_binding_v2 afbBindingV2 = { + .api = "hello", + .specification = NULL, + .verbs = verbs, + .preinit = preinit, + .init = init +}; +``` + +The **binder** now relies only on the exported names +to deduce the type of the binding. +This make the main structure more simple. + +Adapt the init and callback functions +------------------------------------- + +The ***bindings*** version 1 defined 3 exported functions: + +- **afbBindingV1Register** +- **afbBindingV1ServiceInit** +- **afbBindingV1ServiceEvent** + +These function should not be exported any more and there definition changed. + +The function **afbBindingV1Register** is no more used to describe the binding. +When a binding has to take actions when it is loaded, it must set the field +**preinit** of the structure **afbBindingV2**. +This field, this preinit, might be used to check features at load. +When it returns a negative number, the ***binder*** stops before initializing any ***binding***. + +The function **afbBindingV1ServiceInit** is replaced by the field **init** +of the structure **afbBindingV2**. +The init function should return 0 in case of success or a negative error code +in case of problem. +It is called during initialization of services. + +The function **afbBindingV1ServiceEvent**is replaced by the field **onevent** +of the structure **afbBindingV2**. + +The two functions **afbBindingV1Register** and **afbBindingV1ServiceInit**, +were taking as parameter the ***binder*** interface and the service interface respectively. +These interfaces are now managed hiddenly for the **binding** by the **binder**. +So the variable that ***bindings*** version used to store the ***binder*** interface +and the service interface are no more needed and can be removed. + +Example: + +```C +const struct afb_binding_interface *interface; +struct afb_service service; + +static const struct afb_binding plugin_desc = { + .type = AFB_BINDING_VERSION_1, + .v1 = { + .info = "Minimal Hello World Sample", + .prefix = "hello", + .verbs = verbs + } +} + +const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +{ + interface = itf; + NOTICE(interface, "binding register"); + return &plugin_desc; +} + +int afbBindingV1ServiceInit(struct afb_service svc) +{ + service = svc; + NOTICE(interface, "binding init"); + return 0; +} + +void afbBindingV1ServiceEvent(const char *event, struct json_object *object) +{ + NOTICE(interface, "onevent %s", event); +} +``` + +Becomes: + +```C +static int preinit() +{ + AFB_NOTICE("binding preinit (was register)"); + return 0; +} + +static int init() +{ + AFB_NOTICE("binding init"); + return 0; +} + +static void onevent(const char *event, struct json_object *object) +{ + AFB_NOTICE("onevent %s", event); +} + +const struct afb_binding_v2 afbBindingV2 = { + .api = "hello", + .specification = NULL, + .verbs = verbs, + .preinit = preinit, + .init = init, + .onevent = onevent +}; +``` + +The two functions **afbBindingV1Register** and **afbBindingV1ServiceInit**, +were taking as parameter the ***binder*** interface and the service interface respectively. +These interfaces are now managed hiddenly for the **binding** by the **binder**. +So the variable that ***bindings*** version used to store the ***binder*** interface +and the service interface are no more needed and can be removed. + +On the above example the following lines were removed: + +```C +const struct afb_binding_interface *interface; +struct afb_service service; + + interface = itf; + + service = svc; +``` + +Removes the first parameter of functions of classes **daemon** and **service** +------------------------------------------------------------------------------ + +As explained before, many functions loose there first +arguments, this are the functions of the following classes: + +- functions of class **daemon**: + - functions starting with **afb_daemon_...** + - functions for logging: **ERROR**, **WARNING**, **NOTICE**, **INFO**, **DEBUG** +- functions of class **service**: + - functions starting with **afb_service_...** +- callback functions: + - the register function (that is removed) + - the service init function + - the onevent function + +For these functions, the first parameter is now implicit. + +Example: + +```C + afb_daemon_broadcast_event(afbitf->daemon, reason, description); +``` + +Becomes: + +```C + afb_daemon_broadcast_event(reason, description); +``` + +Also, to avoid possible conflicts, we introduced prefixed logging functions: +the macros + +- **ERROR** +- **WARNING** +- **NOTICE** +- **INFO** +- **DEBUG** + +have now a prefixed version: + +- **AFB\_ERROR** +- **AFB\_WARNING** +- **AFB\_NOTICE** +- **AFB\_INFO** +- **AFB\_DEBUG** + +It is now recommended to use the prefixed version. + +Example: + +```C + NOTICE(interface, "hello plugin comes to live"); +``` + +Become: + +```C + NOTICE("hello plugin comes to live"); +``` + +or, better: + +```C + AFB_NOTICE("hello plugin comes to live"); +``` + +To remove definition of the un-prefixed versions of logging macros: + +- **ERROR** +- **WARNING** +- **NOTICE** +- **INFO** +- **DEBUG** + +and just define + +- **AFB_BINDING_PRAGMA_NO_VERBOSE_UNPREFIX** + +before to include **afb/afb-binding.h**. + +```C +#define AFB_BINDING_PRAGMA_NO_VERBOSE_UNPREFIX +#define AFB_BINDING_VERSION 2 +#include +``` + +Consider where to emit logs for requests +---------------------------------------- + +The ***bindings*** v2 now allows to emit log messages associated to ***requests***. +This feature is valuable when debugging because it allows to return +side information associated to a ***request***. + +The defined macros for logging to requests are: + +- **AFB_REQ_ERROR** +- **AFB_REQ_WARNING** +- **AFB_REQ_NOTICE** +- **AFB_REQ_INFO** +- **AFB_REQ_DEBUG** + +We encourage the use of these new logging facilities everywhere it makes sense. + +Example: + +```C + INFO(afbitf, "method 'new' called for boardid %d", board->id); +``` + +Might become: + +```C + AFB_REQ_INFO(req, "method 'new' called for boardid %d", board->id); +``` + +Take care of store/unstore change +--------------------------------- + +For efficiency, the version 2 redefined how storing/un-storing of +requests works. +Storing request is needed for asynchronous handling of requests. + +For ***bindings*** version, the signature of the functions were: + +```C +struct afb_req *afb_req_store(struct afb_req req); +struct afb_req afb_req_unstore(struct afb_req *req); +``` + +For version 2 it becomes + +```C +struct afb_stored_req *afb_req_store(struct afb_req req); +struct afb_req afb_req_unstore(struct afb_stored_req *sreq); +``` + +Where the structure ```struct afb_stored_req``` is opaque. + +It should require few code change. + +Also check the following chapter that explain that asynchronous (sub)calls +can be replaced by synchronous one, avoiding the need to store/unstore +requests. + +Consider use of synchronous (sub)call requests +---------------------------------------------- + +***Bindings*** can emit requests for themselves (calls) or for +their clients (subcalls). +With ***bindings*** version 2 comes also synchronous requests for both cases. + +So when migrating to bindings version 2, a developer can consider +to replace the asynchronous requests (with asynchronous call back) +by synchronous ones. + +See functions ***afb_service_call_sync*** and ***afb_req_subcall_sync***. + +Optionally, removes explicit struct +----------------------------------- + +The new definitions now includes **typedefs** for common +structures, as shown on below sample: + +```C +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_service afb_service; +``` + +So you can remove the keyword **struct** if it bores you. + +Example: + +```C +static void verb(struct afb_req req) +{ + ... +} +``` + +Might become: + +```C +static void verb(afb_req req) +{ + ... +} +``` + +Example of migration +-------------------- + +The first ***binding*** that migrated from v1 to v2 was the sample **HelloWorld**. +Here is shown the differences between the version 1 and the version 2. + +```diff +diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c +index c6fa779..505aee3 100644 +--- a/bindings/samples/HelloWorld.c ++++ b/bindings/samples/HelloWorld.c +@@ -21,9 +21,9 @@ + + #include + ++#define AFB_BINDING_VERSION 2 + #include + +-const struct afb_binding_interface *interface; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + struct event +@@ -79,7 +80,7 @@ static int event_add(const char *tag, const char *name) + strcpy(e->tag, tag); + + /* make the event */ +- e->event = afb_daemon_make_event(interface->daemon, name); ++ e->event = afb_daemon_make_event(name); + if (!e->event.closure) { free(e); return -1; } + + /* link */ +@@ -140,7 +141,7 @@ static void pingBug (struct afb_req request) + static void pingEvent(struct afb_req request) + { + json_object *query = afb_req_json(request); +- afb_daemon_broadcast_event(interface->daemon, "event", json_object_get(query)); ++ afb_daemon_broadcast_event("event", json_object_get(query)); + ping(request, json_object_get(query), "event"); + } + +@@ -288,38 +289,43 @@ static void exitnow (struct afb_req request) + exit(0); + } + ++static int preinit() ++{ ++ AFB_NOTICE("hello binding comes to live"); ++ return 0; ++} ++ ++static int init() ++{ ++ AFB_NOTICE("hello binding starting"); ++ return 0; ++} ++ + // 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[]= { +- {"ping" , AFB_SESSION_NONE, pingSample , "Ping Application Framework"}, +- {"pingfail" , AFB_SESSION_NONE, pingFail , "Fails"}, +- {"pingnull" , AFB_SESSION_NONE, pingNull , "Return NULL"}, +- {"pingbug" , AFB_SESSION_NONE, pingBug , "Do a Memory Violation"}, +- {"pingJson" , AFB_SESSION_NONE, pingJson , "Return a JSON object"}, +- {"pingevent", AFB_SESSION_NONE, pingEvent , "Send an event"}, +- {"subcall", AFB_SESSION_NONE, subcall , "Call api/verb(args)"}, +- {"subcallsync", AFB_SESSION_NONE, subcallsync , "Call api/verb(args)"}, +- {"eventadd", AFB_SESSION_NONE, eventadd , "adds the event of 'name' for the 'tag'"}, +- {"eventdel", AFB_SESSION_NONE, eventdel , "deletes the event of 'tag'"}, +- {"eventsub", AFB_SESSION_NONE, eventsub , "subscribes to the event of 'tag'"}, +- {"eventunsub",AFB_SESSION_NONE, eventunsub , "unsubscribes to the event of 'tag'"}, +- {"eventpush", AFB_SESSION_NONE, eventpush , "pushs the event of 'tag' with the 'data'"}, +- {"exit", AFB_SESSION_NONE, exitnow , "exits from afb-daemon"}, +- {NULL} ++static const struct afb_verb_v2 verbs[]= { ++ { "ping" , pingSample , NULL, AFB_SESSION_NONE }, ++ { "pingfail" , pingFail , NULL, AFB_SESSION_NONE }, ++ { "pingnull" , pingNull , NULL, AFB_SESSION_NONE }, ++ { "pingbug" , pingBug , NULL, AFB_SESSION_NONE }, ++ { "pingJson" , pingJson , NULL, AFB_SESSION_NONE }, ++ { "pingevent", pingEvent , NULL, AFB_SESSION_NONE }, ++ { "subcall", subcall , NULL, AFB_SESSION_NONE }, ++ { "subcallsync", subcallsync, NULL, AFB_SESSION_NONE }, ++ { "eventadd", eventadd , NULL, AFB_SESSION_NONE }, ++ { "eventdel", eventdel , NULL, AFB_SESSION_NONE }, ++ { "eventsub", eventsub , NULL, AFB_SESSION_NONE }, ++ { "eventunsub", eventunsub , NULL, AFB_SESSION_NONE }, ++ { "eventpush", eventpush , NULL, AFB_SESSION_NONE }, ++ { "exit", exitnow , NULL, AFB_SESSION_NONE }, ++ { NULL} + }; + +-static const struct afb_binding plugin_desc = { +- .type = AFB_BINDING_VERSION_1, +- .v1 = { +- .info = "Minimal Hello World Sample", +- .prefix = "hello", +- .verbs = verbs +- } ++const struct afb_binding_v2 afbBindingV2 = { ++ .api = "hello", ++ .specification = NULL, ++ .verbs = verbs, ++ .preinit = preinit, ++ .init = init + }; + +-const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +-{ +- interface = itf; +- NOTICE(interface, "hello plugin comes to live"); +- return &plugin_desc; +-} +``` \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/7_LEGACY_Binding_v2_references.md b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/7_LEGACY_Binding_v2_references.md new file mode 100644 index 0000000..c790db8 --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/Annexes/7_LEGACY_Binding_v2_references.md @@ -0,0 +1,757 @@ +--- +title: LEGACY Binding V2 references +--- + +# Structure for declaring binding +--------------------------------- + +### struct afb_binding_v2 + +The main structure, of type **afb_binding_v2**, for describing the binding +must be exported under the name **afbBindingV2**. + +This structure is defined as below. + +```C +/* + * Description of the bindings of type version 2 + */ +struct afb_binding_v2 +{ + 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 */ +}; +``` + +### struct afb_verb_v2 + +Each verb is described with a structure of type **afb_verb_v2** +defined below: + +```C +/* + * Description of one verb of the API provided by the binding + * This enumeration is valid for bindings of type version 2 + */ +struct afb_verb_v2 +{ + 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 */ +}; +``` + +The **session** flags is one of the constant defined below: + +- AFB_SESSION_NONE : no flag, synonym to 0 +- AFB_SESSION_LOA_0 : Requires the LOA to be 0 or more, synonym to 0 or AFB_SESSION_NONE +- AFB_SESSION_LOA_1 : Requires the LOA to be 1 or more +- AFB_SESSION_LOA_2 : Requires the LOA to be 2 or more +- 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 + +The LOA (Level Of Assurance) is set, by binding, using the function **afb_req_session_set_LOA**. + +### struct afb_auth and enum afb_auth_type + +The structure **afb_auth** is used within verb description to +set security requirements. +The interpretation of the structure depends on the value of the field **type**. + +```C +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; +}; +``` + +The possible values for **type** is defined here: + +```C +/* + * Enum for Session/Token/Assurance middleware. + */ +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 */ +}; +``` + +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] } +}; +``` + +## Functions of class afb_daemon + +The 3 following functions are linked to libsystemd. +They allow use of **sd_event** features and access +to **sd_bus** features. + +```C +/* + * 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 + */ +struct sd_bus *afb_daemon_get_user_bus(); + +/* + * Retrieves the common systemd's system d-bus of AFB + */ +struct sd_bus *afb_daemon_get_system_bus(); +``` + +The 2 following functions are linked to event management. +Broadcasting an event send it to any possible listener. + +```C +/* + * 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. + */ +int afb_daemon_broadcast_event(const char *name, struct json_object *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. + */ +struct afb_event afb_daemon_make_event(const char *name); +``` + +The following function is used by logging macros and should normally +not be used. +Instead, you should use the macros: + +- **AFB\_ERROR** +- **AFB\_WARNING** +- **AFB\_NOTICE** +- **AFB\_INFO** +- **AFB\_DEBUG** + +```C +/* + * 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 + */ +void afb_daemon_verbose(int level, const char *file, int line, const char * func, const char *fmt, ...); +``` + +The 2 following functions MUST be used to access data of the bindings. + +```C +/* + * Get the root directory file descriptor. This file descriptor can + * be used with functions 'openat', 'fstatat', ... + */ +int afb_daemon_rootdir_get_fd(); + +/* + * 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. + */ +int afb_daemon_rootdir_open_locale(const char *filename, int flags, const char *locale); +``` + +The following function is used to queue jobs. + +```C +/* + * 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 re-executed but with + * signum being the signal number (SIGALRM when timeout expired). + * + * Returns 0 in case of success or -1 in case of error. + */ +int afb_daemon_queue_job(void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) +``` + +The following function must be used when a binding depends on other +bindings at its initialization. + +```C +/* + * 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. + */ +int afb_daemon_require_api(const char *name, int initialized) +``` + +This function allows to give a different name to the binding. +It can be called during pre-init. + +```C +/* + * 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. + */ +int afb_daemon_rename_api(const char *name); +``` + +## Functions of class afb_service + +The following functions allow services to call verbs of other +bindings for themselves. + +```C +/** + * 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 occurred, + * 2. 'result' the resulting data as a JSON object. + * + * @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' + */ +void afb_service_call( + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*closure, int status, struct json_object *result), + void *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 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' + */ +int afb_service_call_sync( + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); +``` + +## Functions of class afb_event + +This function checks whether the event is valid. +It must be used when creating events. + +```C +/* + * Checks wether the 'event' is valid or not. + * + * Returns 0 if not valid or 1 if valid. + */ +int afb_event_is_valid(struct afb_event event); +``` + +The two following functions are used to broadcast or push +event with its data. + +```C +/* + * Broadcasts widely the '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. + * + * Returns the count of clients that received the event. + */ +int afb_event_broadcast(struct afb_event event, struct json_object *object); + +/* + * Pushes the '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. + * + * Returns the count of clients that received the event. + */ +int afb_event_push(struct afb_event event, struct json_object *object); +``` + +The following function destroys the event. + +```C +/* + * Drops the data associated to the 'event' + * After calling this function, the event + * MUST NOT BE USED ANYMORE. + */ +void afb_event_drop(struct afb_event event); +``` + +This function allows to retrieve the exact name of the event. + +```C +/* + * Gets the name associated to the 'event'. + */ +const char *afb_event_name(struct afb_event event); +``` + +## Functions of class afb_req + +This function checks the validity of the **req**. + +```C +/* + * Checks wether the request 'req' is valid or not. + * + * Returns 0 if not valid or 1 if valid. + */ +int afb_req_is_valid(struct afb_req req); +``` + +The following functions retrieves parameters of the request. + +```C +/* + * 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. + */ +struct afb_arg afb_req_get(struct afb_req req, const char *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_get(req, name).value + */ +const char *afb_req_value(struct afb_req req, const char *name); + +/* + * 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 + */ +const char *afb_req_path(struct afb_req 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); +``` + +The following functions emit the reply to the request. + +```C +/* + * Sends a reply of kind success to the request 'req'. + * The status of the reply is automatically set to "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. + */ +void afb_req_success(struct afb_req req, struct json_object *obj, const char *info); + +/* + * Same as 'afb_req_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. + */ +void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...); + +/* + * Same as 'afb_req_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. + */ +void afb_req_success_v(struct afb_req 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 + * 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); + +/* + * 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, ...); + +/* + * 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); +``` + +The following functions handle the session data. + +```C +/* + * 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); + +/* + * 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*)); + +/* + * 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'. + */ +void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*)); + +/* + * 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) + */ +void afb_req_context_clear(struct afb_req req); + +/* + * Closes the session associated with 'req' + * and delete all associated contexts. + */ +void afb_req_session_close(struct afb_req req); + +/* + * 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. + */ +int afb_req_session_set_LOA(struct afb_req req, unsigned level); +``` + +The 4 following functions must be used for asynchronous handling requests. + +```C +/* + * 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. + */ +void afb_req_addref(struct afb_req 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); + +/* + * Stores 'req' on heap for asynchronous 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). + */ +struct afb_stored_req *afb_req_store(struct afb_req req); + +/* + * 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. + */ +struct afb_req afb_req_unstore(struct afb_stored_req *sreq); +``` + +The two following functions are used to associate client with events +(subscription). + +```C +/* + * 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. + */ +int afb_req_subscribe(struct afb_req req, struct afb_event 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); +``` + +The following functions must be used to make request in the name of the +client (with its permissions). + +```C +/* + * 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. + * + * See also: + * - 'afb_req_subcall_req' that is convenient to keep request alive automatically. + * - 'afb_req_subcall_sync' the synchronous version + */ +void afb_req_subcall( + struct afb_req req, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void *closure, int status, struct json_object *result), + void *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'. + * On completion, the function 'callback' is invoked with the + * original request 'req', 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_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) +{ + req.itf->subcall_req(req.closure, 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 'req'. + * This call is synchronous, it waits until 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_req_subcall_req' that is convenient to keep request alive automatically. + * - 'afb_req_subcall' that doesn't keep request alive automatically. + */ +int afb_req_subcall_sync( + struct afb_req req, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); +``` + +The following function is used by logging macros and should normally +not be used. +Instead, you should use the macros: + +- **AFB_REQ_ERROR** +- **AFB_REQ_WARNING** +- **AFB_REQ_NOTICE** +- **AFB_REQ_INFO** +- **AFB_REQ_DEBUG** + +```C +/* + * 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 + */ +void afb_req_verbose(struct afb_req 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 +to explicitly check a permission of a client or to get the calling +application identity. + +```C +/* + * Check whether the 'permission' is granted or not to the client + * identified by 'req'. + * + * Returns 1 if the permission is granted or 0 otherwise. + */ +int afb_req_has_permission(struct afb_req req, const char *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 + */ +char *afb_req_get_application_id(struct afb_req req); + +/* + * Get the user identifier (UID) of the client application for the + * request 'req'. + * + * Returns -1 when the application can not be identified. + */ +int afb_req_get_uid(struct afb_req req); +``` + +## Logging macros + +The following macros must be used for logging: + +```C +AFB_ERROR(fmt,...) +AFB_WARNING(fmt,...) +AFB_NOTICE(fmt,...) +AFB_INFO(fmt,...) +AFB_DEBUG(fmt,...) +``` + +The following macros can be used for logging in the context +of a request **req** of type **afb_req**: + +```C +AFB_REQ_ERROR(req,fmt,...) +AFB_REQ_WARNING(req,fmt,...) +AFB_REQ_NOTICE(req,fmt,...) +AFB_REQ_INFO(req,fmt,...) +AFB_REQ_DEBUG(req,fmt,...) +``` + +By default, the logging macros add file, line and function +indication. \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/basis.svg b/docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/basis.svg new file mode 100644 index 0000000..0d42d76 --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/basis.svg @@ -0,0 +1,356 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + APPLICATION + + + + + + + + BINDERafb-daemon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + SECURITYCONTEXT + + + + + + http + + + + + + ws + + + + + + + + \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/interconnection.svg b/docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/interconnection.svg new file mode 100644 index 0000000..4a10217 --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/interconnection.svg @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + APPLICATION + + + + + + + + BINDERafb-daemon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + SECURITYCONTEXT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + APPLICATION + + + + + + + + BINDERafb-daemon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + SECURITYCONTEXT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + APPLICATION + + + + + + + + BINDERafb-daemon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + SECURITYCONTEXT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + APPLICATION + + + + + + + + BINDERafb-daemon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + SECURITYCONTEXT + + + + + + + + + interconnectiondbus, ws,bus1, tls,... + + + + + + + + A + + + + + + + + C + + + + + + + + B + + + + + + + + D + + + + + + + + \ No newline at end of file diff --git a/docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/signaling-basis.svg b/docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/signaling-basis.svg new file mode 100644 index 0000000..b13fcf1 --- /dev/null +++ b/docs/3_Developer_Guides/2_Application_Framework_Binder/pictures/signaling-basis.svg @@ -0,0 +1,145 @@ + + + + + + + request-data + + + + + + client 1 + + + + + + + + client 2 + + + + + + + + : framework + + + + + + + + signaling agent + + + + + + + + + + + request-data + + + + + + afb_daemon_make_event + + + + + + + + + afb_req_subscribe + + + + + reply of request-data + + + + + + afb_req_subscribe + + + + + reply of request-data + + + + + + device + + + + + + + + + setup + + + + + << wake up >> + + + + + afb_event_push + + + + + << event >> + + + + + << event >> + + + + + reply of afb_event_push + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit 1.2.3-korg