From 4521c1e7ae5371ab9d639adc617d17fb4e8ded0c Mon Sep 17 00:00:00 2001 From: José Bollo Date: Mon, 9 Apr 2018 18:16:07 +0200 Subject: api-v3: First draft MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces the bindings v3 API for bindings. The documentation has still to be improved and will come very soon. Change-Id: I8f9007370e29f671fdfd1da87fff7372a17db7af Signed-off-by: José Bollo --- docs/README.md | 32 ++-- docs/REVISIONS.md | 14 ++ docs/SUMMARY.md | 9 +- docs/afb-binding-references.md | 283 ++++++++++++++++++++++++------------ docs/afb-binding-writing.md | 180 ++++++++++------------- docs/afb-daemon-debugging.md | 2 +- docs/afb-daemon-vocabulary.md | 6 +- docs/afb-migration-to-binding-v3.md | 110 ++++++++++++++ docs/afb-migration-v1-to-v2.md | 7 +- docs/afb-overview.md | 6 +- docs/annexes.md | 5 +- docs/migration-to-binding-v3.sed | 68 +++++++++ 12 files changed, 502 insertions(+), 220 deletions(-) create mode 100644 docs/REVISIONS.md create mode 100644 docs/afb-migration-to-binding-v3.md create mode 100644 docs/migration-to-binding-v3.sed (limited to 'docs') diff --git a/docs/README.md b/docs/README.md index 94dc16aa..503b8545 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,13 +1,19 @@ -Document revisions -================== - -| Date | Version | Designation  | Author | -|--------------|------------|----------------------------------------------|-------------------------------------------------------| -| 23 May 2016 | 0.9 | Initial release | J. Bollo [ IoT.bzh ]
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 ] | + +# AGL Framework Binder + +This project provides the binder component of the the microservice architecture +of Automotive Grade Linux (AGL). + +This project is available there https://git.automotivelinux.org/src/app-framework-binder/ + +It can be cloned with **git clone https://git.automotivelinux.org/src/app-framework-binder**. + +## License and copying + +This software is an open source software funded by LinuxFoundation and Renesas. + +This software is delivered under the terms of the open source license Apache 2. + +This license is available in the file LICENSE-2.0.txt or on the worl wide web at the +location https://opensource.org/licenses/Apache-2.0 + diff --git a/docs/REVISIONS.md b/docs/REVISIONS.md new file mode 100644 index 00000000..00787b02 --- /dev/null +++ b/docs/REVISIONS.md @@ -0,0 +1,14 @@ +Document revisions +================== + +| Date | Version | Designation  | Author | +|--------------|:----------:|----------------------------------------------|-------------------------------------------------------| +| 23 May 2016 | 0.9 | Initial release | J. Bollo [ IoT.bzh ]
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/SUMMARY.md b/docs/SUMMARY.md index 44b06f8d..580660ea 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,14 +1,15 @@ # Summary -* [Document revisions](README.md) * [Binder Overview](afb-introduction.md) +* [Binder daemon vocabulary](afb-daemon-vocabulary.md) * [How to write a binding ?](afb-binding-writing.md) * [Binding references](afb-binding-references.md) -* [Migration from v1 to v2](afb-migration-v1-to-v2.md) * [Binder events guide](afb-events-guide.md) * [Binder Application writing guide](afb-application-writing.md) -* [Binder daemon vocabulary](afb-daemon-vocabulary.md) * [Annexes](annexes.md) + * [Migration to binding v3](afb-migration-to-binding-v3.md) * [Installing the binder on a desktop](afb-desktop-package.md) * [Options of afb-daemon](afb-daemon-options.md) - * [Debugging afb-daemon](afb-daemon-debugging.md) + * [Debugging binder and bindings](afb-daemon-debugging.md) + * [(LEGACY) guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md) +* [Document revisions](REVISIONS.md) diff --git a/docs/afb-binding-references.md b/docs/afb-binding-references.md index 0e30ffe7..4ff0f042 100644 --- a/docs/afb-binding-references.md +++ b/docs/afb-binding-references.md @@ -2,47 +2,98 @@ ## Structure for declaring binding -### struct afb_binding_v2 +### afb_binding_t -The main structure, of type **afb_binding_v2**, for describing the binding -must be exported under the name **afbBindingV2**. +The main structure, of type **afb_binding_t**, for describing the binding +must be exported under the name **afbBindingExport**. This structure is defined as below. ```C -/* - * Description of the bindings of type version 2 +typedef struct afb_binding_v3 afb_binding_t; +``` + +Where: + +```C +/** + * Description of the bindings of type version 3 */ -struct afb_binding_v2 +struct afb_binding_v3 { - const char *api; /* api name for the binding */ - const char *specification; /* textual openAPIv3 specification of the binding */ - const char *info; /* some info about the api, can be NULL */ - const struct afb_verb_v2 *verbs; /* array of descriptions of verbs terminated by a NULL name */ - int (*preinit)(); /* callback at load of the binding */ - int (*init)(); /* callback for starting the service */ - void (*onevent)(const char *event, struct json_object *object); /* callback for handling events */ - unsigned noconcurrency: 1; /* avoids concurrent requests to verbs */ + /** api name for the binding, can't be NULL */ + const char *api; + + /** textual specification of the binding, can be NULL */ + const char *specification; + + /** some info about the api, can be NULL */ + const char *info; + + /** array of descriptions of verbs terminated by a NULL name, can be NULL */ + const struct afb_verb_v3 *verbs; + + /** callback at load of the binding */ + int (*preinit)(struct afb_api_x3 *api); + + /** callback for starting the service */ + int (*init)(struct afb_api_x3 *api); + + /** callback for handling events */ + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object); + + /** userdata for afb_api_x3 */ + void *userdata; + + /** space separated list of provided class(es) */ + const char *provide_class; + + /** space separated list of required class(es) */ + const char *require_class; + + /** space separated list of required API(es) */ + const char *require_api; + + /** avoids concurrent requests to verbs */ + unsigned noconcurrency: 1; }; ``` -### struct afb_verb_v2 +### struct afb_verb_t -Each verb is described with a structure of type **afb_verb_v2** +Each verb is described with a structure of type **afb_verb_t** defined below: ```C -/* - * Description of one verb of the API provided by the binding - * This enumeration is valid for bindings of type version 2 +typedef struct afb_verb_v3 afb_verb_t; +``` + +```C +/** + * Description of one verb as provided for binding API version 3 */ -struct afb_verb_v2 +struct afb_verb_v3 { - const char *verb; /* name of the verb */ - void (*callback)(struct afb_req req); /* callback function implementing the verb */ - const struct afb_auth *auth; /* required authorization */ - const char *info; /* some info about the verb, can be NULL */ - uint32_t session; /* authorization and session requirements of the verb */ + /** name of the verb, NULL only at end of the array */ + const char *verb; + + /** callback function implementing the verb */ + void (*callback)(afb_req_t_x2 *req); + + /** required authorization, can be NULL */ + const struct afb_auth *auth; + + /** some info about the verb, can be NULL */ + const char *info; + + /**< data for the verb callback */ + void *vcbdata; + + /** authorization and session requirements of the verb */ + uint16_t session; + + /** is the verb glob name */ + uint16_t glob: 1; }; ``` @@ -55,55 +106,91 @@ The **session** flags is one of the constant defined below: - AFB_SESSION_LOA_3 : Requires the LOA to be 3 or more - AFB_SESSION_CHECK : Requires the token to be set and valid - AFB_SESSION_REFRESH : Implies a token refresh -- AFB_SESSION_CLOSE : Implies cloing the session +- AFB_SESSION_CLOSE : Implies closing the session after request processed -The LOA (Level Of Assurance) is set, by binding, using the function **afb_req_session_set_LOA**. +The LOA (Level Of Assurance) is set, by binding api, using the function **afb_req_session_set_LOA**. -### struct afb_auth and enum afb_auth_type +The session can be closed, by binding api, using the function **afb_req_session_close**. -The structure **afb_auth** is used within verb description to +### afb_auth_t and afb_auth_type_t + +The structure **afb_auth_t** is used within verb description to set security requirements. The interpretation of the structure depends on the value of the field **type**. ```C +typedef struct afb_auth afb_auth_t; + +/** + * Definition of an authorization entry + */ struct afb_auth { - const enum afb_auth_type type; - union { - const char *text; - const unsigned loa; - const struct afb_auth *first; - }; - const struct afb_auth *next; + /** type of entry @see afb_auth_type */ + enum afb_auth_type type; + + union { + /** text when @ref type == @ref afb_auth_Permission */ + const char *text; + + /** level of assurancy when @ref type == @ref afb_auth_LOA */ + unsigned loa; + + /** first child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And, @ref afb_auth_Not } */ + const struct afb_auth *first; + }; + + /** second child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And } */ + const struct afb_auth *next; }; + ``` The possible values for **type** is defined here: ```C -/* - * Enum for Session/Token/Assurance middleware. +typedef enum afb_auth_type afb_auth_type_t; + +/** + * Enumeration for authority (Session/Token/Assurance) definitions. + * + * @see afb_auth */ enum afb_auth_type { - afb_auth_No = 0, /** never authorized, no data */ - afb_auth_Token, /** authorized if token valid, no data */ - afb_auth_LOA, /** authorized if LOA greater than data 'loa' */ - afb_auth_Permission, /** authorized if permission 'text' is granted */ - afb_auth_Or, /** authorized if 'first' or 'next' is authorized */ - afb_auth_And, /** authorized if 'first' and 'next' are authorized */ - afb_auth_Not, /** authorized if 'first' is not authorized */ - afb_auth_Yes /** always authorized, no data */ + /** never authorized, no data */ + afb_auth_No = 0, + + /** authorized if token valid, no data */ + afb_auth_Token, + + /** authorized if LOA greater than data 'loa' */ + afb_auth_LOA, + + /** authorized if permission 'text' is granted */ + afb_auth_Permission, + + /** authorized if 'first' or 'next' is authorized */ + afb_auth_Or, + + /** authorized if 'first' and 'next' are authorized */ + afb_auth_And, + + /** authorized if 'first' is not authorized */ + afb_auth_Not, + + /** always authorized, no data */ + afb_auth_Yes }; ``` Example: ```C -static const struct afb_auth _afb_auths_v2_monitor[] = { - { .type = afb_auth_Permission, .text = "urn:AGL:permission:monitor:public:set" }, - { .type = afb_auth_Permission, .text = "urn:AGL:permission:monitor:public:get" }, - { .type = afb_auth_Or, .first = &_afb_auths_v2_monitor[1], .next = &_afb_auths_v2_monitor[0] } +static const afb_auth_t myauth[] = { + { .type = afb_auth_Permission, .text = "urn:AGL:permission:me:public:set" }, + { .type = afb_auth_Permission, .text = "urn:AGL:permission:me:public:get" }, + { .type = afb_auth_Or, .first = &myauth[1], .next = &myauth[0] } }; ``` @@ -115,17 +202,18 @@ to **sd_bus** features. ```C /* - * Retrieves the common systemd's event loop of AFB + * Retrieves the common systemd's event loop of AFB + * */ struct sd_event *afb_daemon_get_event_loop(); /* - * Retrieves the common systemd's user/session d-bus of AFB + * Retrieves the common systemd's user/session d-bus of AFB if active */ struct sd_bus *afb_daemon_get_user_bus(); /* - * Retrieves the common systemd's system d-bus of AFB + * Retrieves the common systemd's system d-bus of AFB if active or NULL */ struct sd_bus *afb_daemon_get_system_bus(); ``` @@ -155,7 +243,7 @@ int afb_daemon_broadcast_event(const char *name, struct json_object *object); * * See afb_event_is_valid to check if there is an error. */ -struct afb_event afb_daemon_make_event(const char *name); +afb_event_t afb_daemon_make_event(const char *name); ``` The following function is used by logging macros and should normally @@ -319,7 +407,7 @@ It must be used when creating events. * * Returns 0 if not valid or 1 if valid. */ -int afb_event_is_valid(struct afb_event event); +int afb_event_is_valid(afb_event_t event); ``` The two following functions are used to broadcast or push @@ -336,7 +424,7 @@ event with its data. * * Returns the count of clients that received the event. */ -int afb_event_broadcast(struct afb_event event, struct json_object *object); +int afb_event_broadcast(afb_event_t event, struct json_object *object); /* * Pushes the 'event' with the data 'object' to its observers. @@ -348,18 +436,29 @@ int afb_event_broadcast(struct afb_event event, struct json_object *object); * * Returns the count of clients that received the event. */ -int afb_event_push(struct afb_event event, struct json_object *object); +int afb_event_push(afb_event_t event, struct json_object *object); +``` + +The following function remove one reference to the event. + +```C +/* + * Decrease the reference count of the event. + * After calling this function, the event + * MUST NOT BE USED ANYMORE. + */ +void afb_event_unref(afb_event_t event); ``` -The following function destiys the event. +The following function add one reference to the event. ```C /* - * Drops the data associated to the 'event' + * Decrease the reference count of the event. * After calling this function, the event * MUST NOT BE USED ANYMORE. */ -void afb_event_drop(struct afb_event event); +void afb_event_unref(afb_event_t event); ``` This function allows to retrieve the exact name of the event. @@ -368,7 +467,7 @@ This function allows to retrieve the exact name of the event. /* * Gets the name associated to the 'event'. */ -const char *afb_event_name(struct afb_event event); +const char *afb_event_name(afb_event_t event); ``` ## Functions of class afb_req @@ -381,7 +480,7 @@ This function checks the validity of the **req**. * * Returns 0 if not valid or 1 if valid. */ -int afb_req_is_valid(struct afb_req req); +int afb_req_is_valid(afb_req_t req); ``` The following functions retrieves parameters of the request. @@ -399,7 +498,7 @@ The following functions retrieves parameters of the request. * an HTTP POST of Content-Type "application/json". In that case, the * argument of name "" receives the value of the body of the HTTP request. */ -struct afb_arg afb_req_get(struct afb_req req, const char *name); +afb_arg_t afb_req_get(afb_req_t req, const char *name); /* * Gets from the request 'req' the string value of the argument of 'name'. @@ -408,7 +507,7 @@ struct afb_arg afb_req_get(struct afb_req req, const char *name); * * Shortcut for: afb_req_get(req, name).value */ -const char *afb_req_value(struct afb_req req, const char *name); +const char *afb_req_value(afb_req_t req, const char *name); /* * Gets from the request 'req' the path for file attached to the argument of 'name'. @@ -417,13 +516,13 @@ const char *afb_req_value(struct afb_req req, const char *name); * * Shortcut for: afb_req_get(req, name).path */ -const char *afb_req_path(struct afb_req req, const char *name); +const char *afb_req_path(afb_req_t req, const char *name); /* * Gets from the request 'req' the json object hashing the arguments. * The returned object must not be released using 'json_object_put'. */ -struct json_object *afb_req_json(struct afb_req req); +struct json_object *afb_req_json(afb_req_t req); ``` The following functions emit the reply to the request. @@ -439,7 +538,7 @@ The following functions emit the reply to the request. * Thus, in the case where 'obj' should remain available after * the function returns, the function 'json_object_get' shall be used. */ -void afb_req_success(struct afb_req req, struct json_object *obj, const char *info); +void afb_req_success(afb_req_t req, struct json_object *obj, const char *info); /* * Same as 'afb_req_success' but the 'info' is a formatting @@ -449,7 +548,7 @@ void afb_req_success(struct afb_req req, struct json_object *obj, const char *in * Thus, in the case where 'obj' should remain available after * the function returns, the function 'json_object_get' shall be used. */ -void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...); +void afb_req_success_f(afb_req_t req, struct json_object *obj, const char *info, ...); /* * Same as 'afb_req_success_f' but the arguments to the format 'info' @@ -459,30 +558,30 @@ void afb_req_success_f(struct afb_req req, struct json_object *obj, const char * * Thus, in the case where 'obj' should remain available after * the function returns, the function 'json_object_get' shall be used. */ -void afb_req_success_v(struct afb_req req, struct json_object *obj, const char *info, va_list args); +void afb_req_success_v(afb_req_t req, struct json_object *obj, const char *info, va_list args); /* * Sends a reply of kind failure to the request 'req'. * The status of the reply is set to 'status' and an - * informationnal comment 'info' (can also be NULL) can be added. + * informational comment 'info' (can also be NULL) can be added. * * Note that calling afb_req_fail("success", info) is equivalent * to call afb_req_success(NULL, info). Thus even if possible it * is strongly recommended to NEVER use "success" for status. */ -void afb_req_fail(struct afb_req req, const char *status, const char *info); +void afb_req_fail(afb_req_t req, const char *status, const char *info); /* * Same as 'afb_req_fail' but the 'info' is a formatting * string followed by arguments. */ -void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...); +void afb_req_fail_f(afb_req_t req, const char *status, const char *info, ...); /* * Same as 'afb_req_fail_f' but the arguments to the format 'info' * are given as a variable argument list instance. */ -void afb_req_fail_v(struct afb_req req, const char *status, const char *info, va_list args); +void afb_req_fail_v(afb_req_t req, const char *status, const char *info, va_list args); ``` The following functions handle the session data. @@ -492,14 +591,14 @@ The following functions handle the session data. * Gets the pointer stored by the binding for the session of 'req'. * When the binding has not yet recorded a pointer, NULL is returned. */ -void *afb_req_context_get(struct afb_req req); +void *afb_req_context_get(afb_req_t req); /* * Stores for the binding the pointer 'context' to the session of 'req'. * The function 'free_context' will be called when the session is closed * or if binding stores an other pointer. */ -void afb_req_context_set(struct afb_req req, void *context, void (*free_context)(void*)); +void afb_req_context_set(afb_req_t req, void *context, void (*free_context)(void*)); /* * Gets the pointer stored by the binding for the session of 'req'. @@ -508,7 +607,7 @@ void afb_req_context_set(struct afb_req req, void *context, void (*free_context) * the function 'create_context' and stores it with the freeing function * 'free_context'. */ -void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*)); +void *afb_req_context(afb_req_t req, void *(*create_context)(), void (*free_context)(void*)); /* * Frees the pointer stored by the binding for the session of 'req' @@ -516,13 +615,13 @@ void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free * * Shortcut for: afb_req_context_set(req, NULL, NULL) */ -void afb_req_context_clear(struct afb_req req); +void afb_req_context_clear(afb_req_t req); /* * Closes the session associated with 'req' * and delete all associated contexts. */ -void afb_req_session_close(struct afb_req req); +void afb_req_session_close(afb_req_t req); /* * Sets the level of assurance of the session of 'req' @@ -530,7 +629,7 @@ void afb_req_session_close(struct afb_req req); * security policies. * Returns 1 on success or 0 if failed. */ -int afb_req_session_set_LOA(struct afb_req req, unsigned level); +int afb_req_session_set_LOA(afb_req_t req, unsigned level); ``` The 4 following functions must be used for asynchronous handling requests. @@ -541,14 +640,14 @@ The 4 following functions must be used for asynchronous handling requests. * This function MUST be called by asynchronous implementations * of verbs if no reply was sent before returning. */ -void afb_req_addref(struct afb_req req); +void afb_req_addref(afb_req_t req); /* * Substracts one to the count of references of 'req'. * This function MUST be called by asynchronous implementations * of verbs after sending the asynchronous reply. */ -void afb_req_unref(struct afb_req req); +void afb_req_unref(afb_req_t req); /* * Stores 'req' on heap for asynchronous use. @@ -556,7 +655,7 @@ void afb_req_unref(struct afb_req req); * The count of reference to 'req' is incremented on success * (see afb_req_addref). */ -struct afb_stored_req *afb_req_store(struct afb_req req); +struct afb_stored_req *afb_req_store(afb_req_t req); /* * Retrieves the afb_req stored at 'sreq'. @@ -565,7 +664,7 @@ struct afb_stored_req *afb_req_store(struct afb_req req); * function 'afb_req_unref' should be called on the result * after that the asynchronous reply if sent. */ -struct afb_req afb_req_unstore(struct afb_stored_req *sreq); +afb_req_t afb_req_unstore(struct afb_stored_req *sreq); ``` The two following functions are used to associate client with events @@ -577,14 +676,14 @@ The two following functions are used to associate client with events * to the 'event'. * Returns 0 in case of successful subscription or -1 in case of error. */ -int afb_req_subscribe(struct afb_req req, struct afb_event event); +int afb_req_subscribe(afb_req_t req, afb_event_t event); /* * Revokes the subscription established to the 'event' for the client * link identified by 'req'. * Returns 0 in case of successful subscription or -1 in case of error. */ -int afb_req_unsubscribe(struct afb_req req, struct afb_event event); +int afb_req_unsubscribe(afb_req_t req, afb_event_t event); ``` The following functions must be used to make request in the name of the @@ -609,7 +708,7 @@ client (with its permissions). * - 'afb_req_subcall_sync' the synchronous version */ void afb_req_subcall( - struct afb_req req, + afb_req_t req, const char *api, const char *verb, struct json_object *args, @@ -634,7 +733,7 @@ void afb_req_subcall( * - 'afb_req_subcall' that doesn't keep request alive automatically. * - 'afb_req_subcall_sync' the synchronous version */ -static inline void afb_req_subcall_req(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req req), void *closure) +static inline void afb_req_subcall_req(afb_req_t req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, afb_req_t req), void *closure) { req.itf->subcall_req(req.closure, api, verb, args, callback, closure); } @@ -656,7 +755,7 @@ static inline void afb_req_subcall_req(struct afb_req req, const char *api, cons * - 'afb_req_subcall' that doesn't keep request alive automatically. */ int afb_req_subcall_sync( - struct afb_req req, + afb_req_t req, const char *api, const char *verb, struct json_object *args, @@ -691,7 +790,7 @@ Instead, you should use the macros: * INFO 6 Informational * DEBUG 7 Debug-level messages */ -void afb_req_verbose(struct afb_req req, int level, const char *file, int line, const char * func, const char *fmt, ...); +void afb_req_verbose(afb_req_t req, int level, const char *file, int line, const char * func, const char *fmt, ...); ``` The functions below allow a binding involved in the platform security @@ -705,7 +804,7 @@ application identity. * * Returns 1 if the permission is granted or 0 otherwise. */ -int afb_req_has_permission(struct afb_req req, const char *permission); +int afb_req_has_permission(afb_req_t req, const char *permission); /* * Get the application identifier of the client application for the @@ -716,7 +815,7 @@ int afb_req_has_permission(struct afb_req req, const char *permission); * * The returned value if not NULL must be freed by the caller */ -char *afb_req_get_application_id(struct afb_req req); +char *afb_req_get_application_id(afb_req_t req); /* * Get the user identifier (UID) of the client application for the @@ -724,7 +823,7 @@ char *afb_req_get_application_id(struct afb_req req); * * Returns -1 when the application can not be identified. */ -int afb_req_get_uid(struct afb_req req); +int afb_req_get_uid(afb_req_t req); ``` ## Logging macros diff --git a/docs/afb-binding-writing.md b/docs/afb-binding-writing.md index aad422c4..69090e3d 100644 --- a/docs/afb-binding-writing.md +++ b/docs/afb-binding-writing.md @@ -51,14 +51,21 @@ The binder makes no distinctions between upper case and lower case latin letters. So **API/VERB** matches **Api/Verb** or **api/verb**. -Actually it exists 2 ways of writing ***bindings***. +## Versions of the bindings + +Since introduction of the binder, the way how bindings are written +evolved a little. While changing, attention was made to ensure binary +compatibility between the different versions. + +Actually it exists 3 ways of writing ***bindings***. You can either write: -- a binding version 1 (not recommended); -- a binding version 2 (RECOMMENDED). +- a binding version 1 (not more supported); +- a binding version 2 (not recommended); +- a binding version 3 (RECOMMENDED). A ***binder*** loads and runs any of these version in any combination. -This document explain how to write bindings version 2. +This document explain how to write bindings version 3. @@ -67,21 +74,21 @@ This document explain how to write bindings version 2. This is the code of the binding **tuto-1.c**: ```C - 1 #define AFB_BINDING_VERSION 2 + 1 #define AFB_BINDING_VERSION 3 2 #include 3 - 4 void hello(afb_req req) + 4 void hello(afb_req_t req) 5 { 6 AFB_REQ_DEBUG(req, "hello world"); - 7 afb_req_success(req, NULL, "hello world"); + 7 afb_req_reply(req, NULL, NULL, "hello world"); 8 } 9 - 10 const afb_verb_v2 verbs[] = { + 10 const afb_verb_t verbs[] = { 11 { .verb="hello", .callback=hello }, 12 { .verb=NULL } 13 }; 14 - 15 const afb_binding_v2 afbBindingV2 = { + 15 const afb_binding_t afbBindingExport = { 16 .api = "tuto-1", 17 .verbs = verbs 18 }; @@ -93,12 +100,18 @@ Compiling: gcc -fPIC -shared tuto-1.c -o tuto-1.so $(pkg-config --cflags-only-I afb-daemon) ``` +> Note: the variable environment variable PKG_CONFIG_PATH might be necessary +> tuned to get **pkg-config** working properly + Running: ```bash afb-daemon --binding tuto-1.so --port 3333 --token '' ``` +At this point, afb-daemon has started, it loaded the binding tuto-1.so and now +listen at localhost on the port 3333. + Testing using **curl**: ```bash @@ -133,18 +146,15 @@ This shows basic things: The lines 1 and 2 show how to get the include file **afb-binding.h**. ```C - 1 #define AFB_BINDING_VERSION 2 + 1 #define AFB_BINDING_VERSION 3 2 #include ``` -You must define the version of ***binding*** that you are using. -This is done line 1 where we define that this is the version 2. +You must define the version of ***binding*** that you are using. +This is done line 1 where we define that this is the version 3 (earlier +versions 1 and 2 are deprecated). -If you don't define it, a warning message is prompted by the compiler -and the version is switched to version 1. -This behaviour is temporarily and enables to continue to use previously written -***binding*** without change but it will change in some future when -***bindings*** V1 will become obsoletes. +If you don't define it, an error is reported and the compilation aborts. To include **afb-binding.h** successfully, the include search path should be set correctly if needed (not needed only if installed in @@ -156,81 +166,54 @@ Setting the include path is easy using **pkg-config**: pkg-config --cflags-only-I afb-daemon ``` -Note for **C++** developers: - -- The ***binder*** currently expose only **C** language **API**. - The file **afb/afb-binding.h** isn't **C++** ready. - -You should use the construct **extern "C"** as below: +> Note for **C++** developers: +> +> The ***binder*** currently expose a draft version of **C++** api. +> To get it include the file <**afb/afb-binding**> (without **.h**). -```C - #define AFB_BINDING_VERSION 2 - extern "C" { - #include - } -``` - -Future version of the ***binder*** will include a **C++** -interface. -Until it is available, please, use the above construct. ### Declaring the API of the binding Lines 10 to 18 show the declaration of the ***binding***. -The ***binder*** knows that this is a ***binding*** version 2 because -it finds the exported symbol **afbBindingV2** that is expected to be -a structure of type **afb_binding_v2**. +The ***binder*** knows that this is a ***binding*** because +it finds the exported symbol **afbBindingExport** that is expected to be +a structure of type **afb_binding_t**. ```C - 10 const afb_verb_v2 verbs[] = { + 10 const afb_verb_t verbs[] = { 11 { .verb="hello", .callback=hello }, 12 { .verb=NULL } 13 }; 14 - 15 const afb_binding_v2 afbBindingV2 = { + 15 const afb_binding_t afbBindingExport = { 16 .api = "tuto-1", 17 .verbs = verbs 18 }; ``` -The structure **afbBindingV2** actually tells that: +The structure **afbBindingExport** actually tells that: - the exported **API** name is **tuto-1** (line 16) - the array of verbs is the above defined one -The exported list of verb is specified by an array of structures, -each describing a verb, ended with a verb NULL (line 12). +The exported list of verb is specified by an array of structures of +type **afb_verb_t**, each describing a verb, ended with a verb NULL (line 12). The only defined verb here (line 11) is named **hello** (field **.verb**) and the function that handle the related request is **hello** (field **.callback**). -Note that you can explicitly mark the fact that these are -struct by typing the **struct** as below: - -```C - 10 const struct afb_verb_v2 verbs[] = { - 11 { .verb="hello", .callback=hello }, - 12 { .verb=NULL } - 13 }; - 14 - 15 const struct afb_binding_v2 afbBindingV2 = { - 16 .api = "tuto-1", - 17 .verbs = verbs - 18 }; -``` - ### Handling binder's requests As shown above this is by default the common include directory where the AGL stuff is installed. ```C - 4 void hello(afb_req req) + 4 void hello(afb_req_t req) 5 { 6 AFB_REQ_DEBUG(req, "hello world"); - 7 afb_req_success(req, NULL, "hello world"); + 7 afb_req_reply(req, NULL, NULL, "hello world"); 8 } ``` @@ -241,18 +224,15 @@ with the argument **req** that handles the client request. The callback has to treat synchronously or asynchronously the request and should at the end emit a reply for the request. -Here, the callback for **tuto-1/hello** replies a successful answer -(line 7) to the request **req**. -The second parameter (here NULL) is a json object that is sent to the client with the reply. -The third parameter is also sent with the reply and is a string -called info that can be used as some meta data. +At the line 7, the callback for **tuto-1/hello** replies to the request **req**. +Parameters of the reply are: -Here again, you can explicitly mark the fact that -**afb_req** is a structure by declaring **hello** as below: + 1. The first parameter is the replied request + 2. The second parameter is a json object (here NULL) + 3. The third parameter is the error string indication (here NULL: no error) + 4. The fourth parameter is an informative string (that can be NULL) that can be used to provide meta data. -```C - 4 void hello(struct afb_req req) -``` +The 3 last parameters are sent back to the client as the reply content. @@ -268,43 +248,43 @@ This is the code of the binding **tuto-2.c**: ```C 1 #include 2 #include - 3 - 4 #define AFB_BINDING_VERSION 2 + 3 + 4 #define AFB_BINDING_VERSION 3 5 #include - 6 - 7 afb_event event_login, event_logout; - 8 - 9 void login(afb_req req) + 6 + 7 afb_event_t event_login, event_logout; + 8 + 9 void login(afb_req_t req) 10 { 11 json_object *args, *user, *passwd; 12 char *usr; - 13 + 13 14 args = afb_req_json(req); 15 if (!json_object_object_get_ex(args, "user", &user) 16 || !json_object_object_get_ex(args, "password", &passwd)) { 17 AFB_REQ_ERROR(req, "login, bad request: %s", json_object_get_string(args)); - 18 afb_req_fail(req, "bad-request", NULL); + 18 afb_req_reply(req, NULL, "bad-request", NULL); 19 } else if (afb_req_context_get(req)) { 20 AFB_REQ_ERROR(req, "login, bad state, logout first"); - 21 afb_req_fail(req, "bad-state", NULL); + 21 afb_req_reply(req, NULL, "bad-state", NULL); 22 } else if (strcmp(json_object_get_string(passwd), "please")) { 23 AFB_REQ_ERROR(req, "login, unauthorized: %s", json_object_get_string(args)); - 24 afb_req_fail(req, "unauthorized", NULL); + 24 afb_req_reply(req, NULL, "unauthorized", NULL); 25 } else { 26 usr = strdup(json_object_get_string(user)); 27 AFB_REQ_NOTICE(req, "login user: %s", usr); 28 afb_req_session_set_LOA(req, 1); 29 afb_req_context_set(req, usr, free); - 30 afb_req_success(req, NULL, NULL); + 30 afb_req_reply(req, NULL, NULL, NULL); 31 afb_event_push(event_login, json_object_new_string(usr)); 32 } 33 } - 34 - 35 void action(afb_req req) + 34 + 35 void action(afb_req_t req) 36 { 37 json_object *args, *val; 38 char *usr; - 39 + 39 40 args = afb_req_json(req); 41 usr = afb_req_context_get(req); 42 AFB_REQ_NOTICE(req, "action for user %s: %s", usr, json_object_get_string(args)); @@ -319,46 +299,46 @@ This is the code of the binding **tuto-2.c**: 51 afb_req_unsubscribe(req, event_logout); 52 } 53 } - 54 afb_req_success(req, json_object_get(args), NULL); + 54 afb_req_reply(req, json_object_get(args), NULL, NULL); 55 } - 56 - 57 void logout(afb_req req) + 56 + 57 void logout(afb_req_t req) 58 { 59 char *usr; - 60 + 60 61 usr = afb_req_context_get(req); 62 AFB_REQ_NOTICE(req, "login user %s out", usr); 63 afb_event_push(event_logout, json_object_new_string(usr)); 64 afb_req_session_set_LOA(req, 0); 65 afb_req_context_clear(req); - 66 afb_req_success(req, NULL, NULL); + 66 afb_req_reply(req, NULL, NULL, NULL); 67 } - 68 - 69 int preinit() + 68 + 69 int preinit(afb_api_t api) 70 { - 71 AFB_NOTICE("preinit"); + 71 AFB_API_NOTICE(api, "preinit"); 72 return 0; 73 } - 74 - 75 int init() + 74 + 75 int init(afb_api_t api) 76 { - 77 AFB_NOTICE("init"); - 78 event_login = afb_daemon_make_event("login"); - 79 event_logout = afb_daemon_make_event("logout"); + 77 AFB_API_NOTICE(api, "init"); + 78 event_login = afb_api_make_event(api, "login"); + 79 event_logout = afb_api_make_event(api, "logout"); 80 if (afb_event_is_valid(event_login) && afb_event_is_valid(event_logout)) 81 return 0; - 82 AFB_ERROR("Can't create events"); + 82 AFB_API_ERROR(api, "Can't create events"); 83 return -1; 84 } - 85 - 86 const afb_verb_v2 verbs[] = { + 85 + 86 const afb_verb_t verbs[] = { 87 { .verb="login", .callback=login }, 88 { .verb="action", .callback=action, .session=AFB_SESSION_LOA_1 }, 89 { .verb="logout", .callback=logout, .session=AFB_SESSION_LOA_1 }, 90 { .verb=NULL } 91 }; - 92 - 93 const afb_binding_v2 afbBindingV2 = { + 92 + 93 const afb_binding_t afbBindingExport = { 94 .api = "tuto-2", 95 .specification = NULL, 96 .verbs = verbs, diff --git a/docs/afb-daemon-debugging.md b/docs/afb-daemon-debugging.md index dd5fd64b..4cf62bea 100644 --- a/docs/afb-daemon-debugging.md +++ b/docs/afb-daemon-debugging.md @@ -1,4 +1,4 @@ -# Debugging afb-daemon and its bindings +# Debugging binder and bindings When compiled with the symbol AGL_DEVEL defined, the ***binder*** understand the 2 configuration variables: diff --git a/docs/afb-daemon-vocabulary.md b/docs/afb-daemon-vocabulary.md index 6c51f124..efe53d20 100644 --- a/docs/afb-daemon-vocabulary.md +++ b/docs/afb-daemon-vocabulary.md @@ -24,10 +24,6 @@ assurance that the services can expect from the session. The exact definition of the meaning of these levels and how to use it remains to be achieved. -## Plugin - -Old name for binding, see binding. - ## Request A request is an invocation by a client to a binding method using a message @@ -51,7 +47,7 @@ It can serve many client. Each one attached to one session. The framework establishes connection between the services and the clients. -Using DBus currently but other protocols are considered. +Using sockets currently but other protocols are considered. ## Session diff --git a/docs/afb-migration-to-binding-v3.md b/docs/afb-migration-to-binding-v3.md new file mode 100644 index 00000000..8f1e678c --- /dev/null +++ b/docs/afb-migration-to-binding-v3.md @@ -0,0 +1,110 @@ +Migration to binding V3 +======================= + +The ***binding*** interface evolved from version 1 to version 2 +for the following reasons: + +- integration of the security requirements within the bindings +- simplification of the API (after developer feedbacks) +- removal of obscure features, cleanup + +The ***binder*** can run ***bindings*** v1, v2 and/or v3 in any combination. +Thus moving from v1 or v2 to v3 is not enforced at this time. But ... + +In the face to face meeting of Karlsruhe it was decided to remove support +of bindings v1 and to deprecate the use of bindings v2. + +So at the end, **IT IS HIGHLY NEEDED TO SWITCH TO VERSION 3** + +This guide covers the migration of bindings from version 2 to version 3. + +The migration from version 1 is not treated here because bindings version 1 +are very old and probably does not exist anymore. If needed you can refer +to the old [guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md). + + +Differences between version 2 and version 3 +------------------------------------------- + +### in v3 all is api + +The version 3 introduce the concept of "API" that gather what was called before +the daemon and the service. This is the new concept that predates the 2 others. + +The concept of API is intended to allow the definition of multiple APIs +by a same "binding" (a dynamically loaded library). + +Because there is potentially several "API", the functions that were without +context in bindings version 2 need now to tell what API is consumer. + +To be compatible with version 2, the bindings v3 still have a default hidden +context: the default API named **afbBindingV3root**. + +To summarize, the functions of class **daemon** and **service** use the default +hidden API. + +It is encouraged to avoid use of functions of class **daemon** and **service**. +You should replace these implicit calls to explicit **api** calls that +reference **afbBindingV3root**. + +Same thing for the logging macros: **AFB_ERROR**, **AFB_WARNING**, +**AFB_NOTICE**, **AFB_INFO**, **AFB_DEBUG** that becomes respectively +**AFB_API_ERROR**, **AFB_API_WARNING**, **AFB_API_NOTICE**, **AFB_API_INFO**, +**AFB_API_DEBUG**. + +Example of 2 equivalent writes: + +```C + AFB_NOTICE("send stress event"); + afb_daemon_broadcast_event(stressed_event, NULL); +``` + +or + +```C + AFB_API_NOTICE(afbBindingV3root, "send stress event"); + afb_api_broadcast_event(afbBindingV3root, stressed_event, NULL); +``` + +### the reply mechanism predates success and fail + +### subcall has more power + +Task list for the migration +--------------------------- + +This task list is: + +1. Use the automatic migration procedure described below +2. Adapt the init and preinit functions +3. Consider to change to use the new reply +4. Consider to change to use the new (sub)call + +The remaining chapters explain these task with more details. + +Automatic migration! +-------------------- + +A tiny **sed** script is intended to perform a first pass on the code that +you want to upgrade. It can be down using **curl** and applied using **sed** +as below. + +```bash +BASE=https://git.automotivelinux.org/src/app-framework-binder/tree +SED=migration-to-binding-v3.sed +curl -o $SED $BASE/docs/$SED +sed -i -f $SED file1 file2 file3... +``` + +This automatic action does most of the boring job nut not all the job. +The remaining of this guide explains the missing part. + +Adapt the init and preinit functions +------------------------------------ + +Consider to change to use the new reply +--------------------------------------- + +Consider to change to use the new (sub)call +------------------------------------------- + diff --git a/docs/afb-migration-v1-to-v2.md b/docs/afb-migration-v1-to-v2.md index f3182918..9a43454e 100644 --- a/docs/afb-migration-v1-to-v2.md +++ b/docs/afb-migration-v1-to-v2.md @@ -1,6 +1,11 @@ -Migration from binding V1 to binding V2 +[LEGACY] Migration from binding V1 to binding V2 ======================================= +> LEGACY!!! IT IS NOT EXPECTED THAT YOU STILL NEED THIS GUIDE. +> +> THIS GUIDE WILL BE REMOVED IN A NEAR FUTURE + + The ***binding*** interface evolved from version 1 to version 2 for the following reasons: diff --git a/docs/afb-overview.md b/docs/afb-overview.md index 0cff24cc..2682d8d1 100644 --- a/docs/afb-overview.md +++ b/docs/afb-overview.md @@ -6,14 +6,14 @@ the services that it needs. It provides a fast way to securely offer APIs to applications written in any language and running almost anywhere. -- The ***binder*** is developed for AGL. +- The ***binder*** is developed for AGL (Automotive Grade Linux) but it is not bound to AGL. - The ***binder*** is the usual name. - The binary is named **afb-daemon**. - The name **afb-daemon** stands for ***Application Framework Binder Daemon***. The word *daemon*, here, denote the fact that the ***binder*** makes witchcraft to -connect applications to their expected services. -(note: that usually the term of daemon denotes background process but not here). +connect applications to their expected services. (note: that usually the term of +daemon denotes background process but not here). Each ***binder*** **afb-daemon** is in charge to bind one instance of an application or service to the rest of the system, applications and services. diff --git a/docs/annexes.md b/docs/annexes.md index 2304bfb0..10952e0f 100644 --- a/docs/annexes.md +++ b/docs/annexes.md @@ -1,4 +1,7 @@ # Annexes +* [Migration to binding v3](afb-migration-to-binding-v3.md) +* [Options of afb-daemon](afb-daemon-options.md) * [Installing the binder on a desktop](afb-desktop-package.md) -* [Options of afb-daemon](afb-daemon-options.md) \ No newline at end of file +* [Debugging afb-daemon](afb-daemon-debugging.md) +* [(LEGACY) guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md). diff --git a/docs/migration-to-binding-v3.sed b/docs/migration-to-binding-v3.sed new file mode 100644 index 00000000..a6682051 --- /dev/null +++ b/docs/migration-to-binding-v3.sed @@ -0,0 +1,68 @@ +####################################################################################### +# Script sed for migrating from AFB_BINDING_VERSION 2 to AFB_BINDING_VERSION 3 +# See http://docs.automotivelinux.org/docs/apis_services/en/dev/reference/af-binder/afb-migration-to-ibinding-v3.html +####################################################################################### +# update the version +# ------------------ +s:\(\:\13: + +# update common types +# ------------------- +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_req\>:afb_req_t:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_event\>:afb_event_t:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_verb_v2\>:afb_verb_t:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_binding_v2\>:afb_binding_t:g + +# update common names +# ------------------- +s:\:afbBindingExport:g + +# very special +# ------------ +s:( *afb_req_t *) *{ *NULL *, *NULL *}:NULL:g + +# special dynapi +# -------------- +s:\(\:\13: +/^[[:blank:]]*# *define *\/d +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_dynapi\>\([[:blank:]]*\)\*:afb_api_t\2:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_request\>\([[:blank:]]*\)\*:afb_req_t\2:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_eventid\>\([[:blank:]]*\)\*:afb_event_t\2:g +s:\:afbBindingV3entry:g +s:\:api:g +s:\:event:g +s:\:afb_api_make_event:g +s:\:-!&:g +s:\:afb_api_del_verb:g + +# udate legacy calls +# ------------------ +s:\:afb_req_subcall_legacy:g +s:\:afb_req_subcall_sync_legacy:g +s:\:afb_api_call_legacy:g +s:\:afb_api_call_sync_legacy:g +s:\:afb_req_addref:g +s:\ *( *\(.*\) *):\1:g +s:\ *(\):AFB_API_\1afbBindingV3root,:g + +# special app-controller +# ---------------------- +s:\<_\(AFB_SYSLOG_LEVEL_[A-Z]*\)_\>:\1:g + +# UNSAFES (uncomment it if optimistic) +# -------------- +#s:\\( *([^,]*\):afb_req_reply\1\2, NULL:g +#s:\\( *([^,]*,[^,]*\):afb_req_reply\1\2, NULL:g +# +#s:\[^)]*:&, 0:g ;# dynapi +#s:\[^)]*:&, NULL:g ;# dynapi +####################################################################################### -- cgit 1.2.3-korg