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;
87 /* event callback for service */
88 void (*on_event)(const char *event, struct json_object *object);
92 struct afb_binding_interface_v1 v1;
93 struct afb_binding_data_v2 *v2;
97 /*************************************************************************************************************
98 *************************************************************************************************************
99 *************************************************************************************************************
100 *************************************************************************************************************
102 *************************************************************************************************************
103 *************************************************************************************************************
104 *************************************************************************************************************
105 *************************************************************************************************************/
107 /**********************************************
109 **********************************************/
110 static void vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
113 struct afb_export *export = closure;
115 if (!fmt || vasprintf(&p, fmt, args) < 0)
116 vverbose(level, file, line, function, fmt, args);
118 verbose(level, file, line, function, "[API %s] %s", export->apiname, p);
123 static void old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
125 vverbose_cb(closure, level, file, line, NULL, fmt, args);
128 static struct afb_event event_make_cb(void *closure, const char *name)
132 struct afb_export *export = closure;
134 /* check daemon state */
135 if (export->state == Api_State_Pre_Init) {
136 ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->apiname, name);
138 return (struct afb_event){ .itf = NULL, .closure = NULL };
141 /* makes the event name */
142 plen = strlen(export->apiname);
144 event = alloca(nlen + plen + 2);
145 memcpy(event, export->apiname, plen);
147 memcpy(event + plen + 1, name, nlen + 1);
149 /* create the event */
150 return afb_evt_create_event(event);
153 static int event_broadcast_cb(void *closure, const char *name, struct json_object *object)
157 struct afb_export *export = closure;
159 /* check daemon state */
160 if (export->state == Api_State_Pre_Init) {
161 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));
166 /* makes the event name */
167 plen = strlen(export->apiname);
169 event = alloca(nlen + plen + 2);
170 memcpy(event, export->apiname, plen);
172 memcpy(event + plen + 1, name, nlen + 1);
174 /* broadcast the event */
175 return afb_evt_broadcast(event, object);
178 static int rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale)
180 return afb_common_rootdir_open_locale(filename, flags, locale);
183 static int queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
185 return jobs_queue(group, timeout, callback, argument);
188 static struct afb_req unstore_req_cb(void *closure, struct afb_stored_req *sreq)
190 return afb_xreq_unstore(sreq);
193 static int require_api_cb(void *closure, const char *name, int initialized)
195 struct afb_export *export = closure;
196 if (export->state != Api_State_Init) {
197 ERROR("[API %s] Bad call to 'afb_daemon_require(%s, %d)', must be in Init", export->apiname, name, initialized);
201 return -!(initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(main_apiset, name, 1);
204 static int rename_api_cb(void *closure, const char *name)
206 struct afb_export *export = closure;
207 if (export->state != Api_State_Pre_Init) {
208 ERROR("[API %s] Bad call to 'afb_daemon_rename(%s)', must be in PreInit", export->apiname, name);
212 if (!afb_api_is_valid_name(name)) {
213 ERROR("[API %s] Can't rename to %s: bad API name", export->apiname, name);
217 NOTICE("[API %s] renamed to [API %s]", export->apiname, name);
218 afb_export_rename(export, name);
222 /**********************************************
224 **********************************************/
225 static void hooked_vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
227 struct afb_export *export = closure;
230 vverbose_cb(closure, level, file, line, function, fmt, args);
231 afb_hook_ditf_vverbose(export, level, file, line, function, fmt, ap);
235 static void hooked_old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
237 hooked_vverbose_cb(closure, level, file, line, NULL, fmt, args);
240 static struct afb_event hooked_event_make_cb(void *closure, const char *name)
242 struct afb_export *export = closure;
243 struct afb_event r = event_make_cb(closure, name);
244 return afb_hook_ditf_event_make(export, name, r);
247 static int hooked_event_broadcast_cb(void *closure, const char *name, struct json_object *object)
250 struct afb_export *export = closure;
251 json_object_get(object);
252 afb_hook_ditf_event_broadcast_before(export, name, json_object_get(object));
253 r = event_broadcast_cb(closure, name, object);
254 afb_hook_ditf_event_broadcast_after(export, name, object, r);
255 json_object_put(object);
259 static struct sd_event *hooked_get_event_loop(void *closure)
261 struct afb_export *export = closure;
262 struct sd_event *r = afb_common_get_event_loop();
263 return afb_hook_ditf_get_event_loop(export, r);
266 static struct sd_bus *hooked_get_user_bus(void *closure)
268 struct afb_export *export = closure;
269 struct sd_bus *r = afb_common_get_user_bus();
270 return afb_hook_ditf_get_user_bus(export, r);
273 static struct sd_bus *hooked_get_system_bus(void *closure)
275 struct afb_export *export = closure;
276 struct sd_bus *r = afb_common_get_system_bus();
277 return afb_hook_ditf_get_system_bus(export, r);
280 static int hooked_rootdir_get_fd(void *closure)
282 struct afb_export *export = closure;
283 int r = afb_common_rootdir_get_fd();
284 return afb_hook_ditf_rootdir_get_fd(export, r);
287 static int hooked_rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale)
289 struct afb_export *export = closure;
290 int r = rootdir_open_locale_cb(closure, filename, flags, locale);
291 return afb_hook_ditf_rootdir_open_locale(export, filename, flags, locale, r);
294 static int hooked_queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
296 struct afb_export *export = closure;
297 int r = queue_job_cb(closure, callback, argument, group, timeout);
298 return afb_hook_ditf_queue_job(export, callback, argument, group, timeout, r);
301 static struct afb_req hooked_unstore_req_cb(void *closure, struct afb_stored_req *sreq)
303 struct afb_export *export = closure;
304 afb_hook_ditf_unstore_req(export, sreq);
305 return unstore_req_cb(closure, sreq);
308 static int hooked_require_api_cb(void *closure, const char *name, int initialized)
311 struct afb_export *export = closure;
312 afb_hook_ditf_require_api(export, name, initialized);
313 result = require_api_cb(closure, name, initialized);
314 return afb_hook_ditf_require_api_result(export, name, initialized, result);
317 static int hooked_rename_api_cb(void *closure, const char *name)
319 struct afb_export *export = closure;
320 const char *oldname = export->apiname;
321 int result = rename_api_cb(closure, name);
322 return afb_hook_ditf_rename_api(export, oldname, name, result);
325 /**********************************************
327 **********************************************/
328 static const struct afb_daemon_itf daemon_itf = {
329 .vverbose_v1 = old_vverbose_cb,
330 .vverbose_v2 = vverbose_cb,
331 .event_make = event_make_cb,
332 .event_broadcast = event_broadcast_cb,
333 .get_event_loop = afb_common_get_event_loop,
334 .get_user_bus = afb_common_get_user_bus,
335 .get_system_bus = afb_common_get_system_bus,
336 .rootdir_get_fd = afb_common_rootdir_get_fd,
337 .rootdir_open_locale = rootdir_open_locale_cb,
338 .queue_job = queue_job_cb,
339 .unstore_req = unstore_req_cb,
340 .require_api = require_api_cb,
341 .rename_api = rename_api_cb
344 static const struct afb_daemon_itf hooked_daemon_itf = {
345 .vverbose_v1 = hooked_old_vverbose_cb,
346 .vverbose_v2 = hooked_vverbose_cb,
347 .event_make = hooked_event_make_cb,
348 .event_broadcast = hooked_event_broadcast_cb,
349 .get_event_loop = hooked_get_event_loop,
350 .get_user_bus = hooked_get_user_bus,
351 .get_system_bus = hooked_get_system_bus,
352 .rootdir_get_fd = hooked_rootdir_get_fd,
353 .rootdir_open_locale = hooked_rootdir_open_locale_cb,
354 .queue_job = hooked_queue_job_cb,
355 .unstore_req = hooked_unstore_req_cb,
356 .require_api = hooked_require_api_cb,
357 .rename_api = hooked_rename_api_cb
361 /*************************************************************************************************************
362 *************************************************************************************************************
363 *************************************************************************************************************
364 *************************************************************************************************************
366 *************************************************************************************************************
367 *************************************************************************************************************
368 *************************************************************************************************************
369 *************************************************************************************************************/
371 /* the common session for services sharing their session */
372 static struct afb_session *common_session;
374 /*************************************************************************************************************
375 *************************************************************************************************************
376 *************************************************************************************************************
377 *************************************************************************************************************
379 *************************************************************************************************************
380 *************************************************************************************************************
381 *************************************************************************************************************
382 *************************************************************************************************************/
385 * Structure for requests initiated by the service
389 struct afb_xreq xreq;
391 struct afb_export *export;
394 void (*callback)(void*, int, struct json_object*);
398 struct jobloop *jobloop;
399 struct json_object *result;
405 * destroys the call_req
407 static void callreq_destroy(struct afb_xreq *xreq)
409 struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
411 afb_context_disconnect(&callreq->xreq.context);
412 json_object_put(callreq->xreq.json);
413 afb_cred_unref(callreq->xreq.cred);
417 static void callreq_reply(struct afb_xreq *xreq, int status, json_object *obj)
419 struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
420 if (callreq->callback)
421 callreq->callback(callreq->closure, status, obj);
422 json_object_put(obj);
425 static void callreq_sync_leave(struct call_req *callreq)
427 struct jobloop *jobloop = callreq->jobloop;
430 callreq->jobloop = NULL;
435 static void callreq_reply_sync(struct afb_xreq *xreq, int status, json_object *obj)
437 struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
438 callreq->status = status;
439 callreq->result = obj;
440 callreq_sync_leave(callreq);
443 static void callreq_sync_enter(int signum, void *closure, struct jobloop *jobloop)
445 struct call_req *callreq = closure;
448 callreq->jobloop = jobloop;
449 afb_xreq_process(&callreq->xreq, callreq->export->apiset);
451 callreq->result = afb_msg_json_internal_error();
452 callreq->status = -1;
453 callreq_sync_leave(callreq);
457 /* interface for requests of services */
458 const struct afb_xreq_query_itf afb_export_xreq_itf = {
459 .unref = callreq_destroy,
460 .reply = callreq_reply
463 /* interface for requests of services */
464 const struct afb_xreq_query_itf afb_export_xreq_sync_itf = {
465 .unref = callreq_destroy,
466 .reply = callreq_reply_sync
472 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)
474 struct call_req *callreq;
475 size_t lenapi, lenverb;
478 /* allocates the request */
479 lenapi = 1 + strlen(api);
480 lenverb = 1 + strlen(verb);
481 callreq = malloc(lenapi + lenverb + sizeof *callreq);
482 if (callreq != NULL) {
483 /* initialises the request */
484 afb_xreq_init(&callreq->xreq, itf);
485 afb_context_init(&callreq->xreq.context, export->session, NULL);
486 callreq->xreq.context.validated = 1;
487 copy = (char*)&callreq[1];
488 memcpy(copy, api, lenapi);
489 callreq->xreq.api = copy;
490 copy = ©[lenapi];
491 memcpy(copy, verb, lenverb);
492 callreq->xreq.verb = copy;
493 callreq->xreq.listener = export->listener;
494 callreq->xreq.json = args;
495 callreq->export = export;
501 * Initiates a call for the service
503 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)
505 struct afb_export *export = closure;
506 struct call_req *callreq;
507 struct json_object *ierr;
509 /* allocates the request */
510 callreq = callreq_create(export, api, verb, args, &afb_export_xreq_itf);
511 if (callreq == NULL) {
512 ERROR("out of memory");
513 json_object_put(args);
514 ierr = afb_msg_json_internal_error();
516 callback(cbclosure, -1, ierr);
517 json_object_put(ierr);
521 /* initialises the request */
522 callreq->jobloop = NULL;
523 callreq->callback = callback;
524 callreq->closure = cbclosure;
527 /* terminates and frees ressources if needed */
528 afb_xreq_process(&callreq->xreq, export->apiset);
531 static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
532 struct json_object **result)
534 struct afb_export *export = closure;
535 struct call_req *callreq;
536 struct json_object *resu;
539 /* allocates the request */
540 callreq = callreq_create(export, api, verb, args, &afb_export_xreq_sync_itf);
541 if (callreq == NULL) {
542 ERROR("out of memory");
544 json_object_put(args);
545 resu = afb_msg_json_internal_error();
548 /* initialises the request */
549 callreq->jobloop = NULL;
550 callreq->callback = NULL;
551 callreq->result = NULL;
554 afb_xreq_addref(&callreq->xreq);
555 rc = jobs_enter(NULL, 0, callreq_sync_enter, callreq);
557 rc = callreq->status;
558 resu = (rc >= 0 || callreq->result) ? callreq->result : afb_msg_json_internal_error();
559 afb_xreq_unref(&callreq->xreq);
564 json_object_put(resu);
570 struct afb_export *export;
571 void (*callback)(void*, int, struct json_object*);
575 static void svc_hooked_call_result(void *closure, int status, struct json_object *result)
577 struct hooked_call *hc = closure;
578 afb_hook_svc_call_result(hc->export, status, result);
579 hc->callback(hc->cbclosure, status, result);
583 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)
585 struct afb_export *export = closure;
586 struct hooked_call *hc;
588 if (export->hooksvc & afb_hook_flag_svc_call)
589 afb_hook_svc_call(export, api, verb, args);
591 if (export->hooksvc & afb_hook_flag_svc_call_result) {
592 hc = malloc(sizeof *hc);
594 WARNING("allocation failed");
597 hc->callback = callback;
598 hc->cbclosure = cbclosure;
599 callback = svc_hooked_call_result;
603 svc_call(closure, api, verb, args, callback, cbclosure);
606 static int svc_hooked_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
607 struct json_object **result)
609 struct afb_export *export = closure;
610 struct json_object *resu;
613 if (export->hooksvc & afb_hook_flag_svc_callsync)
614 afb_hook_svc_callsync(export, api, verb, args);
616 rc = svc_call_sync(closure, api, verb, args, &resu);
618 if (export->hooksvc & afb_hook_flag_svc_callsync_result)
619 afb_hook_svc_callsync_result(export, rc, resu);
624 json_object_put(resu);
629 /* the interface for services */
630 static const struct afb_service_itf service_itf = {
632 .call_sync = svc_call_sync
635 /* the interface for services */
636 static const struct afb_service_itf hooked_service_itf = {
637 .call = svc_hooked_call,
638 .call_sync = svc_hooked_call_sync
641 /*************************************************************************************************************
642 *************************************************************************************************************
643 *************************************************************************************************************
644 *************************************************************************************************************
646 *************************************************************************************************************
647 *************************************************************************************************************
648 *************************************************************************************************************
649 *************************************************************************************************************/
652 * Propagates the event to the service
654 static void export_on_event(void *closure, const char *event, int eventid, struct json_object *object)
656 struct afb_export *export = closure;
658 if (export->hooksvc & afb_hook_flag_svc_on_event_before)
659 afb_hook_svc_on_event_before(export, event, eventid, object);
660 export->on_event(event, object);
661 if (export->hooksvc & afb_hook_flag_svc_on_event_after)
662 afb_hook_svc_on_event_after(export, event, eventid, object);
663 json_object_put(object);
666 /* the interface for events */
667 static const struct afb_evt_itf evt_itf = {
668 .broadcast = export_on_event,
669 .push = export_on_event
672 /*************************************************************************************************************
673 *************************************************************************************************************
674 *************************************************************************************************************
675 *************************************************************************************************************
677 *************************************************************************************************************
678 *************************************************************************************************************
679 *************************************************************************************************************
680 *************************************************************************************************************/
682 static struct afb_export *create(const char *apiname, enum afb_api_version version)
684 struct afb_export *export;
686 /* session shared with other exports */
687 if (common_session == NULL) {
688 common_session = afb_session_create (NULL, 0);
689 if (common_session == NULL)
692 export = calloc(1, sizeof *export);
696 memset(export, 0, sizeof *export);
697 export->apiname = strdup(apiname);
698 export->version = version;
699 export->state = Api_State_Pre_Init;
700 export->session = afb_session_addref(common_session);
701 export->apiset = afb_apiset_addref(main_apiset);
706 void afb_export_destroy(struct afb_export *export)
709 if (export->listener != NULL)
710 afb_evt_listener_unref(export->listener);
711 afb_session_unref(export->session);
712 afb_apiset_unref(export->apiset);
713 free(export->apiname);
718 struct afb_export *afb_export_create_v1(const char *apiname)
720 struct afb_export *export = create(apiname, Api_Version_1);
722 export->export.v1.verbosity = verbosity;
723 export->export.v1.mode = AFB_MODE_LOCAL;
724 export->export.v1.daemon.closure = export;
725 afb_export_update_hook(export);
730 struct afb_export *afb_export_create_v2(const char *apiname, struct afb_binding_data_v2 *data)
732 struct afb_export *export = create(apiname, Api_Version_2);
734 export->export.v2 = data;
735 data->daemon.closure = export;
736 data->service.closure = export;
737 afb_export_update_hook(export);
742 void afb_export_rename(struct afb_export *export, const char *apiname)
744 free(export->apiname);
745 export->apiname = strdup(apiname);
746 afb_export_update_hook(export);
749 const char *afb_export_apiname(const struct afb_export *export)
751 return export->apiname;
754 void afb_export_update_hook(struct afb_export *export)
756 export->hookditf = afb_hook_flags_ditf(export->apiname);
757 export->hooksvc = afb_hook_flags_svc(export->apiname);
758 switch (export->version) {
760 export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf;
764 export->export.v2->daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf;
765 export->export.v2->service.itf = export->hooksvc ? &hooked_service_itf : &service_itf;
770 struct afb_binding_interface_v1 *afb_export_get_interface_v1(struct afb_export *export)
772 return export->version == Api_Version_1 ? &export->export.v1 : NULL;
775 int afb_export_unshare_session(struct afb_export *export)
777 if (export->session == common_session) {
778 export->session = afb_session_create (NULL, 0);
780 afb_session_unref(common_session);
782 export->session = common_session;
789 void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset)
791 struct afb_apiset *prvset = export->apiset;
792 export->apiset = afb_apiset_addref(apiset);
793 afb_apiset_unref(prvset);
797 * Creates a new service
799 int afb_export_handle_events(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object))
801 if (on_event != export->on_event) {
803 afb_evt_listener_unref(export->listener);
804 export->listener = NULL;
805 } else if (!export->listener) {
806 export->listener = afb_evt_listener_create(&evt_itf, export);
807 if (export->listener == NULL)
810 export->on_event = on_event;
817 int afb_export_is_started(const struct afb_export *export)
819 return export->state != Api_State_Pre_Init;
824 * Starts a new service (v1)
826 struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*))
828 return regfun(&export->export.v1);
832 int afb_export_start_v1(struct afb_export *export, int (*start)(struct afb_service))
835 struct afb_service svc = { .itf = &hooked_service_itf, .closure = export };
837 if (export->hooksvc & afb_hook_flag_svc_start_before)
838 afb_hook_svc_start_before(export);
839 export->state = Api_State_Init;
840 rc = start ? start(svc) : 0;
841 export->state = Api_State_Run;
842 if (export->hooksvc & afb_hook_flag_svc_start_after)
843 afb_hook_svc_start_after(export, rc);
848 * Starts a new service (v2)
850 int afb_export_start_v2(struct afb_export *export, int (*start)())
854 if (export->hooksvc & afb_hook_flag_svc_start_before)
855 afb_hook_svc_start_before(export);
856 export->state = Api_State_Init;
857 rc = start ? start() : 0;
858 export->state = Api_State_Run;
859 if (export->hooksvc & afb_hook_flag_svc_start_after)
860 afb_hook_svc_start_after(export, rc);
862 export->state = Api_State_Run;
866 int afb_export_verbosity_get(const struct afb_export *export)
868 switch (export->version) {
869 case Api_Version_1: return export->export.v1.verbosity;
870 case Api_Version_2: return export->export.v2->verbosity;
875 void afb_export_verbosity_set(struct afb_export *export, int level)
877 switch (export->version) {
878 case Api_Version_1: export->export.v1.verbosity = level; break;
879 case Api_Version_2: export->export.v2->verbosity = level; break;