X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-svc.c;h=ac012914c0aa07cb658bf2eee2af6037c3eccb1f;hb=090379fdaf6ed1860dcff21424135ad71ead0cd2;hp=95617d5db946f3f538af3ae20f865dc989d060e9;hpb=d8ef25780bffa6f91f013ef71b1ede908325e59d;p=src%2Fapp-framework-binder.git diff --git a/src/afb-svc.c b/src/afb-svc.c index 95617d5d..ac012914 100644 --- a/src/afb-svc.c +++ b/src/afb-svc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 "IoT.bzh" + * Copyright (C) 2016, 2017 "IoT.bzh" * Author: José Bollo * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,17 +18,24 @@ #define _GNU_SOURCE #include +#include +#include #include -#include -#include +#include +#include -#include "session.h" +#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-cred.h" +#include "afb-apiset.h" +#include "jobs.h" +#include "verbose.h" /* * Structure for recording service @@ -36,7 +43,10 @@ struct afb_svc { /* session of the service */ - struct AFB_clientCtx *session; + struct afb_session *session; + + /* the apiset for the service */ + struct afb_apiset *apiset; /* event listener of the service or NULL */ struct afb_evt_listener *listener; @@ -50,177 +60,341 @@ struct afb_svc */ struct svc_req { - /* - * CAUTION: 'context' field should be the first because there - * is an implicit convertion to struct afb_context - */ - struct afb_context context; + struct afb_xreq xreq; - /* the service */ struct afb_svc *svc; - /* the count of references to the request */ - int refcount; + /* 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(struct afb_svc *svc, const char *event, int eventid, struct json_object *object); -static void svc_call(struct afb_svc *svc, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*), void *closure); +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 = (void*)svc_call + .call = svc_call, + .call_sync = svc_call_sync }; /* the interface for events */ static const struct afb_evt_itf evt_itf = { - .broadcast = (void*)svc_on_event, - .push = (void*)svc_on_event + .broadcast = svc_on_event, + .push = svc_on_event }; /* functions for requests of services */ -static void svcreq_addref(struct svc_req *svcreq); -static void svcreq_unref(struct svc_req *svcreq); -static int svcreq_subscribe(struct svc_req *svcreq, struct afb_event event); -static int svcreq_unsubscribe(struct svc_req *svcreq, struct afb_event event); -static void svcreq_subcall(struct svc_req *svcreq, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*), void *closure); +static void svcreq_destroy(struct afb_xreq *xreq); +static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj); /* interface for requests of services */ -const struct afb_req_itf afb_svc_req_itf = { - .addref = (void*)svcreq_addref, - .unref = (void*)svcreq_unref, - .context_get = (void*)afb_context_get, - .context_set = (void*)afb_context_set, - .session_close = (void*)afb_context_close, - .session_set_LOA = (void*)afb_context_change_loa, - .subscribe = (void*)svcreq_subscribe, - .unsubscribe = (void*)svcreq_unsubscribe, - .subcall = (void*)svcreq_subcall +const struct afb_xreq_query_itf afb_svc_xreq_itf = { + .unref = svcreq_destroy, + .reply = svcreq_reply }; -/* the common session for services sahring their session */ -static struct AFB_clientCtx *common_session; +/* 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 }; +} /* - * Creates a new service + * Frees a service */ -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)) +static void svc_free(struct afb_svc *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); +} + +/* + * Allocates a new service + */ +static struct afb_svc *afb_svc_alloc( + struct afb_apiset *apiset, + int share_session +) { - int rc; 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->apiset = afb_apiset_addref(apiset); /* instanciate the session */ if (share_session) { /* session shared with other svcs */ if (common_session == NULL) { - common_session = ctxClientCreate (NULL, 0); + common_session = afb_session_create (NULL, 0); if (common_session == NULL) - goto error2; + goto error; } - svc->session = ctxClientAddRef(common_session); + svc->session = afb_session_addref(common_session); } else { /* session dedicated to the svc */ - svc->session = ctxClientCreate (NULL, 0); + svc->session = afb_session_create (NULL, 0); if (svc->session == NULL) - goto error2; + goto error; } + return svc; + +error: + svc_free(svc); + return NULL; +} + +/* + * Creates a new service + */ +struct afb_svc *afb_svc_create_v1( + struct afb_apiset *apiset, + int share_session, + int (*start)(struct afb_service service), + void (*on_event)(const char *event, struct json_object *object) +) +{ + int rc; + struct afb_svc *svc; + + /* allocates the svc handler */ + svc = afb_svc_alloc(apiset, share_session); + if (svc == NULL) + goto error; + /* initialises the listener if needed */ - 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; } /* initialises the svc now */ - rc = init((struct afb_service){ .itf = &service_itf, .closure = svc }); + rc = start(to_afb_service(svc)); if (rc < 0) - goto error4; + goto error; + + return svc; + +error: + svc_free(svc); + return NULL; +} + +/* + * Creates a new service + */ +struct afb_svc *afb_svc_create_v2( + struct afb_apiset *apiset, + int share_session, + int (*start)(), + void (*on_event)(const char *event, struct json_object *object), + struct afb_binding_data_v2 *data +) +{ + int rc; + struct afb_svc *svc; + + /* allocates the svc handler */ + svc = afb_svc_alloc(apiset, share_session); + if (svc == NULL) + goto error; + data->service = to_afb_service(svc); + + /* initialises the listener if needed */ + if (on_event) { + svc->on_event = on_event; + svc->listener = afb_evt_listener_create(&evt_itf, svc); + if (svc->listener == NULL) + goto error; + } + + /* starts the svc if needed */ + if (start) { + rc = start(); + if (rc < 0) + goto error; + } return svc; -error4: - if (svc->listener != NULL) - afb_evt_listener_unref(svc->listener); -error3: - ctxClientUnref(svc->session); -error2: - free(svc); error: + svc_free(svc); return NULL; } /* * Propagates the event to the service */ -static void svc_on_event(struct afb_svc *svc, const char *event, int eventid, struct json_object *object) +static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object) { + struct afb_svc *svc = closure; svc->on_event(event, object); + json_object_put(object); } /* - * Initiates a call for the service + * create an svc_req */ -static void svc_call(struct afb_svc *svc, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) +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 */ - svcreq = malloc(sizeof *svcreq); - if (svcreq == NULL) - return afb_subcall_internal_error(callback, closure); - - /* initialises the request */ - afb_context_init(&svcreq->context, svc->session, NULL); - svcreq->context.validated = 1; - svcreq->svc = svc; - svcreq->refcount = 1; + 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; +} - /* makes the call */ - afb_subcall(&svcreq->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_svc_req_itf, .closure = svcreq }); +/* + * destroys the svc_req + */ +static void svcreq_destroy(struct afb_xreq *xreq) +{ + struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq); - /* terminates and frees ressources if needed */ - svcreq_unref(svcreq); + afb_context_disconnect(&svcreq->xreq.context); + json_object_put(svcreq->xreq.json); + afb_cred_unref(svcreq->xreq.cred); + free(svcreq); } -static void svcreq_addref(struct svc_req *svcreq) +static void svcreq_sync_leave(struct svc_req *svcreq) { - svcreq->refcount++; + struct jobloop *jobloop = svcreq->jobloop; + + if (jobloop) { + svcreq->jobloop = NULL; + jobs_leave(jobloop); + } } -static void svcreq_unref(struct svc_req *svcreq) +static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj) { - if (0 == --svcreq->refcount) { - afb_context_disconnect(&svcreq->context); - free(svcreq); + 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 int svcreq_subscribe(struct svc_req *svcreq, struct afb_event event) +static void svcreq_sync_enter(int signum, void *closure, struct jobloop *jobloop) { - if (svcreq->svc->listener == NULL) - return -1; - return afb_evt_add_watch(svcreq->svc->listener, event); + 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); + } } -static int svcreq_unsubscribe(struct svc_req *svcreq, struct afb_event event) +/* + * Initiates a call for the service + */ +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) { - if (svcreq->svc->listener == NULL) - return -1; - return afb_evt_remove_watch(svcreq->svc->listener, event); + struct afb_svc *svc = closure; + struct svc_req *svcreq; + struct json_object *ierr; + + /* allocates the request */ + svcreq = svcreq_create(svc, api, verb, args); + if (svcreq == NULL) { + ERROR("out of memory"); + json_object_put(args); + ierr = afb_msg_json_internal_error(); + callback(cbclosure, 1, ierr); + json_object_put(ierr); + return; + } + + /* initialises the request */ + svcreq->jobloop = NULL; + svcreq->callback = callback; + svcreq->closure = cbclosure; + + /* terminates and frees ressources if needed */ + afb_xreq_process(&svcreq->xreq, svc->apiset); } -static void svcreq_subcall(struct svc_req *svcreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) +static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args, + struct json_object **result) { - afb_subcall(&svcreq->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_svc_req_itf, .closure = svcreq }); + struct afb_svc *svc = closure; + struct svc_req *svcreq; + int rc; + + /* 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; }