+/******************************************************************************/
+
+static void xreq_finalize(struct afb_xreq *xreq)
+{
+ if (!xreq->replied)
+ afb_xreq_reply(xreq, NULL, "error", "no reply");
+#if WITH_AFB_HOOK
+ if (xreq->hookflags)
+ afb_hook_xreq_end(xreq);
+#endif
+ if (xreq->caller)
+ afb_xreq_unhooked_unref(xreq->caller);
+ xreq->queryitf->unref(xreq);
+}
+
+inline void afb_xreq_unhooked_addref(struct afb_xreq *xreq)
+{
+ __atomic_add_fetch(&xreq->refcount, 1, __ATOMIC_RELAXED);
+}
+
+inline void afb_xreq_unhooked_unref(struct afb_xreq *xreq)
+{
+ if (!__atomic_sub_fetch(&xreq->refcount, 1, __ATOMIC_RELAXED))
+ xreq_finalize(xreq);
+}
+
+/******************************************************************************/
+
+struct json_object *afb_xreq_unhooked_json(struct afb_xreq *xreq)
+{
+ if (!xreq->json && xreq->queryitf->json)
+ xreq->json = xreq->queryitf->json(xreq);
+ return xreq->json;
+}
+
+static struct json_object *xreq_json_cb(struct afb_req_x2 *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ return afb_xreq_unhooked_json(xreq);
+}
+
+static struct afb_arg xreq_get_cb(struct afb_req_x2 *closure, const char *name)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ struct afb_arg arg;
+ struct json_object *object, *value;
+
+ if (xreq->queryitf->get)
+ arg = xreq->queryitf->get(xreq, name);
+ else {
+ object = xreq_json_cb(closure);
+ if (json_object_object_get_ex(object, name, &value)) {
+ arg.name = name;
+ arg.value = json_object_get_string(value);
+ } else {
+ arg.name = NULL;
+ arg.value = NULL;
+ }
+ arg.path = NULL;
+ }
+ return arg;
+}
+
+static void xreq_reply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *info)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+
+ if (xreq->replied) {
+ ERROR("reply called more than one time!!");
+ json_object_put(obj);
+ } else {
+ xreq->replied = 1;
+ xreq->queryitf->reply(xreq, obj, error, info);
+ }
+}
+
+static void xreq_vreply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *fmt, va_list args)
+{
+ char *info;
+ if (fmt == NULL || vasprintf(&info, fmt, args) < 0)
+ info = NULL;
+ xreq_reply_cb(closure, obj, error, info);
+ free(info);
+}
+
+static void xreq_legacy_success_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *info)
+{
+ xreq_reply_cb(closure, obj, NULL, info);
+}
+
+static void xreq_legacy_fail_cb(struct afb_req_x2 *closure, const char *status, const char *info)
+{
+ xreq_reply_cb(closure, NULL, status, info);
+}
+
+static void xreq_legacy_vsuccess_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *fmt, va_list args)
+{
+ xreq_vreply_cb(closure, obj, NULL, fmt, args);
+}
+
+static void xreq_legacy_vfail_cb(struct afb_req_x2 *closure, const char *status, const char *fmt, va_list args)
+{
+ xreq_vreply_cb(closure, NULL, status, fmt, args);
+}
+
+static void *xreq_legacy_context_get_cb(struct afb_req_x2 *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ return afb_context_get(&xreq->context);
+}
+
+static void xreq_legacy_context_set_cb(struct afb_req_x2 *closure, void *value, void (*free_value)(void*))
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ afb_context_set(&xreq->context, value, free_value);
+}
+
+static struct afb_req_x2 *xreq_addref_cb(struct afb_req_x2 *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ afb_xreq_unhooked_addref(xreq);
+ return closure;
+}
+
+static void xreq_unref_cb(struct afb_req_x2 *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ afb_xreq_unhooked_unref(xreq);
+}
+
+static void xreq_session_close_cb(struct afb_req_x2 *closure)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ afb_context_close(&xreq->context);
+}
+
+static int xreq_session_set_LOA_cb(struct afb_req_x2 *closure, unsigned level)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ return afb_context_change_loa(&xreq->context, level);
+}
+
+static int xreq_subscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event)
+{
+ struct afb_xreq *xreq = xreq_from_req_x2(closure);
+ return afb_xreq_subscribe(xreq, event);
+}
+
+static int xreq_legacy_subscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event)
+{
+ return xreq_subscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event));
+}
+
+int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event)
+{
+ if (xreq->replied) {
+ ERROR("request replied, subscription impossible");
+ errno = EINVAL;
+ } else {
+ if (xreq->listener)
+ return afb_evt_event_x2_add_watch(xreq->listener, event);
+ if (xreq->queryitf->subscribe)
+ return xreq->queryitf->subscribe(xreq, event);
+ ERROR("no event listener, subscription impossible");
+ errno = ENOTSUP;
+ }
+ return -1;
+}