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