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"
43 /*************************************************************************
44 * internal types and structures
45 ************************************************************************/
67 /* version of the api */
77 /* session for service */
78 struct afb_session *session;
80 /* apiset for service */
81 struct afb_apiset *apiset;
83 /* event listener for service or NULL */
84 struct afb_evt_listener *listener;
88 int (*v1)(struct afb_service);
94 void (*v12)(const char *event, struct json_object *object);
99 struct afb_binding_interface_v1 v1;
100 struct afb_binding_data_v2 *v2;
104 /*************************************************************************************************************
105 *************************************************************************************************************
106 *************************************************************************************************************
107 *************************************************************************************************************
109 *************************************************************************************************************
110 *************************************************************************************************************
111 *************************************************************************************************************
112 *************************************************************************************************************/
114 /**********************************************
116 **********************************************/
117 static void vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
120 struct afb_export *export = closure;
122 if (!fmt || vasprintf(&p, fmt, args) < 0)
123 vverbose(level, file, line, function, fmt, args);
125 verbose(level, file, line, function, "[API %s] %s", export->apiname, p);
130 static void old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
132 vverbose_cb(closure, level, file, line, NULL, fmt, args);
135 static struct afb_event event_make_cb(void *closure, const char *name)
139 struct afb_export *export = closure;
141 /* check daemon state */
142 if (export->state == Api_State_Pre_Init) {
143 ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->apiname, name);
145 return (struct afb_event){ .itf = NULL, .closure = NULL };
148 /* makes the event name */
149 plen = strlen(export->apiname);
151 event = alloca(nlen + plen + 2);
152 memcpy(event, export->apiname, plen);
154 memcpy(event + plen + 1, name, nlen + 1);
156 /* create the event */
157 return afb_evt_create_event(event);
160 static int event_broadcast_cb(void *closure, const char *name, struct json_object *object)
164 struct afb_export *export = closure;
166 /* check daemon state */
167 if (export->state == Api_State_Pre_Init) {
168 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));
173 /* makes the event name */
174 plen = strlen(export->apiname);
176 event = alloca(nlen + plen + 2);
177 memcpy(event, export->apiname, plen);
179 memcpy(event + plen + 1, name, nlen + 1);
181 /* broadcast the event */
182 return afb_evt_broadcast(event, object);
185 static int rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale)
187 return afb_common_rootdir_open_locale(filename, flags, locale);
190 static int queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
192 return jobs_queue(group, timeout, callback, argument);
195 static struct afb_req unstore_req_cb(void *closure, struct afb_stored_req *sreq)
197 return afb_xreq_unstore(sreq);
200 static int require_api_cb(void *closure, const char *name, int initialized)
202 struct afb_export *export = closure;
203 if (export->state != Api_State_Init) {
204 ERROR("[API %s] Bad call to 'afb_daemon_require(%s, %d)', must be in Init", export->apiname, name, initialized);
208 return -!(initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->apiset, name, 1);
211 static int rename_api_cb(void *closure, const char *name)
213 struct afb_export *export = closure;
214 if (export->state != Api_State_Pre_Init) {
215 ERROR("[API %s] Bad call to 'afb_daemon_rename(%s)', must be in PreInit", export->apiname, name);
219 if (!afb_api_is_valid_name(name)) {
220 ERROR("[API %s] Can't rename to %s: bad API name", export->apiname, name);
224 NOTICE("[API %s] renamed to [API %s]", export->apiname, name);
225 afb_export_rename(export, name);
229 /**********************************************
231 **********************************************/
232 static void hooked_vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
234 struct afb_export *export = closure;
237 vverbose_cb(closure, level, file, line, function, fmt, args);
238 afb_hook_ditf_vverbose(export, level, file, line, function, fmt, ap);
242 static void hooked_old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
244 hooked_vverbose_cb(closure, level, file, line, NULL, fmt, args);
247 static struct afb_event hooked_event_make_cb(void *closure, const char *name)
249 struct afb_export *export = closure;
250 struct afb_event r = event_make_cb(closure, name);
251 return afb_hook_ditf_event_make(export, name, r);
254 static int hooked_event_broadcast_cb(void *closure, const char *name, struct json_object *object)
257 struct afb_export *export = closure;
258 json_object_get(object);
259 afb_hook_ditf_event_broadcast_before(export, name, json_object_get(object));
260 r = event_broadcast_cb(closure, name, object);
261 afb_hook_ditf_event_broadcast_after(export, name, object, r);
262 json_object_put(object);
266 static struct sd_event *hooked_get_event_loop(void *closure)
268 struct afb_export *export = closure;
269 struct sd_event *r = afb_common_get_event_loop();
270 return afb_hook_ditf_get_event_loop(export, r);
273 static struct sd_bus *hooked_get_user_bus(void *closure)
275 struct afb_export *export = closure;
276 struct sd_bus *r = afb_common_get_user_bus();
277 return afb_hook_ditf_get_user_bus(export, r);
280 static struct sd_bus *hooked_get_system_bus(void *closure)
282 struct afb_export *export = closure;
283 struct sd_bus *r = afb_common_get_system_bus();
284 return afb_hook_ditf_get_system_bus(export, r);
287 static int hooked_rootdir_get_fd(void *closure)
289 struct afb_export *export = closure;
290 int r = afb_common_rootdir_get_fd();
291 return afb_hook_ditf_rootdir_get_fd(export, r);
294 static int hooked_rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale)
296 struct afb_export *export = closure;
297 int r = rootdir_open_locale_cb(closure, filename, flags, locale);
298 return afb_hook_ditf_rootdir_open_locale(export, filename, flags, locale, r);
301 static int hooked_queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
303 struct afb_export *export = closure;
304 int r = queue_job_cb(closure, callback, argument, group, timeout);
305 return afb_hook_ditf_queue_job(export, callback, argument, group, timeout, r);
308 static struct afb_req hooked_unstore_req_cb(void *closure, struct afb_stored_req *sreq)
310 struct afb_export *export = closure;
311 afb_hook_ditf_unstore_req(export, sreq);
312 return unstore_req_cb(closure, sreq);
315 static int hooked_require_api_cb(void *closure, const char *name, int initialized)
318 struct afb_export *export = closure;
319 afb_hook_ditf_require_api(export, name, initialized);
320 result = require_api_cb(closure, name, initialized);
321 return afb_hook_ditf_require_api_result(export, name, initialized, result);
324 static int hooked_rename_api_cb(void *closure, const char *name)
326 struct afb_export *export = closure;
327 const char *oldname = export->apiname;
328 int result = rename_api_cb(closure, name);
329 return afb_hook_ditf_rename_api(export, oldname, name, result);
332 /**********************************************
334 **********************************************/
335 static const struct afb_daemon_itf daemon_itf = {
336 .vverbose_v1 = old_vverbose_cb,
337 .vverbose_v2 = vverbose_cb,
338 .event_make = event_make_cb,
339 .event_broadcast = event_broadcast_cb,
340 .get_event_loop = afb_common_get_event_loop,
341 .get_user_bus = afb_common_get_user_bus,
342 .get_system_bus = afb_common_get_system_bus,
343 .rootdir_get_fd = afb_common_rootdir_get_fd,
344 .rootdir_open_locale = rootdir_open_locale_cb,
345 .queue_job = queue_job_cb,
346 .unstore_req = unstore_req_cb,
347 .require_api = require_api_cb,
348 .rename_api = rename_api_cb
351 static const struct afb_daemon_itf hooked_daemon_itf = {
352 .vverbose_v1 = hooked_old_vverbose_cb,
353 .vverbose_v2 = hooked_vverbose_cb,
354 .event_make = hooked_event_make_cb,
355 .event_broadcast = hooked_event_broadcast_cb,
356 .get_event_loop = hooked_get_event_loop,
357 .get_user_bus = hooked_get_user_bus,
358 .get_system_bus = hooked_get_system_bus,
359 .rootdir_get_fd = hooked_rootdir_get_fd,
360 .rootdir_open_locale = hooked_rootdir_open_locale_cb,
361 .queue_job = hooked_queue_job_cb,
362 .unstore_req = hooked_unstore_req_cb,
363 .require_api = hooked_require_api_cb,
364 .rename_api = hooked_rename_api_cb
368 /*************************************************************************************************************
369 *************************************************************************************************************
370 *************************************************************************************************************
371 *************************************************************************************************************
373 *************************************************************************************************************
374 *************************************************************************************************************
375 *************************************************************************************************************
376 *************************************************************************************************************/
378 /* the common session for services sharing their session */
379 static struct afb_session *common_session;
381 /*************************************************************************************************************
382 *************************************************************************************************************
383 *************************************************************************************************************
384 *************************************************************************************************************
386 *************************************************************************************************************
387 *************************************************************************************************************
388 *************************************************************************************************************
389 *************************************************************************************************************/
392 * Structure for requests initiated by the service
396 struct afb_xreq xreq;
398 struct afb_export *export;
401 void (*callback)(void*, int, struct json_object*);
405 struct jobloop *jobloop;
406 struct json_object *result;
412 * destroys the call_req
414 static void callreq_destroy(struct afb_xreq *xreq)
416 struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
418 afb_context_disconnect(&callreq->xreq.context);
419 json_object_put(callreq->xreq.json);
420 afb_cred_unref(callreq->xreq.cred);
424 static void callreq_reply(struct afb_xreq *xreq, int status, json_object *obj)
426 struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
427 if (callreq->callback)
428 callreq->callback(callreq->closure, status, obj);
429 json_object_put(obj);
432 static void callreq_sync_leave(struct call_req *callreq)
434 struct jobloop *jobloop = callreq->jobloop;
437 callreq->jobloop = NULL;
442 static void callreq_reply_sync(struct afb_xreq *xreq, int status, json_object *obj)
444 struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
445 callreq->status = status;
446 callreq->result = obj;
447 callreq_sync_leave(callreq);
450 static void callreq_sync_enter(int signum, void *closure, struct jobloop *jobloop)
452 struct call_req *callreq = closure;
455 callreq->jobloop = jobloop;
456 afb_xreq_process(&callreq->xreq, callreq->export->apiset);
458 callreq->result = afb_msg_json_internal_error();
459 callreq->status = -1;
460 callreq_sync_leave(callreq);
464 /* interface for requests of services */
465 const struct afb_xreq_query_itf afb_export_xreq_itf = {
466 .unref = callreq_destroy,
467 .reply = callreq_reply
470 /* interface for requests of services */
471 const struct afb_xreq_query_itf afb_export_xreq_sync_itf = {
472 .unref = callreq_destroy,
473 .reply = callreq_reply_sync
479 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)
481 struct call_req *callreq;
482 size_t lenapi, lenverb;
485 /* allocates the request */
486 lenapi = 1 + strlen(api);
487 lenverb = 1 + strlen(verb);
488 callreq = malloc(lenapi + lenverb + sizeof *callreq);
489 if (callreq != NULL) {
490 /* initialises the request */
491 afb_xreq_init(&callreq->xreq, itf);
492 afb_context_init(&callreq->xreq.context, export->session, NULL);
493 callreq->xreq.context.validated = 1;
494 copy = (char*)&callreq[1];
495 memcpy(copy, api, lenapi);
496 callreq->xreq.api = copy;
497 copy = ©[lenapi];
498 memcpy(copy, verb, lenverb);
499 callreq->xreq.verb = copy;
500 callreq->xreq.listener = export->listener;
501 callreq->xreq.json = args;
502 callreq->export = export;
508 * Initiates a call for the service
510 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)
512 struct afb_export *export = closure;
513 struct call_req *callreq;
514 struct json_object *ierr;
516 /* allocates the request */
517 callreq = callreq_create(export, api, verb, args, &afb_export_xreq_itf);
518 if (callreq == NULL) {
519 ERROR("out of memory");
520 json_object_put(args);
521 ierr = afb_msg_json_internal_error();
523 callback(cbclosure, -1, ierr);
524 json_object_put(ierr);
528 /* initialises the request */
529 callreq->jobloop = NULL;
530 callreq->callback = callback;
531 callreq->closure = cbclosure;
534 /* terminates and frees ressources if needed */
535 afb_xreq_process(&callreq->xreq, export->apiset);
538 static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
539 struct json_object **result)
541 struct afb_export *export = closure;
542 struct call_req *callreq;
543 struct json_object *resu;
546 /* allocates the request */
547 callreq = callreq_create(export, api, verb, args, &afb_export_xreq_sync_itf);
548 if (callreq == NULL) {
549 ERROR("out of memory");
551 json_object_put(args);
552 resu = afb_msg_json_internal_error();
555 /* initialises the request */
556 callreq->jobloop = NULL;
557 callreq->callback = NULL;
558 callreq->result = NULL;
561 afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */
562 rc = jobs_enter(NULL, 0, callreq_sync_enter, callreq);
564 rc = callreq->status;
565 resu = (rc >= 0 || callreq->result) ? callreq->result : afb_msg_json_internal_error();
566 afb_xreq_unhooked_unref(&callreq->xreq);
571 json_object_put(resu);
577 struct afb_export *export;
578 void (*callback)(void*, int, struct json_object*);
582 static void svc_hooked_call_result(void *closure, int status, struct json_object *result)
584 struct hooked_call *hc = closure;
585 afb_hook_svc_call_result(hc->export, status, result);
586 hc->callback(hc->cbclosure, status, result);
590 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)
592 struct afb_export *export = closure;
593 struct hooked_call *hc;
595 if (export->hooksvc & afb_hook_flag_svc_call)
596 afb_hook_svc_call(export, api, verb, args);
598 if (export->hooksvc & afb_hook_flag_svc_call_result) {
599 hc = malloc(sizeof *hc);
601 WARNING("allocation failed");
604 hc->callback = callback;
605 hc->cbclosure = cbclosure;
606 callback = svc_hooked_call_result;
610 svc_call(closure, api, verb, args, callback, cbclosure);
613 static int svc_hooked_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
614 struct json_object **result)
616 struct afb_export *export = closure;
617 struct json_object *resu;
620 if (export->hooksvc & afb_hook_flag_svc_callsync)
621 afb_hook_svc_callsync(export, api, verb, args);
623 rc = svc_call_sync(closure, api, verb, args, &resu);
625 if (export->hooksvc & afb_hook_flag_svc_callsync_result)
626 afb_hook_svc_callsync_result(export, rc, resu);
631 json_object_put(resu);
636 /* the interface for services */
637 static const struct afb_service_itf service_itf = {
639 .call_sync = svc_call_sync
642 /* the interface for services */
643 static const struct afb_service_itf hooked_service_itf = {
644 .call = svc_hooked_call,
645 .call_sync = svc_hooked_call_sync
648 /*************************************************************************************************************
649 *************************************************************************************************************
650 *************************************************************************************************************
651 *************************************************************************************************************
653 *************************************************************************************************************
654 *************************************************************************************************************
655 *************************************************************************************************************
656 *************************************************************************************************************/
659 * Propagates the event to the service
661 static void export_on_event_v12(void *closure, const char *event, int eventid, struct json_object *object)
663 struct afb_export *export = closure;
665 if (export->hooksvc & afb_hook_flag_svc_on_event_before)
666 afb_hook_svc_on_event_before(export, event, eventid, object);
667 export->on_event.v12(event, object);
668 if (export->hooksvc & afb_hook_flag_svc_on_event_after)
669 afb_hook_svc_on_event_after(export, event, eventid, object);
670 json_object_put(object);
673 /* the interface for events */
674 static const struct afb_evt_itf evt_v12_itf = {
675 .broadcast = export_on_event_v12,
676 .push = export_on_event_v12
679 /*************************************************************************************************************
680 *************************************************************************************************************
681 *************************************************************************************************************
682 *************************************************************************************************************
684 *************************************************************************************************************
685 *************************************************************************************************************
686 *************************************************************************************************************
687 *************************************************************************************************************/
689 static struct afb_export *create(struct afb_apiset *apiset, const char *apiname, enum afb_api_version version)
691 struct afb_export *export;
693 /* session shared with other exports */
694 if (common_session == NULL) {
695 common_session = afb_session_create (NULL, 0);
696 if (common_session == NULL)
699 export = calloc(1, sizeof *export);
703 memset(export, 0, sizeof *export);
704 export->apiname = strdup(apiname);
705 export->version = version;
706 export->state = Api_State_Pre_Init;
707 export->session = afb_session_addref(common_session);
708 export->apiset = afb_apiset_addref(apiset);
713 void afb_export_destroy(struct afb_export *export)
716 if (export->listener != NULL)
717 afb_evt_listener_unref(export->listener);
718 afb_session_unref(export->session);
719 afb_apiset_unref(export->apiset);
720 free(export->apiname);
725 struct afb_export *afb_export_create_v1(struct afb_apiset *apiset, const char *apiname, int (*init)(struct afb_service), void (*onevent)(const char*, struct json_object*))
727 struct afb_export *export = create(apiset, apiname, Api_Version_1);
729 export->init.v1 = init;
730 export->on_event.v12 = onevent;
731 export->export.v1.verbosity = verbosity;
732 export->export.v1.mode = AFB_MODE_LOCAL;
733 export->export.v1.daemon.closure = export;
734 afb_export_update_hook(export);
739 struct afb_export *afb_export_create_v2(struct afb_apiset *apiset, const char *apiname, struct afb_binding_data_v2 *data, int (*init)(), void (*onevent)(const char*, struct json_object*))
741 struct afb_export *export = create(apiset, apiname, Api_Version_2);
743 export->init.v2 = init;
744 export->on_event.v12 = onevent;
745 export->export.v2 = data;
746 data->daemon.closure = export;
747 data->service.closure = export;
748 afb_export_update_hook(export);
753 void afb_export_rename(struct afb_export *export, const char *apiname)
755 free(export->apiname);
756 export->apiname = strdup(apiname);
757 afb_export_update_hook(export);
760 const char *afb_export_apiname(const struct afb_export *export)
762 return export->apiname;
765 void afb_export_update_hook(struct afb_export *export)
767 export->hookditf = afb_hook_flags_ditf(export->apiname);
768 export->hooksvc = afb_hook_flags_svc(export->apiname);
769 switch (export->version) {
771 export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf;
775 export->export.v2->daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf;
776 export->export.v2->service.itf = export->hooksvc ? &hooked_service_itf : &service_itf;
781 struct afb_binding_interface_v1 *afb_export_get_interface_v1(struct afb_export *export)
783 return export->version == Api_Version_1 ? &export->export.v1 : NULL;
786 int afb_export_unshare_session(struct afb_export *export)
788 if (export->session == common_session) {
789 export->session = afb_session_create (NULL, 0);
791 afb_session_unref(common_session);
793 export->session = common_session;
800 void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset)
802 struct afb_apiset *prvset = export->apiset;
803 export->apiset = afb_apiset_addref(apiset);
804 afb_apiset_unref(prvset);
807 struct afb_apiset *afb_export_get_apiset(struct afb_export *export)
809 return export->apiset;
813 * Creates a new service
815 int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object))
818 switch (export->version) {
819 case Api_Version_1: case Api_Version_2: break;
821 ERROR("invalid version 12 for API %s", export->apiname);
826 /* set the event handler */
828 if (export->listener) {
829 afb_evt_listener_unref(export->listener);
830 export->listener = NULL;
832 export->on_event.v12 = on_event;
834 export->on_event.v12 = on_event;
835 if (!export->listener) {
836 export->listener = afb_evt_listener_create(&evt_v12_itf, export);
837 if (export->listener == NULL)
845 * Starts a new service (v1)
847 struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*))
849 return regfun(&export->export.v1);
852 int afb_export_verbosity_get(const struct afb_export *export)
854 switch (export->version) {
855 case Api_Version_1: return export->export.v1.verbosity;
856 case Api_Version_2: return export->export.v2->verbosity;
861 void afb_export_verbosity_set(struct afb_export *export, int level)
863 switch (export->version) {
864 case Api_Version_1: export->export.v1.verbosity = level; break;
865 case Api_Version_2: export->export.v2->verbosity = level; break;
869 /*************************************************************************************************************
870 *************************************************************************************************************
871 *************************************************************************************************************
872 *************************************************************************************************************
874 *************************************************************************************************************
875 *************************************************************************************************************
876 *************************************************************************************************************
877 *************************************************************************************************************/
879 int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset)
884 if (export->state != Api_State_Pre_Init) {
885 /* not an error when onneed */
889 /* already started: it is an error */
890 ERROR("Service of API %s already started", export->apiname);
894 /* unshare the session if asked */
895 if (!share_session) {
896 rc = afb_export_unshare_session(export);
898 ERROR("Can't unshare the session for %s", export->apiname);
903 /* set event handling */
904 switch (export->version) {
907 rc = afb_export_handle_events_v12(export, export->on_event.v12);
914 ERROR("Can't set event handler for %s", export->apiname);
918 /* Starts the service */
919 if (export->hooksvc & afb_hook_flag_svc_start_before)
920 afb_hook_svc_start_before(export);
921 export->state = Api_State_Init;
922 switch (export->version) {
924 rc = export->init.v1 ? export->init.v1((struct afb_service){ .itf = &hooked_service_itf, .closure = export }) : 0;
927 rc = export->init.v2 ? export->init.v2() : 0;
932 export->state = Api_State_Run;
933 if (export->hooksvc & afb_hook_flag_svc_start_after)
934 afb_hook_svc_start_after(export, rc);
936 /* initialisation error */
937 ERROR("Initialisation of service API %s failed (%d): %m", export->apiname, rc);