2 * Copyright (C) 2016, 2017 "IoT.bzh"
3 * Author: José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
24 #include <json-c/json.h>
26 #include <afb/afb-binding-v1.h>
27 #include <afb/afb-binding-v2.h>
30 #include "afb-apiset.h"
31 #include "afb-common.h"
34 #include "afb-export.h"
36 #include "afb-msg-json.h"
37 #include "afb-session.h"
42 extern struct afb_apiset *main_apiset;
44 /*************************************************************************
45 * internal types and structures
46 ************************************************************************/
68 /* version of the api */
78 /* session for service */
79 struct afb_session *session;
81 /* apiset for service */
82 struct afb_apiset *apiset;
84 /* event listener for service or NULL */
85 struct afb_evt_listener *listener;
89 int (*v1)(struct afb_service);
95 void (*v12)(const char *event, struct json_object *object);
100 struct afb_binding_interface_v1 v1;
101 struct afb_binding_data_v2 *v2;
105 /*************************************************************************************************************
106 *************************************************************************************************************
107 *************************************************************************************************************
108 *************************************************************************************************************
110 *************************************************************************************************************
111 *************************************************************************************************************
112 *************************************************************************************************************
113 *************************************************************************************************************/
115 /**********************************************
117 **********************************************/
118 static void vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
121 struct afb_export *export = closure;
123 if (!fmt || vasprintf(&p, fmt, args) < 0)
124 vverbose(level, file, line, function, fmt, args);
126 verbose(level, file, line, function, "[API %s] %s", export->apiname, p);
131 static void old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
133 vverbose_cb(closure, level, file, line, NULL, fmt, args);
136 static struct afb_event event_make_cb(void *closure, const char *name)
140 struct afb_export *export = closure;
142 /* check daemon state */
143 if (export->state == Api_State_Pre_Init) {
144 ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->apiname, name);
146 return (struct afb_event){ .itf = NULL, .closure = NULL };
149 /* makes the event name */
150 plen = strlen(export->apiname);
152 event = alloca(nlen + plen + 2);
153 memcpy(event, export->apiname, plen);
155 memcpy(event + plen + 1, name, nlen + 1);
157 /* create the event */
158 return afb_evt_create_event(event);
161 static int event_broadcast_cb(void *closure, const char *name, struct json_object *object)
165 struct afb_export *export = closure;
167 /* check daemon state */
168 if (export->state == Api_State_Pre_Init) {
169 ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit", export->apiname, name, json_object_to_json_string(object));
174 /* makes the event name */
175 plen = strlen(export->apiname);
177 event = alloca(nlen + plen + 2);
178 memcpy(event, export->apiname, plen);
180 memcpy(event + plen + 1, name, nlen + 1);
182 /* broadcast the event */
183 return afb_evt_broadcast(event, object);
186 static int rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale)
188 return afb_common_rootdir_open_locale(filename, flags, locale);
191 static int queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
193 return jobs_queue(group, timeout, callback, argument);
196 static struct afb_req unstore_req_cb(void *closure, struct afb_stored_req *sreq)
198 return afb_xreq_unstore(sreq);
201 static int require_api_cb(void *closure, const char *name, int initialized)
203 struct afb_export *export = closure;
204 if (export->state != Api_State_Init) {
205 ERROR("[API %s] Bad call to 'afb_daemon_require(%s, %d)', must be in Init", export->apiname, name, initialized);
209 return -!(initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(main_apiset, name, 1);
212 static int rename_api_cb(void *closure, const char *name)
214 struct afb_export *export = closure;
215 if (export->state != Api_State_Pre_Init) {
216 ERROR("[API %s] Bad call to 'afb_daemon_rename(%s)', must be in PreInit", export->apiname, name);
220 if (!afb_api_is_valid_name(name)) {
221 ERROR("[API %s] Can't rename to %s: bad API name", export->apiname, name);
225 NOTICE("[API %s] renamed to [API %s]", export->apiname, name);
226 afb_export_rename(export, name);
230 /**********************************************
232 **********************************************/
233 static void hooked_vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
235 struct afb_export *export = closure;
238 vverbose_cb(closure, level, file, line, function, fmt, args);
239 afb_hook_ditf_vverbose(export, level, file, line, function, fmt, ap);
243 static void hooked_old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
245 hooked_vverbose_cb(closure, level, file, line, NULL, fmt, args);
248 static struct afb_event hooked_event_make_cb(void *closure, const char *name)
250 struct afb_export *export = closure;
251 struct afb_event r = event_make_cb(closure, name);
252 return afb_hook_ditf_event_make(export, name, r);
255 static int hooked_event_broadcast_cb(void *closure, const char *name, struct json_object *object)
258 struct afb_export *export = closure;
259 json_object_get(object);
260 afb_hook_ditf_event_broadcast_before(export, name, json_object_get(object));
261 r = event_broadcast_cb(closure, name, object);
262 afb_hook_ditf_event_broadcast_after(export, name, object, r);
263 json_object_put(object);
267 static struct sd_event *hooked_get_event_loop(void *closure)
269 struct afb_export *export = closure;
270 struct sd_event *r = afb_common_get_event_loop();
271 return afb_hook_ditf_get_event_loop(export, r);
274 static struct sd_bus *hooked_get_user_bus(void *closure)
276 struct afb_export *export = closure;
277 struct sd_bus *r = afb_common_get_user_bus();
278 return afb_hook_ditf_get_user_bus(export, r);
281 static struct sd_bus *hooked_get_system_bus(void *closure)
283 struct afb_export *export = closure;
284 struct sd_bus *r = afb_common_get_system_bus();
285 return afb_hook_ditf_get_system_bus(export, r);
288 static int hooked_rootdir_get_fd(void *closure)
290 struct afb_export *export = closure;
291 int r = afb_common_rootdir_get_fd();
292 return afb_hook_ditf_rootdir_get_fd(export, r);
295 static int hooked_rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale)
297 struct afb_export *export = closure;
298 int r = rootdir_open_locale_cb(closure, filename, flags, locale);
299 return afb_hook_ditf_rootdir_open_locale(export, filename, flags, locale, r);
302 static int hooked_queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
304 struct afb_export *export = closure;
305 int r = queue_job_cb(closure, callback, argument, group, timeout);
306 return afb_hook_ditf_queue_job(export, callback, argument, group, timeout, r);
309 static struct afb_req hooked_unstore_req_cb(void *closure, struct afb_stored_req *sreq)
311 struct afb_export *export = closure;
312 afb_hook_ditf_unstore_req(export, sreq);
313 return unstore_req_cb(closure, sreq);
316 static int hooked_require_api_cb(void *closure, const char *name, int initialized)
319 struct afb_export *export = closure;
320 afb_hook_ditf_require_api(export, name, initialized);
321 result = require_api_cb(closure, name, initialized);
322 return afb_hook_ditf_require_api_result(export, name, initialized, result);
325 static int hooked_rename_api_cb(void *closure, const char *name)
327 struct afb_export *export = closure;
328 const char *oldname = export->apiname;
329 int result = rename_api_cb(closure, name);
330 return afb_hook_ditf_rename_api(export, oldname, name, result);
333 /**********************************************
335 **********************************************/
336 static const struct afb_daemon_itf daemon_itf = {
337 .vverbose_v1 = old_vverbose_cb,
338 .vverbose_v2 = vverbose_cb,
339 .event_make = event_make_cb,
340 .event_broadcast = event_broadcast_cb,
341 .get_event_loop = afb_common_get_event_loop,
342 .get_user_bus = afb_common_get_user_bus,
343 .get_system_bus = afb_common_get_system_bus,
344 .rootdir_get_fd = afb_common_rootdir_get_fd,
345 .rootdir_open_locale = rootdir_open_locale_cb,
346 .queue_job = queue_job_cb,
347 .unstore_req = unstore_req_cb,
348 .require_api = require_api_cb,
349 .rename_api = rename_api_cb
352 static const struct afb_daemon_itf hooked_daemon_itf = {
353 .vverbose_v1 = hooked_old_vverbose_cb,
354 .vverbose_v2 = hooked_vverbose_cb,
355 .event_make = hooked_event_make_cb,
356 .event_broadcast = hooked_event_broadcast_cb,
357 .get_event_loop = hooked_get_event_loop,
358 .get_user_bus = hooked_get_user_bus,
359 .get_system_bus = hooked_get_system_bus,
360 .rootdir_get_fd = hooked_rootdir_get_fd,
361 .rootdir_open_locale = hooked_rootdir_open_locale_cb,
362 .queue_job = hooked_queue_job_cb,
363 .unstore_req = hooked_unstore_req_cb,
364 .require_api = hooked_require_api_cb,
365 .rename_api = hooked_rename_api_cb
369 /*************************************************************************************************************
370 *************************************************************************************************************
371 *************************************************************************************************************
372 *************************************************************************************************************
374 *************************************************************************************************************
375 *************************************************************************************************************
376 *************************************************************************************************************
377 *************************************************************************************************************/
379 /* the common session for services sharing their session */
380 static struct afb_session *common_session;
382 /*************************************************************************************************************
383 *************************************************************************************************************
384 *************************************************************************************************************
385 *************************************************************************************************************
387 *************************************************************************************************************
388 *************************************************************************************************************
389 *************************************************************************************************************
390 *************************************************************************************************************/
393 * Structure for requests initiated by the service
397 struct afb_xreq xreq;
399 struct afb_export *export;
402 void (*callback)(void*, int, struct json_object*);
406 struct jobloop *jobloop;
407 struct json_object *result;
413 * destroys the call_req
415 static void callreq_destroy(struct afb_xreq *xreq)
417 struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
419 afb_context_disconnect(&callreq->xreq.context);
420 json_object_put(callreq->xreq.json);
421 afb_cred_unref(callreq->xreq.cred);
425 static void callreq_reply(struct afb_xreq *xreq, int status, json_object *obj)
427 struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
428 if (callreq->callback)
429 callreq->callback(callreq->closure, status, obj);
430 json_object_put(obj);
433 static void callreq_sync_leave(struct call_req *callreq)
435 struct jobloop *jobloop = callreq->jobloop;
438 callreq->jobloop = NULL;
443 static void callreq_reply_sync(struct afb_xreq *xreq, int status, json_object *obj)
445 struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
446 callreq->status = status;
447 callreq->result = obj;
448 callreq_sync_leave(callreq);
451 static void callreq_sync_enter(int signum, void *closure, struct jobloop *jobloop)
453 struct call_req *callreq = closure;
456 callreq->jobloop = jobloop;
457 afb_xreq_process(&callreq->xreq, callreq->export->apiset);
459 callreq->result = afb_msg_json_internal_error();
460 callreq->status = -1;
461 callreq_sync_leave(callreq);
465 /* interface for requests of services */
466 const struct afb_xreq_query_itf afb_export_xreq_itf = {
467 .unref = callreq_destroy,
468 .reply = callreq_reply
471 /* interface for requests of services */
472 const struct afb_xreq_query_itf afb_export_xreq_sync_itf = {
473 .unref = callreq_destroy,
474 .reply = callreq_reply_sync
480 static struct call_req *callreq_create(struct afb_export *export, const char *api, const char *verb, struct json_object *args, const struct afb_xreq_query_itf *itf)
482 struct call_req *callreq;
483 size_t lenapi, lenverb;
486 /* allocates the request */
487 lenapi = 1 + strlen(api);
488 lenverb = 1 + strlen(verb);
489 callreq = malloc(lenapi + lenverb + sizeof *callreq);
490 if (callreq != NULL) {
491 /* initialises the request */
492 afb_xreq_init(&callreq->xreq, itf);
493 afb_context_init(&callreq->xreq.context, export->session, NULL);
494 callreq->xreq.context.validated = 1;
495 copy = (char*)&callreq[1];
496 memcpy(copy, api, lenapi);
497 callreq->xreq.api = copy;
498 copy = ©[lenapi];
499 memcpy(copy, verb, lenverb);
500 callreq->xreq.verb = copy;
501 callreq->xreq.listener = export->listener;
502 callreq->xreq.json = args;
503 callreq->export = export;
509 * Initiates a call for the service
511 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)
513 struct afb_export *export = closure;
514 struct call_req *callreq;
515 struct json_object *ierr;
517 /* allocates the request */
518 callreq = callreq_create(export, api, verb, args, &afb_export_xreq_itf);
519 if (callreq == NULL) {
520 ERROR("out of memory");
521 json_object_put(args);
522 ierr = afb_msg_json_internal_error();
524 callback(cbclosure, -1, ierr);
525 json_object_put(ierr);
529 /* initialises the request */
530 callreq->jobloop = NULL;
531 callreq->callback = callback;
532 callreq->closure = cbclosure;
535 /* terminates and frees ressources if needed */
536 afb_xreq_process(&callreq->xreq, export->apiset);
539 static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
540 struct json_object **result)
542 struct afb_export *export = closure;
543 struct call_req *callreq;
544 struct json_object *resu;
547 /* allocates the request */
548 callreq = callreq_create(export, api, verb, args, &afb_export_xreq_sync_itf);
549 if (callreq == NULL) {
550 ERROR("out of memory");
552 json_object_put(args);
553 resu = afb_msg_json_internal_error();
556 /* initialises the request */
557 callreq->jobloop = NULL;
558 callreq->callback = NULL;
559 callreq->result = NULL;
562 afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */
563 rc = jobs_enter(NULL, 0, callreq_sync_enter, callreq);
565 rc = callreq->status;
566 resu = (rc >= 0 || callreq->result) ? callreq->result : afb_msg_json_internal_error();
567 afb_xreq_unhooked_unref(&callreq->xreq);
572 json_object_put(resu);
578 struct afb_export *export;
579 void (*callback)(void*, int, struct json_object*);
583 static void svc_hooked_call_result(void *closure, int status, struct json_object *result)
585 struct hooked_call *hc = closure;
586 afb_hook_svc_call_result(hc->export, status, result);
587 hc->callback(hc->cbclosure, status, result);
591 static void svc_hooked_call(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cbclosure)
593 struct afb_export *export = closure;
594 struct hooked_call *hc;
596 if (export->hooksvc & afb_hook_flag_svc_call)
597 afb_hook_svc_call(export, api, verb, args);
599 if (export->hooksvc & afb_hook_flag_svc_call_result) {
600 hc = malloc(sizeof *hc);
602 WARNING("allocation failed");
605 hc->callback = callback;
606 hc->cbclosure = cbclosure;
607 callback = svc_hooked_call_result;
611 svc_call(closure, api, verb, args, callback, cbclosure);
614 static int svc_hooked_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
615 struct json_object **result)
617 struct afb_export *export = closure;
618 struct json_object *resu;
621 if (export->hooksvc & afb_hook_flag_svc_callsync)
622 afb_hook_svc_callsync(export, api, verb, args);
624 rc = svc_call_sync(closure, api, verb, args, &resu);
626 if (export->hooksvc & afb_hook_flag_svc_callsync_result)
627 afb_hook_svc_callsync_result(export, rc, resu);
632 json_object_put(resu);
637 /* the interface for services */
638 static const struct afb_service_itf service_itf = {
640 .call_sync = svc_call_sync
643 /* the interface for services */
644 static const struct afb_service_itf hooked_service_itf = {
645 .call = svc_hooked_call,
646 .call_sync = svc_hooked_call_sync
649 /*************************************************************************************************************
650 *************************************************************************************************************
651 *************************************************************************************************************
652 *************************************************************************************************************
654 *************************************************************************************************************
655 *************************************************************************************************************
656 *************************************************************************************************************
657 *************************************************************************************************************/
660 * Propagates the event to the service
662 static void export_on_event_v12(void *closure, const char *event, int eventid, struct json_object *object)
664 struct afb_export *export = closure;
666 if (export->hooksvc & afb_hook_flag_svc_on_event_before)
667 afb_hook_svc_on_event_before(export, event, eventid, object);
668 export->on_event.v12(event, object);
669 if (export->hooksvc & afb_hook_flag_svc_on_event_after)
670 afb_hook_svc_on_event_after(export, event, eventid, object);
671 json_object_put(object);
674 /* the interface for events */
675 static const struct afb_evt_itf evt_v12_itf = {
676 .broadcast = export_on_event_v12,
677 .push = export_on_event_v12
680 /*************************************************************************************************************
681 *************************************************************************************************************
682 *************************************************************************************************************
683 *************************************************************************************************************
685 *************************************************************************************************************
686 *************************************************************************************************************
687 *************************************************************************************************************
688 *************************************************************************************************************/
690 static struct afb_export *create(const char *apiname, enum afb_api_version version)
692 struct afb_export *export;
694 /* session shared with other exports */
695 if (common_session == NULL) {
696 common_session = afb_session_create (NULL, 0);
697 if (common_session == NULL)
700 export = calloc(1, sizeof *export);
704 memset(export, 0, sizeof *export);
705 export->apiname = strdup(apiname);
706 export->version = version;
707 export->state = Api_State_Pre_Init;
708 export->session = afb_session_addref(common_session);
709 export->apiset = afb_apiset_addref(main_apiset);
714 void afb_export_destroy(struct afb_export *export)
717 if (export->listener != NULL)
718 afb_evt_listener_unref(export->listener);
719 afb_session_unref(export->session);
720 afb_apiset_unref(export->apiset);
721 free(export->apiname);
726 struct afb_export *afb_export_create_v1(const char *apiname, int (*init)(struct afb_service), void (*onevent)(const char*, struct json_object*))
728 struct afb_export *export = create(apiname, Api_Version_1);
730 export->init.v1 = init;
731 export->on_event.v12 = onevent;
732 export->export.v1.verbosity = verbosity;
733 export->export.v1.mode = AFB_MODE_LOCAL;
734 export->export.v1.daemon.closure = export;
735 afb_export_update_hook(export);
740 struct afb_export *afb_export_create_v2(const char *apiname, struct afb_binding_data_v2 *data, int (*init)(), void (*onevent)(const char*, struct json_object*))
742 struct afb_export *export = create(apiname, Api_Version_2);
744 export->init.v2 = init;
745 export->on_event.v12 = onevent;
746 export->export.v2 = data;
747 data->daemon.closure = export;
748 data->service.closure = export;
749 afb_export_update_hook(export);
754 void afb_export_rename(struct afb_export *export, const char *apiname)
756 free(export->apiname);
757 export->apiname = strdup(apiname);
758 afb_export_update_hook(export);
761 const char *afb_export_apiname(const struct afb_export *export)
763 return export->apiname;
766 void afb_export_update_hook(struct afb_export *export)
768 export->hookditf = afb_hook_flags_ditf(export->apiname);
769 export->hooksvc = afb_hook_flags_svc(export->apiname);
770 switch (export->version) {
772 export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf;
776 export->export.v2->daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf;
777 export->export.v2->service.itf = export->hooksvc ? &hooked_service_itf : &service_itf;
782 struct afb_binding_interface_v1 *afb_export_get_interface_v1(struct afb_export *export)
784 return export->version == Api_Version_1 ? &export->export.v1 : NULL;
787 int afb_export_unshare_session(struct afb_export *export)
789 if (export->session == common_session) {
790 export->session = afb_session_create (NULL, 0);
792 afb_session_unref(common_session);
794 export->session = common_session;
801 void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset)
803 struct afb_apiset *prvset = export->apiset;
804 export->apiset = afb_apiset_addref(apiset);
805 afb_apiset_unref(prvset);
808 struct afb_apiset *afb_export_get_apiset(struct afb_export *export)
810 return export->apiset;
814 * Creates a new service
816 int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object))
819 switch (export->version) {
820 case Api_Version_1: case Api_Version_2: break;
822 ERROR("invalid version 12 for API %s", export->apiname);
827 /* set the event handler */
829 if (export->listener) {
830 afb_evt_listener_unref(export->listener);
831 export->listener = NULL;
833 export->on_event.v12 = on_event;
835 export->on_event.v12 = on_event;
836 if (!export->listener) {
837 export->listener = afb_evt_listener_create(&evt_v12_itf, export);
838 if (export->listener == NULL)
846 * Starts a new service (v1)
848 struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*))
850 return regfun(&export->export.v1);
853 int afb_export_verbosity_get(const struct afb_export *export)
855 switch (export->version) {
856 case Api_Version_1: return export->export.v1.verbosity;
857 case Api_Version_2: return export->export.v2->verbosity;
862 void afb_export_verbosity_set(struct afb_export *export, int level)
864 switch (export->version) {
865 case Api_Version_1: export->export.v1.verbosity = level; break;
866 case Api_Version_2: export->export.v2->verbosity = level; break;
870 /*************************************************************************************************************
871 *************************************************************************************************************
872 *************************************************************************************************************
873 *************************************************************************************************************
875 *************************************************************************************************************
876 *************************************************************************************************************
877 *************************************************************************************************************
878 *************************************************************************************************************/
880 int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset)
885 if (export->state != Api_State_Pre_Init) {
886 /* not an error when onneed */
890 /* already started: it is an error */
891 ERROR("Service of API %s already started", export->apiname);
895 /* unshare the session if asked */
896 if (!share_session) {
897 rc = afb_export_unshare_session(export);
899 ERROR("Can't unshare the session for %s", export->apiname);
904 /* set event handling */
905 switch (export->version) {
908 rc = afb_export_handle_events_v12(export, export->on_event.v12);
915 ERROR("Can't set event handler for %s", export->apiname);
919 /* Starts the service */
920 if (export->hooksvc & afb_hook_flag_svc_start_before)
921 afb_hook_svc_start_before(export);
922 export->state = Api_State_Init;
923 switch (export->version) {
925 rc = export->init.v1 ? export->init.v1((struct afb_service){ .itf = &hooked_service_itf, .closure = export }) : 0;
928 rc = export->init.v2 ? export->init.v2() : 0;
933 export->state = Api_State_Run;
934 if (export->hooksvc & afb_hook_flag_svc_start_after)
935 afb_hook_svc_start_after(export, rc);
937 /* initialisation error */
938 ERROR("Initialisation of service API %s failed (%d): %m", export->apiname, rc);