SLOT_finish,
SLOT_consume,
SLOT_produce,
+ SLOT_checkout,
SLOT_count
};
#define SLOT_size sizeof(int)
LAYER_UNREGISTER(L, api, finish);
LAYER_UNREGISTER(L, api, consume);
LAYER_UNREGISTER(L, api, produce);
+ LAYER_UNREGISTER(L, api, checkout);
LAYER_UNREGISTER(L, api, reset);
free(api);
}
lua_pushlightuserdata(L, pkt);
return l_ffi_call(L, 3);
}
+
+static int l_ffi_layer_checkout(kr_layer_t *ctx, knot_pkt_t *pkt, struct sockaddr *dst, int type)
+{
+ if (ctx->state & (KR_STATE_FAIL)) {
+ return ctx->state; /* Already failed or done, skip */
+ }
+ LAYER_FFI_CALL(ctx, checkout);
+ lua_pushlightuserdata(L, ctx->req);
+ lua_pushlightuserdata(L, pkt);
+ lua_pushlightuserdata(L, dst);
+ lua_pushboolean(L, type == SOCK_STREAM);
+ return l_ffi_call(L, 5);
+}
#undef LAYER_FFI_CALL
/** @internal Conditionally register layer trampoline
LAYER_REGISTER(L, api, finish);
LAYER_REGISTER(L, api, consume);
LAYER_REGISTER(L, api, produce);
+ LAYER_REGISTER(L, api, checkout);
LAYER_REGISTER(L, api, reset);
/* Begin is always set, as it initializes layer baton. */
api->begin = l_ffi_layer_begin;
/** Produce either an answer to the request or a query for upstream (or fail). */
int (*produce)(kr_layer_t *ctx, knot_pkt_t *pkt);
+ /** Finalises the outbound query packet with the knowledge of the IP addresses.
+ * The checkout layer doesn't persist the state, so canceled subrequests
+ * don't affect the resolution or rest of the processing. */
+ int (*checkout)(kr_layer_t *ctx, knot_pkt_t *packet, struct sockaddr *dst, int type);
+
/** The module can store anything in here. */
void *data;
};
static int reset_yield(kr_layer_t *ctx) { return kr_ok(); }
static int finish_yield(kr_layer_t *ctx) { return kr_ok(); }
static int produce_yield(kr_layer_t *ctx, knot_pkt_t *pkt) { return kr_ok(); }
+static int checkout_yield(kr_layer_t *ctx, knot_pkt_t *packet, struct sockaddr *dst, int type) { return kr_ok(); }
/** @internal Macro for iterating module layers. */
#define RESUME_LAYERS(from, r, qry, func, ...) \
}
struct kr_query *qry = array_tail(rplan->pending);
+ /* Run the checkout layers and cancel on failure. */
+ int state = request->state;
+ ITERATE_LAYERS(request, qry, checkout, packet, dst, type);
+ if (request->state == KR_STATE_FAIL) {
+ request->state = state; /* Restore */
+ return kr_error(ECANCELED);
+ }
+
#if defined(ENABLE_COOKIES)
/* Update DNS cookies in request. */
if (type == SOCK_DGRAM) { /* @todo: Add cookies also over TCP? */