2 * Copyright (C) 2016-2019 "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 #define AFB_BINDING_VERSION 0
27 #include <afb/afb-binding.h>
29 #include "afb-calls.h"
32 #include "afb-export.h"
34 #include "afb-msg-json.h"
35 #include "afb-session.h"
37 #include "afb-error-text.h"
42 #define CALLFLAGS (afb_req_x2_subcall_api_session|afb_req_x2_subcall_catch_events)
43 #define LEGACY_SUBCALLFLAGS (afb_req_x2_subcall_pass_events|afb_req_x2_subcall_on_behalf)
46 /************************************************************************/
55 #define mode_sync ((struct modes){ .hooked=0, .sync=1, .legacy=0 })
56 #define mode_async ((struct modes){ .hooked=0, .sync=0, .legacy=0 })
57 #define mode_legacy_sync ((struct modes){ .hooked=0, .sync=1, .legacy=1 })
58 #define mode_legacy_async ((struct modes){ .hooked=0, .sync=0, .legacy=1 })
61 #define mode_hooked_sync ((struct modes){ .hooked=1, .sync=1, .legacy=0 })
62 #define mode_hooked_async ((struct modes){ .hooked=1, .sync=0, .legacy=0 })
63 #define mode_hooked_legacy_sync ((struct modes){ .hooked=1, .sync=1, .legacy=1 })
64 #define mode_hooked_legacy_async ((struct modes){ .hooked=1, .sync=0, .legacy=1 })
70 void (*legacy_v1)(void*, int, struct json_object*);
71 void (*legacy_v2)(void*, int, struct json_object*, struct afb_req_x1);
72 void (*legacy_v3)(void*, int, struct json_object*, struct afb_req_x2*);
73 void (*x3)(void*, struct json_object*, const char*, const char *, struct afb_req_x2*);
76 void (*legacy_v12)(void*, int, struct json_object*);
77 void (*legacy_v3)(void*, int, struct json_object*, struct afb_api_x3*);
78 void (*x3)(void*, struct json_object*, const char*, const char*, struct afb_api_x3*);
86 struct afb_export *export;
94 struct jobloop *jobloop;
97 struct json_object **object;
102 union callback callback;
105 void (*final)(void*, struct json_object*, const char*, const char*, union callback, struct afb_export*,struct afb_xreq*);
106 void (*legacy_final)(void*, int, struct json_object*, union callback, struct afb_export*,struct afb_xreq*);
112 /******************************************************************************/
114 static int store_reply(
115 struct json_object *iobject, const char *ierror, const char *iinfo,
116 struct json_object **sobject, char **serror, char **sinfo)
121 else if (!(*serror = strdup(ierror))) {
122 ERROR("can't report error %s", ierror);
123 json_object_put(iobject);
132 json_object_put(iobject);
137 else if (!(*sinfo = strdup(iinfo)))
138 ERROR("can't report info %s", iinfo);
144 /******************************************************************************/
146 static void sync_leave(struct callreq *callreq)
148 struct jobloop *jobloop = __atomic_exchange_n(&callreq->jobloop, NULL, __ATOMIC_RELAXED);
153 static void sync_enter(int signum, void *closure, struct jobloop *jobloop)
155 struct callreq *callreq = closure;
157 callreq->jobloop = jobloop;
158 afb_export_process_xreq(callreq->export, &callreq->xreq);
160 afb_xreq_reply(&callreq->xreq, NULL, afb_error_text_internal_error, NULL);
164 /******************************************************************************/
166 static void callreq_destroy_cb(struct afb_xreq *xreq)
168 struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
170 afb_context_disconnect(&callreq->xreq.context);
171 json_object_put(callreq->xreq.json);
172 afb_cred_unref(callreq->xreq.cred);
176 static void callreq_reply_cb(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
178 struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
181 /* centralized hooking */
182 if (callreq->mode.hooked) {
183 if (callreq->mode.sync) {
184 if (callreq->xreq.caller)
185 afb_hook_xreq_subcallsync_result(callreq->xreq.caller, -!!error, object, error, info);
187 afb_hook_api_callsync_result(callreq->export, -!!error, object, error, info);
189 if (callreq->xreq.caller)
190 afb_hook_xreq_subcall_result(callreq->xreq.caller, object, error, info);
192 afb_hook_api_call_result(callreq->export, object, error, info);
197 /* true report of the result */
198 if (callreq->mode.sync) {
199 callreq->returned = 1;
200 if (callreq->mode.legacy) {
201 callreq->status = -!!error;
203 *callreq->object = afb_msg_json_reply(object, error, info, NULL);
205 json_object_put(object);
207 callreq->status = store_reply(object, error, info,
208 callreq->object, callreq->error, callreq->info);
212 if (callreq->mode.legacy) {
213 object = afb_msg_json_reply(object, error, info, NULL);
214 callreq->legacy_final(callreq->closure, -!!error, object, callreq->callback, callreq->export, callreq->xreq.caller);
216 callreq->final(callreq->closure, object, error, info, callreq->callback, callreq->export, callreq->xreq.caller);
218 json_object_put(object);
222 static int callreq_subscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event)
225 struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
227 if (callreq->flags & afb_req_x2_subcall_pass_events)
228 rc = afb_xreq_subscribe(callreq->xreq.caller, event);
229 if (callreq->flags & afb_req_x2_subcall_catch_events) {
230 rc2 = afb_export_subscribe(callreq->export, event);
237 static int callreq_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event)
240 struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
242 if (callreq->flags & afb_req_x2_subcall_pass_events)
243 rc = afb_xreq_unsubscribe(callreq->xreq.caller, event);
244 if (callreq->flags & afb_req_x2_subcall_catch_events) {
245 rc2 = afb_export_unsubscribe(callreq->export, event);
252 /******************************************************************************/
254 const struct afb_xreq_query_itf afb_calls_xreq_itf = {
255 .unref = callreq_destroy_cb,
256 .reply = callreq_reply_cb,
257 .subscribe = callreq_subscribe_cb,
258 .unsubscribe = callreq_unsubscribe_cb
261 /******************************************************************************/
263 static struct callreq *callreq_create(
264 struct afb_export *export,
265 struct afb_xreq *caller,
268 struct json_object *args,
272 struct callreq *callreq;
273 size_t lenapi, lenverb;
276 lenapi = 1 + strlen(api);
277 lenverb = 1 + strlen(verb);
278 callreq = malloc(lenapi + lenverb + sizeof *callreq);
280 ERROR("out of memory");
281 json_object_put(args);
284 afb_xreq_init(&callreq->xreq, &afb_calls_xreq_itf);
285 callreq->xreq.context.validated = 1;
286 api2 = (char*)&callreq[1];
287 callreq->xreq.request.called_api = memcpy(api2, api, lenapi);;
288 verb2 = &api2[lenapi];
289 callreq->xreq.request.called_verb = memcpy(verb2, verb, lenverb);
290 callreq->xreq.json = args;
291 callreq->mode = mode;
293 export = afb_export_from_api_x3(caller->request.api);
294 if (flags & afb_req_x2_subcall_on_behalf)
295 callreq->xreq.cred = afb_cred_addref(caller->cred);
296 callreq->xreq.caller = caller;
297 afb_xreq_unhooked_addref(caller);
299 if (caller && (flags & afb_req_x2_subcall_api_session))
300 afb_context_subinit(&callreq->xreq.context, &caller->context);
302 afb_export_context_init(export, &callreq->xreq.context);
303 callreq->export = export;
304 callreq->flags = flags;
309 /******************************************************************************/
312 struct afb_export *export,
313 struct afb_xreq *caller,
316 struct json_object *args,
318 struct json_object **object,
323 struct callreq *callreq;
326 /* allocates the request */
327 callreq = callreq_create(export, caller, api, verb, args, flags, mode);
331 /* initializes the request */
332 callreq->jobloop = NULL;
333 callreq->returned = 0;
335 callreq->object = object;
336 callreq->error = error;
337 callreq->info = info;
339 afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */
341 rc = jobs_enter(NULL, 0, sync_enter, callreq);
342 if (rc >= 0 && callreq->returned) {
343 rc = callreq->status;
344 afb_xreq_unhooked_unref(&callreq->xreq);
348 afb_xreq_unhooked_unref(&callreq->xreq);
350 return store_reply(NULL, afb_error_text_internal_error, NULL, object, error, info);
353 /******************************************************************************/
355 static void do_async(
356 struct afb_export *export,
357 struct afb_xreq *caller,
360 struct json_object *args,
364 void (*final)(void*, struct json_object*, const char*, const char*, union callback, struct afb_export*,struct afb_xreq*),
367 struct callreq *callreq;
369 callreq = callreq_create(export, caller, api, verb, args, flags, mode);
372 final(closure, NULL, afb_error_text_internal_error, NULL, (union callback){ .any = callback }, export, caller);
374 callreq->callback.any = callback;
375 callreq->closure = closure;
376 callreq->final = final;
378 afb_export_process_xreq(callreq->export, &callreq->xreq);
382 /******************************************************************************/
384 static void final_call(
386 struct json_object *object,
389 union callback callback,
390 struct afb_export *export,
391 struct afb_xreq *caller)
393 if (callback.call.x3)
394 callback.call.x3(closure, object, error, info, afb_export_to_api_x3(export));
397 static void final_subcall(
399 struct json_object *object,
402 union callback callback,
403 struct afb_export *export,
404 struct afb_xreq *caller)
406 if (callback.subcall.x3)
407 callback.subcall.x3(closure, object, error, info, xreq_to_req_x2(caller));
410 /******************************************************************************/
413 struct afb_export *export,
416 struct json_object *args,
417 void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*),
420 do_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_call, mode_async);
423 int afb_calls_call_sync(
424 struct afb_export *export,
427 struct json_object *args,
428 struct json_object **object,
432 return do_sync(export, NULL, api, verb, args, CALLFLAGS, object, error, info, mode_sync);
435 void afb_calls_subcall(
436 struct afb_xreq *xreq,
439 struct json_object *args,
441 void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
444 do_async(NULL, xreq, api, verb, args, flags, callback, closure, final_subcall, mode_async);
447 int afb_calls_subcall_sync(
448 struct afb_xreq *xreq,
451 struct json_object *args,
453 struct json_object **object,
457 return do_sync(NULL, xreq, api, verb, args, flags, object, error, info, mode_sync);
461 void afb_calls_hooked_call(
462 struct afb_export *export,
465 struct json_object *args,
466 void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*),
469 afb_hook_api_call(export, api, verb, args);
470 do_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_call, mode_hooked_async);
473 int afb_calls_hooked_call_sync(
474 struct afb_export *export,
477 struct json_object *args,
478 struct json_object **object,
482 afb_hook_api_callsync(export, api, verb, args);
483 return do_sync(export, NULL, api, verb, args, CALLFLAGS, object, error, info, mode_hooked_sync);
486 void afb_calls_hooked_subcall(
487 struct afb_xreq *xreq,
490 struct json_object *args,
492 void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
495 afb_hook_xreq_subcall(xreq, api, verb, args, flags);
496 do_async(NULL, xreq, api, verb, args, flags, callback, closure, final_subcall, mode_hooked_async);
499 int afb_calls_hooked_subcall_sync(
500 struct afb_xreq *xreq,
503 struct json_object *args,
505 struct json_object **object,
509 afb_hook_xreq_subcallsync(xreq, api, verb, args, flags);
510 return do_sync(NULL, xreq, api, verb, args, flags, object, error, info, mode_hooked_sync);
514 /******************************************************************************/
515 /******************************************************************************/
516 /******************************************************************************/
517 /******************************************************************************/
518 /******************************************************************************/
519 /******************************************************************************/
520 /******************************************************************************/
521 /******************************************************************************/
523 static int do_legacy_sync(
524 struct afb_export *export,
525 struct afb_xreq *caller,
528 struct json_object *args,
530 struct json_object **object,
533 struct callreq *callreq;
536 /* allocates the request */
537 callreq = callreq_create(export, caller, api, verb, args, flags, mode);
541 /* initializes the request */
542 callreq->jobloop = NULL;
543 callreq->returned = 0;
545 callreq->object = object;
547 afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */
549 rc = jobs_enter(NULL, 0, sync_enter, callreq);
550 if (rc >= 0 && callreq->returned) {
551 rc = callreq->status;
552 afb_xreq_unhooked_unref(&callreq->xreq);
556 afb_xreq_unhooked_unref(&callreq->xreq);
559 *object = afb_msg_json_reply(NULL, afb_error_text_internal_error, NULL, NULL);
563 /******************************************************************************/
565 static void do_legacy_async(
566 struct afb_export *export,
567 struct afb_xreq *caller,
570 struct json_object *args,
574 void (*final)(void*, int, struct json_object*, union callback, struct afb_export*,struct afb_xreq*),
577 struct callreq *callreq;
578 struct json_object *ie;
580 callreq = callreq_create(export, caller, api, verb, args, flags, mode);
583 ie = afb_msg_json_reply(NULL, afb_error_text_internal_error, NULL, NULL);
584 final(closure, -1, ie, (union callback){ .any = callback }, export, caller);
587 callreq->callback.any = callback;
588 callreq->closure = closure;
589 callreq->legacy_final = final;
591 afb_export_process_xreq(callreq->export, &callreq->xreq);
595 /******************************************************************************/
597 static void final_legacy_call_v12(
600 struct json_object *object,
601 union callback callback,
602 struct afb_export *export,
603 struct afb_xreq *caller)
605 if (callback.call.legacy_v12)
606 callback.call.legacy_v12(closure, status, object);
609 static void final_legacy_call_v3(
612 struct json_object *object,
613 union callback callback,
614 struct afb_export *export,
615 struct afb_xreq *caller)
617 if (callback.call.legacy_v3)
618 callback.call.legacy_v3(closure, status, object, afb_export_to_api_x3(export));
621 /******************************************************************************/
623 void afb_calls_legacy_call_v12(
624 struct afb_export *export,
627 struct json_object *args,
628 void (*callback)(void*, int, struct json_object*),
631 do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v12, mode_legacy_async);
634 void afb_calls_legacy_call_v3(
635 struct afb_export *export,
638 struct json_object *args,
639 void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *),
642 do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v3, mode_legacy_async);
645 int afb_calls_legacy_call_sync(
646 struct afb_export *export,
649 struct json_object *args,
650 struct json_object **result)
652 return do_legacy_sync(export, NULL, api, verb, args, CALLFLAGS, result, mode_legacy_sync);
656 void afb_calls_legacy_hooked_call_v12(
657 struct afb_export *export,
660 struct json_object *args,
661 void (*callback)(void*, int, struct json_object*),
664 afb_hook_api_call(export, api, verb, args);
665 do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v12, mode_hooked_legacy_async);
668 void afb_calls_legacy_hooked_call_v3(
669 struct afb_export *export,
672 struct json_object *args,
673 void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *),
676 afb_hook_api_call(export, api, verb, args);
677 do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v3, mode_hooked_legacy_async);
680 int afb_calls_legacy_hooked_call_sync(
681 struct afb_export *export,
684 struct json_object *args,
685 struct json_object **result)
688 struct json_object *object;
690 afb_hook_api_callsync(export, api, verb, args);
691 rc = do_legacy_sync(export, NULL, api, verb, args, CALLFLAGS, &object, mode_hooked_legacy_sync);
695 json_object_put(object);
700 /******************************************************************************/
702 static void final_legacy_subcall_v1(
705 struct json_object *object,
706 union callback callback,
707 struct afb_export *export,
708 struct afb_xreq *caller)
710 if (callback.subcall.legacy_v1)
711 callback.subcall.legacy_v1(closure, status, object);
714 static void final_legacy_subcall_v2(
717 struct json_object *object,
718 union callback callback,
719 struct afb_export *export,
720 struct afb_xreq *caller)
722 if (callback.subcall.legacy_v2)
723 callback.subcall.legacy_v2(closure, status, object, xreq_to_req_x1(caller));
726 static void final_legacy_subcall_v3(
729 struct json_object *object,
730 union callback callback,
731 struct afb_export *export,
732 struct afb_xreq *caller)
734 if (callback.subcall.legacy_v3)
735 callback.subcall.legacy_v3(closure, status, object, xreq_to_req_x2(caller));
738 /******************************************************************************/
740 void afb_calls_legacy_subcall_v1(
741 struct afb_xreq *caller,
744 struct json_object *args,
745 void (*callback)(void*, int, struct json_object*),
748 do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v1, mode_legacy_async);
751 void afb_calls_legacy_subcall_v2(
752 struct afb_xreq *caller,
755 struct json_object *args,
756 void (*callback)(void*, int, struct json_object*, struct afb_req_x1),
759 do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v2, mode_legacy_async);
762 void afb_calls_legacy_subcall_v3(
763 struct afb_xreq *caller,
766 struct json_object *args,
767 void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *),
770 do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v3, mode_legacy_async);
773 int afb_calls_legacy_subcall_sync(
774 struct afb_xreq *caller,
777 struct json_object *args,
778 struct json_object **result)
780 return do_legacy_sync(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, result, mode_legacy_sync);
784 void afb_calls_legacy_hooked_subcall_v1(
785 struct afb_xreq *caller,
788 struct json_object *args,
789 void (*callback)(void*, int, struct json_object*),
792 afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
793 do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v1, mode_hooked_legacy_async);
796 void afb_calls_legacy_hooked_subcall_v2(
797 struct afb_xreq *caller,
800 struct json_object *args,
801 void (*callback)(void*, int, struct json_object*, struct afb_req_x1),
804 afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
805 do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v2, mode_hooked_legacy_async);
808 void afb_calls_legacy_hooked_subcall_v3(
809 struct afb_xreq *caller,
812 struct json_object *args,
813 void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *),
816 afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
817 do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v3, mode_hooked_legacy_async);
820 int afb_calls_legacy_hooked_subcall_sync(
821 struct afb_xreq *caller,
824 struct json_object *args,
825 struct json_object **result)
827 afb_hook_xreq_subcallsync(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
828 return do_legacy_sync(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, result, mode_hooked_legacy_sync);