- The API and ABI for modules changes slightly (details below).
KR_MODULE_API is bumped to avoid loading incompatible code.
We have bumped libkres ABIVER since the last release 1.1.1,
so leaving that one intact.
- Make KR_STATE_YIELD not reuse 0 value anymore.
It's easy to e.g. return kr_ok() by mistake.
- struct kr_layer_t:
* ::mm was unused, uninitialized, etc.
* Make ::state an int, as it was everywhere else.
* void *data was ugly and always containing struct kr_request *
- struct kr_layer_api:
* Drop the void* parameter from ::begin, as it was only used
for the request which is available as ctx->req anyway
(formerly ctx->data).
* Drop ::fail. It wasn't even called. Modules can watch for
KR_STATE_FAIL in ::finish.
- Document the apparent meaning of the layer interface, deduced mainly
from the way it's used in the code. Caveats:
* enum knot_layer_state handling seems to assume that it holds exactly
one of the possibilities at a time. The cookie module does NOT
follow that (intentionally), apparently depending on the exact
implementation of the handling at that moment. It feels fragile.
* I was unable to deduce a plausible description of when ::reset is
called. It's practically unused in modules, too.
lua_rawgeti(L, LUA_REGISTRYINDEX, cb_slot[SLOT_ ## slot]); \
lua_pushnumber(L, ctx->state)
-static int l_ffi_layer_begin(kr_layer_t *ctx, void *module_param)
+static int l_ffi_layer_begin(kr_layer_t *ctx)
{
LAYER_FFI_CALL(ctx, begin);
- lua_pushlightuserdata(L, ctx->data);
+ lua_pushlightuserdata(L, ctx->req);
return l_ffi_call(L, 2);
}
static int l_ffi_layer_reset(kr_layer_t *ctx)
{
LAYER_FFI_CALL(ctx, reset);
- lua_pushlightuserdata(L, ctx->data);
+ lua_pushlightuserdata(L, ctx->req);
return l_ffi_call(L, 2);
}
static int l_ffi_layer_finish(kr_layer_t *ctx)
{
- struct kr_request *req = ctx->data;
+ struct kr_request *req = ctx->req;
LAYER_FFI_CALL(ctx, finish);
lua_pushlightuserdata(L, req);
lua_pushlightuserdata(L, req->answer);
return ctx->state; /* Already failed, skip */
}
LAYER_FFI_CALL(ctx, consume);
- lua_pushlightuserdata(L, ctx->data);
+ lua_pushlightuserdata(L, ctx->req);
lua_pushlightuserdata(L, pkt);
return l_ffi_call(L, 3);
}
return ctx->state; /* Already failed or done, skip */
}
LAYER_FFI_CALL(ctx, produce);
- lua_pushlightuserdata(L, ctx->data);
+ lua_pushlightuserdata(L, ctx->req);
lua_pushlightuserdata(L, pkt);
return l_ffi_call(L, 3);
}
section = ffi.new('struct pkt_section'),
rcode = ffi.new('struct pkt_rcode'),
query = query_flag,
- NOOP = 0, YIELD = 0, CONSUME = 1, PRODUCE = 2, DONE = 4, FAIL = 8,
+ CONSUME = 1, PRODUCE = 2, DONE = 4, FAIL = 8, YIELD = 16,
-- Metatypes
pkt_t = function (udata) return ffi.cast('knot_pkt_t *', udata) end,
request_t = function (udata) return ffi.cast('struct kr_request *', udata) end,
int consume(kr_layer_t *ctx, knot_pkt_t *pkt)
{
- struct kr_request *request = ctx->data;
- struct kr_query *query = request->current_query;
+ struct kr_request *req = ctx->req;
+ struct kr_query *qry = req->current_query;
}
This is only passive processing of the incoming answer. If you want to change the course of resolution, say satisfy a query from a local cache before the library issues a query to the nameserver, you can use states (see the :ref:`Static hints <mod-hints>` for example).
int produce(kr_layer_t *ctx, knot_pkt_t *pkt)
{
- struct kr_request *request = ctx->data;
- struct kr_query *cur = request->current_query;
+ struct kr_request *req = ctx->req;
+ struct kr_query *qry = req->current_query;
/* Query can be satisfied locally. */
- if (can_satisfy(cur)) {
+ if (can_satisfy(qry)) {
/* This flag makes the resolver move the query
* to the "resolved" list. */
- cur->flags |= QUERY_RESOLVED;
+ qry->flags |= QUERY_RESOLVED;
return KR_STATE_DONE;
}
int finish(kr_layer_t *ctx)
{
- struct kr_request *request = ctx->data;
- struct kr_rplan *rplan = request->rplan;
+ struct kr_request *req = ctx->req;
+ struct kr_rplan *rplan = req->rplan;
/* Print the query sequence with start time. */
char qname_str[KNOT_DNAME_MAXLEN];
#define QRDEBUG(query, cls, fmt, ...)
#endif
-/*! Layer processing states.
+/** Layer processing states. Only one value at a time (but see TODO).
+ *
* Each state represents the state machine transition,
* and determines readiness for the next action.
+ * See struct kr_layer_api for the actions.
+ *
+ * TODO: the cookie module sometimes sets (_FAIL | _DONE) on purpose (!)
*/
enum kr_layer_state {
- KR_STATE_NOOP = 0, /*!< N/A */
KR_STATE_CONSUME = 1 << 0, /*!< Consume data. */
KR_STATE_PRODUCE = 1 << 1, /*!< Produce data. */
- KR_STATE_DONE = 1 << 2, /*!< Finished. */
- KR_STATE_FAIL = 1 << 3 /*!< Error. */
+ KR_STATE_DONE = 1 << 2, /*!< Finished successfully. */
+ KR_STATE_FAIL = 1 << 3, /*!< Error. */
+ KR_STATE_YIELD = 1 << 4, /*!< Paused, waiting for a sub-query. */
};
/* Forward declarations. */
struct kr_layer_api;
-/*! \brief Packet processing context. */
+/** Packet processing context. */
typedef struct kr_layer {
- knot_mm_t *mm; /* Processing memory context. */
- uint16_t state; /* Bitmap of enum kr_layer_state. */
- void *data; /* Module specific. */
+ int state; /*!< The current state; bitmap of enum kr_layer_state. */
+ struct kr_request *req; /*!< The corresponding request. */
const struct kr_layer_api *api;
} kr_layer_t;
-/*! \brief Packet processing module API. */
+/** Packet processing module API. All functions return the new kr_layer_state. */
struct kr_layer_api {
- int (*begin)(kr_layer_t *ctx, void *module_param);
+ /** Start of processing the DNS request. */
+ int (*begin)(kr_layer_t *ctx);
+
int (*reset)(kr_layer_t *ctx);
+
+ /** Paired to begin, called both on successes and failures. */
int (*finish)(kr_layer_t *ctx);
+
+ /** Processing an answer from upstream or the answer to the request. */
int (*consume)(kr_layer_t *ctx, knot_pkt_t *pkt);
+
+ /** Produce either an answer to the request or a query for upstream (or fail). */
int (*produce)(kr_layer_t *ctx, knot_pkt_t *pkt);
- int (*fail)(kr_layer_t *ctx, knot_pkt_t *pkt);
+
+ /** The module can store anything in here. */
void *data;
};
unsigned state;
};
-/* Repurpose layer states. */
-#define KR_STATE_YIELD KR_STATE_NOOP
static int reset(kr_layer_t *ctx) { return KR_STATE_PRODUCE; }
/* Set resolution context and parameters. */
-static int begin(kr_layer_t *ctx, void *module_param)
+static int begin(kr_layer_t *ctx)
{
if (ctx->state & (KR_STATE_DONE|KR_STATE_FAIL)) {
return ctx->state;
* Server cookie queries must be handled by the cookie module/layer
* before this layer.
*/
- const struct kr_request *req = ctx->data;
- const knot_pkt_t *pkt = req->qsource.packet;
+ const knot_pkt_t *pkt = ctx->req->qsource.packet;
if (!pkt || knot_wire_get_qdcount(pkt->wire) == 0) {
return KR_STATE_FAIL;
}
static int prepare_query(kr_layer_t *ctx, knot_pkt_t *pkt)
{
assert(pkt && ctx);
- struct kr_request *req = ctx->data;
- struct kr_query *query = req->current_query;
+ struct kr_query *query = ctx->req->current_query;
if (!query || ctx->state & (KR_STATE_DONE|KR_STATE_FAIL)) {
return ctx->state;
}
static int resolve(kr_layer_t *ctx, knot_pkt_t *pkt)
{
assert(pkt && ctx);
- struct kr_request *req = ctx->data;
+ struct kr_request *req = ctx->req;
struct kr_query *query = req->current_query;
if (!query || (query->flags & (QUERY_RESOLVED|QUERY_BADCOOKIE_AGAIN))) {
return ctx->state;
static int pktcache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
{
- struct kr_request *req = ctx->data;
- struct kr_query *qry = req->current_query;
+ struct kr_query *qry = ctx->req->current_query;
if (ctx->state & (KR_STATE_FAIL|KR_STATE_DONE) || (qry->flags & QUERY_NO_CACHE)) {
return ctx->state; /* Already resolved/failed */
}
/* Fetch either answer to original or minimized query */
uint8_t flags = 0;
- struct kr_cache *cache = &req->ctx->cache;
+ struct kr_cache *cache = &ctx->req->ctx->cache;
int ret = loot_pktcache(cache, pkt, qry, &flags);
if (ret == 0) {
DEBUG_MSG(qry, "=> satisfied from cache\n");
static int pktcache_stash(kr_layer_t *ctx, knot_pkt_t *pkt)
{
- struct kr_request *req = ctx->data;
- struct kr_query *qry = req->current_query;
+ struct kr_query *qry = ctx->req->current_query;
/* Cache only answers that make query resolved (i.e. authoritative)
* that didn't fail during processing and are negative. */
if (qry->flags & QUERY_CACHED || ctx->state & KR_STATE_FAIL) {
}
/* Check if we can replace (allow current or better rank, SECURE is always accepted). */
- struct kr_cache *cache = &req->ctx->cache;
+ struct kr_cache *cache = &ctx->req->ctx->cache;
if (header.rank < KR_RANK_SECURE) {
int cached_rank = kr_cache_peek_rank(cache, KR_CACHE_PKT, qname, qtype, header.timestamp);
if (cached_rank > header.rank) {
static int rrcache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
{
- struct kr_request *req = ctx->data;
- struct kr_query *qry = req->current_query;
+ struct kr_query *qry = ctx->req->current_query;
if (ctx->state & (KR_STATE_FAIL|KR_STATE_DONE) || (qry->flags & QUERY_NO_CACHE)) {
return ctx->state; /* Already resolved/failed */
}
* it may either be a CNAME chain or direct answer.
* Only one step of the chain is resolved at a time.
*/
- struct kr_cache *cache = &req->ctx->cache;
+ struct kr_cache *cache = &ctx->req->ctx->cache;
int ret = -1;
if (qry->stype != KNOT_RRTYPE_ANY) {
ret = loot_rrcache(cache, pkt, qry, qry->stype, (qry->flags & QUERY_DNSSEC_WANT));
static int rrcache_stash(kr_layer_t *ctx, knot_pkt_t *pkt)
{
- struct kr_request *req = ctx->data;
+ struct kr_request *req = ctx->req;
struct kr_query *qry = req->current_query;
if (!qry || ctx->state & KR_STATE_FAIL) {
return ctx->state;
static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
{
int ret = 0;
- struct kr_request *req = ctx->data;
+ struct kr_request *req = ctx->req;
struct kr_query *qry = req->current_query;
/* Ignore faulty or unprocessed responses. */
if (ctx->state & (KR_STATE_FAIL|KR_STATE_CONSUME)) {
typedef const kr_layer_api_t* (module_layer_cb)(struct kr_module *);
typedef struct kr_prop *(module_prop_cb)(void);
typedef char *(kr_prop_cb)(void *, struct kr_module *, const char *);
-#define KR_MODULE_API ((uint32_t) 0x20150402)
+#define KR_MODULE_API ((uint32_t) 0x20161108)
/* @endcond */
/**
*/
static int consume_yield(kr_layer_t *ctx, knot_pkt_t *pkt)
{
- struct kr_request *req = ctx->data;
+ struct kr_request *req = ctx->req;
knot_pkt_t *pkt_copy = knot_pkt_new(NULL, pkt->size, &req->pool);
struct kr_layer_pickle *pickle = mm_alloc(&req->pool, sizeof(*pickle));
if (pickle && pkt_copy && knot_pkt_copy(pkt_copy, pkt) == 0) {
}
return kr_error(ENOMEM);
}
-static int begin_yield(kr_layer_t *ctx, void *module) { return kr_ok(); }
+static int begin_yield(kr_layer_t *ctx) { return kr_ok(); }
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(); }
/** @internal Macro for iterating module layers. */
-#define RESUME_LAYERS(from, req, qry, func, ...) \
- (req)->current_query = (qry); \
- for (size_t i = (from); i < (req)->ctx->modules->len; ++i) { \
- struct kr_module *mod = (req)->ctx->modules->at[i]; \
+#define RESUME_LAYERS(from, r, qry, func, ...) \
+ (r)->current_query = (qry); \
+ for (size_t i = (from); i < (r)->ctx->modules->len; ++i) { \
+ struct kr_module *mod = (r)->ctx->modules->at[i]; \
if (mod->layer) { \
- struct kr_layer layer = {.state = (req)->state, .api = mod->layer(mod), .data = (req)}; \
+ struct kr_layer layer = {.state = (r)->state, .api = mod->layer(mod), .req = (r)}; \
if (layer.api && layer.api->func) { \
- (req)->state = layer.api->func(&layer, ##__VA_ARGS__); \
- if ((req)->state == KR_STATE_YIELD) { \
+ (r)->state = layer.api->func(&layer, ##__VA_ARGS__); \
+ if ((r)->state == KR_STATE_YIELD) { \
func ## _yield(&layer, ##__VA_ARGS__); \
break; \
} \
} \
} \
} /* Invalidate current query. */ \
- (req)->current_query = NULL
+ (r)->current_query = NULL
/** @internal Macro for starting module iteration. */
#define ITERATE_LAYERS(req, qry, func, ...) RESUME_LAYERS(0, req, qry, func, ##__VA_ARGS__)
/* Expect answer, pop if satisfied immediately */
request->qsource.packet = packet;
- ITERATE_LAYERS(request, qry, begin, request);
+ ITERATE_LAYERS(request, qry, begin);
request->qsource.packet = NULL;
if (request->state == KR_STATE_DONE) {
kr_rplan_pop(rplan, qry);
/** Process incoming response. */
int check_response(kr_layer_t *ctx, knot_pkt_t *pkt)
{
- struct kr_request *req = ctx->data;
+ struct kr_request *req = ctx->req;
struct kr_query *qry = req->current_query;
struct kr_cookie_ctx *cookie_ctx = &req->ctx->cookie_ctx;
return state;
}
-int check_request(kr_layer_t *ctx, void *module_param)
+int check_request(kr_layer_t *ctx)
{
- struct kr_request *req = ctx->data;
+ struct kr_request *req = ctx->req;
struct kr_cookie_settings *srvr_sett = &req->ctx->cookie_ctx.srvr;
knot_pkt_t *answer = req->answer;
#include "lib/layer.h"
-/**
- * @brief Checks cookies of inbound requests.
- * @param ctx layer context
- * @param module_param module parameters
- * @return layer state
- */
-int check_request(kr_layer_t *ctx, void *module_param);
+/** Checks cookies of inbound requests. It's for kr_layer_api_t::begin. */
+int check_request(kr_layer_t *ctx);
-/**
- * @brief Checks cookies of received responses.
- * @param ctx layer context
- * @param pkt response packet
- * @return layer state
- */
+/** Checks cookies of received responses. It's for kr_layer_api_t::consume. */
int check_response(kr_layer_t *ctx, knot_pkt_t *pkt);
size_t addr_len;
};
-static int begin(kr_layer_t *ctx, void *module_param)
-{
- ctx->data = module_param;
- return ctx->state;
-}
-
static int put_answer(knot_pkt_t *pkt, knot_rrset_t *rr)
{
int ret = 0;
static int query(kr_layer_t *ctx, knot_pkt_t *pkt)
{
- struct kr_request *req = ctx->data;
- struct kr_query *qry = req->current_query;
+ struct kr_query *qry = ctx->req->current_query;
if (!qry || ctx->state & (KR_STATE_FAIL)) {
return ctx->state;
}
const kr_layer_api_t *hints_layer(struct kr_module *module)
{
static kr_layer_api_t _layer = {
- .begin = &begin,
.produce = &query,
};
/* Store module reference */
static int collect_rtt(kr_layer_t *ctx, knot_pkt_t *pkt)
{
- struct kr_request *req = ctx->data;
+ struct kr_request *req = ctx->req;
struct kr_query *qry = req->current_query;
if (qry->flags & QUERY_CACHED || !req->upstream.addr) {
return ctx->state;
static int collect(kr_layer_t *ctx)
{
- struct kr_request *param = ctx->data;
+ struct kr_request *param = ctx->req;
struct kr_module *module = ctx->api->data;
struct kr_rplan *rplan = ¶m->rplan;
struct stat_data *data = module->data;