From: José Bollo Date: Mon, 29 May 2017 12:16:13 +0000 (+0200) Subject: Add 'afb_service_call_sync' function X-Git-Tag: dab_3.99.2~51 X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?p=src%2Fapp-framework-binder.git;a=commitdiff_plain;h=090379fdaf6ed1860dcff21424135ad71ead0cd2 Add 'afb_service_call_sync' function This new function allows to call features for the services synchronously. Also refactoring how are handled arguments to calls. The call to 'json_object_put' is now always done by the binder. Change-Id: I910517da75b179aeafc824da4ce29bc299711990 Signed-off-by: José Bollo --- diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c index 505aee30..6c904bde 100644 --- a/bindings/samples/HelloWorld.c +++ b/bindings/samples/HelloWorld.c @@ -182,10 +182,8 @@ static void subcall (struct afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); - else { + else afb_req_subcall(request, api, verb, object, subcallcb, afb_req_store(request)); - json_object_put(object); - } } static void subcallsync (struct afb_req request) @@ -200,13 +198,12 @@ static void subcallsync (struct afb_req request) afb_req_fail(request, "failed", "bad arguments"); else { rc = afb_req_subcall_sync(request, api, verb, object, &result); - if (rc) { + if (rc) afb_req_success(request, result, NULL); - } else { + else { afb_req_fail(request, "failed", json_object_to_json_string(result)); json_object_put(result); } - json_object_put(object); } } @@ -284,6 +281,50 @@ static void eventpush (struct afb_req request) json_object_put(object); } +static void callcb (void *prequest, int iserror, json_object *object) +{ + struct afb_req request = afb_req_unstore(prequest); + if (iserror) + afb_req_fail(request, "failed", json_object_to_json_string(object)); + else + afb_req_success(request, json_object_get(object), NULL); + afb_req_unref(request); +} + +static void call (struct afb_req request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_service_call(api, verb, object, callcb, afb_req_store(request)); +} + +static void callsync (struct afb_req request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_service_call_sync(api, verb, object, &result); + if (rc) + afb_req_success(request, result, NULL); + else { + afb_req_fail(request, "failed", json_object_to_json_string(result)); + json_object_put(result); + } + } +} + static void exitnow (struct afb_req request) { exit(0); @@ -317,6 +358,8 @@ static const struct afb_verb_v2 verbs[]= { { "eventsub", eventsub , NULL, AFB_SESSION_NONE }, { "eventunsub", eventunsub , NULL, AFB_SESSION_NONE }, { "eventpush", eventpush , NULL, AFB_SESSION_NONE }, + { "call", call , NULL, AFB_SESSION_NONE }, + { "callsync", callsync , NULL, AFB_SESSION_NONE }, { "exit", exitnow , NULL, AFB_SESSION_NONE }, { NULL} }; diff --git a/include/afb/afb-binding-v1.h b/include/afb/afb-binding-v1.h index e6f322fb..b627d5c4 100644 --- a/include/afb/afb-binding-v1.h +++ b/include/afb/afb-binding-v1.h @@ -162,70 +162,5 @@ struct afb_binding_interface_v1 #endif -/***************************************************************************************************/ - -#if AFB_BINDING_VERSION == 1 - -# define afb_binding afb_binding_v1 -# define afb_binding_interface afb_binding_interface_v1 - -# define AFB_SESSION_NONE AFB_SESSION_NONE_V1 -# define AFB_SESSION_CREATE AFB_SESSION_CREATE_V1 -# define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_V1 -# define AFB_SESSION_RENEW AFB_SESSION_RENEW_V1 -# define AFB_SESSION_CHECK AFB_SESSION_CHECK_V1 - -# define AFB_SESSION_LOA_GE AFB_SESSION_LOA_GE_V1 -# define AFB_SESSION_LOA_LE AFB_SESSION_LOA_LE_V1 -# define AFB_SESSION_LOA_EQ AFB_SESSION_LOA_EQ_V1 - -# define AFB_SESSION_LOA_SHIFT AFB_SESSION_LOA_SHIFT_V1 -# define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_V1 - -# define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_V1 -# define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_V1 -# define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_V1 -# define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_V1 -# define AFB_SESSION_LOA_4 AFB_SESSION_LOA_4_V1 - -# define AFB_SESSION_LOA_LE_0 AFB_SESSION_LOA_LE_0_V1 -# define AFB_SESSION_LOA_LE_1 AFB_SESSION_LOA_LE_1_V1 -# define AFB_SESSION_LOA_LE_2 AFB_SESSION_LOA_LE_2_V1 -# define AFB_SESSION_LOA_LE_3 AFB_SESSION_LOA_LE_3_V1 - -# define AFB_SESSION_LOA_EQ_0 AFB_SESSION_LOA_EQ_0_V1 -# define AFB_SESSION_LOA_EQ_1 AFB_SESSION_LOA_EQ_1_V1 -# define AFB_SESSION_LOA_EQ_2 AFB_SESSION_LOA_EQ_2_V1 -# define AFB_SESSION_LOA_EQ_3 AFB_SESSION_LOA_EQ_3_V1 - -# define AFB_SESSION_LOA_GE_0 AFB_SESSION_LOA_GE_0_V1 -# define AFB_SESSION_LOA_GE_1 AFB_SESSION_LOA_GE_1_V1 -# define AFB_SESSION_LOA_GE_2 AFB_SESSION_LOA_GE_2_V1 -# define AFB_SESSION_LOA_GE_3 AFB_SESSION_LOA_GE_3_V1 - -# if !defined(AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO) - -# define ERROR AFB_ERROR_V1 -# define WARNING AFB_WARNING_V1 -# define NOTICE AFB_NOTICE_V1 -# define INFO AFB_INFO_V1 -# define DEBUG AFB_DEBUG_V1 - -# endif - -#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v1 -#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v1 -#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v1 -#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v1 -#define afb_daemon_make_event afb_daemon_make_event_v1 -#define afb_daemon_verbose afb_daemon_verbose_v1 -#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v1 -#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v1 -#define afb_daemon_queue_job afb_daemon_queue_job_v1 - -#define afb_service_call afb_service_call_v1 - -#endif - diff --git a/include/afb/afb-binding-v2.h b/include/afb/afb-binding-v2.h index 6f8eb953..e763f1cf 100644 --- a/include/afb/afb-binding-v2.h +++ b/include/afb/afb-binding-v2.h @@ -77,11 +77,10 @@ extern const struct afb_binding_v2 afbBindingV2; #define AFB_BINDING_DATA_NAME_V2 afbBindingV2data #endif -#if AFB_BINDING_VERSION == 2 -struct afb_binding_data_v2 AFB_BINDING_DATA_NAME_V2 __attribute__ ((weak)); -#else -extern struct afb_binding_data_v2 AFB_BINDING_DATA_NAME_V2; +#if AFB_BINDING_VERSION != 2 +extern #endif +struct afb_binding_data_v2 AFB_BINDING_DATA_NAME_V2 __attribute__ ((weak)); #define afb_get_verbosity_v2() (AFB_BINDING_DATA_NAME_V2.verbosity) #define afb_get_daemon_v2() (AFB_BINDING_DATA_NAME_V2.daemon) @@ -114,46 +113,3 @@ extern struct afb_binding_data_v2 AFB_BINDING_DATA_NAME_V2; #include "afb-daemon-v2.h" #include "afb-service-v2.h" -/***************************************************************************************************/ - -#if AFB_BINDING_VERSION == 2 - -# define afb_binding afb_binding_v2 -# define afb_binding_interface afb_binding_interface_v2 - -# define AFB_SESSION_NONE AFB_SESSION_NONE_V2 -# define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_V2 -# define AFB_SESSION_RENEW AFB_SESSION_REFRESH_V2 -# define AFB_SESSION_REFRESH AFB_SESSION_REFRESH_V2 -# define AFB_SESSION_CHECK AFB_SESSION_CHECK_V2 - -# define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_V2 - -# define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_V2 -# define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_V2 -# define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_V2 -# define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_V2 - -# if !defined(AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO) - -# define ERROR AFB_ERROR_V2 -# define WARNING AFB_WARNING_V2 -# define NOTICE AFB_NOTICE_V2 -# define INFO AFB_INFO_V2 -# define DEBUG AFB_DEBUG_V2 - -# endif - -#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v2 -#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v2 -#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v2 -#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v2 -#define afb_daemon_make_event afb_daemon_make_event_v2 -#define afb_daemon_verbose afb_daemon_verbose_v2 -#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v2 -#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v2 -#define afb_daemon_queue_job afb_daemon_queue_job_v2 - -#define afb_service_call afb_service_call_v2 - -#endif diff --git a/include/afb/afb-binding.h b/include/afb/afb-binding.h index ac750c7a..e2fd34d8 100644 --- a/include/afb/afb-binding.h +++ b/include/afb/afb-binding.h @@ -53,3 +53,113 @@ #include "afb-binding-v1.h" #include "afb-binding-v2.h" +/***************************************************************************************************/ + +#if AFB_BINDING_VERSION == 1 + +# define afb_binding afb_binding_v1 +# define afb_binding_interface afb_binding_interface_v1 + +# define AFB_SESSION_NONE AFB_SESSION_NONE_V1 +# define AFB_SESSION_CREATE AFB_SESSION_CREATE_V1 +# define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_V1 +# define AFB_SESSION_RENEW AFB_SESSION_RENEW_V1 +# define AFB_SESSION_CHECK AFB_SESSION_CHECK_V1 + +# define AFB_SESSION_LOA_GE AFB_SESSION_LOA_GE_V1 +# define AFB_SESSION_LOA_LE AFB_SESSION_LOA_LE_V1 +# define AFB_SESSION_LOA_EQ AFB_SESSION_LOA_EQ_V1 + +# define AFB_SESSION_LOA_SHIFT AFB_SESSION_LOA_SHIFT_V1 +# define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_V1 + +# define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_V1 +# define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_V1 +# define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_V1 +# define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_V1 +# define AFB_SESSION_LOA_4 AFB_SESSION_LOA_4_V1 + +# define AFB_SESSION_LOA_LE_0 AFB_SESSION_LOA_LE_0_V1 +# define AFB_SESSION_LOA_LE_1 AFB_SESSION_LOA_LE_1_V1 +# define AFB_SESSION_LOA_LE_2 AFB_SESSION_LOA_LE_2_V1 +# define AFB_SESSION_LOA_LE_3 AFB_SESSION_LOA_LE_3_V1 + +# define AFB_SESSION_LOA_EQ_0 AFB_SESSION_LOA_EQ_0_V1 +# define AFB_SESSION_LOA_EQ_1 AFB_SESSION_LOA_EQ_1_V1 +# define AFB_SESSION_LOA_EQ_2 AFB_SESSION_LOA_EQ_2_V1 +# define AFB_SESSION_LOA_EQ_3 AFB_SESSION_LOA_EQ_3_V1 + +# define AFB_SESSION_LOA_GE_0 AFB_SESSION_LOA_GE_0_V1 +# define AFB_SESSION_LOA_GE_1 AFB_SESSION_LOA_GE_1_V1 +# define AFB_SESSION_LOA_GE_2 AFB_SESSION_LOA_GE_2_V1 +# define AFB_SESSION_LOA_GE_3 AFB_SESSION_LOA_GE_3_V1 + +# if !defined(AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO) + +# define ERROR AFB_ERROR_V1 +# define WARNING AFB_WARNING_V1 +# define NOTICE AFB_NOTICE_V1 +# define INFO AFB_INFO_V1 +# define DEBUG AFB_DEBUG_V1 + +# endif + +#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v1 +#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v1 +#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v1 +#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v1 +#define afb_daemon_make_event afb_daemon_make_event_v1 +#define afb_daemon_verbose afb_daemon_verbose_v1 +#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v1 +#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v1 +#define afb_daemon_queue_job afb_daemon_queue_job_v1 + +#define afb_service_call afb_service_call_v1 +#define afb_service_call_sync afb_service_call_sync_v1 + +#endif + +/***************************************************************************************************/ + +#if AFB_BINDING_VERSION == 2 + +# define afb_binding afb_binding_v2 +# define afb_binding_interface afb_binding_interface_v2 + +# define AFB_SESSION_NONE AFB_SESSION_NONE_V2 +# define AFB_SESSION_CLOSE AFB_SESSION_CLOSE_V2 +# define AFB_SESSION_RENEW AFB_SESSION_REFRESH_V2 +# define AFB_SESSION_REFRESH AFB_SESSION_REFRESH_V2 +# define AFB_SESSION_CHECK AFB_SESSION_CHECK_V2 + +# define AFB_SESSION_LOA_MASK AFB_SESSION_LOA_MASK_V2 + +# define AFB_SESSION_LOA_0 AFB_SESSION_LOA_0_V2 +# define AFB_SESSION_LOA_1 AFB_SESSION_LOA_1_V2 +# define AFB_SESSION_LOA_2 AFB_SESSION_LOA_2_V2 +# define AFB_SESSION_LOA_3 AFB_SESSION_LOA_3_V2 + +# if !defined(AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO) + +# define ERROR AFB_ERROR_V2 +# define WARNING AFB_WARNING_V2 +# define NOTICE AFB_NOTICE_V2 +# define INFO AFB_INFO_V2 +# define DEBUG AFB_DEBUG_V2 + +# endif + +#define afb_daemon_get_event_loop afb_daemon_get_event_loop_v2 +#define afb_daemon_get_user_bus afb_daemon_get_user_bus_v2 +#define afb_daemon_get_system_bus afb_daemon_get_system_bus_v2 +#define afb_daemon_broadcast_event afb_daemon_broadcast_event_v2 +#define afb_daemon_make_event afb_daemon_make_event_v2 +#define afb_daemon_verbose afb_daemon_verbose_v2 +#define afb_daemon_rootdir_get_fd afb_daemon_rootdir_get_fd_v2 +#define afb_daemon_rootdir_open_locale afb_daemon_rootdir_open_locale_v2 +#define afb_daemon_queue_job afb_daemon_queue_job_v2 + +#define afb_service_call afb_service_call_v2 +#define afb_service_call_sync afb_service_call_sync_v2 + +#endif diff --git a/include/afb/afb-req-itf.h b/include/afb/afb-req-itf.h index 8f8dc8a9..1d60daee 100644 --- a/include/afb/afb-req-itf.h +++ b/include/afb/afb-req-itf.h @@ -359,7 +359,12 @@ static inline int afb_req_unsubscribe(struct afb_req req, struct afb_event event * On completion, the function 'callback' is invoked with the * 'closure' given at call and two other parameters: 'iserror' and 'result'. * 'iserror' is a boolean that indicates if the reply is an error reply. - * 'result' is the json object of the 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. */ static inline void afb_req_subcall(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result), void *closure) { @@ -373,6 +378,10 @@ static inline void afb_req_subcall(struct afb_req req, const char *api, const ch * It returns 0 on an error answer and returns 1 when no error was detected. * 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. */ static inline int afb_req_subcall_sync(struct afb_req req, const char *api, const char *verb, struct json_object *args, struct json_object **result) { diff --git a/include/afb/afb-service-common.h b/include/afb/afb-service-common.h index 76f8e4e4..081b1db6 100644 --- a/include/afb/afb-service-common.h +++ b/include/afb/afb-service-common.h @@ -32,6 +32,9 @@ struct afb_service_itf void (*call)(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *callback_closure); + + int (*call_sync)(void *closure, const char *api, const char *verb, struct json_object *args, + struct json_object **result); }; /* diff --git a/include/afb/afb-service-v1.h b/include/afb/afb-service-v1.h index 6e85a293..f3f55a56 100644 --- a/include/afb/afb-service-v1.h +++ b/include/afb/afb-service-v1.h @@ -21,6 +21,10 @@ * 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. 'iserror' a boolean status being true (not null) when an error occured, @@ -33,8 +37,6 @@ * @param callback The to call on completion * @param callback_closure The closure to pass to the callback * - * @returns 0 in case of success or -1 in case of error. - * * @see also 'afb_req_subcall' */ static inline void afb_service_call_v1( @@ -48,3 +50,31 @@ static inline void afb_service_call_v1( service.itf->call(service.closure, api, verb, args, callback, callback_closure); } +/** + * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. + * 'result' will receive the response. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param service The service as received during initialisation + * @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 1 in case of success or 0 in case of error. + * + * @see also 'afb_req_subcall' + */ +static inline int afb_service_call_sync_v1( + struct afb_service service, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + return service.itf->call_sync(service.closure, api, verb, args, result); +} + diff --git a/include/afb/afb-service-v2.h b/include/afb/afb-service-v2.h index 84da1209..2d138350 100644 --- a/include/afb/afb-service-v2.h +++ b/include/afb/afb-service-v2.h @@ -21,6 +21,10 @@ * 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. 'iserror' a boolean status being true (not null) when an error occured, @@ -32,8 +36,6 @@ * @param callback The to call on completion * @param callback_closure The closure to pass to the callback * - * @returns 0 in case of success or -1 in case of error. - * * @see also 'afb_req_subcall' */ static inline void afb_service_call_v2( @@ -46,3 +48,30 @@ static inline void afb_service_call_v2( afb_get_service_v2().itf->call(afb_get_service_v2().closure, api, verb, args, callback, callback_closure); } +/** + * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. + * 'result' will receive the response. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param service The service as received during initialisation + * @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 1 in case of success or 0 in case of error. + * + * @see also 'afb_req_subcall' + */ +static inline int afb_service_call_sync_v2( + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + return afb_get_service_v2().itf->call_sync(afb_get_service_v2().closure, api, verb, args, result); +} + diff --git a/src/afb-hreq.c b/src/afb-hreq.c index 389a67e2..62b322c3 100644 --- a/src/afb-hreq.c +++ b/src/afb-hreq.c @@ -37,7 +37,6 @@ #include "afb-msg-json.h" #include "afb-context.h" #include "afb-hreq.h" -#include "afb-subcall.h" #include "afb-session.h" #include "afb-cred.h" #include "verbose.h" diff --git a/src/afb-stub-ws.c b/src/afb-stub-ws.c index 8298fc7b..c7b4b2ec 100644 --- a/src/afb-stub-ws.c +++ b/src/afb-stub-ws.c @@ -354,7 +354,7 @@ static void server_req_subcall_cb(struct afb_xreq *xreq, const char *api, const sc = malloc(sizeof *sc); if (!sc) { - + callback(cb_closure, 1, afb_msg_json_internal_error()); } else { sc->callback = callback; sc->closure = cb_closure; diff --git a/src/afb-subcall.c b/src/afb-subcall.c index ef114077..857f48ed 100644 --- a/src/afb-subcall.c +++ b/src/afb-subcall.c @@ -94,9 +94,10 @@ void afb_subcall( lenapi = 1 + strlen(api); lenverb = 1 + strlen(verb); subcall = malloc(lenapi + lenverb + sizeof *subcall); - if (subcall == NULL) + if (subcall == NULL) { + json_object_put(args); /* keep args existing */ callback(closure, 1, afb_msg_json_internal_error()); - else { + } else { afb_xreq_init(&subcall->xreq, &afb_subcall_xreq_itf); afb_context_subinit(&subcall->xreq.context, &caller->context); subcall->xreq.cred = afb_cred_addref(caller->cred); @@ -111,7 +112,6 @@ void afb_subcall( subcall->callback = callback; subcall->closure = closure; afb_xreq_addref(caller); - json_object_get(args); /* keep args existing */ afb_xreq_process(&subcall->xreq, caller->apiset); } } diff --git a/src/afb-svc.c b/src/afb-svc.c index 8976dc6c..ac012914 100644 --- a/src/afb-svc.c +++ b/src/afb-svc.c @@ -18,6 +18,7 @@ #define _GNU_SOURCE #include +#include #include #include @@ -33,6 +34,7 @@ #include "afb-xreq.h" #include "afb-cred.h" #include "afb-apiset.h" +#include "jobs.h" #include "verbose.h" /* @@ -51,8 +53,6 @@ struct afb_svc /* on event callback for the service */ void (*on_event)(const char *event, struct json_object *object); - - struct afb_binding_data_v2 *v2; }; /* @@ -62,19 +62,29 @@ struct svc_req { struct afb_xreq xreq; + struct afb_svc *svc; + /* the args */ void (*callback)(void*, int, struct json_object*); void *closure; + + /* sync */ + struct jobloop *jobloop; + struct json_object *result; + int iserror; }; /* functions for services */ static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object); static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cbclosure); +static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args, + struct json_object **result); /* the interface for services */ static const struct afb_service_itf service_itf = { - .call = svc_call + .call = svc_call, + .call_sync = svc_call_sync }; /* the interface for events */ @@ -96,12 +106,7 @@ const struct afb_xreq_query_itf afb_svc_xreq_itf = { /* the common session for services sharing their session */ static struct afb_session *common_session; -static inline struct afb_service to_afb_service_v1(struct afb_svc *svc) -{ - return (struct afb_service){ .itf = &service_itf, .closure = svc }; -} - -static inline struct afb_service to_afb_service_v2(struct afb_svc *svc) +static inline struct afb_service to_afb_service(struct afb_svc *svc) { return (struct afb_service){ .itf = &service_itf, .closure = svc }; } @@ -189,7 +194,7 @@ struct afb_svc *afb_svc_create_v1( } /* initialises the svc now */ - rc = start(to_afb_service_v1(svc)); + rc = start(to_afb_service(svc)); if (rc < 0) goto error; @@ -218,8 +223,7 @@ struct afb_svc *afb_svc_create_v2( svc = afb_svc_alloc(apiset, share_session); if (svc == NULL) goto error; - svc->v2 = data; - data->service = to_afb_service_v2(svc); + data->service = to_afb_service(svc); /* initialises the listener if needed */ if (on_event) { @@ -253,6 +257,88 @@ static void svc_on_event(void *closure, const char *event, int eventid, struct j json_object_put(object); } +/* + * create an svc_req + */ +static struct svc_req *svcreq_create(struct afb_svc *svc, const char *api, const char *verb, struct json_object *args) +{ + struct svc_req *svcreq; + size_t lenapi, lenverb; + char *copy; + + /* allocates the request */ + lenapi = 1 + strlen(api); + lenverb = 1 + strlen(verb); + svcreq = malloc(lenapi + lenverb + sizeof *svcreq); + if (svcreq != NULL) { + /* initialises the request */ + afb_xreq_init(&svcreq->xreq, &afb_svc_xreq_itf); + afb_context_init(&svcreq->xreq.context, svc->session, NULL); + svcreq->xreq.context.validated = 1; + svcreq->xreq.cred = afb_cred_current(); + copy = (char*)&svcreq[1]; + memcpy(copy, api, lenapi); + svcreq->xreq.api = copy; + copy = ©[lenapi]; + memcpy(copy, verb, lenverb); + svcreq->xreq.verb = copy; + svcreq->xreq.listener = svc->listener; + svcreq->xreq.json = args; + svcreq->svc = svc; + } + return svcreq; +} + +/* + * destroys the svc_req + */ +static void svcreq_destroy(struct afb_xreq *xreq) +{ + struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq); + + afb_context_disconnect(&svcreq->xreq.context); + json_object_put(svcreq->xreq.json); + afb_cred_unref(svcreq->xreq.cred); + free(svcreq); +} + +static void svcreq_sync_leave(struct svc_req *svcreq) +{ + struct jobloop *jobloop = svcreq->jobloop; + + if (jobloop) { + svcreq->jobloop = NULL; + jobs_leave(jobloop); + } +} + +static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj) +{ + struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq); + if (svcreq->callback) { + svcreq->callback(svcreq->closure, iserror, obj); + json_object_put(obj); + } else { + svcreq->iserror = iserror; + svcreq->result = obj; + svcreq_sync_leave(svcreq); + } +} + +static void svcreq_sync_enter(int signum, void *closure, struct jobloop *jobloop) +{ + struct svc_req *svcreq = closure; + + if (!signum) { + svcreq->jobloop = jobloop; + afb_xreq_process(&svcreq->xreq, svcreq->svc->apiset); + } else { + svcreq->result = afb_msg_json_internal_error(); + svcreq->iserror = 1; + svcreq_sync_leave(svcreq); + } +} + /* * Initiates a call for the service */ @@ -260,25 +346,21 @@ static void svc_call(void *closure, const char *api, const char *verb, struct js { struct afb_svc *svc = closure; struct svc_req *svcreq; + struct json_object *ierr; /* allocates the request */ - svcreq = calloc(1, sizeof *svcreq); + svcreq = svcreq_create(svc, api, verb, args); if (svcreq == NULL) { ERROR("out of memory"); json_object_put(args); - callback(cbclosure, 1, afb_msg_json_internal_error()); + ierr = afb_msg_json_internal_error(); + callback(cbclosure, 1, ierr); + json_object_put(ierr); return; } /* initialises the request */ - afb_xreq_init(&svcreq->xreq, &afb_svc_xreq_itf); - afb_context_init(&svcreq->xreq.context, svc->session, NULL); - svcreq->xreq.context.validated = 1; - svcreq->xreq.cred = afb_cred_current(); - svcreq->xreq.api = api; - svcreq->xreq.verb = verb; - svcreq->xreq.listener = svc->listener; - svcreq->xreq.json = args; + svcreq->jobloop = NULL; svcreq->callback = callback; svcreq->closure = cbclosure; @@ -286,19 +368,33 @@ static void svc_call(void *closure, const char *api, const char *verb, struct js afb_xreq_process(&svcreq->xreq, svc->apiset); } -static void svcreq_destroy(struct afb_xreq *xreq) +static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args, + struct json_object **result) { - struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq); - afb_context_disconnect(&svcreq->xreq.context); - json_object_put(svcreq->xreq.json); - afb_cred_unref(svcreq->xreq.cred); - free(svcreq); -} + struct afb_svc *svc = closure; + struct svc_req *svcreq; + int rc; -static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj) -{ - struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq); - svcreq->callback(svcreq->closure, iserror, obj); - json_object_put(obj); + /* allocates the request */ + svcreq = svcreq_create(svc, api, verb, args); + if (svcreq == NULL) { + ERROR("out of memory"); + errno = ENOMEM; + json_object_put(args); + *result = afb_msg_json_internal_error(); + return -1; + } + + /* initialises the request */ + svcreq->jobloop = NULL; + svcreq->callback = NULL; + svcreq->result = NULL; + svcreq->iserror = 1; + afb_xreq_addref(&svcreq->xreq); + rc = jobs_enter(NULL, 0, svcreq_sync_enter, svcreq); + rc = rc >= 0 && !svcreq->iserror; + *result = (rc || svcreq->result) ? svcreq->result : afb_msg_json_internal_error(); + afb_xreq_unref(&svcreq->xreq); + return rc; } diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c index bdd1286c..3d1f29dc 100644 --- a/src/afb-ws-json1.c +++ b/src/afb-ws-json1.c @@ -37,7 +37,6 @@ #include "afb-xreq.h" #include "afb-context.h" #include "afb-evt.h" -#include "afb-subcall.h" #include "verbose.h" /* predeclaration of structures */ diff --git a/src/afb-xreq.c b/src/afb-xreq.c index 4c5becca..9478f154 100644 --- a/src/afb-xreq.c +++ b/src/afb-xreq.c @@ -179,10 +179,12 @@ static void xreq_subcall_cb(void *closure, const char *api, const char *verb, st { struct afb_xreq *xreq = closure; - if (xreq->queryitf->subcall) + if (xreq->queryitf->subcall) { xreq->queryitf->subcall(xreq, api, verb, args, callback, cb_closure); - else + json_object_put(args); + } else { afb_subcall(xreq, api, verb, args, callback, cb_closure); + } } struct xreq_sync @@ -220,7 +222,7 @@ static void xreq_sync_enter(int signum, void *closure, struct jobloop *jobloop) if (!signum) { sync->jobloop = jobloop; - xreq_subcall_cb(sync->caller, sync->api, sync->verb, sync->args, xreq_sync_reply, sync); + xreq_subcall_cb(sync->caller, sync->api, sync->verb, json_object_get(sync->args), xreq_sync_reply, sync); } else { sync->iserror = 1; xreq_sync_leave(sync); @@ -242,6 +244,7 @@ static int xreq_subcallsync_cb(void *closure, const char *api, const char *verb, sync.iserror = 1; rc = jobs_enter(NULL, 0, xreq_sync_enter, &sync); + json_object_put(args); if (rc < 0 || sync.iserror) { *result = sync.result ? : afb_msg_json_internal_error(); return 0;