Commit cc47973e authored by Vladimír Čunát's avatar Vladimír Čunát

layer: refactor and better describe the API

- 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.
parent 4ad98bff
......@@ -146,23 +146,23 @@ static int l_ffi_deinit(struct kr_module *module)
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);
......@@ -175,7 +175,7 @@ static int l_ffi_layer_consume(kr_layer_t *ctx, knot_pkt_t *pkt)
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);
}
......@@ -186,7 +186,7 @@ static int l_ffi_layer_produce(kr_layer_t *ctx, knot_pkt_t *pkt)
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);
}
......
......@@ -489,7 +489,7 @@ local kres = {
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,
......
......@@ -94,8 +94,8 @@ This structure contains pointers to resolution context, resolution plan and also
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).
......@@ -104,14 +104,14 @@ This is only passive processing of the incoming answer. If you want to change th
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;
}
......@@ -125,8 +125,8 @@ It is possible to not only act during the query resolution, but also to view the
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];
......
......@@ -30,37 +30,49 @@
#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;
};
......@@ -74,5 +86,3 @@ struct kr_layer_pickle {
unsigned state;
};
/* Repurpose layer states. */
#define KR_STATE_YIELD KR_STATE_NOOP
......@@ -507,7 +507,7 @@ static int resolve_error(knot_pkt_t *pkt, struct kr_request *req)
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;
......@@ -519,8 +519,7 @@ static int begin(kr_layer_t *ctx, void *module_param)
* 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;
}
......@@ -550,8 +549,7 @@ int kr_make_query(struct kr_query *query, knot_pkt_t *pkt)
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;
}
......@@ -587,7 +585,7 @@ static int resolve_badmsg(knot_pkt_t *pkt, struct kr_request *req, struct kr_que
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;
......
......@@ -102,8 +102,7 @@ static int loot_pktcache(struct kr_cache *cache, knot_pkt_t *pkt, struct kr_quer
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 */
}
......@@ -116,7 +115,7 @@ static int pktcache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
/* 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");
......@@ -172,8 +171,7 @@ static uint32_t packet_ttl(knot_pkt_t *pkt, bool is_negative)
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) {
......@@ -220,7 +218,7 @@ static int pktcache_stash(kr_layer_t *ctx, knot_pkt_t *pkt)
}
/* 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) {
......
......@@ -112,8 +112,7 @@ static int loot_rrcache(struct kr_cache *cache, knot_pkt_t *pkt, struct kr_query
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 */
}
......@@ -125,7 +124,7 @@ static int rrcache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
* 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));
......@@ -322,7 +321,7 @@ static int stash_answer(struct kr_query *qry, knot_pkt_t *pkt, map_t *stash, kno
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;
......
......@@ -372,7 +372,7 @@ static const knot_dname_t *signature_authority(knot_pkt_t *pkt)
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)) {
......
......@@ -37,7 +37,7 @@ typedef int (module_config_cb)(struct kr_module *, const char *);
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 */
/**
......
......@@ -43,7 +43,7 @@
*/
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) {
......@@ -57,28 +57,28 @@ static int consume_yield(kr_layer_t *ctx, knot_pkt_t *pkt)
}
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__)
......@@ -480,7 +480,7 @@ static int resolve_query(struct kr_request *request, const knot_pkt_t *packet)
/* 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);
......
......@@ -218,7 +218,7 @@ static bool check_cookie_content_and_cache(const struct kr_cookie_settings *clnt
/** 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;
......@@ -347,9 +347,9 @@ static int invalid_sc_status(int state, bool sc_present, bool ignore_badcookie,
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;
......
......@@ -20,18 +20,8 @@
#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);
......@@ -48,12 +48,6 @@ struct rev_search_baton {
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;
......@@ -181,8 +175,7 @@ static int satisfy_forward(struct kr_zonecut *hints, knot_pkt_t *pkt, struct kr_
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;
}
......@@ -442,7 +435,6 @@ KR_EXPORT
const kr_layer_api_t *hints_layer(struct kr_module *module)
{
static kr_layer_api_t _layer = {
.begin = &begin,
.produce = &query,
};
/* Store module reference */
......
......@@ -156,7 +156,7 @@ static void collect_sample(struct stat_data *data, struct kr_rplan *rplan, knot_
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;
......@@ -185,7 +185,7 @@ static int collect_rtt(kr_layer_t *ctx, knot_pkt_t *pkt)
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 = &param->rplan;
struct stat_data *data = module->data;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment