]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
RR (de)serialization: move to a separate file
authorVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 10 Nov 2017 14:41:39 +0000 (15:41 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 10 Nov 2017 16:55:10 +0000 (17:55 +0100)
lib/cache.c
lib/cache/entry_rr.c [new file with mode: 0644]
lib/cache/impl.h
lib/lib.mk

index 64c89d1f149b71ba33cfd696bc5e20ae7c8109da..2c0e2f1081f5e0933fa400e167912b5ea3127352 100644 (file)
@@ -235,164 +235,18 @@ static knot_db_val_t closest_NS(kr_layer_t *ctx, struct key *k);
 
 
 
-struct answer {
-       int rcode;      /**< PKT_NODATA, etc. ?? */
-       uint8_t nsec_v; /**< 1 or 3 */
-       knot_mm_t *mm;  /**< Allocator for rrsets */
-       struct answer_rrset {
-               ranked_rr_array_entry_t set;    /**< set+rank for the main data */
-               knot_rdataset_t sig_rds;        /**< RRSIG data, if any */
-       } rrsets[1+1+3]; /**< see AR_ANSWER and friends; only required records are filled */
-};
-enum {
-       AR_ANSWER = 0,  /**< Positive answer record.  It might be wildcard-expanded. */
-       AR_SOA,         /**< SOA record. */
-       AR_NSEC,        /**< NSEC* covering the SNAME. */
-       AR_WILD,        /**< NSEC* covering or matching the source of synthesis. */
-       AR_CPE,         /**< NSEC3 matching the closest provable encloser. */
-};
 
 
 
 /* TODO: move rdataset_* and pkt_* and entry2answer functions into a separate c-file. */
-/** Materialize a knot_rdataset_t from cache with given TTL.
- * Return the number of bytes consumed or an error code.
- */
-static int rdataset_materialize(knot_rdataset_t * restrict rds, const void *data,
-               const void *data_bound, uint32_t ttl, knot_mm_t *pool)
-{
-       assert(rds && data && data_bound && data_bound > data && !rds->data);
-       const void *d = data; /* iterates over the cache data */
-       {
-               uint8_t rr_count;
-               memcpy(&rr_count, d++, sizeof(rr_count));
-               rds->rr_count = rr_count;
-       }
-       /* First sum up the sizes for wire format length. */
-       size_t rdata_len_sum = 0;
-       for (int i = 0; i < rds->rr_count; ++i) {
-               if (d + 2 > data_bound) {
-                       VERBOSE_MSG(NULL, "materialize: EILSEQ!\n");
-                       return kr_error(EILSEQ);
-               }
-               uint16_t len;
-               memcpy(&len, d, sizeof(len));
-               d += sizeof(len) + len;
-               rdata_len_sum += len;
-       }
-       /* Each item in knot_rdataset_t needs TTL (4B) + rdlength (2B) + rdata */
-       rds->data = mm_alloc(pool, rdata_len_sum + ((size_t)rds->rr_count) * (4 + 2));
-       if (!rds->data) {
-               return kr_error(ENOMEM);
-       }
-       /* Construct the output, one "RR" at a time. */
-       d = data + 1/*sizeof(rr_count)*/;
-       knot_rdata_t *d_out = rds->data; /* iterates over the output being materialized */
-       for (int i = 0; i < rds->rr_count; ++i) {
-               uint16_t len;
-               memcpy(&len, d, sizeof(len));
-               d += sizeof(len);
-               knot_rdata_init(d_out, len, d, ttl);
-               d += len;
-               //d_out = kr_rdataset_next(d_out);
-               d_out += 4 + 2 + len; /* TTL + rdlen + rdata */
-       }
-       VERBOSE_MSG(NULL, "materialized from %d B\n", (int)(d - data));
-       return d - data;
-}
 
-int kr_cache_materialize(knot_rdataset_t *dst, const struct kr_cache_p *ref,
-                        uint32_t new_ttl, knot_mm_t *pool)
-{
-       struct entry_h *eh = ref->raw_data;
-       return rdataset_materialize(dst, eh->data, ref->raw_bound, new_ttl, pool);
-}
 
 
-/** Materialize RRset + RRSIGs into ans->rrsets[id].
- * LATER(optim.): it's slightly wasteful that we allocate knot_rrset_t for the packet
- */
-static int entry2answer(struct answer *ans, int id,
-               const struct entry_h *eh, const void *eh_bound,
-               const knot_dname_t *owner, uint16_t type, uint32_t new_ttl)
-{
-       /* We assume it's zeroed.  Do basic sanity check. */
-       if (ans->rrsets[id].set.rr || ans->rrsets[id].sig_rds.data
-           || (type == KNOT_RRTYPE_NSEC && ans->nsec_v != 1)
-           || (type == KNOT_RRTYPE_NSEC3 && ans->nsec_v != 3)) {
-               assert(false);
-               return kr_error(EINVAL);
-       }
-       /* Materialize the base RRset. */
-       knot_rrset_t *rr = ans->rrsets[id].set.rr
-               = knot_rrset_new(owner, type, KNOT_CLASS_IN, ans->mm);
-       if (!rr) return kr_error(ENOMEM);
-       int ret = rdataset_materialize(&rr->rrs, eh->data, eh_bound, new_ttl, ans->mm);
-       if (ret < 0) goto fail;
-       size_t data_off = ret;
-       ans->rrsets[id].set.rank = eh->rank;
-       ans->rrsets[id].set.expiring = is_expiring(eh->ttl, new_ttl);
-       /* Materialize the RRSIG RRset for the answer in (pseudo-)packet. */
-       bool want_rrsigs = kr_rank_test(eh->rank, KR_RANK_SECURE);
-                       //^^ TODO: vague; function parameter instead?
-       if (want_rrsigs) {
-               ret = rdataset_materialize(&ans->rrsets[id].sig_rds, eh->data + data_off,
-                                          eh_bound, new_ttl, ans->mm);
-               if (ret < 0) goto fail;
-
-               // TODO
-               #if 0
-               /* sanity check: we consumed exactly all data */
-               int unused_bytes = eh_bound - (void *)eh->data - data_off - ret;
-               if (ktype != KNOT_RRTYPE_NS && unused_bytes) {
-                       /* ^^ it doesn't have to hold in multi-RRset entries; LATER: more checks? */
-                       VERBOSE_MSG(qry, "BAD?  Unused bytes: %d\n", unused_bytes);
-               }
-               #endif
-       }
-       return kr_ok();
-fail:
-       /* Cleanup the item that we might've (partially) written to. */
-       knot_rrset_free(&ans->rrsets[id].set.rr, ans->mm);
-       knot_rdataset_clear(&ans->rrsets[id].sig_rds, ans->mm);
-       memset(&ans->rrsets[id], 0, sizeof(ans->rrsets[id]));
-       return kr_error(ret);
-}
-
 
 
-/** Compute size of dematerialized rdataset.  NULL is accepted as empty set. */
-static int rdataset_dematerialize_size(const knot_rdataset_t *rds)
-{
-       return 1/*sizeof(rr_count)*/ + (rds
-               ? knot_rdataset_size(rds) - 4 * rds->rr_count /*TTLs*/
-               : 0);
-}
-/** Dematerialize a rdataset. */
-static int rdataset_dematerialize(const knot_rdataset_t *rds, void * restrict data)
-{
-       assert(data);
-       if (rds && rds->rr_count > 255) {
-               return kr_error(ENOSPC);
-       }
-       uint8_t rr_count = rds ? rds->rr_count : 0;
-       memcpy(data++, &rr_count, sizeof(rr_count));
 
-       knot_rdata_t *rd = rds->data;
-       for (int i = 0; i < rr_count; ++i, rd = kr_rdataset_next(rd)) {
-               uint16_t len = knot_rdata_rdlen(rd);
-               memcpy(data, &len, sizeof(len));
-               data += sizeof(len);
-               memcpy(data, knot_rdata_data(rd), len);
-               data += len;
-       }
-       return kr_ok();
-}
-
-
-/**
- */
-int pkt_renew(knot_pkt_t *pkt, const knot_dname_t *name, uint16_t type)
+/** Prepare answer packet to be filled by RRs (without RR data in wire). */
+static int pkt_renew(knot_pkt_t *pkt, const knot_dname_t *name, uint16_t type)
 {
        /* Update packet question if needed. */
        if (!knot_dname_is_equal(knot_pkt_qname(pkt), name)
@@ -412,7 +266,7 @@ int pkt_renew(knot_pkt_t *pkt, const knot_dname_t *name, uint16_t type)
 /** Reserve space for additional `count` RRsets.
  * \note pkt->rr_info gets correct length but is always zeroed
  */
-int pkt_alloc_space(knot_pkt_t *pkt, int count)
+static int pkt_alloc_space(knot_pkt_t *pkt, int count)
 {
        size_t allocd_orig = pkt->rrset_allocd;
        if (pkt->rrset_count + count <= allocd_orig) {
@@ -443,7 +297,7 @@ int pkt_alloc_space(knot_pkt_t *pkt, int count)
  * \note it works with empty set as well (skipped).
  * \note KNOT_CLASS_IN is assumed
  */
-int pkt_append(knot_pkt_t *pkt, const struct answer_rrset *rrset, uint8_t rank)
+static int pkt_append(knot_pkt_t *pkt, const struct answer_rrset *rrset, uint8_t rank)
 {
        /* allocate space, to be sure */
        int rrset_cnt = (rrset->set.rr->rrs.rr_count > 0) + (rrset->sig_rds.rr_count > 0);
diff --git a/lib/cache/entry_rr.c b/lib/cache/entry_rr.c
new file mode 100644 (file)
index 0000000..ed8dfc6
--- /dev/null
@@ -0,0 +1,144 @@
+/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/** @file
+ * Implementation of RRset (de)materialization, i.e. (de)serialization to storage
+ * format used in cache (some repeated fields are omitted).  Prototypes in ./impl.h
+ */
+
+#include "lib/cache/impl.h"
+
+int rdataset_dematerialize(const knot_rdataset_t *rds, void * restrict data)
+{
+       assert(data);
+       if (rds && rds->rr_count > 255) {
+               return kr_error(ENOSPC);
+       }
+       uint8_t rr_count = rds ? rds->rr_count : 0;
+       memcpy(data++, &rr_count, sizeof(rr_count));
+
+       knot_rdata_t *rd = rds->data;
+       for (int i = 0; i < rr_count; ++i, rd = kr_rdataset_next(rd)) {
+               uint16_t len = knot_rdata_rdlen(rd);
+               memcpy(data, &len, sizeof(len));
+               data += sizeof(len);
+               memcpy(data, knot_rdata_data(rd), len);
+               data += len;
+       }
+       return kr_ok();
+}
+
+/** Materialize a knot_rdataset_t from cache with given TTL.
+ * Return the number of bytes consumed or an error code.
+ */
+static int rdataset_materialize(knot_rdataset_t * restrict rds, const void *data,
+               const void *data_bound, uint32_t ttl, knot_mm_t *pool)
+{
+       assert(rds && data && data_bound && data_bound > data && !rds->data);
+       const void *d = data; /* iterates over the cache data */
+       {
+               uint8_t rr_count;
+               memcpy(&rr_count, d++, sizeof(rr_count));
+               rds->rr_count = rr_count;
+       }
+       /* First sum up the sizes for wire format length. */
+       size_t rdata_len_sum = 0;
+       for (int i = 0; i < rds->rr_count; ++i) {
+               if (d + 2 > data_bound) {
+                       VERBOSE_MSG(NULL, "materialize: EILSEQ!\n");
+                       return kr_error(EILSEQ);
+               }
+               uint16_t len;
+               memcpy(&len, d, sizeof(len));
+               d += sizeof(len) + len;
+               rdata_len_sum += len;
+       }
+       /* Each item in knot_rdataset_t needs TTL (4B) + rdlength (2B) + rdata */
+       rds->data = mm_alloc(pool, rdata_len_sum + ((size_t)rds->rr_count) * (4 + 2));
+       if (!rds->data) {
+               return kr_error(ENOMEM);
+       }
+       /* Construct the output, one "RR" at a time. */
+       d = data + 1/*sizeof(rr_count)*/;
+       knot_rdata_t *d_out = rds->data; /* iterates over the output being materialized */
+       for (int i = 0; i < rds->rr_count; ++i) {
+               uint16_t len;
+               memcpy(&len, d, sizeof(len));
+               d += sizeof(len);
+               knot_rdata_init(d_out, len, d, ttl);
+               d += len;
+               //d_out = kr_rdataset_next(d_out);
+               d_out += 4 + 2 + len; /* TTL + rdlen + rdata */
+       }
+       VERBOSE_MSG(NULL, "materialized from %d B\n", (int)(d - data));
+       return d - data;
+}
+
+int kr_cache_materialize(knot_rdataset_t *dst, const struct kr_cache_p *ref,
+                        uint32_t new_ttl, knot_mm_t *pool)
+{
+       struct entry_h *eh = ref->raw_data;
+       return rdataset_materialize(dst, eh->data, ref->raw_bound, new_ttl, pool);
+}
+
+
+int entry2answer(struct answer *ans, int id,
+               const struct entry_h *eh, const void *eh_bound,
+               const knot_dname_t *owner, uint16_t type, uint32_t new_ttl)
+{
+       /* We assume it's zeroed.  Do basic sanity check. */
+       if (ans->rrsets[id].set.rr || ans->rrsets[id].sig_rds.data
+           || (type == KNOT_RRTYPE_NSEC && ans->nsec_v != 1)
+           || (type == KNOT_RRTYPE_NSEC3 && ans->nsec_v != 3)) {
+               assert(false);
+               return kr_error(EINVAL);
+       }
+       /* Materialize the base RRset. */
+       knot_rrset_t *rr = ans->rrsets[id].set.rr
+               = knot_rrset_new(owner, type, KNOT_CLASS_IN, ans->mm);
+       if (!rr) return kr_error(ENOMEM);
+       int ret = rdataset_materialize(&rr->rrs, eh->data, eh_bound, new_ttl, ans->mm);
+       if (ret < 0) goto fail;
+       size_t data_off = ret;
+       ans->rrsets[id].set.rank = eh->rank;
+       ans->rrsets[id].set.expiring = is_expiring(eh->ttl, new_ttl);
+       /* Materialize the RRSIG RRset for the answer in (pseudo-)packet. */
+       bool want_rrsigs = kr_rank_test(eh->rank, KR_RANK_SECURE);
+                       //^^ TODO: vague; function parameter instead?
+       if (want_rrsigs) {
+               ret = rdataset_materialize(&ans->rrsets[id].sig_rds, eh->data + data_off,
+                                          eh_bound, new_ttl, ans->mm);
+               if (ret < 0) goto fail;
+
+               // TODO
+               #if 0
+               /* sanity check: we consumed exactly all data */
+               int unused_bytes = eh_bound - (void *)eh->data - data_off - ret;
+               if (ktype != KNOT_RRTYPE_NS && unused_bytes) {
+                       /* ^^ it doesn't have to hold in multi-RRset entries; LATER: more checks? */
+                       VERBOSE_MSG(qry, "BAD?  Unused bytes: %d\n", unused_bytes);
+               }
+               #endif
+       }
+       return kr_ok();
+fail:
+       /* Cleanup the item that we might've (partially) written to. */
+       knot_rrset_free(&ans->rrsets[id].set.rr, ans->mm);
+       knot_rdataset_clear(&ans->rrsets[id].sig_rds, ans->mm);
+       memset(&ans->rrsets[id], 0, sizeof(ans->rrsets[id]));
+       return kr_error(ret);
+}
+
index ca07428f9b46c8c904d17410197723c775769464..4f11fc9fff97bd9907690d1f668cbebc64068ff5 100644 (file)
@@ -137,6 +137,47 @@ static inline bool is_expiring(uint32_t orig_ttl, uint32_t new_ttl)
 
 int32_t get_new_ttl(const struct entry_h *entry, uint32_t current_time);
 
+
+/* RRset (de)materialization; implementation in ./entry_rr.c */
+
+/** Compute size of dematerialized rdataset.  NULL is accepted as empty set. */
+static inline int rdataset_dematerialize_size(const knot_rdataset_t *rds)
+{
+       return 1/*sizeof(rr_count)*/ + (rds
+               ? knot_rdataset_size(rds) - 4 * rds->rr_count /*TTLs*/
+               : 0);
+}
+
+/** Dematerialize a rdataset. */
+int rdataset_dematerialize(const knot_rdataset_t *rds, void * restrict data);
+
+/** Partially constructed answer when gathering RRsets from cache. */
+struct answer {
+       int rcode;      /**< PKT_NODATA, etc. ?? */
+       uint8_t nsec_v; /**< 1 or 3 */
+       knot_mm_t *mm;  /**< Allocator for rrsets */
+       struct answer_rrset {
+               ranked_rr_array_entry_t set;    /**< set+rank for the main data */
+               knot_rdataset_t sig_rds;        /**< RRSIG data, if any */
+       } rrsets[1+1+3]; /**< see AR_ANSWER and friends; only required records are filled */
+};
+enum {
+       AR_ANSWER = 0,  /**< Positive answer record.  It might be wildcard-expanded. */
+       AR_SOA,         /**< SOA record. */
+       AR_NSEC,        /**< NSEC* covering the SNAME. */
+       AR_WILD,        /**< NSEC* covering or matching the source of synthesis. */
+       AR_CPE,         /**< NSEC3 matching the closest provable encloser. */
+};
+
+/** Materialize RRset + RRSIGs into ans->rrsets[id].
+ * LATER(optim.): it's slightly wasteful that we allocate knot_rrset_t for the packet
+ */
+int entry2answer(struct answer *ans, int id,
+               const struct entry_h *eh, const void *eh_bound,
+               const knot_dname_t *owner, uint16_t type, uint32_t new_ttl);
+
+
+
 #define VERBOSE_MSG(qry, fmt...) QRVERBOSE((qry), "cach",  fmt)
 
 
index f5d6c55dd423a48182683a6441b5706385640f8b..987d7d4adde74ca0e1a9c7099f7b1db99ff87cf0 100644 (file)
@@ -18,6 +18,7 @@ libkres_SOURCES := \
        lib/cache.c            \
        lib/cache/entry_list.c \
        lib/cache/entry_pkt.c  \
+       lib/cache/entry_rr.c  \
        lib/cdb_lmdb.c
 
 libkres_HEADERS := \