X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-apis.c;h=6e093550e4113cde18613a80f1f20ff1184c1c38;hb=5d248158cc380d0a164fa56b46a7bdede4115407;hp=9ffffdb3b5d22ed632f419c7e7df20bef83e09b4;hpb=3bf52bb36ed428d0a7b947519fbccc7c376fd4a9;p=src%2Fapp-framework-binder.git diff --git a/src/afb-apis.c b/src/afb-apis.c index 9ffffdb3..6e093550 100644 --- a/src/afb-apis.c +++ b/src/afb-apis.c @@ -27,16 +27,31 @@ #include "verbose.h" #include "afb-apis.h" #include "afb-context.h" -#include "afb-hook.h" +#include "afb-xreq.h" +#include "jobs.h" + #include +/** + * Internal description of an api + */ struct api_desc { - const char *name; - struct afb_api api; + const char *name; /**< name of the api */ + struct afb_api api; /**< handler of the api */ }; static struct api_desc *apis_array = NULL; static int apis_count = 0; +static int apis_timeout = 15; + +/** + * Set the API timeout + * @param to the timeout in seconds + */ +void afb_apis_set_timeout(int to) +{ + apis_timeout = to; +} /** * Checks wether 'name' is a valid API name. @@ -131,6 +146,8 @@ int afb_apis_add(const char *name, struct afb_api api) apis->name = name; apis_count++; + NOTICE("API %s added", name); + return 0; error: @@ -138,21 +155,15 @@ error: } /** - * Dispatch the request 'req' with the 'context' to the - * method of 'api' and 'verb'. - * @param req the request to dispatch - * @param context the context of the request + * Search the 'api'. * @param api the api of the verb - * @param verb the verb within the api + * @return the descriptor if found or NULL otherwise */ -void afb_apis_call(struct afb_req req, struct afb_context *context, const char *api, const char *verb) +static const struct api_desc *search(const char *api) { int i, c, up, lo; const struct api_desc *a; - /* init hooking the request */ - req = afb_hook_req_call(req, context, api, verb); - /* dichotomic search of the api */ /* initial slice */ lo = 0; @@ -160,19 +171,16 @@ void afb_apis_call(struct afb_req req, struct afb_context *context, const char * for (;;) { /* check remaining slice */ if (lo >= up) { - /* empty ?! */ - afb_req_fail(req, "fail", "api not found"); - break; + /* not found */ + return NULL; } /* check the mid of the slice */ i = (lo + up) >> 1; a = &apis_array[i]; c = strcasecmp(a->name, api); if (c == 0) { - /* api found */ - context->api_key = a->api.closure; - a->api.call(a->api.closure, req, context, verb); - break; + /* found */ + return a; } /* update the slice */ if (c < 0) @@ -182,27 +190,198 @@ void afb_apis_call(struct afb_req req, struct afb_context *context, const char * } } +/** + * Starts a service by its 'api' name. + * @param api name of the service to start + * @param share_session if true start the servic"e in a shared session + * if false start it in its own session + * @param onneed if true start the service if possible, if false the api + * must be a service + * @return a positive number on success + */ int afb_apis_start_service(const char *api, int share_session, int onneed) { int i; for (i = 0 ; i < apis_count ; i++) { if (!strcasecmp(apis_array[i].name, api)) - return apis_array[i].api.service_start(apis_array[i].api.closure, share_session, onneed); + return apis_array[i].api.itf->service_start(apis_array[i].api.closure, share_session, onneed); } ERROR("can't find service %s", api); + errno = ENOENT; return -1; } +/** + * Starts all possible services but stops at first error. + * @param share_session if true start the servic"e in a shared session + * if false start it in its own session + * @return 0 on success or a negative number when an error is found + */ int afb_apis_start_all_services(int share_session) { int i, rc; for (i = 0 ; i < apis_count ; i++) { - rc = apis_array[i].api.service_start(apis_array[i].api.closure, share_session, 1); + rc = apis_array[i].api.itf->service_start(apis_array[i].api.closure, share_session, 1); if (rc < 0) return rc; } return 0; } +/** + * Internal direct dispatch of the request 'xreq' + * @param xreq the request to dispatch + */ +static void do_call_direct(struct afb_xreq *xreq) +{ + const struct api_desc *a; + + /* search the api */ + a = search(xreq->api); + if (!a) + afb_xreq_fail_f(xreq, "unknown-api", "api %s not found", xreq->api); + else { + xreq->context.api_key = a->api.closure; + a->api.itf->call(a->api.closure, xreq); + } +} + +/** + * Asynchronous dispatch callback for the request 'xreq' + * @param signum 0 on normal flow or the signal number that interupted the normal flow + */ +static void do_call_async(int signum, void *arg) +{ + struct afb_xreq *xreq = arg; + + if (signum != 0) + afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum); + else { + do_call_direct(xreq); + } + afb_xreq_unref(xreq); +} + +/** + * Dispatch the request 'xreq' synchronously and directly. + * @param xreq the request to dispatch + */ +void afb_apis_call_direct(struct afb_xreq *xreq) +{ + afb_xreq_begin(xreq); + do_call_direct(xreq); +} + +/** + * Dispatch the request 'xreq' asynchronously. + * @param xreq the request to dispatch + */ +void afb_apis_call(struct afb_xreq *xreq) +{ + int rc; + + afb_xreq_begin(xreq); + afb_xreq_addref(xreq); + rc = jobs_queue(NULL, apis_timeout, do_call_async, xreq); + if (rc < 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"); + afb_xreq_unref(xreq); + } +} + +/** + * Ask to update the hook flags of the 'api' + * @param api the api to update (NULL updates all) + */ +void afb_apis_update_hooks(const char *api) +{ + const struct api_desc *i, *e; + + if (!api) { + i = apis_array; + e = &apis_array[apis_count]; + } else { + i = search(api); + e = &i[!!i]; + } + while (i != e) { + if (i->api.itf->update_hooks) + i->api.itf->update_hooks(i->api.closure); + i++; + } +} + +/** + * Set the verbosity level of the 'api' + * @param api the api to set (NULL set all) + */ +void afb_apis_set_verbosity(const char *api, int level) +{ + const struct api_desc *i, *e; + + if (!api) { + i = apis_array; + e = &apis_array[apis_count]; + } else { + i = search(api); + e = &i[!!i]; + } + while (i != e) { + if (i->api.itf->set_verbosity) + i->api.itf->set_verbosity(i->api.closure, level); + i++; + } +} + +/** + * Set the verbosity level of the 'api' + * @param api the api to set (NULL set all) + */ +int afb_apis_get_verbosity(const char *api) +{ + const struct api_desc *i; + + i = api ? search(api) : NULL; + if (!i) { + errno = ENOENT; + return -1; + } + if (!i->api.itf->get_verbosity) + return 0; + + return i->api.itf->get_verbosity(i->api.closure); +} + +/** + * Get the list of api names + * @return a NULL terminated array of api names. Must be freed. + */ +const char **afb_apis_get_names() +{ + size_t size; + char *dest; + const char **names; + int i; + + size = apis_count * (1 + sizeof(*names)) + sizeof(*names); + for (i = 0 ; i < apis_count ; i++) + size += strlen(apis_array[i].name); + + names = malloc(size); + if (!names) + errno = ENOMEM; + else { + dest = (void*)&names[apis_count+1]; + for (i = 0 ; i < apis_count ; i++) { + names[i] = dest; + dest = stpcpy(dest, apis_array[i].name) + 1; + } + names[i] = NULL; + } + return names; +} +