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

Merge !550: add trie from knot-dns...

... and migrate kr_zonecut to it.
parents defe4a70 e75711d2
......@@ -594,9 +594,8 @@ static int init_resolver(struct engine *engine)
knot_edns_init(engine->resolver.opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, engine->pool);
/* Use default TLS padding */
engine->resolver.tls_padding = -1;
/* Set default root hints */
/* Empty init; filled via ./lua/config.lua */
kr_zonecut_init(&engine->resolver.root_hints, (const uint8_t *)"", engine->pool);
kr_zonecut_set_sbelt(&engine->resolver, &engine->resolver.root_hints);
/* Open NS rtt + reputation cache */
lru_create(&engine->resolver.cache_rtt, LRU_RTT_SIZE, engine->pool, NULL);
lru_create(&engine->resolver.cache_rep, LRU_REP_SIZE, engine->pool, NULL);
......
......@@ -19,7 +19,8 @@ if not cache.current_size then
cache.size = 100 * MB
end
if kres.context().root_hints.nsset.root == nil then
-- If no addresses for root servers are set, load them from the default file
if require('ffi').C.kr_zonecut_is_empty(kres.context().root_hints) then
_hint_root_file()
end
......
......@@ -119,12 +119,13 @@ typedef struct {
size_t len;
size_t cap;
} ranked_rr_array_t;
typedef struct trie trie_t;
struct kr_zonecut {
knot_dname_t *name;
knot_rrset_t *key;
knot_rrset_t *trust_anchor;
struct kr_zonecut *parent;
map_t nsset;
trie_t *nsset;
knot_mm_t *pool;
};
typedef struct {
......@@ -286,6 +287,7 @@ int kr_ranked_rrarray_add(ranked_rr_array_t *, const knot_rrset_t *, uint8_t, _B
void kr_qflags_set(struct kr_qflags *, struct kr_qflags);
void kr_qflags_clear(struct kr_qflags *, struct kr_qflags);
int kr_zonecut_add(struct kr_zonecut *, const knot_dname_t *, const knot_rdata_t *);
_Bool kr_zonecut_is_empty(struct kr_zonecut *);
void kr_zonecut_set(struct kr_zonecut *, const knot_dname_t *);
uint64_t kr_now();
knot_rrset_t *kr_ta_get(map_t *, const knot_dname_t *);
......
......@@ -57,6 +57,7 @@ typedef void (*trace_callback_f)(struct kr_request *);
struct ranked_rr_array_entry
ranked_rr_array_entry_t
ranked_rr_array_t
trie_t
struct kr_zonecut
kr_qarray_t
struct kr_rplan
......@@ -154,6 +155,7 @@ EOF
kr_qflags_set
kr_qflags_clear
kr_zonecut_add
kr_zonecut_is_empty
kr_zonecut_set
kr_now
# Trust anchors
......
......@@ -8,9 +8,10 @@ as long as it comes with a test case in `tests/test_generics.c`.
* array_ - a set of simple macros to make working with dynamic arrays easier.
* map_ - a `Crit-bit tree`_ key-value map implementation (public domain) that comes with tests.
* set_ - set abstraction implemented on top of ``map``.
* set_ - set abstraction implemented on top of ``map`` (unused now).
* pack_ - length-prefixed list of objects (i.e. array-list).
* lru_ - LRU-like hash table
* trie_ - a trie-based key-value map, taken from knot-dns
array
~~~~~
......@@ -42,4 +43,11 @@ lru
.. doxygenfile:: lru.h
:project: libkres
trie
~~~~
.. doxygenfile:: trie.h
:project: libkres
.. _`Crit-bit tree`: https://cr.yp.to/critbit.html
......@@ -104,25 +104,28 @@ static inline void array_std_free(void *baton, void *p)
/** Zero-initialize the array. */
#define array_init(array) ((array).at = NULL, (array).len = (array).cap = 0)
/** Free and zero-initialize the array. */
/** Free and zero-initialize the array (plain malloc/free). */
#define array_clear(array) \
array_clear_mm(array, array_std_free, NULL)
/** @internal Clear array with a callback. */
/** Make the array empty and free pointed-to memory.
* Mempool usage: pass mm_free and a knot_mm_t* . */
#define array_clear_mm(array, free, baton) \
(free)((baton), (array).at), array_init(array)
/**
* Reserve capacity up to 'n' bytes.
* @return 0 if success, <0 on failure
*/
/** Reserve capacity for at least n elements.
* @return 0 if success, <0 on failure */
#define array_reserve(array, n) \
array_reserve_mm(array, n, array_std_reserve, NULL)
/** @internal Reserve capacity using callback. */
/** Reserve capacity for at least n elements.
* Mempool usage: pass kr_memreserve and a knot_mm_t* .
* @return 0 if success, <0 on failure */
#define array_reserve_mm(array, n, reserve, baton) \
(reserve)((baton), (char **) &(array).at, sizeof((array).at[0]), (n), &(array).cap)
/**
* Push value at the end of the array, resize it if necessary.
* Push value at the end of the array, resize it if necessary (malloc/free).
* @note May fail if the capacity is not reserved.
* @return element index on success, <0 on failure
*/
......
......@@ -75,21 +75,31 @@ typedef array_t(uint8_t) pack_t;
/** Zero-initialize the pack. */
#define pack_init(pack) \
array_init(pack)
/** Free and the pack. */
/** Make the pack empty and free pointed-to memory (plain malloc/free). */
#define pack_clear(pack) \
array_clear(pack)
/** @internal Clear pack with a callback. */
/** Make the pack empty and free pointed-to memory.
* Mempool usage: pass mm_free and a knot_mm_t* . */
#define pack_clear_mm(pack, free, baton) \
array_clear_mm((pack), (free), (baton))
/** Incrementally reserve objects in the pack. */
/** Reserve space for *additional* objects in the pack (plain malloc/free).
* @return 0 if success, <0 on failure */
#define pack_reserve(pack, objs_count, objs_len) \
pack_reserve_mm((pack), (objs_count), (objs_len), array_std_reserve, NULL)
/** @internal Reservation with a callback. */
/** Reserve space for *additional* objects in the pack.
* Mempool usage: pass kr_memreserve and a knot_mm_t* .
* @return 0 if success, <0 on failure */
#define pack_reserve_mm(pack, objs_count, objs_len, reserve, baton) \
array_reserve_mm((pack), (pack).len + (sizeof(pack_objlen_t)*(objs_count) + (objs_len)), (reserve), (baton))
/** Return pointer to first packed object. */
#define pack_head(pack) \
((pack).len > 0 ? &((pack).at[0]) : NULL)
/** Return pack end pointer. */
#define pack_tail(pack) \
&((pack).at[(pack).len])
......@@ -182,6 +192,32 @@ static inline int pack_obj_del(pack_t *pack, const uint8_t *obj, pack_objlen_t l
return -1;
}
/** Clone a pack, replacing destination pack; (*dst == NULL) is valid input.
* @return kr_error(ENOMEM) on allocation failure. */
static inline int pack_clone(pack_t **dst, const pack_t *src, knot_mm_t *pool)
{
if (!dst || !src) {
assert(false);
return kr_error(EINVAL);
}
/* Get a valid pack_t. */
if (!*dst) {
*dst = mm_alloc(pool, sizeof(pack_t));
if (!*dst) return kr_error(ENOMEM);
pack_init(**dst);
/* Clone data only if needed */
if (src->len == 0) return kr_ok();
}
/* Replace the contents of the pack_t. */
int ret = array_reserve_mm(**dst, src->len, kr_memreserve, pool);
if (ret < 0) {
return kr_error(ENOMEM);
}
memcpy((*dst)->at, src->at, src->len);
(*dst)->len = src->len;
return kr_ok();
}
#ifdef __cplusplus
}
#endif
......
This diff is collapsed.
/* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <libknot/mm_ctx.h>
#include "lib/defines.h"
/*!
* \brief Native API of QP-tries:
*
* - keys are char strings, not necessarily zero-terminated,
* the structure copies the contents of the passed keys
* - values are void* pointers, typically you get an ephemeral pointer to it
* - key lengths are limited by 2^32-1 ATM
*
* XXX EDITORS: trie.{h,c} are synced from
* https://gitlab.labs.nic.cz/knot/knot-dns/tree/68352fc969/src/contrib/qp-trie
* only with tiny adjustments, mostly #includes and KR_EXPORT.
*/
/*! \brief Element value. */
typedef void* trie_val_t;
/*! \brief Opaque structure holding a QP-trie. */
typedef struct trie trie_t;
/*! \brief Opaque type for holding a QP-trie iterator. */
typedef struct trie_it trie_it_t;
/*! \brief Create a trie instance. */
trie_t* trie_create(knot_mm_t *mm);
/*! \brief Free a trie instance. */
void trie_free(trie_t *tbl);
/*! \brief Clear a trie instance (make it empty). */
void trie_clear(trie_t *tbl);
/*! \brief Return the number of keys in the trie. */
size_t trie_weight(const trie_t *tbl);
/*! \brief Search the trie, returning NULL on failure. */
trie_val_t* trie_get_try(trie_t *tbl, const char *key, uint32_t len);
/*! \brief Search the trie, inserting NULL trie_val_t on failure. */
trie_val_t* trie_get_ins(trie_t *tbl, const char *key, uint32_t len);
/*!
* \brief Search for less-or-equal element.
*
* \param tbl Trie.
* \param key Searched key.
* \param len Key length.
* \param val Must be valid; it will be set to NULL if not found or errored.
* \return KNOT_EOK for exact match, 1 for previous, KNOT_ENOENT for not-found,
* or KNOT_E*.
*/
int trie_get_leq(trie_t *tbl, const char *key, uint32_t len, trie_val_t **val);
/*!
* \brief Apply a function to every trie_val_t, in order.
*
* \param d Parameter passed as the second argument to f().
* \return First nonzero from f() or zero (i.e. KNOT_EOK).
*/
int trie_apply(trie_t *tbl, int (*f)(trie_val_t *, void *), void *d);
/*!
* \brief Remove an item, returning KNOT_EOK if succeeded or KNOT_ENOENT if not found.
*
* If val!=NULL and deletion succeeded, the deleted value is set.
*/
int trie_del(trie_t *tbl, const char *key, uint32_t len, trie_val_t *val);
/*! \brief Create a new iterator pointing to the first element (if any). */
KR_EXPORT
trie_it_t* trie_it_begin(trie_t *tbl);
/*!
* \brief Advance the iterator to the next element.
*
* Iteration is in ascending lexicographical order.
* In particular, the empty string would be considered as the very first.
*/
KR_EXPORT
void trie_it_next(trie_it_t *it);
/*! \brief Test if the iterator has gone past the last element. */
KR_EXPORT
bool trie_it_finished(trie_it_t *it);
/*! \brief Free any resources of the iterator. It's OK to call it on NULL. */
KR_EXPORT
void trie_it_free(trie_it_t *it);
/*!
* \brief Return pointer to the key of the current element.
*
* \note The optional len is uint32_t internally but size_t is better for our usage,
* as it is without an additional type conversion.
*/
KR_EXPORT
const char* trie_it_key(trie_it_t *it, size_t *len);
/*! \brief Return pointer to the value of the current element (writable). */
KR_EXPORT
trie_val_t* trie_it_val(trie_it_t *it);
......@@ -13,6 +13,7 @@ libkres_SOURCES := \
lib/dnssec/ta.c \
lib/generic/lru.c \
lib/generic/map.c \
lib/generic/trie.c \
lib/layer/cache.c \
lib/layer/iterate.c \
lib/layer/validate.c \
......@@ -38,7 +39,7 @@ libkres_HEADERS := \
lib/generic/lru.h \
lib/generic/map.h \
lib/generic/pack.h \
lib/generic/set.h \
lib/generic/trie.h \
lib/layer.h \
lib/layer/iterate.h \
lib/module.h \
......
......@@ -82,7 +82,7 @@ static void update_nsrep_set(struct kr_nsrep *ns, const knot_dname_t *name, uint
#undef ADDR_SET
static unsigned eval_addr_set(pack_t *addr_set, struct kr_context *ctx,
static unsigned eval_addr_set(const pack_t *addr_set, struct kr_context *ctx,
unsigned score, uint8_t *addr[])
{
kr_nsrep_rtt_lru_t *rtt_cache = ctx->cache_rtt;
......@@ -209,9 +209,8 @@ get_next_iterator :
return rtt_cache_entry_score[0];
}
static int eval_nsrep(const char *k, void *v, void *baton)
static int eval_nsrep(const knot_dname_t *owner, const pack_t *addr_set, struct kr_query *qry)
{
struct kr_query *qry = baton;
struct kr_nsrep *ns = &qry->ns;
struct kr_context *ctx = ns->ctx;
unsigned score = KR_NS_MAX_SCORE;
......@@ -220,8 +219,8 @@ static int eval_nsrep(const char *k, void *v, void *baton)
/* Fetch NS reputation */
if (ctx->cache_rep) {
unsigned *cached = lru_get_try(ctx->cache_rep, k,
knot_dname_size((const uint8_t *)k));
unsigned *cached = lru_get_try(ctx->cache_rep, (const char *)owner,
knot_dname_size(owner));
if (cached) {
reputation = *cached;
}
......@@ -229,7 +228,6 @@ static int eval_nsrep(const char *k, void *v, void *baton)
/* Favour nameservers with unknown addresses to probe them,
* otherwise discover the current best address for the NS. */
pack_t *addr_set = (pack_t *)v;
if (addr_set->len == 0) {
score = KR_NS_UNKNOWN;
/* If the server doesn't have IPv6, give it disadvantage. */
......@@ -261,19 +259,19 @@ static int eval_nsrep(const char *k, void *v, void *baton)
return kr_ok();
} else if (score <= ns->score &&
(score < KR_NS_LONG || qry->flags.NO_THROTTLE)) {
update_nsrep_set(ns, (const knot_dname_t *)k, addr_choice, score);
update_nsrep_set(ns, owner, addr_choice, score);
ns->reputation = reputation;
} else if ((kr_rand_uint(100) < 10) &&
(kr_rand_uint(KR_NS_MAX_SCORE) >= score)) {
/* With 10% chance probe server with a probability
* given by its RTT / MAX_RTT. */
update_nsrep_set(ns, (const knot_dname_t *)k, addr_choice, score);
update_nsrep_set(ns, owner, addr_choice, score);
ns->reputation = reputation;
return 1; /* Stop evaluation */
} else if (ns->score > KR_NS_MAX_SCORE) {
/* Check if any server was already selected.
* If no, pick current server and continue evaluation. */
update_nsrep_set(ns, (const knot_dname_t *)k, addr_choice, score);
update_nsrep_set(ns, owner, addr_choice, score);
ns->reputation = reputation;
}
......@@ -339,7 +337,18 @@ int kr_nsrep_elect(struct kr_query *qry, struct kr_context *ctx)
struct kr_nsrep *ns = &qry->ns;
ELECT_INIT(ns, ctx);
int ret = map_walk(&qry->zone_cut.nsset, eval_nsrep, qry);
int ret = kr_ok();
trie_it_t *it;
for (it = trie_it_begin(qry->zone_cut.nsset); !trie_it_finished(it);
trie_it_next(it)) {
ret = eval_nsrep(/* we trust it's a correct dname */
(const knot_dname_t *)trie_it_key(it, NULL),
(const pack_t *)*trie_it_val(it), qry);
if (ret) break;
}
trie_it_free(it);
if (qry->ns.score <= KR_NS_MAX_SCORE && qry->ns.score >= KR_NS_LONG) {
/* This is a low-reliability probe,
* go with TCP to get ICMP reachability check. */
......@@ -357,7 +366,7 @@ int kr_nsrep_elect_addr(struct kr_query *qry, struct kr_context *ctx)
/* Get address list for this NS */
struct kr_nsrep *ns = &qry->ns;
ELECT_INIT(ns, ctx);
pack_t *addr_set = map_get(&qry->zone_cut.nsset, (const char *)ns->name);
pack_t *addr_set = kr_zonecut_find(&qry->zone_cut, ns->name);
if (!addr_set) {
return kr_error(ENOENT);
}
......
......@@ -268,7 +268,7 @@ static int ns_fetch_cut(struct kr_query *qry, const knot_dname_t *requested_name
}
/* Check if any DNSKEY found for cached cut */
if (qry->flags.DNSSEC_WANT && cut_found.key == NULL &&
!kr_zonecut_has_glue(&cut_found)) {
kr_zonecut_is_empty(&cut_found)) {
/* Cut found and there are no proofs of zone insecurity.
* But no DNSKEY found and no glue fetched.
* We have got circular dependency - must fetch A\AAAA
......@@ -1428,7 +1428,7 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
}
kr_nsrep_elect(qry, request->ctx);
if (qry->ns.score > KR_NS_MAX_SCORE) {
if (!qry->zone_cut.nsset.root) {
if (kr_zonecut_is_empty(&qry->zone_cut)) {
VERBOSE_MSG(qry, "=> no NS with an address\n");
} else {
VERBOSE_MSG(qry, "=> no valid NS left\n");
......
......@@ -53,6 +53,13 @@ static isaac_ctx ISAAC;
static bool isaac_seeded = false;
#define SEED_SIZE 256
void *mm_malloc(void *ctx, size_t n)
{
(void)ctx;
return malloc(n);
}
/*
* Macros.
*/
......
......@@ -121,6 +121,17 @@ static inline void *mm_realloc(knot_mm_t *mm, void *what, size_t size, size_t pr
return realloc(what, size);
}
}
/** Trivial malloc() wrapper. */
void *mm_malloc(void *ctx, size_t n);
/** Initialize mm with standard malloc+free. */
static inline void mm_ctx_init(knot_mm_t *mm)
{
mm->ctx = NULL;
mm->alloc = mm_malloc;
mm->free = free;
}
/* @endcond */
/** Return time difference in miliseconds.
......
......@@ -60,15 +60,25 @@ int kr_zonecut_init(struct kr_zonecut *cut, const knot_dname_t *name, knot_mm_t
cut->key = NULL;
cut->trust_anchor = NULL;
cut->parent = NULL;
cut->nsset = map_make(pool);
return kr_ok();
cut->nsset = trie_create(pool);
return cut->name && cut->nsset ? kr_ok() : kr_error(ENOMEM);
}
static int free_addr_set(const char *k, void *v, void *baton)
/** Completely free a pack_t. */
static inline void free_addr_set(pack_t *pack, knot_mm_t *pool)
{
if (unlikely(!pack)) {
/* promised we don't store NULL packs */
assert(false);
return;
}
pack_clear_mm(*pack, mm_free, pool);
mm_free(pool, pack);
}
/** Trivial wrapper for use in trie_apply, due to ugly casting. */
static int free_addr_set_cb(trie_val_t *v, void *pool)
{
pack_t *pack = v;
pack_clear_mm(*pack, mm_free, baton);
mm_free(baton, pack);
free_addr_set(*v, pool);
return kr_ok();
}
......@@ -78,8 +88,11 @@ void kr_zonecut_deinit(struct kr_zonecut *cut)
return;
}
mm_free(cut->pool, cut->name);
map_walk(&cut->nsset, free_addr_set, cut->pool);
map_clear(&cut->nsset);
if (cut->nsset) {
trie_apply(cut->nsset, free_addr_set_cb, cut->pool);
trie_free(cut->nsset);
cut->nsset = NULL;
}
knot_rrset_free(&cut->key, cut->pool);
knot_rrset_free(&cut->trust_anchor, cut->pool);
cut->name = NULL;
......@@ -99,43 +112,31 @@ void kr_zonecut_set(struct kr_zonecut *cut, const knot_dname_t *name)
cut->trust_anchor = ta;
}
static int copy_addr_set(const char *k, void *v, void *baton)
{
pack_t *addr_set = v;
struct kr_zonecut *dst = baton;
/* Clone addr_set pack */
pack_t *new_set = mm_alloc(dst->pool, sizeof(*new_set));
if (!new_set) {
return kr_error(ENOMEM);
}
pack_init(*new_set);
/* Clone data only if needed */
if (addr_set->len > 0) {
new_set->at = mm_alloc(dst->pool, addr_set->len);
if (!new_set->at) {
mm_free(dst->pool, new_set);
return kr_error(ENOMEM);
}
memcpy(new_set->at, addr_set->at, addr_set->len);
new_set->len = addr_set->len;
new_set->cap = addr_set->len;
}
/* Reinsert */
if (map_set(&dst->nsset, k, new_set) != 0) {
pack_clear_mm(*new_set, mm_free, dst->pool);
mm_free(dst->pool, new_set);
return kr_error(ENOMEM);
}
return kr_ok();
}
int kr_zonecut_copy(struct kr_zonecut *dst, const struct kr_zonecut *src)
{
if (!dst || !src) {
return kr_error(EINVAL);
}
/* We're not touching src nsset, I promise */
return map_walk((map_t *)&src->nsset, copy_addr_set, dst);
if (!dst->nsset) {
dst->nsset = trie_create(dst->pool);
}
/* Copy the contents, one by one. */
int ret = kr_ok();
trie_it_t *it;
for (it = trie_it_begin(src->nsset); !trie_it_finished(it); trie_it_next(it)) {
size_t klen;
const char * const k = trie_it_key(it, &klen);
pack_t **new_pack = (pack_t **)trie_get_ins(dst->nsset, k, klen);
if (!new_pack) {
ret = kr_error(ENOMEM);
break;
}
const pack_t *old_pack = *trie_it_val(it);
ret = pack_clone(new_pack, old_pack, dst->pool);
if (ret) break;
}
trie_it_free(it);
return ret;
}
int kr_zonecut_copy_trust(struct kr_zonecut *dst, const struct kr_zonecut *src)
......@@ -168,18 +169,16 @@ int kr_zonecut_copy_trust(struct kr_zonecut *dst, const struct kr_zonecut *src)
int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata)
{
if (!cut || !ns) {
if (!cut || !ns || !cut->nsset) {
return kr_error(EINVAL);
}
/* Fetch/insert nameserver. */
pack_t *pack = kr_zonecut_find(cut, ns);
if (pack == NULL) {
pack = mm_alloc(cut->pool, sizeof(*pack));
if (!pack || (map_set(&cut->nsset, (const char *)ns, pack) != 0)) {
mm_free(cut->pool, pack);
return kr_error(ENOMEM);
}
pack_init(*pack);
/* Get a pack_t for the ns. */
pack_t **pack = (pack_t **)trie_get_ins(cut->nsset, (const char *)ns, knot_dname_size(ns));
if (!pack) return kr_error(ENOMEM);
if (*pack == NULL) {
*pack = mm_alloc(cut->pool, sizeof(pack_t));
if (*pack == NULL) return kr_error(ENOMEM);
pack_init(**pack);
}
/* Insert data (if has any) */
if (rdata == NULL) {
......@@ -188,15 +187,15 @@ int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rd
/* Check for duplicates */
uint16_t rdlen = knot_rdata_rdlen(rdata);
uint8_t *raw_addr = knot_rdata_data(rdata);
if (pack_obj_find(pack, raw_addr, rdlen)) {
if (pack_obj_find(*pack, raw_addr, rdlen)) {
return kr_ok();
}
/* Push new address */
int ret = pack_reserve_mm(*pack, 1, rdlen, kr_memreserve, cut->pool);
int ret = pack_reserve_mm(**pack, 1, rdlen, kr_memreserve, cut->pool);
if (ret != 0) {
return kr_error(ENOMEM);
}
return pack_obj_push(pack, raw_addr, rdlen);
return pack_obj_push(*pack, raw_addr, rdlen);
}
int kr_zonecut_del(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata)
......@@ -217,8 +216,10 @@ int kr_zonecut_del(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rd
}
/* No servers left, remove NS from the set. */
if (pack->len == 0) {
free_addr_set((const char *)ns, pack, cut->pool);
return map_del(&cut->nsset, (const char *)ns);
free_addr_set(pack, cut->pool);
ret = trie_del(cut->nsset, (const char *)ns, knot_dname_size(ns), NULL);
assert(ret == 0); /* only KNOT_ENOENT and that *can't* happen */
return (ret == 0) ? kr_ok() : kr_error(ret);
}
return ret;
......@@ -231,12 +232,15 @@ int kr_zonecut_del_all(struct kr_zonecut *cut, const knot_dname_t *ns)
}
/* Find the address list; then free and remove it. */
pack_t *pack = kr_zonecut_find(cut, ns);
if (pack == NULL) {
pack_t *pack;
int ret = trie_del(cut->nsset, (const char *)ns, knot_dname_size(ns),
(trie_val_t *)&pack);
if (ret) { /* deletion failed */
assert(ret == KNOT_ENOENT);
return kr_error(ENOENT);
}
free_addr_set((const char *)ns, pack, cut->pool);
return map_del(&cut->nsset, (const char *)ns);
free_addr_set(pack, cut->pool);
return kr_ok();
}
pack_t *kr_zonecut_find(struct kr_zonecut *cut, const knot_dname_t *ns)
......@@ -244,58 +248,39 @@ pack_t *kr_zonecut_find(struct kr_zonecut *cut, const knot_dname_t *ns)
if (!cut || !ns) {
return NULL;
}
const char *key = (const char *)ns;
map_t *nsset = &cut->nsset;
return map_get(nsset, key);
trie_val_t *val = trie_get_try(cut->nsset, (const char *)ns, knot_dname_size(ns));
/* we get pointer to the pack_t pointer */
return val ? (pack_t *)*val : NULL;
}
static int has_glue(const char *k, void *v, void *baton)
static int has_address(trie_val_t *v, void *baton_)
{
bool *glue_found = (bool *)baton;
if (*glue_found) {
assert(false);
return 1; /* short-circuit */
}
pack_t *pack = (pack_t *)v;
if (pack != NULL && pack->len != 0) {
*glue_found = true;
return 1; /* short-circuit */
}
return kr_ok();
const pack_t *pack = *v;
const bool found = pack != NULL && pack->len != 0;
return found;
}
bool kr_zonecut_has_glue(struct kr_zonecut *cut)
bool kr_zonecut_is_empty(struct kr_zonecut *cut)
{
if (!cut) {
return false;
if (!cut || !cut->nsset) {
assert(false);
return true;
}
bool glue_found = false;
map_t *nsset = &cut->nsset;
map_walk(nsset, has_glue, &glue_found);
return glue_found;
return !trie_apply(cut->nsset, has_address, NULL);
}
int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut)
{
if (!ctx || !cut) {
if (!ctx || !cut || !ctx->root_hints.nsset) {
return kr_error(EINVAL);
}
update_cut_name(cut, U8(""));
map_walk(&cut->nsset, free_addr_set, cut->pool);
map_clear(&cut->nsset);
trie_apply(cut->nsset, free_addr_set_cb, cut->pool);
trie_clear(cut->nsset);
update_cut_name(cut, U8(""));
/* Copy root hints from resolution context. */
int ret = 0;
if (ctx->root_hints.nsset.root) {
ret = kr_zonecut_copy(cut, &ctx->root_hints);
}
return ret;
return kr_zonecut_copy(cut, &ctx->root_hints);
}
/** Fetch address for zone cut. Any rank is accepted (i.e. glue as well). */
......
......@@ -16,10 +16,10 @@
#pragma once