]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
layer: refactor and better describe the API
authorVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 8 Nov 2016 16:02:43 +0000 (17:02 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 8 Nov 2016 17:12:23 +0000 (18:12 +0100)
- 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.

14 files changed:
daemon/ffimodule.c
daemon/lua/kres.lua
lib/README.rst
lib/layer.h
lib/layer/iterate.c
lib/layer/pktcache.c
lib/layer/rrcache.c
lib/layer/validate.c
lib/module.h
lib/resolve.c
modules/cookies/cookiemonster.c
modules/cookies/cookiemonster.h
modules/hints/hints.c
modules/stats/stats.c

index 65410a367f66c824225867eab3e25467d7218929..af7e46dae3d92aa6e4af9d3fc4c6697700a341d3 100644 (file)
@@ -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);
 }
index 96a34649c8ee38387bd564c9e1cb508ad656997b..4a214e9fa2618c3a2e6117f8bf50356682f9f367 100644 (file)
@@ -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,
index d82b30667823b4ff3d2302e3ae240332faa4f285..198a667c15ea3a7301c01ead1e6d5a3c527b9c8c 100644 (file)
@@ -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];
index 95892bd5ccd7588e36df4b75a3af18aba670c146..a4725092dfa5bc5b10da80eaa99d5d1ced9cd6f0 100644 (file)
  #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
index 37759041bea38720a1bd9ce90ef91161c24593e1..c90894670ac82fec968b80bf179f681a287b0906 100644 (file)
@@ -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;
index 0d0087ec908176b92a45a5119b4102e53b0a165d..747d2e4d511ec8f27715582b4798df225afe620c 100644 (file)
@@ -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) {
index 315337b3f1aab355b2ff34db29cf4c3cb2634d1d..d30c79e648f031f2cb09df65eddc9b96722be7ea 100644 (file)
@@ -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;
index 4174f49e6594f4ea9b3bbd0a9b80b6885cb9287a..7a5887fb65b3b3d64dc8f2a34320f46a04f65944 100644 (file)
@@ -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)) {
index 70279e24f5678f2887ae9712a5539fa399adf423..0a06bf861c43a17dc830cb2f7ae1bdcc264290c1 100644 (file)
@@ -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 */
 
 /**
index 369236d93a16d18539f30d5ec9a44b87c7c70b32..7b115acd7570a75ad7d3c41d7bcc9c8ea39040a7 100644 (file)
@@ -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);
index 414e1b7be854251f6512b7287024992993e1c808..dbeb64c6e0460a1789f2f59adffedc567624d817 100644 (file)
@@ -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;
index 480de903fc9097568bcd05fb5556ddff570a68c0..62574c297cdf5fae6ab5f66a736be12d04a01451 100644 (file)
 
 #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);
index 0cb936cd05fa3f8222d7dfdda0b910141da5c9a6..f7348680dffddfd77f380c476c9c6f42826c3afa 100644 (file)
@@ -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 */
index 55036e068b8b393147c4df437197a0dba89b9af3..c0ede0b4283bf95159a76091af28451db8a4298e 100644 (file)
@@ -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;