X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-xreq.c;h=ea830d9df048ef6237220b182c95b6ca2386e3fd;hb=86134053455a621eac709d2a2d766b80b7ba7ec7;hp=3535ce5c889176750db12e331ac0aaa0dc63d392;hpb=85bca06fe0ee2923421f013da3e9f53abbfff673;p=src%2Fapp-framework-binder.git diff --git a/src/afb-xreq.c b/src/afb-xreq.c index 3535ce5c..ea830d9d 100644 --- a/src/afb-xreq.c +++ b/src/afb-xreq.c @@ -16,7 +16,6 @@ */ #define _GNU_SOURCE -#define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO #include #include @@ -53,6 +52,8 @@ static inline void xreq_unref(struct afb_xreq *xreq) afb_xreq_fail(xreq, "error", "no reply"); if (xreq->hookflags) afb_hook_xreq_end(xreq); + if (xreq->caller) + xreq_unref(xreq->caller); xreq->queryitf->unref(xreq); } } @@ -72,9 +73,9 @@ static inline struct afb_req to_req(struct afb_xreq *xreq) struct subcall { struct afb_xreq xreq; - struct afb_xreq *caller; - void (*callback)(void*, int, struct json_object*); - void *closure; + + void (*completion)(struct subcall*, int, struct json_object*); + union { struct { struct jobloop *jobloop; @@ -87,48 +88,47 @@ struct subcall void (*callback2)(void*, int, struct json_object*, struct afb_req); }; void *closure; - } hooked; + }; }; }; -static int subcall_subscribe(struct afb_xreq *xreq, struct afb_event event) +static int subcall_subscribe_cb(struct afb_xreq *xreq, struct afb_event event) { struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - return afb_xreq_subscribe(subcall->caller, event); + return afb_xreq_subscribe(subcall->xreq.caller, event); } -static int subcall_unsubscribe(struct afb_xreq *xreq, struct afb_event event) +static int subcall_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event event) { struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - return afb_xreq_unsubscribe(subcall->caller, event); + return afb_xreq_unsubscribe(subcall->xreq.caller, event); } -static void subcall_reply(struct afb_xreq *xreq, int status, struct json_object *obj) +static void subcall_reply_cb(struct afb_xreq *xreq, int status, struct json_object *result) { struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - if (subcall->callback) - subcall->callback(subcall->closure, status, obj); - json_object_put(obj); + subcall->completion(subcall, status, result); + json_object_put(result); + afb_xreq_unref(&subcall->xreq); } -static void subcall_destroy(struct afb_xreq *xreq) +static void subcall_destroy_cb(struct afb_xreq *xreq) { struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); json_object_put(subcall->xreq.json); afb_cred_unref(subcall->xreq.cred); - xreq_unref(subcall->caller); free(subcall); } const struct afb_xreq_query_itf afb_xreq_subcall_itf = { - .reply = subcall_reply, - .unref = subcall_destroy, - .subscribe = subcall_subscribe, - .unsubscribe = subcall_unsubscribe + .reply = subcall_reply_cb, + .unref = subcall_destroy_cb, + .subscribe = subcall_subscribe_cb, + .unsubscribe = subcall_unsubscribe_cb }; static struct subcall *subcall_alloc( @@ -161,21 +161,87 @@ static struct subcall *subcall_alloc( subcall->xreq.json = args; subcall->xreq.api = api; subcall->xreq.verb = verb; - subcall->caller = caller; + subcall->xreq.caller = caller; xreq_addref(caller); } return subcall; } -static void subcall_process(struct subcall *subcall) + +static void subcall_on_reply(struct subcall *subcall, int status, struct json_object *result) +{ + subcall->callback(subcall->closure, status, result); +} + +static void subcall_req_on_reply(struct subcall *subcall, int status, struct json_object *result) +{ + subcall->callback2(subcall->closure, status, result, to_req(subcall->xreq.caller)); +} + +static void subcall_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result) { - if (subcall->caller->queryitf->subcall) { - subcall->caller->queryitf->subcall( - subcall->caller, subcall->xreq.api, subcall->xreq.verb, - subcall->xreq.json, subcall->callback, subcall->closure); - xreq_unref(&subcall->xreq); - } else - afb_xreq_process(&subcall->xreq, subcall->caller->apiset); + afb_hook_xreq_subcall_result(subcall->xreq.caller, status, result); + subcall_on_reply(subcall, status, result); +} + +static void subcall_req_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result) +{ + afb_hook_xreq_subcall_req_result(subcall->xreq.caller, status, result); + subcall_req_on_reply(subcall, status, result); +} + +static void subcall_reply_direct_cb(void *closure, int status, struct json_object *result) +{ + struct afb_xreq *xreq = closure; + + if (xreq->replied) { + ERROR("subcall replied more than one time!!"); + json_object_put(result); + } else { + xreq->replied = 1; + subcall_reply_cb(xreq, status, result); + } +} + +static void subcall_process(struct subcall *subcall, void (*completion)(struct subcall*, int, struct json_object*)) +{ + subcall->completion = completion; + if (subcall->xreq.caller->queryitf->subcall) { + subcall->xreq.caller->queryitf->subcall( + subcall->xreq.caller, subcall->xreq.api, subcall->xreq.verb, + subcall->xreq.json, subcall_reply_direct_cb, &subcall->xreq); + } else { + afb_xreq_addref(&subcall->xreq); + afb_xreq_process(&subcall->xreq, subcall->xreq.caller->apiset); + } +} + +static void subcall(struct subcall *subcall, void (*callback)(void*, int, struct json_object*), void *cb_closure) +{ + subcall->callback = callback; + subcall->closure = cb_closure; + subcall_process(subcall, subcall_on_reply); +} + +static void subcall_req(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) +{ + subcall->callback2 = callback; + subcall->closure = cb_closure; + subcall_process(subcall, subcall_req_on_reply); +} + +static void subcall_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*), void *cb_closure) +{ + subcall->callback = callback; + subcall->closure = cb_closure; + subcall_process(subcall, subcall_hooked_on_reply); +} + +static void subcall_req_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) +{ + subcall->callback2 = callback; + subcall->closure = cb_closure; + subcall_process(subcall, subcall_req_hooked_on_reply); } static void subcall_sync_leave(struct subcall *subcall) @@ -185,12 +251,10 @@ static void subcall_sync_leave(struct subcall *subcall) jobs_leave(jobloop); } -static void subcall_sync_reply(void *closure, int status, struct json_object *obj) +static void subcall_sync_reply(struct subcall *subcall, int status, struct json_object *result) { - struct subcall *subcall = closure; - subcall->status = status; - subcall->result = json_object_get(obj); + subcall->result = json_object_get(result); subcall_sync_leave(subcall); } @@ -200,13 +264,30 @@ static void subcall_sync_enter(int signum, void *closure, struct jobloop *jobloo if (!signum) { subcall->jobloop = jobloop; - subcall_process(subcall); + subcall->result = NULL; + subcall->status = 0; + subcall_process(subcall, subcall_sync_reply); } else { subcall->status = -1; subcall_sync_leave(subcall); } } +static int subcallsync(struct subcall *subcall, struct json_object **result) +{ + int rc; + + afb_xreq_addref(&subcall->xreq); + rc = jobs_enter(NULL, 0, subcall_sync_enter, subcall); + *result = subcall->result; + if (rc < 0 || subcall->status < 0) { + *result = *result ?: afb_msg_json_internal_error(); + rc = -1; + } + afb_xreq_unref(&subcall->xreq); + return rc; +} + /******************************************************************************/ static void vinfo(void *first, void *second, const char *fmt, va_list args, void (*fun)(void*,void*,const char*)) @@ -364,42 +445,30 @@ int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_event event) static void xreq_subcall_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure) { struct afb_xreq *xreq = closure; - struct subcall *subcall; + struct subcall *sc; - subcall = subcall_alloc(xreq, api, verb, args); - if (subcall == NULL) { + sc = subcall_alloc(xreq, api, verb, args); + if (sc == NULL) { if (callback) callback(cb_closure, 1, afb_msg_json_internal_error()); json_object_put(args); } else { - subcall->callback = callback; - subcall->closure = cb_closure; - subcall_process(subcall); + subcall(sc, callback, cb_closure); } } -static void xreq_subcall_req_reply_cb(void *closure, int status, struct json_object *result) -{ - struct subcall *subcall = closure; - subcall->hooked.callback2(subcall->hooked.closure, status, result, to_req(subcall->caller)); -} - static void xreq_subcall_req_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) { struct afb_xreq *xreq = closure; - struct subcall *subcall; + struct subcall *sc; - subcall = subcall_alloc(xreq, api, verb, args); - if (subcall == NULL) { + sc = subcall_alloc(xreq, api, verb, args); + if (sc == NULL) { if (callback) callback(cb_closure, 1, afb_msg_json_internal_error(), to_req(xreq)); json_object_put(args); } else { - subcall->callback = xreq_subcall_req_reply_cb; - subcall->closure = subcall; - subcall->hooked.callback2 = callback; - subcall->hooked.closure = cb_closure; - subcall_process(subcall); + subcall_req(sc, callback, cb_closure); } } @@ -407,27 +476,17 @@ static void xreq_subcall_req_cb(void *closure, const char *api, const char *verb static int xreq_subcallsync_cb(void *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result) { int rc; - struct subcall *subcall; + struct subcall *sc; struct afb_xreq *xreq = closure; struct json_object *resu; - subcall = subcall_alloc(xreq, api, verb, args); - if (!subcall) { + sc = subcall_alloc(xreq, api, verb, args); + if (!sc) { rc = -1; resu = afb_msg_json_internal_error(); json_object_put(args); } else { - subcall->callback = subcall_sync_reply; - subcall->closure = subcall; - subcall->jobloop = NULL; - subcall->result = NULL; - subcall->status = 0; - rc = jobs_enter(NULL, 0, subcall_sync_enter, subcall); - resu = subcall->result; - if (rc < 0 || subcall->status < 0) { - resu = resu ?: afb_msg_json_internal_error(); - rc = -1; - } + rc = subcallsync(sc, &resu); } if (result) *result = resu; @@ -438,8 +497,15 @@ static int xreq_subcallsync_cb(void *closure, const char *api, const char *verb, static void xreq_vverbose_cb(void*closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args) { - /* TODO: improves the implementation. example: on condition make a list of log messages that will be returned */ - vverbose(level, file, line, func, fmt, args); + char *p; + struct afb_xreq *xreq = closure; + + if (!fmt || vasprintf(&p, fmt, args) < 0) + vverbose(level, file, line, func, fmt, args); + else { + verbose(level, file, line, func, "[REQ/API %s] %s", xreq->api, p); + free(p); + } } static struct afb_stored_req *xreq_store_cb(void *closure) @@ -454,6 +520,12 @@ static int xreq_has_permission_cb(void*closure, const char *permission) return afb_auth_has_permission(xreq, permission); } +static char *xreq_get_application_id_cb(void*closure) +{ + struct afb_xreq *xreq = closure; + return xreq->cred && xreq->cred->id ? strdup(xreq->cred->id) : NULL; +} + /******************************************************************************/ static struct json_object *xreq_hooked_json_cb(void *closure) @@ -550,59 +622,35 @@ static int xreq_hooked_unsubscribe_cb(void *closure, struct afb_event event) return afb_hook_xreq_unsubscribe(xreq, event, r); } -static void xreq_hooked_subcall_reply_cb(void *closure, int status, struct json_object *result) -{ - struct subcall *subcall = closure; - - afb_hook_xreq_subcall_result(subcall->caller, status, result); - subcall->hooked.callback(subcall->hooked.closure, status, result); -} - static void xreq_hooked_subcall_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure) { struct afb_xreq *xreq = closure; - struct subcall *subcall; + struct subcall *sc; afb_hook_xreq_subcall(xreq, api, verb, args); - subcall = subcall_alloc(xreq, api, verb, args); - if (subcall == NULL) { + sc = subcall_alloc(xreq, api, verb, args); + if (sc == NULL) { if (callback) callback(cb_closure, 1, afb_msg_json_internal_error()); json_object_put(args); } else { - subcall->callback = xreq_hooked_subcall_reply_cb; - subcall->closure = subcall; - subcall->hooked.callback = callback; - subcall->hooked.closure = cb_closure; - subcall_process(subcall); + subcall_hooked(sc, callback, cb_closure); } } -static void xreq_hooked_subcall_req_reply_cb(void *closure, int status, struct json_object *result) -{ - struct subcall *subcall = closure; - - afb_hook_xreq_subcall_req_result(subcall->caller, status, result); - subcall->hooked.callback2(subcall->hooked.closure, status, result, to_req(subcall->caller)); -} - static void xreq_hooked_subcall_req_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) { struct afb_xreq *xreq = closure; - struct subcall *subcall; + struct subcall *sc; afb_hook_xreq_subcall_req(xreq, api, verb, args); - subcall = subcall_alloc(xreq, api, verb, args); - if (subcall == NULL) { + sc = subcall_alloc(xreq, api, verb, args); + if (sc == NULL) { if (callback) callback(cb_closure, 1, afb_msg_json_internal_error(), to_req(xreq)); json_object_put(args); } else { - subcall->callback = xreq_hooked_subcall_req_reply_cb; - subcall->closure = subcall; - subcall->hooked.callback2 = callback; - subcall->hooked.closure = cb_closure; - subcall_process(subcall); + subcall_req_hooked(sc, callback, cb_closure); } } @@ -640,6 +688,13 @@ static int xreq_hooked_has_permission_cb(void*closure, const char *permission) return afb_hook_xreq_has_permission(xreq, permission, r); } +static char *xreq_hooked_get_application_id_cb(void*closure) +{ + struct afb_xreq *xreq = closure; + char *r = xreq_get_application_id_cb(closure); + return afb_hook_xreq_get_application_id(xreq, r); +} + /******************************************************************************/ const struct afb_req_itf xreq_itf = { @@ -662,7 +717,8 @@ const struct afb_req_itf xreq_itf = { .vverbose = xreq_vverbose_cb, .store = xreq_store_cb, .subcall_req = xreq_subcall_req_cb, - .has_permission = xreq_has_permission_cb + .has_permission = xreq_has_permission_cb, + .get_application_id = xreq_get_application_id_cb }; const struct afb_req_itf xreq_hooked_itf = { @@ -685,7 +741,8 @@ const struct afb_req_itf xreq_hooked_itf = { .vverbose = xreq_hooked_vverbose_cb, .store = xreq_hooked_store_cb, .subcall_req = xreq_hooked_subcall_req_cb, - .has_permission = xreq_hooked_has_permission_cb + .has_permission = xreq_hooked_has_permission_cb, + .get_application_id = xreq_hooked_get_application_id_cb }; /******************************************************************************/ @@ -925,19 +982,37 @@ static void process_async(int signum, void *arg) void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset) { + const void *jobkey; const struct afb_api *api; + struct afb_xreq *caller; xreq->apiset = apiset; api = afb_apiset_lookup_started(apiset, xreq->api, 1); - xreq->context.api_key = (void*)api; + xreq->context.api_key = api; + if (!api || !api->noconcurrency) + jobkey = NULL; + else { + caller = xreq->caller; + while (caller) { + if (caller->context.api_key == api) { + /* noconcurrency lock detected */ + ERROR("self-lock detected in call stack for API %s", xreq->api); + afb_xreq_fail_f(xreq, "cancelled", "recursive self lock, API %s", xreq->api); + goto end; + } + caller = caller->caller; + } + jobkey = api; + } xreq_addref(xreq); - if (jobs_queue(api && api->noconcurrency ? (void*)api : NULL, afb_apiset_timeout_get(apiset), process_async, xreq) < 0) { + if (jobs_queue(jobkey, afb_apiset_timeout_get(apiset), process_async, xreq) < 0) { /* TODO: allows or not to proccess it directly as when no threading? (see above) */ ERROR("can't process job with threads: %m"); afb_xreq_fail_f(xreq, "cancelled", "not able to create a job for the task"); xreq_unref(xreq); } +end: xreq_unref(xreq); }