Make single afb_request_subcall
[src/app-framework-binder.git] / src / afb-xreq.c
1 /*
2  * Copyright (C) 2017 "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 <stdio.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include <json-c/json.h>
26 #include <afb/afb-binding-v1.h>
27 #include <afb/afb-binding-v2.h>
28 #include <afb/afb-request.h>
29
30 #include "afb-context.h"
31 #include "afb-xreq.h"
32 #include "afb-evt.h"
33 #include "afb-msg-json.h"
34 #include "afb-cred.h"
35 #include "afb-hook.h"
36 #include "afb-api.h"
37 #include "afb-apiset.h"
38 #include "afb-auth.h"
39 #include "jobs.h"
40 #include "verbose.h"
41
42 /******************************************************************************/
43
44 static void xreq_finalize(struct afb_xreq *xreq)
45 {
46         if (!xreq->replied)
47                 afb_xreq_fail(xreq, "error", "no reply");
48         if (xreq->hookflags)
49                 afb_hook_xreq_end(xreq);
50         if (xreq->caller)
51                 afb_xreq_unhooked_unref(xreq->caller);
52         xreq->queryitf->unref(xreq);
53 }
54
55 inline void afb_xreq_unhooked_addref(struct afb_xreq *xreq)
56 {
57         __atomic_add_fetch(&xreq->refcount, 1, __ATOMIC_RELAXED);
58 }
59
60 inline void afb_xreq_unhooked_unref(struct afb_xreq *xreq)
61 {
62         if (!__atomic_sub_fetch(&xreq->refcount, 1, __ATOMIC_RELAXED))
63                 xreq_finalize(xreq);
64 }
65
66 /******************************************************************************/
67
68 static inline struct afb_request *to_request(struct afb_xreq *xreq)
69 {
70         return &xreq->request;
71 }
72
73 static inline struct afb_req to_req(struct afb_xreq *xreq)
74 {
75         return (struct afb_req){ .itf = xreq->request.itf, .closure = &xreq->request };
76 }
77
78 static inline struct afb_xreq *from_request(struct afb_request *request)
79 {
80         return CONTAINER_OF(struct afb_xreq, request, request);
81 }
82
83 /******************************************************************************/
84
85 struct subcall
86 {
87         struct afb_xreq xreq;
88
89         void (*completion)(struct subcall*, int, struct json_object*);
90
91         union {
92                 struct {
93                         struct jobloop *jobloop;
94                         struct json_object *result;
95                         int status;
96                 };
97                 struct {
98                         union {
99                                 void (*callback)(void*, int, struct json_object*);
100                                 void (*callback_req)(void*, int, struct json_object*, struct afb_req);
101                                 void (*callback_request)(void*, int, struct json_object*, struct afb_request*);
102                         };
103                         void *closure;
104                 };
105         };
106 };
107
108 static int subcall_subscribe_cb(struct afb_xreq *xreq, struct afb_eventid *eventid)
109 {
110         struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
111
112         return afb_xreq_subscribe(subcall->xreq.caller, eventid);
113 }
114
115 static int subcall_unsubscribe_cb(struct afb_xreq *xreq, struct afb_eventid *eventid)
116 {
117         struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
118
119         return afb_xreq_unsubscribe(subcall->xreq.caller, eventid);
120 }
121
122 static void subcall_reply_cb(struct afb_xreq *xreq, int status, struct json_object *result)
123 {
124         struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
125
126         subcall->completion(subcall, status, result);
127         json_object_put(result);
128         afb_xreq_unhooked_unref(&subcall->xreq);
129 }
130
131 static void subcall_destroy_cb(struct afb_xreq *xreq)
132 {
133         struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq);
134
135         json_object_put(subcall->xreq.json);
136         afb_cred_unref(subcall->xreq.cred);
137         free(subcall);
138 }
139
140 const struct afb_xreq_query_itf afb_xreq_subcall_itf = {
141         .reply = subcall_reply_cb,
142         .unref = subcall_destroy_cb,
143         .subscribe = subcall_subscribe_cb,
144         .unsubscribe = subcall_unsubscribe_cb
145 };
146
147 static struct subcall *subcall_alloc(
148                 struct afb_xreq *caller,
149                 const char *api,
150                 const char *verb,
151                 struct json_object *args
152 )
153 {
154         struct subcall *subcall;
155         size_t lenapi, lenverb;
156         char *copy;
157
158         lenapi = 1 + strlen(api);
159         lenverb = 1 + strlen(verb);
160         subcall = malloc(lenapi + lenverb + sizeof *subcall);
161         if (!subcall)
162                 ERROR("out of memory");
163         else {
164                 copy = (char*)&subcall[1];
165                 memcpy(copy, api, lenapi);
166                 api = copy;
167                 copy = &copy[lenapi];
168                 memcpy(copy, verb, lenverb);
169                 verb = copy;
170
171                 afb_xreq_init(&subcall->xreq, &afb_xreq_subcall_itf);
172                 afb_context_subinit(&subcall->xreq.context, &caller->context);
173                 subcall->xreq.cred = afb_cred_addref(caller->cred);
174                 subcall->xreq.json = args;
175                 subcall->xreq.api = api;
176                 subcall->xreq.verb = verb;
177                 subcall->xreq.caller = caller;
178                 afb_xreq_unhooked_addref(caller);
179         }
180         return subcall;
181 }
182
183
184 static void subcall_on_reply(struct subcall *subcall, int status, struct json_object *result)
185 {
186         subcall->callback(subcall->closure, status, result);
187 }
188
189 static void subcall_req_on_reply(struct subcall *subcall, int status, struct json_object *result)
190 {
191         subcall->callback_req(subcall->closure, status, result, to_req(subcall->xreq.caller));
192 }
193
194 static void subcall_request_on_reply(struct subcall *subcall, int status, struct json_object *result)
195 {
196         subcall->callback_request(subcall->closure, status, result, to_request(subcall->xreq.caller));
197 }
198
199 static void subcall_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result)
200 {
201         afb_hook_xreq_subcall_result(subcall->xreq.caller, status, result);
202         subcall_on_reply(subcall, status, result);
203 }
204
205 static void subcall_req_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result)
206 {
207         afb_hook_xreq_subcall_req_result(subcall->xreq.caller, status, result);
208         subcall_req_on_reply(subcall, status, result);
209 }
210
211 static void subcall_request_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result)
212 {
213         afb_hook_xreq_subcall_result(subcall->xreq.caller, status, result);
214         subcall_request_on_reply(subcall, status, result);
215 }
216
217 static void subcall_reply_direct_cb(void *closure, int status, struct json_object *result)
218 {
219         struct afb_xreq *xreq = closure;
220
221         if (xreq->replied) {
222                 ERROR("subcall replied more than one time!!");
223                 json_object_put(result);
224         } else {
225                 xreq->replied = 1;
226                 subcall_reply_cb(xreq, status, result);
227         }
228 }
229
230 static void subcall_process(struct subcall *subcall, void (*completion)(struct subcall*, int, struct json_object*))
231 {
232         subcall->completion = completion;
233         if (subcall->xreq.caller->queryitf->subcall) {
234                 subcall->xreq.caller->queryitf->subcall(
235                         subcall->xreq.caller, subcall->xreq.api, subcall->xreq.verb,
236                         subcall->xreq.json, subcall_reply_direct_cb, &subcall->xreq);
237         } else {
238                 afb_xreq_unhooked_addref(&subcall->xreq);
239                 afb_xreq_process(&subcall->xreq, subcall->xreq.caller->apiset);
240         }
241 }
242
243 static void subcall(struct subcall *subcall, void (*callback)(void*, int, struct json_object*), void *cb_closure)
244 {
245         subcall->callback = callback;
246         subcall->closure = cb_closure;
247         subcall_process(subcall, subcall_on_reply);
248 }
249
250 static void subcall_req(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure)
251 {
252         subcall->callback_req = callback;
253         subcall->closure = cb_closure;
254         subcall_process(subcall, subcall_req_on_reply);
255 }
256
257 static void subcall_request(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure)
258 {
259         subcall->callback_request = callback;
260         subcall->closure = cb_closure;
261         subcall_process(subcall, subcall_request_on_reply);
262 }
263
264 static void subcall_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*), void *cb_closure)
265 {
266         subcall->callback = callback;
267         subcall->closure = cb_closure;
268         subcall_process(subcall, subcall_hooked_on_reply);
269 }
270
271 static void subcall_req_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure)
272 {
273         subcall->callback_req = callback;
274         subcall->closure = cb_closure;
275         subcall_process(subcall, subcall_req_hooked_on_reply);
276 }
277
278 static void subcall_request_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure)
279 {
280         subcall->callback_request = callback;
281         subcall->closure = cb_closure;
282         subcall_process(subcall, subcall_request_hooked_on_reply);
283 }
284
285 static void subcall_sync_leave(struct subcall *subcall)
286 {
287         struct jobloop *jobloop = __atomic_exchange_n(&subcall->jobloop, NULL, __ATOMIC_RELAXED);
288         if (jobloop)
289                 jobs_leave(jobloop);
290 }
291
292 static void subcall_sync_reply(struct subcall *subcall, int status, struct json_object *result)
293 {
294         subcall->status = status;
295         subcall->result = json_object_get(result);
296         subcall_sync_leave(subcall);
297 }
298
299 static void subcall_sync_enter(int signum, void *closure, struct jobloop *jobloop)
300 {
301         struct subcall *subcall = closure;
302
303         if (!signum) {
304                 subcall->jobloop = jobloop;
305                 subcall->result = NULL;
306                 subcall->status = 0;
307                 subcall_process(subcall, subcall_sync_reply);
308         } else {
309                 subcall->status = -1;
310                 subcall_sync_leave(subcall);
311         }
312 }
313
314 static int subcallsync(struct subcall *subcall, struct json_object **result)
315 {
316         int rc;
317
318         afb_xreq_unhooked_addref(&subcall->xreq);
319         rc = jobs_enter(NULL, 0, subcall_sync_enter, subcall);
320         *result = subcall->result;
321         if (rc < 0 || subcall->status < 0) {
322                 *result = *result ?: afb_msg_json_internal_error();
323                 rc = -1;
324         }
325         afb_xreq_unhooked_unref(&subcall->xreq);
326         return rc;
327 }
328
329 /******************************************************************************/
330
331 static void vinfo(void *first, void *second, const char *fmt, va_list args, void (*fun)(void*,void*,const char*))
332 {
333         char *info;
334         if (fmt == NULL || vasprintf(&info, fmt, args) < 0)
335                 info = NULL;
336         fun(first, second, info);
337         free(info);
338 }
339
340 /******************************************************************************/
341
342 static struct json_object *xreq_json_cb(struct afb_request *closure)
343 {
344         struct afb_xreq *xreq = from_request(closure);
345         if (!xreq->json && xreq->queryitf->json)
346                 xreq->json = xreq->queryitf->json(xreq);
347         return xreq->json;
348 }
349
350 static struct afb_arg xreq_get_cb(struct afb_request *closure, const char *name)
351 {
352         struct afb_xreq *xreq = from_request(closure);
353         struct afb_arg arg;
354         struct json_object *object, *value;
355
356         if (xreq->queryitf->get)
357                 arg = xreq->queryitf->get(xreq, name);
358         else {
359                 object = xreq_json_cb(closure);
360                 if (json_object_object_get_ex(object, name, &value)) {
361                         arg.name = name;
362                         arg.value = json_object_get_string(value);
363                 } else {
364                         arg.name = NULL;
365                         arg.value = NULL;
366                 }
367                 arg.path = NULL;
368         }
369         return arg;
370 }
371
372 static void xreq_success_cb(struct afb_request *closure, struct json_object *obj, const char *info)
373 {
374         struct afb_xreq *xreq = from_request(closure);
375
376         if (xreq->replied) {
377                 ERROR("reply called more than one time!!");
378                 json_object_put(obj);
379         } else {
380                 xreq->replied = 1;
381                 if (xreq->queryitf->success)
382                         xreq->queryitf->success(xreq, obj, info);
383                 else
384                         xreq->queryitf->reply(xreq, 0, afb_msg_json_reply_ok(info, obj, &xreq->context, NULL));
385         }
386 }
387
388 static void xreq_fail_cb(struct afb_request *closure, const char *status, const char *info)
389 {
390         struct afb_xreq *xreq = from_request(closure);
391
392         if (xreq->replied) {
393                 ERROR("reply called more than one time!!");
394         } else {
395                 xreq->replied = 1;
396                 if (xreq->queryitf->fail)
397                         xreq->queryitf->fail(xreq, status, info);
398                 else
399                         xreq->queryitf->reply(xreq, -1, afb_msg_json_reply_error(status, info, &xreq->context, NULL));
400         }
401 }
402
403 static void xreq_vsuccess_cb(struct afb_request *closure, struct json_object *obj, const char *fmt, va_list args)
404 {
405         vinfo(closure, obj, fmt, args, (void*)xreq_success_cb);
406 }
407
408 static void xreq_vfail_cb(struct afb_request *closure, const char *status, const char *fmt, va_list args)
409 {
410         vinfo(closure, (void*)status, fmt, args, (void*)xreq_fail_cb);
411 }
412
413 static void *xreq_context_get_cb(struct afb_request *closure)
414 {
415         struct afb_xreq *xreq = from_request(closure);
416         return afb_context_get(&xreq->context);
417 }
418
419 static void xreq_context_set_cb(struct afb_request *closure, void *value, void (*free_value)(void*))
420 {
421         struct afb_xreq *xreq = from_request(closure);
422         afb_context_set(&xreq->context, value, free_value);
423 }
424
425 static struct afb_request *xreq_addref_cb(struct afb_request *closure)
426 {
427         struct afb_xreq *xreq = from_request(closure);
428         afb_xreq_unhooked_addref(xreq);
429         return closure;
430 }
431
432 static void xreq_unref_cb(struct afb_request *closure)
433 {
434         struct afb_xreq *xreq = from_request(closure);
435         afb_xreq_unhooked_unref(xreq);
436 }
437
438 static void xreq_session_close_cb(struct afb_request *closure)
439 {
440         struct afb_xreq *xreq = from_request(closure);
441         afb_context_close(&xreq->context);
442 }
443
444 static int xreq_session_set_LOA_cb(struct afb_request *closure, unsigned level)
445 {
446         struct afb_xreq *xreq = from_request(closure);
447         return afb_context_change_loa(&xreq->context, level);
448 }
449
450 static int xreq_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid);
451 static int xreq_subscribe_cb(struct afb_request *closure, struct afb_event event)
452 {
453         return xreq_subscribe_eventid_cb(closure, afb_event_to_eventid(event));
454 }
455
456 static int xreq_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid)
457 {
458         struct afb_xreq *xreq = from_request(closure);
459         return afb_xreq_subscribe(xreq, eventid);
460 }
461
462 int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid)
463 {
464         if (xreq->listener)
465                 return afb_evt_add_watch(xreq->listener, eventid);
466         if (xreq->queryitf->subscribe)
467                 return xreq->queryitf->subscribe(xreq, eventid);
468         ERROR("no event listener, subscription impossible");
469         errno = EINVAL;
470         return -1;
471 }
472
473 static int xreq_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid);
474 static int xreq_unsubscribe_cb(struct afb_request *closure, struct afb_event event)
475 {
476         return xreq_unsubscribe_eventid_cb(closure, afb_event_to_eventid(event));
477 }
478
479 static int xreq_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid)
480 {
481         struct afb_xreq *xreq = from_request(closure);
482         return afb_xreq_unsubscribe(xreq, eventid);
483 }
484
485 int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid)
486 {
487         if (xreq->listener)
488                 return afb_evt_remove_watch(xreq->listener, eventid);
489         if (xreq->queryitf->unsubscribe)
490                 return xreq->queryitf->unsubscribe(xreq, eventid);
491         ERROR("no event listener, unsubscription impossible");
492         errno = EINVAL;
493         return -1;
494 }
495
496 static void xreq_subcall_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
497 {
498         struct afb_xreq *xreq = from_request(closure);
499         struct subcall *sc;
500
501         sc = subcall_alloc(xreq, api, verb, args);
502         if (sc == NULL) {
503                 if (callback)
504                         callback(cb_closure, 1, afb_msg_json_internal_error());
505                 json_object_put(args);
506         } else {
507                 subcall(sc, callback, cb_closure);
508         }
509 }
510
511 static void xreq_subcall_req_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure)
512 {
513         struct afb_xreq *xreq = from_request(closure);
514         struct subcall *sc;
515
516         sc = subcall_alloc(xreq, api, verb, args);
517         if (sc == NULL) {
518                 if (callback)
519                         callback(cb_closure, 1, afb_msg_json_internal_error(), to_req(xreq));
520                 json_object_put(args);
521         } else {
522                 subcall_req(sc, callback, cb_closure);
523         }
524 }
525
526 static void xreq_subcall_request_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure)
527 {
528         struct afb_xreq *xreq = from_request(closure);
529         struct subcall *sc;
530
531         sc = subcall_alloc(xreq, api, verb, args);
532         if (sc == NULL) {
533                 if (callback)
534                         callback(cb_closure, 1, afb_msg_json_internal_error(), to_request(xreq));
535                 json_object_put(args);
536         } else {
537                 subcall_request(sc, callback, cb_closure);
538         }
539 }
540
541
542 static int xreq_subcallsync_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result)
543 {
544         int rc;
545         struct subcall *sc;
546         struct afb_xreq *xreq = from_request(closure);
547         struct json_object *resu;
548
549         sc = subcall_alloc(xreq, api, verb, args);
550         if (!sc) {
551                 rc = -1;
552                 resu = afb_msg_json_internal_error();
553                 json_object_put(args);
554         } else {
555                 rc = subcallsync(sc, &resu);
556         }
557         if (result)
558                 *result = resu;
559         else
560                 json_object_put(resu);
561         return rc;
562 }
563
564 static void xreq_vverbose_cb(struct afb_request *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
565 {
566         char *p;
567         struct afb_xreq *xreq = from_request(closure);
568
569         if (!fmt || vasprintf(&p, fmt, args) < 0)
570                 vverbose(level, file, line, func, fmt, args);
571         else {
572                 verbose(level, file, line, func, "[REQ/API %s] %s", xreq->api, p);
573                 free(p);
574         }
575 }
576
577 static struct afb_stored_req *xreq_store_cb(struct afb_request *closure)
578 {
579         xreq_addref_cb(closure);
580         return (struct afb_stored_req*)closure;
581 }
582
583 static int xreq_has_permission_cb(struct afb_request *closure, const char *permission)
584 {
585         struct afb_xreq *xreq = from_request(closure);
586         return afb_auth_has_permission(xreq, permission);
587 }
588
589 static char *xreq_get_application_id_cb(struct afb_request *closure)
590 {
591         struct afb_xreq *xreq = from_request(closure);
592         return xreq->cred && xreq->cred->id ? strdup(xreq->cred->id) : NULL;
593 }
594
595 static void *xreq_context_make_cb(struct afb_request *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure)
596 {
597         struct afb_xreq *xreq = from_request(closure);
598         return afb_context_make(&xreq->context, replace, create_value, free_value, create_closure);
599 }
600
601 /******************************************************************************/
602
603 static struct json_object *xreq_hooked_json_cb(struct afb_request *closure)
604 {
605         struct json_object *r = xreq_json_cb(closure);
606         struct afb_xreq *xreq = from_request(closure);
607         return afb_hook_xreq_json(xreq, r);
608 }
609
610 static struct afb_arg xreq_hooked_get_cb(struct afb_request *closure, const char *name)
611 {
612         struct afb_arg r = xreq_get_cb(closure, name);
613         struct afb_xreq *xreq = from_request(closure);
614         return afb_hook_xreq_get(xreq, name, r);
615 }
616
617 static void xreq_hooked_success_cb(struct afb_request *closure, struct json_object *obj, const char *info)
618 {
619         struct afb_xreq *xreq = from_request(closure);
620         afb_hook_xreq_success(xreq, obj, info);
621         xreq_success_cb(closure, obj, info);
622 }
623
624 static void xreq_hooked_fail_cb(struct afb_request *closure, const char *status, const char *info)
625 {
626         struct afb_xreq *xreq = from_request(closure);
627         afb_hook_xreq_fail(xreq, status, info);
628         xreq_fail_cb(closure, status, info);
629 }
630
631 static void xreq_hooked_vsuccess_cb(struct afb_request *closure, struct json_object *obj, const char *fmt, va_list args)
632 {
633         vinfo(closure, obj, fmt, args, (void*)xreq_hooked_success_cb);
634 }
635
636 static void xreq_hooked_vfail_cb(struct afb_request *closure, const char *status, const char *fmt, va_list args)
637 {
638         vinfo(closure, (void*)status, fmt, args, (void*)xreq_hooked_fail_cb);
639 }
640
641 static void *xreq_hooked_context_get_cb(struct afb_request *closure)
642 {
643         void *r = xreq_context_get_cb(closure);
644         struct afb_xreq *xreq = from_request(closure);
645         return afb_hook_xreq_context_get(xreq, r);
646 }
647
648 static void xreq_hooked_context_set_cb(struct afb_request *closure, void *value, void (*free_value)(void*))
649 {
650         struct afb_xreq *xreq = from_request(closure);
651         afb_hook_xreq_context_set(xreq, value, free_value);
652         xreq_context_set_cb(closure, value, free_value);
653 }
654
655 static struct afb_request *xreq_hooked_addref_cb(struct afb_request *closure)
656 {
657         struct afb_xreq *xreq = from_request(closure);
658         afb_hook_xreq_addref(xreq);
659         return xreq_addref_cb(closure);
660 }
661
662 static void xreq_hooked_unref_cb(struct afb_request *closure)
663 {
664         struct afb_xreq *xreq = from_request(closure);
665         afb_hook_xreq_unref(xreq);
666         xreq_unref_cb(closure);
667 }
668
669 static void xreq_hooked_session_close_cb(struct afb_request *closure)
670 {
671         struct afb_xreq *xreq = from_request(closure);
672         afb_hook_xreq_session_close(xreq);
673         xreq_session_close_cb(closure);
674 }
675
676 static int xreq_hooked_session_set_LOA_cb(struct afb_request *closure, unsigned level)
677 {
678         int r = xreq_session_set_LOA_cb(closure, level);
679         struct afb_xreq *xreq = from_request(closure);
680         return afb_hook_xreq_session_set_LOA(xreq, level, r);
681 }
682
683 static int xreq_hooked_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid);
684 static int xreq_hooked_subscribe_cb(struct afb_request *closure, struct afb_event event)
685 {
686         return xreq_hooked_subscribe_eventid_cb(closure, afb_event_to_eventid(event));
687 }
688
689 static int xreq_hooked_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid)
690 {
691         int r = xreq_subscribe_eventid_cb(closure, eventid);
692         struct afb_xreq *xreq = from_request(closure);
693         return afb_hook_xreq_subscribe(xreq, eventid, r);
694 }
695
696 static int xreq_hooked_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid);
697 static int xreq_hooked_unsubscribe_cb(struct afb_request *closure, struct afb_event event)
698 {
699         return xreq_hooked_unsubscribe_eventid_cb(closure, afb_event_to_eventid(event));
700 }
701
702 static int xreq_hooked_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid)
703 {
704         int r = xreq_unsubscribe_eventid_cb(closure, eventid);
705         struct afb_xreq *xreq = from_request(closure);
706         return afb_hook_xreq_unsubscribe(xreq, eventid, r);
707 }
708
709 static void xreq_hooked_subcall_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
710 {
711         struct afb_xreq *xreq = from_request(closure);
712         struct subcall *sc;
713
714         afb_hook_xreq_subcall(xreq, api, verb, args);
715         sc = subcall_alloc(xreq, api, verb, args);
716         if (sc == NULL) {
717                 if (callback)
718                         callback(cb_closure, 1, afb_msg_json_internal_error());
719                 json_object_put(args);
720         } else {
721                 subcall_hooked(sc, callback, cb_closure);
722         }
723 }
724
725 static void xreq_hooked_subcall_req_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure)
726 {
727         struct afb_xreq *xreq = from_request(closure);
728         struct subcall *sc;
729
730         afb_hook_xreq_subcall_req(xreq, api, verb, args);
731         sc = subcall_alloc(xreq, api, verb, args);
732         if (sc == NULL) {
733                 if (callback)
734                         callback(cb_closure, 1, afb_msg_json_internal_error(), to_req(xreq));
735                 json_object_put(args);
736         } else {
737                 subcall_req_hooked(sc, callback, cb_closure);
738         }
739 }
740
741 static void xreq_hooked_subcall_request_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure)
742 {
743         struct afb_xreq *xreq = from_request(closure);
744         struct subcall *sc;
745
746         afb_hook_xreq_subcall(xreq, api, verb, args);
747         sc = subcall_alloc(xreq, api, verb, args);
748         if (sc == NULL) {
749                 if (callback)
750                         callback(cb_closure, 1, afb_msg_json_internal_error(), to_request(xreq));
751                 json_object_put(args);
752         } else {
753                 subcall_request_hooked(sc, callback, cb_closure);
754         }
755 }
756
757 static int xreq_hooked_subcallsync_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result)
758 {
759         int r;
760         struct afb_xreq *xreq = from_request(closure);
761         afb_hook_xreq_subcallsync(xreq, api, verb, args);
762         r = xreq_subcallsync_cb(closure, api, verb, args, result);
763         return afb_hook_xreq_subcallsync_result(xreq, r, *result);
764 }
765
766 static void xreq_hooked_vverbose_cb(struct afb_request *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
767 {
768         struct afb_xreq *xreq = from_request(closure);
769         va_list ap;
770         va_copy(ap, args);
771         xreq_vverbose_cb(closure, level, file, line, func, fmt, args);
772         afb_hook_xreq_vverbose(xreq, level, file, line, func, fmt, ap);
773         va_end(ap);
774 }
775
776 static struct afb_stored_req *xreq_hooked_store_cb(struct afb_request *closure)
777 {
778         struct afb_xreq *xreq = from_request(closure);
779         struct afb_stored_req *r = xreq_store_cb(closure);
780         afb_hook_xreq_store(xreq, r);
781         return r;
782 }
783
784 static int xreq_hooked_has_permission_cb(struct afb_request *closure, const char *permission)
785 {
786         struct afb_xreq *xreq = from_request(closure);
787         int r = xreq_has_permission_cb(closure, permission);
788         return afb_hook_xreq_has_permission(xreq, permission, r);
789 }
790
791 static char *xreq_hooked_get_application_id_cb(struct afb_request *closure)
792 {
793         struct afb_xreq *xreq = from_request(closure);
794         char *r = xreq_get_application_id_cb(closure);
795         return afb_hook_xreq_get_application_id(xreq, r);
796 }
797
798 static void *xreq_hooked_context_make_cb(struct afb_request *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure)
799 {
800         struct afb_xreq *xreq = from_request(closure);
801         void *result = xreq_context_make_cb(closure, replace, create_value, free_value, create_closure);
802         return afb_hook_xreq_context_make(xreq, replace, create_value, free_value, create_closure, result);
803 }
804
805 /******************************************************************************/
806
807 const struct afb_request_itf xreq_itf = {
808         .json = xreq_json_cb,
809         .get = xreq_get_cb,
810         .success = xreq_success_cb,
811         .fail = xreq_fail_cb,
812         .vsuccess = xreq_vsuccess_cb,
813         .vfail = xreq_vfail_cb,
814         .context_get = xreq_context_get_cb,
815         .context_set = xreq_context_set_cb,
816         .addref = xreq_addref_cb,
817         .unref = xreq_unref_cb,
818         .session_close = xreq_session_close_cb,
819         .session_set_LOA = xreq_session_set_LOA_cb,
820         .subscribe = xreq_subscribe_cb,
821         .unsubscribe = xreq_unsubscribe_cb,
822         .subcall = xreq_subcall_cb,
823         .subcallsync = xreq_subcallsync_cb,
824         .vverbose = xreq_vverbose_cb,
825         .store = xreq_store_cb,
826         .subcall_req = xreq_subcall_req_cb,
827         .has_permission = xreq_has_permission_cb,
828         .get_application_id = xreq_get_application_id_cb,
829         .context_make = xreq_context_make_cb,
830         .subscribe_eventid = xreq_subscribe_eventid_cb,
831         .unsubscribe_eventid = xreq_unsubscribe_eventid_cb,
832         .subcall_request = xreq_subcall_request_cb,
833 };
834
835 const struct afb_request_itf xreq_hooked_itf = {
836         .json = xreq_hooked_json_cb,
837         .get = xreq_hooked_get_cb,
838         .success = xreq_hooked_success_cb,
839         .fail = xreq_hooked_fail_cb,
840         .vsuccess = xreq_hooked_vsuccess_cb,
841         .vfail = xreq_hooked_vfail_cb,
842         .context_get = xreq_hooked_context_get_cb,
843         .context_set = xreq_hooked_context_set_cb,
844         .addref = xreq_hooked_addref_cb,
845         .unref = xreq_hooked_unref_cb,
846         .session_close = xreq_hooked_session_close_cb,
847         .session_set_LOA = xreq_hooked_session_set_LOA_cb,
848         .subscribe = xreq_hooked_subscribe_cb,
849         .unsubscribe = xreq_hooked_unsubscribe_cb,
850         .subcall = xreq_hooked_subcall_cb,
851         .subcallsync = xreq_hooked_subcallsync_cb,
852         .vverbose = xreq_hooked_vverbose_cb,
853         .store = xreq_hooked_store_cb,
854         .subcall_req = xreq_hooked_subcall_req_cb,
855         .has_permission = xreq_hooked_has_permission_cb,
856         .get_application_id = xreq_hooked_get_application_id_cb,
857         .context_make = xreq_hooked_context_make_cb,
858         .subscribe_eventid = xreq_hooked_subscribe_eventid_cb,
859         .unsubscribe_eventid = xreq_hooked_unsubscribe_eventid_cb,
860         .subcall_request = xreq_hooked_subcall_request_cb,
861 };
862
863 /******************************************************************************/
864
865 struct afb_req afb_xreq_unstore(struct afb_stored_req *sreq)
866 {
867         struct afb_xreq *xreq = (struct afb_xreq *)sreq;
868         if (xreq->hookflags)
869                 afb_hook_xreq_unstore(xreq);
870         return to_req(xreq);
871 }
872
873 struct json_object *afb_xreq_json(struct afb_xreq *xreq)
874 {
875         return afb_request_json(to_request(xreq));
876 }
877
878 void afb_xreq_success(struct afb_xreq *xreq, struct json_object *obj, const char *info)
879 {
880         afb_request_success(to_request(xreq), obj, info);
881 }
882
883 void afb_xreq_success_f(struct afb_xreq *xreq, struct json_object *obj, const char *info, ...)
884 {
885         va_list args;
886
887         va_start(args, info);
888         afb_request_success_v(to_request(xreq), obj, info, args);
889         va_end(args);
890 }
891
892 void afb_xreq_fail(struct afb_xreq *xreq, const char *status, const char *info)
893 {
894         afb_request_fail(to_request(xreq), status, info);
895 }
896
897 void afb_xreq_fail_f(struct afb_xreq *xreq, const char *status, const char *info, ...)
898 {
899         va_list args;
900
901         va_start(args, info);
902         afb_request_fail_v(to_request(xreq), status, info, args);
903         va_end(args);
904
905 }
906
907 const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size)
908 {
909         struct json_object *obj = xreq_json_cb(to_request(xreq));
910         const char *result = json_object_to_json_string(obj);
911         if (size != NULL)
912                 *size = strlen(result);
913         return result;
914 }
915
916 void afb_xreq_addref(struct afb_xreq *xreq)
917 {
918         afb_request_addref(to_request(xreq));
919 }
920
921 void afb_xreq_unref(struct afb_xreq *xreq)
922 {
923         afb_request_unref(to_request(xreq));
924 }
925
926 void afb_xreq_unhooked_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure)
927 {
928         xreq_subcall_request_cb(to_request(xreq), api, verb, args, callback, cb_closure);
929 }
930
931 void afb_xreq_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure)
932 {
933         afb_request_subcall(to_request(xreq), api, verb, args, callback, cb_closure);
934 }
935
936 int afb_xreq_unhooked_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result)
937 {
938         return xreq_subcallsync_cb(to_request(xreq), api, verb, args, result);
939 }
940
941 int afb_xreq_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result)
942 {
943         return afb_request_subcall_sync(to_request(xreq), api, verb, args, result);
944 }
945
946 static int xreq_session_check_apply_v1(struct afb_xreq *xreq, int sessionflags)
947 {
948         int loa;
949
950         if ((sessionflags & (AFB_SESSION_CLOSE_V1|AFB_SESSION_RENEW_V1|AFB_SESSION_CHECK_V1|AFB_SESSION_LOA_EQ_V1)) != 0) {
951                 if (!afb_context_check(&xreq->context)) {
952                         afb_context_close(&xreq->context);
953                         afb_xreq_fail_f(xreq, "denied", "invalid token's identity");
954                         errno = EINVAL;
955                         return -1;
956                 }
957         }
958
959         if ((sessionflags & AFB_SESSION_LOA_GE_V1) != 0) {
960                 loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1;
961                 if (!afb_context_check_loa(&xreq->context, loa)) {
962                         afb_xreq_fail_f(xreq, "denied", "invalid LOA");
963                         errno = EPERM;
964                         return -1;
965                 }
966         }
967
968         if ((sessionflags & AFB_SESSION_LOA_LE_V1) != 0) {
969                 loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1;
970                 if (afb_context_check_loa(&xreq->context, loa + 1)) {
971                         afb_xreq_fail_f(xreq, "denied", "invalid LOA");
972                         errno = EPERM;
973                         return -1;
974                 }
975         }
976
977         if ((sessionflags & AFB_SESSION_RENEW_V1) != 0) {
978                 afb_context_refresh(&xreq->context);
979         }
980         if ((sessionflags & AFB_SESSION_CLOSE_V1) != 0) {
981                 afb_context_change_loa(&xreq->context, 0);
982                 afb_context_close(&xreq->context);
983         }
984
985         return 0;
986 }
987
988 static int xreq_session_check_apply_v2(struct afb_xreq *xreq, uint32_t sessionflags, const struct afb_auth *auth)
989 {
990         int loa;
991
992         if (sessionflags != 0) {
993                 if (!afb_context_check(&xreq->context)) {
994                         afb_context_close(&xreq->context);
995                         afb_xreq_fail_f(xreq, "denied", "invalid token's identity");
996                         errno = EINVAL;
997                         return -1;
998                 }
999         }
1000
1001         loa = (int)(sessionflags & AFB_SESSION_LOA_MASK_V2);
1002         if (loa && !afb_context_check_loa(&xreq->context, loa)) {
1003                 afb_xreq_fail_f(xreq, "denied", "invalid LOA");
1004                 errno = EPERM;
1005                 return -1;
1006         }
1007
1008         if (auth && !afb_auth_check(xreq, auth)) {
1009                 afb_xreq_fail_f(xreq, "denied", "authorisation refused");
1010                 errno = EPERM;
1011                 return -1;
1012         }
1013
1014         if ((sessionflags & AFB_SESSION_REFRESH_V2) != 0) {
1015                 afb_context_refresh(&xreq->context);
1016         }
1017         if ((sessionflags & AFB_SESSION_CLOSE_V2) != 0) {
1018                 afb_context_close(&xreq->context);
1019         }
1020
1021         return 0;
1022 }
1023
1024 void afb_xreq_call_verb_v1(struct afb_xreq *xreq, const struct afb_verb_desc_v1 *verb)
1025 {
1026         if (!verb)
1027                 afb_xreq_fail_unknown_verb(xreq);
1028         else
1029                 if (!xreq_session_check_apply_v1(xreq, verb->session))
1030                         verb->callback(to_req(xreq));
1031 }
1032
1033 void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb)
1034 {
1035         if (!verb)
1036                 afb_xreq_fail_unknown_verb(xreq);
1037         else
1038                 if (!xreq_session_check_apply_v2(xreq, verb->session, verb->auth))
1039                         verb->callback(to_req(xreq));
1040 }
1041
1042 void afb_xreq_init(struct afb_xreq *xreq, const struct afb_xreq_query_itf *queryitf)
1043 {
1044         memset(xreq, 0, sizeof *xreq);
1045         xreq->request.itf = &xreq_hooked_itf; /* hook by default */
1046         xreq->refcount = 1;
1047         xreq->queryitf = queryitf;
1048 }
1049
1050 void afb_xreq_fail_unknown_api(struct afb_xreq *xreq)
1051 {
1052         afb_xreq_fail_f(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->api, xreq->verb);
1053 }
1054
1055 void afb_xreq_fail_unknown_verb(struct afb_xreq *xreq)
1056 {
1057         afb_xreq_fail_f(xreq, "unknown-verb", "verb %s unknown within api %s", xreq->verb, xreq->api);
1058 }
1059
1060 static void init_hooking(struct afb_xreq *xreq)
1061 {
1062         afb_hook_init_xreq(xreq);
1063         if (xreq->hookflags)
1064                 afb_hook_xreq_begin(xreq);
1065         else
1066                 xreq->request.itf = &xreq_itf; /* unhook the interface */
1067 }
1068
1069 /**
1070  * job callback for asynchronous and secured processing of the request.
1071  */
1072 static void process_async(int signum, void *arg)
1073 {
1074         struct afb_xreq *xreq = arg;
1075         const struct afb_api *api;
1076
1077         if (signum != 0) {
1078                 /* emit the error (assumes that hooking is initialised) */
1079                 afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum);
1080         } else {
1081                 /* init hooking */
1082                 init_hooking(xreq);
1083                 /* invoke api call method to process the reqiest */
1084                 api = (const struct afb_api*)xreq->context.api_key;
1085                 api->itf->call(api->closure, xreq);
1086         }
1087         /* release the request */
1088         afb_xreq_unhooked_unref(xreq);
1089 }
1090
1091 /**
1092  * Early request failure of the request 'xreq' with, as usual, 'status' and 'info'
1093  * The early failure occurs only in function 'afb_xreq_process' where normally,
1094  * the hooking is not initialised. So this "early" failure takes care to initialise
1095  * the hooking in first.
1096  */
1097 static void early_failure(struct afb_xreq *xreq, const char *status, const char *info, ...)
1098 {
1099         va_list args;
1100
1101         /* init hooking */
1102         init_hooking(xreq);
1103
1104         /* send error */
1105         va_start(args, info);
1106         afb_request_fail_v(to_request(xreq), status, info, args);
1107         va_end(args);
1108 }
1109
1110 /**
1111  * Enqueue a job for processing the request 'xreq' using the given 'apiset'.
1112  * Errors are reported as request failures.
1113  */
1114 void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset)
1115 {
1116         const struct afb_api *api;
1117         struct afb_xreq *caller;
1118
1119         /* lookup at the api */
1120         xreq->apiset = apiset;
1121         api = afb_apiset_lookup_started(apiset, xreq->api, 1);
1122         if (!api) {
1123                 if (errno == ENOENT)
1124                         early_failure(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->api, xreq->verb);
1125                 else
1126                         early_failure(xreq, "bad-api-state", "api %s not started correctly: %m", xreq->api);
1127                 goto end;
1128         }
1129         xreq->context.api_key = api;
1130
1131         /* check self locking */
1132         if (api->group) {
1133                 caller = xreq->caller;
1134                 while (caller) {
1135                         if (((const struct afb_api *)caller->context.api_key)->group == api->group) {
1136                                 /* noconcurrency lock detected */
1137                                 ERROR("self-lock detected in call stack for API %s", xreq->api);
1138                                 early_failure(xreq, "self-locked", "recursive self lock, API %s", xreq->api);
1139                                 goto end;
1140                         }
1141                         caller = caller->caller;
1142                 }
1143         }
1144
1145         /* queue the request job */
1146         afb_xreq_unhooked_addref(xreq);
1147         if (jobs_queue(api->group, afb_apiset_timeout_get(apiset), process_async, xreq) < 0) {
1148                 /* TODO: allows or not to proccess it directly as when no threading? (see above) */
1149                 ERROR("can't process job with threads: %m");
1150                 early_failure(xreq, "cancelled", "not able to create a job for the task");
1151                 afb_xreq_unhooked_unref(xreq);
1152         }
1153 end:
1154         afb_xreq_unhooked_unref(xreq);
1155 }
1156