Update copyright dates
[src/app-framework-binder.git] / src / afb-calls.c
1 /*
2  * Copyright (C) 2015-2020 "IoT.bzh"
3  * Author: José Bollo <jose.bollo@iot.bzh>
4  *
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
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23
24 #include <json-c/json.h>
25
26 #define AFB_BINDING_VERSION 0
27 #include <afb/afb-binding.h>
28
29 #include "afb-calls.h"
30 #include "afb-evt.h"
31 #include "afb-export.h"
32 #include "afb-hook.h"
33 #include "afb-msg-json.h"
34 #include "afb-session.h"
35 #include "afb-xreq.h"
36 #include "afb-error-text.h"
37
38 #include "jobs.h"
39 #include "verbose.h"
40
41 #define CALLFLAGS            (afb_req_x2_subcall_api_session|afb_req_x2_subcall_catch_events)
42 #define LEGACY_SUBCALLFLAGS  (afb_req_x2_subcall_pass_events|afb_req_x2_subcall_on_behalf)
43
44
45 /************************************************************************/
46
47 struct modes
48 {
49         unsigned hooked: 1;
50         unsigned sync: 1;
51         unsigned legacy: 1;
52 };
53
54 #define mode_sync  ((struct modes){ .hooked=0, .sync=1, .legacy=0 })
55 #define mode_async  ((struct modes){ .hooked=0, .sync=0, .legacy=0 })
56 #define mode_legacy_sync  ((struct modes){ .hooked=0, .sync=1, .legacy=1 })
57 #define mode_legacy_async  ((struct modes){ .hooked=0, .sync=0, .legacy=1 })
58
59 #if WITH_AFB_HOOK
60 #define mode_hooked_sync  ((struct modes){ .hooked=1, .sync=1, .legacy=0 })
61 #define mode_hooked_async  ((struct modes){ .hooked=1, .sync=0, .legacy=0 })
62 #define mode_hooked_legacy_sync  ((struct modes){ .hooked=1, .sync=1, .legacy=1 })
63 #define mode_hooked_legacy_async  ((struct modes){ .hooked=1, .sync=0, .legacy=1 })
64 #endif
65
66 union callback {
67         void *any;
68         union {
69                 void (*legacy_v1)(void*, int, struct json_object*);
70                 void (*legacy_v2)(void*, int, struct json_object*, struct afb_req_x1);
71                 void (*legacy_v3)(void*, int, struct json_object*, struct afb_req_x2*);
72                 void (*x3)(void*, struct json_object*, const char*, const char *, struct afb_req_x2*);
73         } subcall;
74         union {
75                 void (*legacy_v12)(void*, int, struct json_object*);
76                 void (*legacy_v3)(void*, int, struct json_object*, struct afb_api_x3*);
77                 void (*x3)(void*, struct json_object*, const char*, const char*, struct afb_api_x3*);
78         } call;
79 };
80
81 struct callreq
82 {
83         struct afb_xreq xreq;
84
85         struct afb_export *export;
86
87         struct modes mode;
88
89         int flags;
90
91         union {
92                 struct {
93                         struct jobloop *jobloop;
94                         int returned;
95                         int status;
96                         struct json_object **object;
97                         char **error;
98                         char **info;
99                 };
100                 struct {
101                         union callback callback;
102                         void *closure;
103                         union {
104                                 void (*final)(void*, struct json_object*, const char*, const char*, union callback, struct afb_export*,struct afb_xreq*);
105                                 void (*legacy_final)(void*, int, struct json_object*, union callback, struct afb_export*,struct afb_xreq*);
106                         };
107                 };
108         };
109 };
110
111 /******************************************************************************/
112
113 static int store_reply(
114                 struct json_object *iobject, const char *ierror, const char *iinfo,
115                 struct json_object **sobject, char **serror, char **sinfo)
116 {
117         if (serror) {
118                 if (!ierror)
119                         *serror = NULL;
120                 else if (!(*serror = strdup(ierror))) {
121                         ERROR("can't report error %s", ierror);
122                         json_object_put(iobject);
123                         iobject = NULL;
124                         iinfo = NULL;
125                 }
126         }
127
128         if (sobject)
129                 *sobject = iobject;
130         else
131                 json_object_put(iobject);
132
133         if (sinfo) {
134                 if (!iinfo)
135                         *sinfo = NULL;
136                 else if (!(*sinfo = strdup(iinfo)))
137                         ERROR("can't report info %s", iinfo);
138         }
139
140         return -!!ierror;
141 }
142
143 /******************************************************************************/
144
145 static void sync_leave(struct callreq *callreq)
146 {
147         struct jobloop *jobloop = __atomic_exchange_n(&callreq->jobloop, NULL, __ATOMIC_RELAXED);
148         if (jobloop)
149                 jobs_leave(jobloop);
150 }
151
152 static void sync_enter(int signum, void *closure, struct jobloop *jobloop)
153 {
154         struct callreq *callreq = closure;
155         if (!signum) {
156                 callreq->jobloop = jobloop;
157                 afb_export_process_xreq(callreq->export, &callreq->xreq);
158         } else {
159                 afb_xreq_reply(&callreq->xreq, NULL, afb_error_text_internal_error, NULL);
160         }
161 }
162
163 /******************************************************************************/
164
165 static void callreq_destroy_cb(struct afb_xreq *xreq)
166 {
167         struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
168
169         afb_context_disconnect(&callreq->xreq.context);
170         json_object_put(callreq->xreq.json);
171         free(callreq);
172 }
173
174 static void callreq_reply_cb(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
175 {
176         struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
177
178 #if WITH_AFB_HOOK
179         /* centralized hooking */
180         if (callreq->mode.hooked) {
181                 if (callreq->mode.sync) {
182                         if (callreq->xreq.caller)
183                                 afb_hook_xreq_subcallsync_result(callreq->xreq.caller, -!!error, object, error, info);
184                         else
185                                 afb_hook_api_callsync_result(callreq->export, -!!error, object, error, info);
186                 } else {
187                         if (callreq->xreq.caller)
188                                 afb_hook_xreq_subcall_result(callreq->xreq.caller, object, error, info);
189                         else
190                                 afb_hook_api_call_result(callreq->export, object, error, info);
191                 }
192         }
193 #endif
194
195         /* true report of the result */
196         if (callreq->mode.sync) {
197                 callreq->returned = 1;
198                 if (callreq->mode.legacy) {
199                         callreq->status = -!!error;
200                         if (callreq->object)
201                                 *callreq->object = afb_msg_json_reply(object, error, info, NULL);
202                         else
203                                 json_object_put(object);
204                 } else {
205                         callreq->status = store_reply(object, error, info,
206                                         callreq->object, callreq->error, callreq->info);
207                 }
208                 sync_leave(callreq);
209         } else {
210                 if (callreq->mode.legacy) {
211                         object = afb_msg_json_reply(object, error, info, NULL);
212                         callreq->legacy_final(callreq->closure, -!!error, object, callreq->callback, callreq->export, callreq->xreq.caller);
213                 } else {
214                         callreq->final(callreq->closure, object, error, info, callreq->callback, callreq->export, callreq->xreq.caller);
215                 }
216                 json_object_put(object);
217         }
218 }
219
220 static int callreq_subscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event)
221 {
222         int rc = 0, rc2;
223         struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
224
225         if (callreq->flags & afb_req_x2_subcall_pass_events)
226                 rc = afb_xreq_subscribe(callreq->xreq.caller, event);
227         if (callreq->flags & afb_req_x2_subcall_catch_events) {
228                 rc2 = afb_export_subscribe(callreq->export, event);
229                 if (rc2 < 0)
230                         rc = rc2;
231         }
232         return rc;
233 }
234
235 static int callreq_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event)
236 {
237         int rc = 0, rc2;
238         struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq);
239
240         if (callreq->flags & afb_req_x2_subcall_pass_events)
241                 rc = afb_xreq_unsubscribe(callreq->xreq.caller, event);
242         if (callreq->flags & afb_req_x2_subcall_catch_events) {
243                 rc2 = afb_export_unsubscribe(callreq->export, event);
244                 if (rc2 < 0)
245                         rc = rc2;
246         }
247         return rc;
248 }
249
250 /******************************************************************************/
251
252 const struct afb_xreq_query_itf afb_calls_xreq_itf = {
253         .unref = callreq_destroy_cb,
254         .reply = callreq_reply_cb,
255         .subscribe = callreq_subscribe_cb,
256         .unsubscribe = callreq_unsubscribe_cb
257 };
258
259 /******************************************************************************/
260
261 static struct callreq *callreq_create(
262                 struct afb_export *export,
263                 struct afb_xreq *caller,
264                 const char *api,
265                 const char *verb,
266                 struct json_object *args,
267                 int flags,
268                 struct modes mode)
269 {
270         struct callreq *callreq;
271         size_t lenapi, lenverb;
272         char *api2, *verb2;
273
274         lenapi = 1 + strlen(api);
275         lenverb = 1 + strlen(verb);
276         callreq = malloc(lenapi + lenverb + sizeof *callreq);
277         if (!callreq) {
278                 ERROR("out of memory");
279                 json_object_put(args);
280                 errno = ENOMEM;
281         } else {
282                 afb_xreq_init(&callreq->xreq, &afb_calls_xreq_itf);
283                 api2 = (char*)&callreq[1];
284                 callreq->xreq.request.called_api = memcpy(api2, api, lenapi);;
285                 verb2 = &api2[lenapi];
286                 callreq->xreq.request.called_verb = memcpy(verb2, verb, lenverb);
287                 callreq->xreq.json = args;
288                 callreq->mode = mode;
289                 if (!caller)
290                         afb_export_context_init(export, &callreq->xreq.context);
291                 else {
292                         if (flags & afb_req_x2_subcall_api_session)
293                                 afb_export_context_init(export, &callreq->xreq.context);
294                         else
295                                 afb_context_subinit(&callreq->xreq.context, &caller->context);
296                         if (flags & afb_req_x2_subcall_on_behalf)
297                                 afb_context_on_behalf_other_context(&callreq->xreq.context, &caller->context);
298                         callreq->xreq.caller = caller;
299                         afb_xreq_unhooked_addref(caller);
300                         export = afb_export_from_api_x3(caller->request.api);
301                 }
302                 callreq->export = export;
303                 callreq->flags = flags;
304         }
305         return callreq;
306 }
307
308 /******************************************************************************/
309
310 static int do_sync(
311                 struct afb_export *export,
312                 struct afb_xreq *caller,
313                 const char *api,
314                 const char *verb,
315                 struct json_object *args,
316                 int flags,
317                 struct json_object **object,
318                 char **error,
319                 char **info,
320                 struct modes mode)
321 {
322         struct callreq *callreq;
323         int rc;
324
325         /* allocates the request */
326         callreq = callreq_create(export, caller, api, verb, args, flags, mode);
327         if (!callreq)
328                 goto interr;
329
330         /* initializes the request */
331         callreq->jobloop = NULL;
332         callreq->returned = 0;
333         callreq->status = 0;
334         callreq->object = object;
335         callreq->error = error;
336         callreq->info = info;
337
338         afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */
339
340         rc = jobs_enter(NULL, 0, sync_enter, callreq);
341         if (rc >= 0 && callreq->returned) {
342                 rc = callreq->status;
343                 afb_xreq_unhooked_unref(&callreq->xreq);
344                 return rc;
345         }
346
347         afb_xreq_unhooked_unref(&callreq->xreq);
348 interr:
349         return store_reply(NULL, afb_error_text_internal_error, NULL, object, error, info);
350 }
351
352 /******************************************************************************/
353
354 static void do_async(
355                 struct afb_export *export,
356                 struct afb_xreq *caller,
357                 const char *api,
358                 const char *verb,
359                 struct json_object *args,
360                 int flags,
361                 void *callback,
362                 void *closure,
363                 void (*final)(void*, struct json_object*, const char*, const char*, union callback, struct afb_export*,struct afb_xreq*),
364                 struct modes mode)
365 {
366         struct callreq *callreq;
367
368         callreq = callreq_create(export, caller, api, verb, args, flags, mode);
369
370         if (!callreq)
371                 final(closure, NULL, afb_error_text_internal_error, NULL, (union callback){ .any = callback }, export, caller);
372         else {
373                 callreq->callback.any = callback;
374                 callreq->closure = closure;
375                 callreq->final = final;
376
377                 afb_export_process_xreq(callreq->export, &callreq->xreq);
378         }
379 }
380
381 /******************************************************************************/
382
383 static void final_call(
384         void *closure,
385         struct json_object *object,
386         const char *error,
387         const char *info,
388         union callback callback,
389         struct afb_export *export,
390         struct afb_xreq *caller)
391 {
392         if (callback.call.x3)
393                 callback.call.x3(closure, object, error, info, afb_export_to_api_x3(export));
394 }
395
396 static void final_subcall(
397         void *closure,
398         struct json_object *object,
399         const char *error,
400         const char *info,
401         union callback callback,
402         struct afb_export *export,
403         struct afb_xreq *caller)
404 {
405         if (callback.subcall.x3)
406                 callback.subcall.x3(closure, object, error, info, xreq_to_req_x2(caller));
407 }
408
409 /******************************************************************************/
410
411 void afb_calls_call(
412                 struct afb_export *export,
413                 const char *api,
414                 const char *verb,
415                 struct json_object *args,
416                 void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*),
417                 void *closure)
418 {
419         do_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_call, mode_async);
420 }
421
422 int afb_calls_call_sync(
423                 struct afb_export *export,
424                 const char *api,
425                 const char *verb,
426                 struct json_object *args,
427                 struct json_object **object,
428                 char **error,
429                 char **info)
430 {
431         return do_sync(export, NULL, api, verb, args, CALLFLAGS, object, error, info, mode_sync);
432 }
433
434 void afb_calls_subcall(
435                         struct afb_xreq *xreq,
436                         const char *api,
437                         const char *verb,
438                         struct json_object *args,
439                         int flags,
440                         void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
441                         void *closure)
442 {
443         do_async(NULL, xreq, api, verb, args, flags, callback, closure, final_subcall, mode_async);
444 }
445
446 int afb_calls_subcall_sync(
447                         struct afb_xreq *xreq,
448                         const char *api,
449                         const char *verb,
450                         struct json_object *args,
451                         int flags,
452                         struct json_object **object,
453                         char **error,
454                         char **info)
455 {
456         return do_sync(NULL, xreq, api, verb, args, flags, object, error, info, mode_sync);
457 }
458
459 #if WITH_AFB_HOOK
460 void afb_calls_hooked_call(
461                 struct afb_export *export,
462                 const char *api,
463                 const char *verb,
464                 struct json_object *args,
465                 void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*),
466                 void *closure)
467 {
468         afb_hook_api_call(export, api, verb, args);
469         do_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_call, mode_hooked_async);
470 }
471
472 int afb_calls_hooked_call_sync(
473                 struct afb_export *export,
474                 const char *api,
475                 const char *verb,
476                 struct json_object *args,
477                 struct json_object **object,
478                 char **error,
479                 char **info)
480 {
481         afb_hook_api_callsync(export, api, verb, args);
482         return do_sync(export, NULL, api, verb, args, CALLFLAGS, object, error, info, mode_hooked_sync);
483 }
484
485 void afb_calls_hooked_subcall(
486                         struct afb_xreq *xreq,
487                         const char *api,
488                         const char *verb,
489                         struct json_object *args,
490                         int flags,
491                         void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req),
492                         void *closure)
493 {
494         afb_hook_xreq_subcall(xreq, api, verb, args, flags);
495         do_async(NULL, xreq, api, verb, args, flags, callback, closure, final_subcall, mode_hooked_async);
496 }
497
498 int afb_calls_hooked_subcall_sync(
499                         struct afb_xreq *xreq,
500                         const char *api,
501                         const char *verb,
502                         struct json_object *args,
503                         int flags,
504                         struct json_object **object,
505                         char **error,
506                         char **info)
507 {
508         afb_hook_xreq_subcallsync(xreq, api, verb, args, flags);
509         return do_sync(NULL, xreq, api, verb, args, flags, object, error, info, mode_hooked_sync);
510 }
511 #endif
512
513 /******************************************************************************/
514 /******************************************************************************/
515 /******************************************************************************/
516 /******************************************************************************/
517 /******************************************************************************/
518 /******************************************************************************/
519 /******************************************************************************/
520 /******************************************************************************/
521
522 static int do_legacy_sync(
523                 struct afb_export *export,
524                 struct afb_xreq *caller,
525                 const char *api,
526                 const char *verb,
527                 struct json_object *args,
528                 int flags,
529                 struct json_object **object,
530                 struct modes mode)
531 {
532         struct callreq *callreq;
533         int rc;
534
535         /* allocates the request */
536         callreq = callreq_create(export, caller, api, verb, args, flags, mode);
537         if (!callreq)
538                 goto interr;
539
540         /* initializes the request */
541         callreq->jobloop = NULL;
542         callreq->returned = 0;
543         callreq->status = 0;
544         callreq->object = object;
545
546         afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */
547
548         rc = jobs_enter(NULL, 0, sync_enter, callreq);
549         if (rc >= 0 && callreq->returned) {
550                 rc = callreq->status;
551                 afb_xreq_unhooked_unref(&callreq->xreq);
552                 return rc;
553         }
554
555         afb_xreq_unhooked_unref(&callreq->xreq);
556 interr:
557         if (object)
558                 *object = afb_msg_json_reply(NULL, afb_error_text_internal_error, NULL, NULL);
559         return -1;
560 }
561
562 /******************************************************************************/
563
564 static void do_legacy_async(
565                 struct afb_export *export,
566                 struct afb_xreq *caller,
567                 const char *api,
568                 const char *verb,
569                 struct json_object *args,
570                 int flags,
571                 void *callback,
572                 void *closure,
573                 void (*final)(void*, int, struct json_object*, union callback, struct afb_export*,struct afb_xreq*),
574                 struct modes mode)
575 {
576         struct callreq *callreq;
577         struct json_object *ie;
578
579         callreq = callreq_create(export, caller, api, verb, args, flags, mode);
580
581         if (!callreq) {
582                 ie = afb_msg_json_reply(NULL, afb_error_text_internal_error, NULL, NULL);
583                 final(closure, -1, ie, (union callback){ .any = callback }, export, caller);
584                 json_object_put(ie);
585         } else {
586                 callreq->callback.any = callback;
587                 callreq->closure = closure;
588                 callreq->legacy_final = final;
589
590                 afb_export_process_xreq(callreq->export, &callreq->xreq);
591         }
592 }
593
594 /******************************************************************************/
595
596 static void final_legacy_call_v12(
597         void *closure,
598         int status,
599         struct json_object *object,
600         union callback callback,
601         struct afb_export *export,
602         struct afb_xreq *caller)
603 {
604         if (callback.call.legacy_v12)
605                 callback.call.legacy_v12(closure, status, object);
606 }
607
608 static void final_legacy_call_v3(
609         void *closure,
610         int status,
611         struct json_object *object,
612         union callback callback,
613         struct afb_export *export,
614         struct afb_xreq *caller)
615 {
616         if (callback.call.legacy_v3)
617                 callback.call.legacy_v3(closure, status, object, afb_export_to_api_x3(export));
618 }
619
620 /******************************************************************************/
621
622 void afb_calls_legacy_call_v12(
623                 struct afb_export *export,
624                 const char *api,
625                 const char *verb,
626                 struct json_object *args,
627                 void (*callback)(void*, int, struct json_object*),
628                 void *closure)
629 {
630         do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v12, mode_legacy_async);
631 }
632
633 void afb_calls_legacy_call_v3(
634                 struct afb_export *export,
635                 const char *api,
636                 const char *verb,
637                 struct json_object *args,
638                 void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *),
639                 void *closure)
640 {
641         do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v3, mode_legacy_async);
642 }
643
644 int afb_calls_legacy_call_sync(
645                 struct afb_export *export,
646                 const char *api,
647                 const char *verb,
648                 struct json_object *args,
649                 struct json_object **result)
650 {
651         return do_legacy_sync(export, NULL, api, verb, args, CALLFLAGS, result, mode_legacy_sync);
652 }
653
654 #if WITH_AFB_HOOK
655 void afb_calls_legacy_hooked_call_v12(
656                 struct afb_export *export,
657                 const char *api,
658                 const char *verb,
659                 struct json_object *args,
660                 void (*callback)(void*, int, struct json_object*),
661                 void *closure)
662 {
663         afb_hook_api_call(export, api, verb, args);
664         do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v12, mode_hooked_legacy_async);
665 }
666
667 void afb_calls_legacy_hooked_call_v3(
668                 struct afb_export *export,
669                 const char *api,
670                 const char *verb,
671                 struct json_object *args,
672                 void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *),
673                 void *closure)
674 {
675         afb_hook_api_call(export, api, verb, args);
676         do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v3, mode_hooked_legacy_async);
677 }
678
679 int afb_calls_legacy_hooked_call_sync(
680                 struct afb_export *export,
681                 const char *api,
682                 const char *verb,
683                 struct json_object *args,
684                 struct json_object **result)
685 {
686         int rc;
687         struct json_object *object;
688
689         afb_hook_api_callsync(export, api, verb, args);
690         rc = do_legacy_sync(export, NULL, api, verb, args, CALLFLAGS, &object, mode_hooked_legacy_sync);
691         if (result)
692                 *result = object;
693         else
694                 json_object_put(object);
695         return rc;
696 }
697 #endif
698
699 /******************************************************************************/
700
701 static void final_legacy_subcall_v1(
702         void *closure,
703         int status,
704         struct json_object *object,
705         union callback callback,
706         struct afb_export *export,
707         struct afb_xreq *caller)
708 {
709         if (callback.subcall.legacy_v1)
710                 callback.subcall.legacy_v1(closure, status, object);
711 }
712
713 static void final_legacy_subcall_v2(
714         void *closure,
715         int status,
716         struct json_object *object,
717         union callback callback,
718         struct afb_export *export,
719         struct afb_xreq *caller)
720 {
721         if (callback.subcall.legacy_v2)
722                 callback.subcall.legacy_v2(closure, status, object, xreq_to_req_x1(caller));
723 }
724
725 static void final_legacy_subcall_v3(
726         void *closure,
727         int status,
728         struct json_object *object,
729         union callback callback,
730         struct afb_export *export,
731         struct afb_xreq *caller)
732 {
733         if (callback.subcall.legacy_v3)
734                 callback.subcall.legacy_v3(closure, status, object, xreq_to_req_x2(caller));
735 }
736
737 /******************************************************************************/
738
739 void afb_calls_legacy_subcall_v1(
740                 struct afb_xreq *caller,
741                 const char *api,
742                 const char *verb,
743                 struct json_object *args,
744                 void (*callback)(void*, int, struct json_object*),
745                 void *closure)
746 {
747         do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v1, mode_legacy_async);
748 }
749
750 void afb_calls_legacy_subcall_v2(
751                 struct afb_xreq *caller,
752                 const char *api,
753                 const char *verb,
754                 struct json_object *args,
755                 void (*callback)(void*, int, struct json_object*, struct afb_req_x1),
756                 void *closure)
757 {
758         do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v2, mode_legacy_async);
759 }
760
761 void afb_calls_legacy_subcall_v3(
762                 struct afb_xreq *caller,
763                 const char *api,
764                 const char *verb,
765                 struct json_object *args,
766                 void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *),
767                 void *closure)
768 {
769         do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v3, mode_legacy_async);
770 }
771
772 int afb_calls_legacy_subcall_sync(
773                 struct afb_xreq *caller,
774                 const char *api,
775                 const char *verb,
776                 struct json_object *args,
777                 struct json_object **result)
778 {
779         return do_legacy_sync(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, result, mode_legacy_sync);
780 }
781
782 #if WITH_AFB_HOOK
783 void afb_calls_legacy_hooked_subcall_v1(
784                 struct afb_xreq *caller,
785                 const char *api,
786                 const char *verb,
787                 struct json_object *args,
788                 void (*callback)(void*, int, struct json_object*),
789                 void *closure)
790 {
791         afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
792         do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v1, mode_hooked_legacy_async);
793 }
794
795 void afb_calls_legacy_hooked_subcall_v2(
796                 struct afb_xreq *caller,
797                 const char *api,
798                 const char *verb,
799                 struct json_object *args,
800                 void (*callback)(void*, int, struct json_object*, struct afb_req_x1),
801                 void *closure)
802 {
803         afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
804         do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v2, mode_hooked_legacy_async);
805 }
806
807 void afb_calls_legacy_hooked_subcall_v3(
808                 struct afb_xreq *caller,
809                 const char *api,
810                 const char *verb,
811                 struct json_object *args,
812                 void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *),
813                 void *closure)
814 {
815         afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
816         do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v3, mode_hooked_legacy_async);
817 }
818
819 int afb_calls_legacy_hooked_subcall_sync(
820                 struct afb_xreq *caller,
821                 const char *api,
822                 const char *verb,
823                 struct json_object *args,
824                 struct json_object **result)
825 {
826         afb_hook_xreq_subcallsync(caller, api, verb, args, LEGACY_SUBCALLFLAGS);
827         return do_legacy_sync(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, result, mode_hooked_legacy_sync);
828 }
829 #endif
830