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