X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-svc.c;h=212ecfa3d157406d4318f53370451a7e50a98dfc;hb=11e2d4395056c7bd2a618b4fa7ffdd70af05d14e;hp=58e2b6d31392ef46dd5904dd0a983f274de83338;hpb=7087ad1b81b55fb2c1c14e7d9cbb49c0bf75e28e;p=src%2Fapp-framework-binder.git diff --git a/src/afb-svc.c b/src/afb-svc.c index 58e2b6d3..212ecfa3 100644 --- a/src/afb-svc.c +++ b/src/afb-svc.c @@ -18,35 +18,28 @@ #define _GNU_SOURCE #include +#include +#include #include -#include -#include +#include +#include #include "afb-session.h" #include "afb-context.h" #include "afb-evt.h" -#include "afb-subcall.h" +#include "afb-msg-json.h" #include "afb-svc.h" #include "afb-xreq.h" -#include "afb-apis.h" +#include "afb-cred.h" +#include "afb-apiset.h" +#include "afb-hook.h" +#include "jobs.h" #include "verbose.h" -/* - * Structure for recording service - */ -struct afb_svc -{ - /* session of the service */ - struct afb_session *session; - /* event listener of the service or NULL */ - struct afb_evt_listener *listener; - - /* on event callback for the service */ - void (*on_event)(const char *event, struct json_object *object); -}; +#define HOOK(x,...) if((svc)->hookflags & afb_hook_flag_svc_##x) afb_hook_svc_##x(__VA_ARGS__) /* * Structure for requests initiated by the service @@ -55,23 +48,30 @@ struct svc_req { struct afb_xreq xreq; + struct afb_svc *svc; + /* the args */ - struct json_object *args; void (*callback)(void*, int, struct json_object*); void *closure; - /* the service */ - struct afb_svc *svc; + /* sync */ + struct jobloop *jobloop; + struct json_object *result; + int status; + int async; }; /* 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 */ @@ -81,31 +81,63 @@ static const struct afb_evt_itf evt_itf = { }; /* functions for requests of services */ -static struct json_object *svcreq_json(void *closure); -static void svcreq_destroy(void *closure); -static void svcreq_reply(void *closure, int iserror, json_object *obj); +static void svcreq_destroy(struct afb_xreq *xreq); +static void svcreq_reply(struct afb_xreq *xreq, int status, json_object *obj); /* interface for requests of services */ const struct afb_xreq_query_itf afb_svc_xreq_itf = { .unref = svcreq_destroy, - .json = svcreq_json, .reply = svcreq_reply }; /* the common session for services sharing their session */ static struct afb_session *common_session; +static inline struct afb_service to_afb_service(struct afb_svc *svc) +{ + return (struct afb_service){ .itf = &service_itf, .closure = svc }; +} + /* - * Allocates a new service + * Frees a service */ -static struct afb_svc *afb_svc_alloc(int share_session, void (*on_event)(const char *event, struct json_object *object)) +void afb_svc_destroy(struct afb_svc *svc, struct afb_service *service) +{ + if (service) + *service = (struct afb_service){ .itf = NULL, .closure = NULL }; + if (svc) { + if (svc->listener != NULL) + afb_evt_listener_unref(svc->listener); + if (svc->session) + afb_session_unref(svc->session); + afb_apiset_unref(svc->apiset); + free(svc); + } +} + +/* + * Creates a new service + */ +struct afb_svc *afb_svc_create( + const char *api, + struct afb_apiset *apiset, + int share_session, + void (*on_event)(const char *event, struct json_object *object), + struct afb_service *service +) { struct afb_svc *svc; /* allocates the svc handler */ - svc = malloc(sizeof * svc); - if (svc == NULL) - goto error; + svc = calloc(1, sizeof * svc); + if (svc == NULL) { + errno = ENOMEM; + return NULL; + } + + /* instanciate the apiset */ + svc->api = api; + svc->apiset = afb_apiset_addref(apiset); /* instanciate the session */ if (share_session) { @@ -113,96 +145,67 @@ static struct afb_svc *afb_svc_alloc(int share_session, void (*on_event)(const c if (common_session == NULL) { common_session = afb_session_create (NULL, 0); if (common_session == NULL) - goto error2; + goto error; } svc->session = afb_session_addref(common_session); } else { /* session dedicated to the svc */ svc->session = afb_session_create (NULL, 0); if (svc->session == NULL) - goto error2; + goto error; } + svc->hookflags = afb_hook_flags_svc(svc->api); + if (service) + *service = to_afb_service(svc); + /* initialises the listener if needed */ - svc->on_event = on_event; - if (on_event == NULL) - svc->listener = NULL; - else { + if (on_event) { + svc->on_event = on_event; svc->listener = afb_evt_listener_create(&evt_itf, svc); if (svc->listener == NULL) - goto error3; + goto error; } return svc; -error3: - afb_session_unref(svc->session); -error2: - free(svc); error: + afb_svc_destroy(svc, service); return NULL; } /* - * Creates a new service + * Starts a new service (v1) */ -struct afb_svc *afb_svc_create(int share_session, int (*init)(struct afb_service service), void (*on_event)(const char *event, struct json_object *object)) +int afb_svc_start_v1(struct afb_svc *svc, int (*start)(struct afb_service)) { int rc; - struct afb_svc *svc; - /* allocates the svc handler */ - svc = afb_svc_alloc(share_session, on_event); - if (svc == NULL) - goto error; - - /* initialises the svc now */ - rc = init((struct afb_service){ .itf = &service_itf, .closure = svc }); - if (rc < 0) - goto error2; - - return svc; - -error2: - if (svc->listener != NULL) - afb_evt_listener_unref(svc->listener); - afb_session_unref(svc->session); - free(svc); -error: - return NULL; + HOOK(start_before, svc); + rc = start(to_afb_service(svc)); + HOOK(start_after, svc, rc); + return rc; } /* - * Creates a new service + * Starts a new service (v2) */ -struct afb_svc *afb_svc_create_v2( - int share_session, - void (*on_event)(const char *event, struct json_object *object), - int (*start)(const struct afb_binding_interface *interface, struct afb_service service), - const struct afb_binding_interface *interface) +int afb_svc_start_v2(struct afb_svc *svc, int (*start)()) { int rc; - struct afb_svc *svc; - - /* allocates the svc handler */ - svc = afb_svc_alloc(share_session, on_event); - if (svc == NULL) - goto error; - /* initialises the svc now */ - rc = start(interface, (struct afb_service){ .itf = &service_itf, .closure = svc }); - if (rc < 0) - goto error2; - - return svc; + HOOK(start_before, svc); + rc = start(); + HOOK(start_after, svc, rc); + return rc; +} -error2: - if (svc->listener != NULL) - afb_evt_listener_unref(svc->listener); - afb_session_unref(svc->session); - free(svc); -error: - return NULL; +/* + * Request to updates the hooks + */ +void afb_svc_update_hook(struct afb_svc *svc) +{ + svc->hookflags = afb_hook_flags_svc(svc->api); } /* @@ -211,10 +214,97 @@ error: static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object) { struct afb_svc *svc = closure; + + HOOK(on_event_before, svc, event, eventid, object); svc->on_event(event, object); + HOOK(on_event_after, svc, event, eventid, object); 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; + 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 status, json_object *obj) +{ + struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq); + if (svcreq->async) { + struct afb_svc *svc = svcreq->svc; + if (svcreq->callback) + svcreq->callback(svcreq->closure, status, obj); + HOOK(call_result, svc, status, obj); + json_object_put(obj); + } else { + svcreq->status = status; + 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->status = -1; + svcreq_sync_leave(svcreq); + } +} + /* * Initiates a call for the service */ @@ -222,52 +312,70 @@ 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; + + HOOK(call, svc, api, verb, args); /* 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); - return afb_subcall_internal_error(callback, cbclosure); + ierr = afb_msg_json_internal_error(); + if (callback) + callback(cbclosure, -1, ierr); + HOOK(call_result, svc, -1, ierr); + json_object_put(ierr); + return; } /* initialises the request */ - afb_context_init(&svcreq->xreq.context, svc->session, NULL); - svcreq->xreq.context.validated = 1; - svcreq->xreq.refcount = 1; - svcreq->xreq.query = svcreq; - svcreq->xreq.queryitf = &afb_svc_xreq_itf; - svcreq->xreq.api = api; - svcreq->xreq.verb = verb; - svcreq->xreq.listener = svc->listener; - svcreq->args = args; + svcreq->jobloop = NULL; svcreq->callback = callback; svcreq->closure = cbclosure; - svcreq->svc = svc; + svcreq->async = 1; /* terminates and frees ressources if needed */ - afb_apis_xcall(&svcreq->xreq); - afb_xreq_unref(&svcreq->xreq); + afb_xreq_process(&svcreq->xreq, svc->apiset); } -static void svcreq_destroy(void *closure) +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 = closure; - afb_context_disconnect(&svcreq->xreq.context); - json_object_put(svcreq->args); - free(svcreq); -} + struct afb_svc *svc = closure; + struct svc_req *svcreq; + struct json_object *resu; + int rc; -static struct json_object *svcreq_json(void *closure) -{ - struct svc_req *svcreq = closure; - return svcreq->args; -} + HOOK(callsync, svc, api, verb, args); -static void svcreq_reply(void *closure, int iserror, json_object *obj) -{ - struct svc_req *svcreq = closure; - 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); + resu = afb_msg_json_internal_error(); + rc = -1; + } else { + /* initialises the request */ + svcreq->jobloop = NULL; + svcreq->callback = NULL; + svcreq->result = NULL; + svcreq->status = 0; + svcreq->async = 0; + afb_xreq_addref(&svcreq->xreq); + rc = jobs_enter(NULL, 0, svcreq_sync_enter, svcreq); + if (rc >= 0) + rc = svcreq->status; + resu = (rc >= 0 || svcreq->result) ? svcreq->result : afb_msg_json_internal_error(); + afb_xreq_unref(&svcreq->xreq); + } + HOOK(callsync_result, svc, rc, resu); + if (result) + *result = resu; + else + json_object_put(resu); + return rc; }