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