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