xref: /openbsd/usr.sbin/nsd/radtree.c (revision a904e103)
1d3fecca9Ssthen /*
2d3fecca9Ssthen  * radtree -- generic radix tree for binary strings.
3d3fecca9Ssthen  *
4d3fecca9Ssthen  * Copyright (c) 2010, NLnet Labs.  See LICENSE for license.
5d3fecca9Ssthen  */
6d3fecca9Ssthen #include "config.h"
7d3fecca9Ssthen #include <assert.h>
8d3fecca9Ssthen #include <stdlib.h>
9d3fecca9Ssthen #include <string.h>
10d3fecca9Ssthen #include <unistd.h>
11d3fecca9Ssthen #include <time.h>
12d3fecca9Ssthen #include "radtree.h"
13d3fecca9Ssthen #include "util.h"
14d3fecca9Ssthen #include "region-allocator.h"
15d3fecca9Ssthen 
16d3fecca9Ssthen #include <stdio.h>
17d3fecca9Ssthen #include <ctype.h>
18d3fecca9Ssthen 
radix_tree_create(struct region * region)19d3fecca9Ssthen struct radtree* radix_tree_create(struct region* region)
20d3fecca9Ssthen {
21d3fecca9Ssthen 	struct radtree* rt = (struct radtree*)region_alloc(region, sizeof(*rt));
22d3fecca9Ssthen 	if(!rt) return NULL;
23d3fecca9Ssthen 	rt->region = region;
24d3fecca9Ssthen 	radix_tree_init(rt);
25d3fecca9Ssthen 	return rt;
26d3fecca9Ssthen }
27d3fecca9Ssthen 
radix_tree_init(struct radtree * rt)28d3fecca9Ssthen void radix_tree_init(struct radtree* rt)
29d3fecca9Ssthen {
30d3fecca9Ssthen 	rt->root = NULL;
31d3fecca9Ssthen 	rt->count = 0;
32d3fecca9Ssthen }
33d3fecca9Ssthen 
34d3fecca9Ssthen /** delete radnodes in postorder recursion */
radnode_del_postorder(struct region * region,struct radnode * n)35d3fecca9Ssthen static void radnode_del_postorder(struct region* region, struct radnode* n)
36d3fecca9Ssthen {
37d3fecca9Ssthen 	unsigned i;
38d3fecca9Ssthen 	if(!n) return;
39d3fecca9Ssthen 	for(i=0; i<n->len; i++) {
40d3fecca9Ssthen 		radnode_del_postorder(region, n->array[i].node);
41d3fecca9Ssthen 		region_recycle(region, n->array[i].str, n->array[i].len);
42d3fecca9Ssthen 	}
43d3fecca9Ssthen 	region_recycle(region, n->array, n->capacity*sizeof(struct radsel));
44d3fecca9Ssthen 	region_recycle(region, n, sizeof(*n));
45d3fecca9Ssthen }
46d3fecca9Ssthen 
radix_tree_clear(struct radtree * rt)47d3fecca9Ssthen void radix_tree_clear(struct radtree* rt)
48d3fecca9Ssthen {
49d3fecca9Ssthen 	radnode_del_postorder(rt->region, rt->root);
50d3fecca9Ssthen 	rt->root = NULL;
51d3fecca9Ssthen 	rt->count = 0;
52d3fecca9Ssthen }
53d3fecca9Ssthen 
radix_tree_delete(struct radtree * rt)54d3fecca9Ssthen void radix_tree_delete(struct radtree* rt)
55d3fecca9Ssthen {
56d3fecca9Ssthen 	if(!rt) return;
57d3fecca9Ssthen 	radix_tree_clear(rt);
58d3fecca9Ssthen 	region_recycle(rt->region, rt, sizeof(*rt));
59d3fecca9Ssthen }
60d3fecca9Ssthen 
61d3fecca9Ssthen /** return last elem-containing node in this subtree (excl self) */
62d3fecca9Ssthen static struct radnode*
radnode_last_in_subtree(struct radnode * n)63d3fecca9Ssthen radnode_last_in_subtree(struct radnode* n)
64d3fecca9Ssthen {
65d3fecca9Ssthen 	int idx;
66d3fecca9Ssthen 	/* try last entry in array first */
67d3fecca9Ssthen 	for(idx=((int)n->len)-1; idx >= 0; idx--) {
68d3fecca9Ssthen 		if(n->array[idx].node) {
69d3fecca9Ssthen 			/* does it have entries in its subtrees? */
70d3fecca9Ssthen 			if(n->array[idx].node->len > 0) {
71d3fecca9Ssthen 				struct radnode* s = radnode_last_in_subtree(
72d3fecca9Ssthen 					n->array[idx].node);
73d3fecca9Ssthen 				if(s) return s;
74d3fecca9Ssthen 			}
75d3fecca9Ssthen 			/* no, does it have an entry itself? */
76d3fecca9Ssthen 			if(n->array[idx].node->elem)
77d3fecca9Ssthen 				return n->array[idx].node;
78d3fecca9Ssthen 		}
79d3fecca9Ssthen 	}
80d3fecca9Ssthen 	return NULL;
81d3fecca9Ssthen }
82d3fecca9Ssthen 
83d3fecca9Ssthen /** last in subtree, incl self */
84d3fecca9Ssthen static struct radnode*
radnode_last_in_subtree_incl_self(struct radnode * n)85d3fecca9Ssthen radnode_last_in_subtree_incl_self(struct radnode* n)
86d3fecca9Ssthen {
87d3fecca9Ssthen 	struct radnode* s = radnode_last_in_subtree(n);
88d3fecca9Ssthen 	if(s) return s;
89d3fecca9Ssthen 	if(n->elem) return n;
90d3fecca9Ssthen 	return NULL;
91d3fecca9Ssthen }
92d3fecca9Ssthen 
93d3fecca9Ssthen /** return first elem-containing node in this subtree (excl self) */
94d3fecca9Ssthen static struct radnode*
radnode_first_in_subtree(struct radnode * n)95d3fecca9Ssthen radnode_first_in_subtree(struct radnode* n)
96d3fecca9Ssthen {
97d3fecca9Ssthen 	unsigned idx;
98d3fecca9Ssthen 	struct radnode* s;
99d3fecca9Ssthen 	/* try every subnode */
100d3fecca9Ssthen 	for(idx=0; idx<n->len; idx++) {
101d3fecca9Ssthen 		if(n->array[idx].node) {
102d3fecca9Ssthen 			/* does it have elem itself? */
103d3fecca9Ssthen 			if(n->array[idx].node->elem)
104d3fecca9Ssthen 				return n->array[idx].node;
105d3fecca9Ssthen 			/* try its subtrees */
106d3fecca9Ssthen 			if((s=radnode_first_in_subtree(n->array[idx].node))!=0)
107d3fecca9Ssthen 				return s;
108d3fecca9Ssthen 		}
109d3fecca9Ssthen 	}
110d3fecca9Ssthen 	return NULL;
111d3fecca9Ssthen }
112d3fecca9Ssthen 
113d3fecca9Ssthen /** Find an entry in arrays from idx-1 to 0 */
114d3fecca9Ssthen static struct radnode*
radnode_find_prev_from_idx(struct radnode * n,unsigned from)115d3fecca9Ssthen radnode_find_prev_from_idx(struct radnode* n, unsigned from)
116d3fecca9Ssthen {
117d3fecca9Ssthen 	unsigned idx = from;
118d3fecca9Ssthen 	while(idx > 0) {
119d3fecca9Ssthen 		idx --;
120d3fecca9Ssthen 		if(n->array[idx].node) {
121d3fecca9Ssthen 			struct radnode* s = radnode_last_in_subtree_incl_self(
122d3fecca9Ssthen 				n->array[idx].node);
123d3fecca9Ssthen 			if(s) return s;
124d3fecca9Ssthen 		}
125d3fecca9Ssthen 	}
126d3fecca9Ssthen 	return NULL;
127d3fecca9Ssthen }
128d3fecca9Ssthen 
129d3fecca9Ssthen /**
130d3fecca9Ssthen  * Find a prefix of the key, in whole-nodes.
131d3fecca9Ssthen  * Finds the longest prefix that corresponds to a whole radnode entry.
132d3fecca9Ssthen  * There may be a slightly longer prefix in one of the array elements.
133d3fecca9Ssthen  * @param result: the longest prefix, the entry itself if *respos==len,
134d3fecca9Ssthen  * 	otherwise an array entry, residx.
135d3fecca9Ssthen  * @param respos: pos in string where next unmatched byte is, if == len an
136d3fecca9Ssthen  * 	exact match has been found.  If == 0 then a "" match was found.
137d3fecca9Ssthen  * @return false if no prefix found, not even the root "" prefix.
138d3fecca9Ssthen  */
radix_find_prefix_node(struct radtree * rt,uint8_t * k,radstrlen_type len,struct radnode ** result,radstrlen_type * respos)139d3fecca9Ssthen static int radix_find_prefix_node(struct radtree* rt, uint8_t* k,
140fe5fe5f6Sflorian 	radstrlen_type len, struct radnode** result, radstrlen_type* respos)
141d3fecca9Ssthen {
142d3fecca9Ssthen 	struct radnode* n = rt->root;
143fe5fe5f6Sflorian 	radstrlen_type pos = 0;
144d3fecca9Ssthen 	uint8_t byte;
145d3fecca9Ssthen 	*respos = 0;
146d3fecca9Ssthen 	*result = n;
147d3fecca9Ssthen 	if(!n) return 0;
148d3fecca9Ssthen 	while(n) {
149d3fecca9Ssthen 		if(pos == len) {
150d3fecca9Ssthen 			return 1;
151d3fecca9Ssthen 		}
152d3fecca9Ssthen 		byte = k[pos];
153d3fecca9Ssthen 		if(byte < n->offset) {
154d3fecca9Ssthen 			return 1;
155d3fecca9Ssthen 		}
156d3fecca9Ssthen 		byte -= n->offset;
157d3fecca9Ssthen 		if(byte >= n->len) {
158d3fecca9Ssthen 			return 1;
159d3fecca9Ssthen 		}
160d3fecca9Ssthen 		pos++;
161d3fecca9Ssthen 		if(n->array[byte].len != 0) {
162d3fecca9Ssthen 			/* must match additional string */
163d3fecca9Ssthen 			if(pos+n->array[byte].len > len) {
164d3fecca9Ssthen 				return 1;
165d3fecca9Ssthen 			}
166d3fecca9Ssthen 			if(memcmp(&k[pos], n->array[byte].str,
167d3fecca9Ssthen 				n->array[byte].len) != 0) {
168d3fecca9Ssthen 				return 1;
169d3fecca9Ssthen 			}
170d3fecca9Ssthen 			pos += n->array[byte].len;
171d3fecca9Ssthen 		}
172d3fecca9Ssthen 		n = n->array[byte].node;
173d3fecca9Ssthen 		if(!n) return 1;
174d3fecca9Ssthen 		*respos = pos;
175d3fecca9Ssthen 		*result = n;
176d3fecca9Ssthen 	}
177308d2509Sflorian 	/* cannot reach because of returns when !n above */
178*a904e103Sflorian 	/* ENOTREACH */
179d3fecca9Ssthen 	return 1;
180d3fecca9Ssthen }
181d3fecca9Ssthen 
182d3fecca9Ssthen /** grow array to at least the given size, offset unchanged */
183d3fecca9Ssthen static int
radnode_array_grow(struct region * region,struct radnode * n,unsigned want)184d3fecca9Ssthen radnode_array_grow(struct region* region, struct radnode* n, unsigned want)
185d3fecca9Ssthen {
186d3fecca9Ssthen 	unsigned ns = ((unsigned)n->capacity)*2;
187d3fecca9Ssthen 	struct radsel* a;
188d3fecca9Ssthen 	assert(want <= 256); /* cannot be more, range of uint8 */
189d3fecca9Ssthen 	if(want > ns)
190d3fecca9Ssthen 		ns = want;
191d3fecca9Ssthen 	if(ns > 256) ns = 256;
192d3fecca9Ssthen 	/* we do not use realloc, because we want to keep the old array
193d3fecca9Ssthen 	 * in case alloc fails, so that the tree is still usable */
194c939baa4Ssthen 	a = (struct radsel*)region_alloc_array(region, ns, sizeof(struct radsel));
195d3fecca9Ssthen 	if(!a) return 0;
196d3fecca9Ssthen 	assert(n->len <= n->capacity);
197d3fecca9Ssthen 	assert(n->capacity < ns);
198d3fecca9Ssthen 	memcpy(&a[0], &n->array[0], n->len*sizeof(struct radsel));
199d3fecca9Ssthen 	region_recycle(region, n->array, n->capacity*sizeof(struct radsel));
200d3fecca9Ssthen 	n->array = a;
201d3fecca9Ssthen 	n->capacity = ns;
202d3fecca9Ssthen 	return 1;
203d3fecca9Ssthen }
204d3fecca9Ssthen 
205d3fecca9Ssthen /** make space in radnode array for another byte */
206d3fecca9Ssthen static int
radnode_array_space(struct region * region,struct radnode * n,uint8_t byte)207d3fecca9Ssthen radnode_array_space(struct region* region, struct radnode* n, uint8_t byte)
208d3fecca9Ssthen {
209d3fecca9Ssthen 	/* is there an array? */
210d3fecca9Ssthen 	if(!n->array || n->capacity == 0) {
211d3fecca9Ssthen 		n->array = (struct radsel*)region_alloc(region,
212d3fecca9Ssthen 			sizeof(struct radsel));
213d3fecca9Ssthen 		if(!n->array) return 0;
214d3fecca9Ssthen 		memset(&n->array[0], 0, sizeof(struct radsel));
215d3fecca9Ssthen 		n->len = 1;
216d3fecca9Ssthen 		n->capacity = 1;
217d3fecca9Ssthen 		n->offset = byte;
218d3fecca9Ssthen 	/* is the array unused? */
219d3fecca9Ssthen 	} else if(n->len == 0 && n->capacity != 0) {
220d3fecca9Ssthen 		n->len = 1;
221d3fecca9Ssthen 		n->offset = byte;
222d3fecca9Ssthen 		memset(&n->array[0], 0, sizeof(struct radsel));
223d3fecca9Ssthen 	/* is it below the offset? */
224d3fecca9Ssthen 	} else if(byte < n->offset) {
225d3fecca9Ssthen 		/* is capacity enough? */
226d3fecca9Ssthen 		unsigned idx;
227d3fecca9Ssthen 		unsigned need = n->offset-byte;
228d3fecca9Ssthen 		if(n->len+need > n->capacity) {
229d3fecca9Ssthen 			/* grow array */
230d3fecca9Ssthen 			if(!radnode_array_grow(region, n, n->len+need))
231d3fecca9Ssthen 				return 0;
232d3fecca9Ssthen 		}
233d3fecca9Ssthen 		/* reshuffle items to end */
234d3fecca9Ssthen 		memmove(&n->array[need], &n->array[0],
235d3fecca9Ssthen 				n->len*sizeof(struct radsel));
236d3fecca9Ssthen 		/* fixup pidx */
237d3fecca9Ssthen 		for(idx = 0; idx < n->len; idx++) {
238d3fecca9Ssthen 			if(n->array[idx+need].node)
239d3fecca9Ssthen 				n->array[idx+need].node->pidx = idx+need;
240d3fecca9Ssthen 		}
241d3fecca9Ssthen 		/* zero the first */
242d3fecca9Ssthen 		memset(&n->array[0], 0, need*sizeof(struct radsel));
243d3fecca9Ssthen 		n->len += need;
244d3fecca9Ssthen 		n->offset = byte;
245d3fecca9Ssthen 	/* is it above the max? */
246d3fecca9Ssthen 	} else if(byte-n->offset >= n->len) {
247d3fecca9Ssthen 		/* is capacity enough? */
248d3fecca9Ssthen 		unsigned need = (byte-n->offset) - n->len + 1;
249d3fecca9Ssthen 		/* grow array */
250d3fecca9Ssthen 		if(n->len + need > n->capacity) {
251d3fecca9Ssthen 			if(!radnode_array_grow(region, n, n->len+need))
252d3fecca9Ssthen 				return 0;
253d3fecca9Ssthen 		}
254d3fecca9Ssthen 		/* zero added entries */
255d3fecca9Ssthen 		memset(&n->array[n->len], 0, need*sizeof(struct radsel));
256d3fecca9Ssthen 		/* grow length */
257d3fecca9Ssthen 		n->len += need;
258d3fecca9Ssthen 	}
259d3fecca9Ssthen 	return 1;
260d3fecca9Ssthen }
261d3fecca9Ssthen 
262d3fecca9Ssthen /** create a prefix in the array strs */
263d3fecca9Ssthen static int
radsel_str_create(struct region * region,struct radsel * r,uint8_t * k,radstrlen_type pos,radstrlen_type len)264d3fecca9Ssthen radsel_str_create(struct region* region, struct radsel* r, uint8_t* k,
265fe5fe5f6Sflorian 	radstrlen_type pos, radstrlen_type len)
266d3fecca9Ssthen {
267d3fecca9Ssthen 	r->str = (uint8_t*)region_alloc(region, sizeof(uint8_t)*(len-pos));
268d3fecca9Ssthen 	if(!r->str)
269d3fecca9Ssthen 		return 0; /* out of memory */
270d3fecca9Ssthen 	memmove(r->str, k+pos, len-pos);
271d3fecca9Ssthen 	r->len = len-pos;
272d3fecca9Ssthen 	return 1;
273d3fecca9Ssthen }
274d3fecca9Ssthen 
275d3fecca9Ssthen /** see if one byte string p is a prefix of another x (equality is true) */
276d3fecca9Ssthen static int
bstr_is_prefix(uint8_t * p,radstrlen_type plen,uint8_t * x,radstrlen_type xlen)277fe5fe5f6Sflorian bstr_is_prefix(uint8_t* p, radstrlen_type plen, uint8_t* x,
278fe5fe5f6Sflorian 	radstrlen_type xlen)
279d3fecca9Ssthen {
280d3fecca9Ssthen 	/* if plen is zero, it is an (empty) prefix */
281d3fecca9Ssthen 	if(plen == 0)
282d3fecca9Ssthen 		return 1;
283d3fecca9Ssthen 	/* if so, p must be shorter */
284d3fecca9Ssthen 	if(plen > xlen)
285d3fecca9Ssthen 		return 0;
286d3fecca9Ssthen 	return (memcmp(p, x, plen) == 0);
287d3fecca9Ssthen }
288d3fecca9Ssthen 
289d3fecca9Ssthen /** number of bytes in common for the two strings */
290fe5fe5f6Sflorian static radstrlen_type
bstr_common(uint8_t * x,radstrlen_type xlen,uint8_t * y,radstrlen_type ylen)291fe5fe5f6Sflorian bstr_common(uint8_t* x, radstrlen_type xlen, uint8_t* y, radstrlen_type ylen)
292d3fecca9Ssthen {
293d3fecca9Ssthen 	unsigned i, max = ((xlen<ylen)?xlen:ylen);
294d3fecca9Ssthen 	for(i=0; i<max; i++) {
295d3fecca9Ssthen 		if(x[i] != y[i])
296d3fecca9Ssthen 			return i;
297d3fecca9Ssthen 	}
298d3fecca9Ssthen 	return max;
299d3fecca9Ssthen }
300d3fecca9Ssthen 
301d3fecca9Ssthen 
302d3fecca9Ssthen int
bstr_is_prefix_ext(uint8_t * p,radstrlen_type plen,uint8_t * x,radstrlen_type xlen)303fe5fe5f6Sflorian bstr_is_prefix_ext(uint8_t* p, radstrlen_type plen, uint8_t* x,
304fe5fe5f6Sflorian 	radstrlen_type xlen)
305d3fecca9Ssthen {
306d3fecca9Ssthen 	return bstr_is_prefix(p, plen, x, xlen);
307d3fecca9Ssthen }
308d3fecca9Ssthen 
309fe5fe5f6Sflorian radstrlen_type
bstr_common_ext(uint8_t * x,radstrlen_type xlen,uint8_t * y,radstrlen_type ylen)310fe5fe5f6Sflorian bstr_common_ext(uint8_t* x, radstrlen_type xlen, uint8_t* y,
311fe5fe5f6Sflorian 	radstrlen_type ylen)
312d3fecca9Ssthen {
313d3fecca9Ssthen 	return bstr_common(x, xlen, y, ylen);
314d3fecca9Ssthen }
315d3fecca9Ssthen 
316d3fecca9Ssthen /** allocate remainder from prefixes for a split:
317d3fecca9Ssthen  * plen: len prefix, l: longer bstring, llen: length of l. */
318d3fecca9Ssthen static int
radsel_prefix_remainder(struct region * region,radstrlen_type plen,uint8_t * l,radstrlen_type llen,uint8_t ** s,radstrlen_type * slen)319fe5fe5f6Sflorian radsel_prefix_remainder(struct region* region, radstrlen_type plen,
320fe5fe5f6Sflorian 	uint8_t* l, radstrlen_type llen,
321fe5fe5f6Sflorian 	uint8_t** s, radstrlen_type* slen)
322d3fecca9Ssthen {
323d3fecca9Ssthen 	*slen = llen - plen;
324d3fecca9Ssthen 	*s = (uint8_t*)region_alloc(region, (*slen)*sizeof(uint8_t));
325d3fecca9Ssthen 	if(!*s)
326d3fecca9Ssthen 		return 0;
327d3fecca9Ssthen 	memmove(*s, l+plen, llen-plen);
328d3fecca9Ssthen 	return 1;
329d3fecca9Ssthen }
330d3fecca9Ssthen 
331d3fecca9Ssthen /** radsel create a split when two nodes have shared prefix.
332d3fecca9Ssthen  * @param r: radsel that gets changed, it contains a node.
333d3fecca9Ssthen  * @param k: key byte string
334d3fecca9Ssthen  * @param pos: position where the string enters the radsel (e.g. r.str)
335d3fecca9Ssthen  * @param len: length of k.
336d3fecca9Ssthen  * @param add: additional node for the string k.
337d3fecca9Ssthen  * 	removed by called on failure.
338d3fecca9Ssthen  * @return false on alloc failure, no changes made.
339d3fecca9Ssthen  */
340d3fecca9Ssthen static int
radsel_split(struct region * region,struct radsel * r,uint8_t * k,radstrlen_type pos,radstrlen_type len,struct radnode * add)341d3fecca9Ssthen radsel_split(struct region* region, struct radsel* r, uint8_t* k,
342fe5fe5f6Sflorian 	radstrlen_type pos, radstrlen_type len, struct radnode* add)
343d3fecca9Ssthen {
344d3fecca9Ssthen 	uint8_t* addstr = k+pos;
345fe5fe5f6Sflorian 	radstrlen_type addlen = len-pos;
346d3fecca9Ssthen 	if(bstr_is_prefix(addstr, addlen, r->str, r->len)) {
347d3fecca9Ssthen 		uint8_t* split_str=NULL, *dupstr=NULL;
348fe5fe5f6Sflorian 		radstrlen_type split_len=0;
349d3fecca9Ssthen 		/* 'add' is a prefix of r.node */
350d3fecca9Ssthen 		/* also for empty addstr */
351d3fecca9Ssthen 		/* set it up so that the 'add' node has r.node as child */
352d3fecca9Ssthen 		/* so, r.node gets moved below the 'add' node, but we do
353d3fecca9Ssthen 		 * this so that the r.node stays the same pointer for its
354d3fecca9Ssthen 		 * key name */
355d3fecca9Ssthen 		assert(addlen != r->len);
356d3fecca9Ssthen 		assert(addlen < r->len);
357d3fecca9Ssthen 		if(r->len-addlen > 1) {
358d3fecca9Ssthen 			/* shift one because a char is in the lookup array */
359d3fecca9Ssthen 			if(!radsel_prefix_remainder(region, addlen+1, r->str,
360d3fecca9Ssthen 				r->len, &split_str, &split_len))
361d3fecca9Ssthen 				return 0;
362d3fecca9Ssthen 		}
363d3fecca9Ssthen 		if(addlen != 0) {
364d3fecca9Ssthen 			dupstr = (uint8_t*)region_alloc(region,
365d3fecca9Ssthen 				addlen*sizeof(uint8_t));
366d3fecca9Ssthen 			if(!dupstr) {
367d3fecca9Ssthen 				region_recycle(region, split_str, split_len);
368d3fecca9Ssthen 				return 0;
369d3fecca9Ssthen 			}
370d3fecca9Ssthen 			memcpy(dupstr, addstr, addlen);
371d3fecca9Ssthen 		}
372d3fecca9Ssthen 		if(!radnode_array_space(region, add, r->str[addlen])) {
373d3fecca9Ssthen 			region_recycle(region, split_str, split_len);
374d3fecca9Ssthen 			region_recycle(region, dupstr, addlen);
375d3fecca9Ssthen 			return 0;
376d3fecca9Ssthen 		}
377d3fecca9Ssthen 		/* alloc succeeded, now link it in */
378d3fecca9Ssthen 		add->parent = r->node->parent;
379d3fecca9Ssthen 		add->pidx = r->node->pidx;
380d3fecca9Ssthen 		add->array[0].node = r->node;
381d3fecca9Ssthen 		add->array[0].str = split_str;
382d3fecca9Ssthen 		add->array[0].len = split_len;
383d3fecca9Ssthen 		r->node->parent = add;
384d3fecca9Ssthen 		r->node->pidx = 0;
385d3fecca9Ssthen 
386d3fecca9Ssthen 		r->node = add;
387d3fecca9Ssthen 		region_recycle(region, r->str, r->len);
388d3fecca9Ssthen 		r->str = dupstr;
389d3fecca9Ssthen 		r->len = addlen;
390d3fecca9Ssthen 	} else if(bstr_is_prefix(r->str, r->len, addstr, addlen)) {
391d3fecca9Ssthen 		uint8_t* split_str = NULL;
392fe5fe5f6Sflorian 		radstrlen_type split_len = 0;
393d3fecca9Ssthen 		/* r.node is a prefix of 'add' */
394d3fecca9Ssthen 		/* set it up so that the 'r.node' has 'add' as child */
395d3fecca9Ssthen 		/* and basically, r.node is already completely fine,
396d3fecca9Ssthen 		 * we only need to create a node as its child */
397d3fecca9Ssthen 		assert(addlen != r->len);
398d3fecca9Ssthen 		assert(r->len < addlen);
399d3fecca9Ssthen 		if(addlen-r->len > 1) {
400d3fecca9Ssthen 			/* shift one because a character goes into array */
401d3fecca9Ssthen 			if(!radsel_prefix_remainder(region, r->len+1, addstr,
402d3fecca9Ssthen 				addlen, &split_str, &split_len))
403d3fecca9Ssthen 				return 0;
404d3fecca9Ssthen 		}
405d3fecca9Ssthen 		if(!radnode_array_space(region, r->node, addstr[r->len])) {
406d3fecca9Ssthen 			region_recycle(region, split_str, split_len);
407d3fecca9Ssthen 			return 0;
408d3fecca9Ssthen 		}
409d3fecca9Ssthen 		/* alloc succeeded, now link it in */
410d3fecca9Ssthen 		add->parent = r->node;
411d3fecca9Ssthen 		add->pidx = addstr[r->len] - r->node->offset;
412d3fecca9Ssthen 		r->node->array[add->pidx].node = add;
413d3fecca9Ssthen 		r->node->array[add->pidx].str = split_str;
414d3fecca9Ssthen 		r->node->array[add->pidx].len = split_len;
415d3fecca9Ssthen 	} else {
416d3fecca9Ssthen 		/* okay we need to create a new node that chooses between
417d3fecca9Ssthen 		 * the nodes 'add' and r.node
418d3fecca9Ssthen 		 * We do this so that r.node stays the same pointer for its
419d3fecca9Ssthen 		 * key name. */
420d3fecca9Ssthen 		struct radnode* com;
421d3fecca9Ssthen 		uint8_t* common_str=NULL, *s1_str=NULL, *s2_str=NULL;
422fe5fe5f6Sflorian 		radstrlen_type common_len, s1_len=0, s2_len=0;
423d3fecca9Ssthen 		common_len = bstr_common(r->str, r->len, addstr, addlen);
424d3fecca9Ssthen 		assert(common_len < r->len);
425d3fecca9Ssthen 		assert(common_len < addlen);
426d3fecca9Ssthen 
427d3fecca9Ssthen 		/* create the new node for choice */
428d3fecca9Ssthen 		com = (struct radnode*)region_alloc_zero(region, sizeof(*com));
429d3fecca9Ssthen 		if(!com) return 0; /* out of memory */
430d3fecca9Ssthen 
431d3fecca9Ssthen 		/* create the two substrings for subchoices */
432d3fecca9Ssthen 		if(r->len-common_len > 1) {
433d3fecca9Ssthen 			/* shift by one char because it goes in lookup array */
434d3fecca9Ssthen 			if(!radsel_prefix_remainder(region, common_len+1,
435d3fecca9Ssthen 				r->str, r->len, &s1_str, &s1_len)) {
436d3fecca9Ssthen 				region_recycle(region, com, sizeof(*com));
437d3fecca9Ssthen 				return 0;
438d3fecca9Ssthen 			}
439d3fecca9Ssthen 		}
440d3fecca9Ssthen 		if(addlen-common_len > 1) {
441d3fecca9Ssthen 			if(!radsel_prefix_remainder(region, common_len+1,
442d3fecca9Ssthen 				addstr, addlen, &s2_str, &s2_len)) {
443d3fecca9Ssthen 				region_recycle(region, com, sizeof(*com));
444d3fecca9Ssthen 				region_recycle(region, s1_str, s1_len);
445d3fecca9Ssthen 				return 0;
446d3fecca9Ssthen 			}
447d3fecca9Ssthen 		}
448d3fecca9Ssthen 
449d3fecca9Ssthen 		/* create the shared prefix to go in r */
450d3fecca9Ssthen 		if(common_len > 0) {
451d3fecca9Ssthen 			common_str = (uint8_t*)region_alloc(region,
452cbbc2d6cSbrad 				common_len*sizeof(uint8_t));
453d3fecca9Ssthen 			if(!common_str) {
454d3fecca9Ssthen 				region_recycle(region, com, sizeof(*com));
455d3fecca9Ssthen 				region_recycle(region, s1_str, s1_len);
456d3fecca9Ssthen 				region_recycle(region, s2_str, s2_len);
457d3fecca9Ssthen 				return 0;
458d3fecca9Ssthen 			}
459d3fecca9Ssthen 			memcpy(common_str, addstr, common_len);
460d3fecca9Ssthen 		}
461d3fecca9Ssthen 
462d3fecca9Ssthen 		/* make space in the common node array */
463d3fecca9Ssthen 		if(!radnode_array_space(region, com, r->str[common_len]) ||
464d3fecca9Ssthen 			!radnode_array_space(region, com, addstr[common_len])) {
465d3fecca9Ssthen 			region_recycle(region, com->array, com->capacity*sizeof(struct radsel));
466d3fecca9Ssthen 			region_recycle(region, com, sizeof(*com));
467d3fecca9Ssthen 			region_recycle(region, common_str, common_len);
468d3fecca9Ssthen 			region_recycle(region, s1_str, s1_len);
469d3fecca9Ssthen 			region_recycle(region, s2_str, s2_len);
470d3fecca9Ssthen 			return 0;
471d3fecca9Ssthen 		}
472d3fecca9Ssthen 
473d3fecca9Ssthen 		/* allocs succeeded, proceed to link it all up */
474d3fecca9Ssthen 		com->parent = r->node->parent;
475d3fecca9Ssthen 		com->pidx = r->node->pidx;
476d3fecca9Ssthen 		r->node->parent = com;
477d3fecca9Ssthen 		r->node->pidx = r->str[common_len]-com->offset;
478d3fecca9Ssthen 		add->parent = com;
479d3fecca9Ssthen 		add->pidx = addstr[common_len]-com->offset;
480d3fecca9Ssthen 		com->array[r->node->pidx].node = r->node;
481d3fecca9Ssthen 		com->array[r->node->pidx].str = s1_str;
482d3fecca9Ssthen 		com->array[r->node->pidx].len = s1_len;
483d3fecca9Ssthen 		com->array[add->pidx].node = add;
484d3fecca9Ssthen 		com->array[add->pidx].str = s2_str;
485d3fecca9Ssthen 		com->array[add->pidx].len = s2_len;
486d3fecca9Ssthen 		region_recycle(region, r->str, r->len);
487d3fecca9Ssthen 		r->str = common_str;
488d3fecca9Ssthen 		r->len = common_len;
489d3fecca9Ssthen 		r->node = com;
490d3fecca9Ssthen 	}
491d3fecca9Ssthen 	return 1;
492d3fecca9Ssthen }
493d3fecca9Ssthen 
radix_insert(struct radtree * rt,uint8_t * k,radstrlen_type len,void * elem)494fe5fe5f6Sflorian struct radnode* radix_insert(struct radtree* rt, uint8_t* k,
495fe5fe5f6Sflorian 	radstrlen_type len, void* elem)
496d3fecca9Ssthen {
497d3fecca9Ssthen 	struct radnode* n;
498fe5fe5f6Sflorian 	radstrlen_type pos = 0;
499d3fecca9Ssthen 	/* create new element to add */
500d3fecca9Ssthen 	struct radnode* add = (struct radnode*)region_alloc_zero(rt->region,
501d3fecca9Ssthen 		sizeof(*add));
502d3fecca9Ssthen 	if(!add) return NULL; /* out of memory */
503d3fecca9Ssthen 	add->elem = elem;
504d3fecca9Ssthen 
505d3fecca9Ssthen 	/* find out where to add it */
506d3fecca9Ssthen 	if(!radix_find_prefix_node(rt, k, len, &n, &pos)) {
507d3fecca9Ssthen 		/* new root */
508d3fecca9Ssthen 		assert(rt->root == NULL);
509d3fecca9Ssthen 		if(len == 0) {
510d3fecca9Ssthen 			rt->root = add;
511d3fecca9Ssthen 		} else {
512d3fecca9Ssthen 			/* add a root to point to new node */
513d3fecca9Ssthen 			n = (struct radnode*)region_alloc_zero(rt->region,
514d3fecca9Ssthen 				sizeof(*n));
515a1bac035Sflorian 			if(!n) {
516a1bac035Sflorian 				region_recycle(rt->region, add, sizeof(*add));
517a1bac035Sflorian 				return NULL;
518a1bac035Sflorian 			}
519d3fecca9Ssthen 			if(!radnode_array_space(rt->region, n, k[0])) {
520d3fecca9Ssthen 				region_recycle(rt->region, n->array,
521d3fecca9Ssthen 					n->capacity*sizeof(struct radsel));
522d3fecca9Ssthen 				region_recycle(rt->region, n, sizeof(*n));
523d3fecca9Ssthen 				region_recycle(rt->region, add, sizeof(*add));
524d3fecca9Ssthen 				return NULL;
525d3fecca9Ssthen 			}
526d3fecca9Ssthen 			add->parent = n;
527d3fecca9Ssthen 			add->pidx = 0;
528d3fecca9Ssthen 			n->array[0].node = add;
529d3fecca9Ssthen 			if(len > 1) {
530d3fecca9Ssthen 				if(!radsel_prefix_remainder(rt->region, 1, k, len,
531d3fecca9Ssthen 					&n->array[0].str, &n->array[0].len)) {
532d3fecca9Ssthen 					region_recycle(rt->region, n->array,
533d3fecca9Ssthen 						n->capacity*sizeof(struct radsel));
534d3fecca9Ssthen 					region_recycle(rt->region, n, sizeof(*n));
535d3fecca9Ssthen 					region_recycle(rt->region, add, sizeof(*add));
536d3fecca9Ssthen 					return NULL;
537d3fecca9Ssthen 				}
538d3fecca9Ssthen 			}
539d3fecca9Ssthen 			rt->root = n;
540d3fecca9Ssthen 		}
541d3fecca9Ssthen 	} else if(pos == len) {
542d3fecca9Ssthen 		/* found an exact match */
543d3fecca9Ssthen 		if(n->elem) {
544d3fecca9Ssthen 			/* already exists, failure */
545d3fecca9Ssthen 			region_recycle(rt->region, add, sizeof(*add));
546d3fecca9Ssthen 			return NULL;
547d3fecca9Ssthen 		}
548d3fecca9Ssthen 		n->elem = elem;
549d3fecca9Ssthen 		region_recycle(rt->region, add, sizeof(*add));
550d3fecca9Ssthen 		add = n;
551d3fecca9Ssthen 	} else {
552d3fecca9Ssthen 		/* n is a node which can accomodate */
553d3fecca9Ssthen 		uint8_t byte;
554d3fecca9Ssthen 		assert(pos < len);
555d3fecca9Ssthen 		byte = k[pos];
556d3fecca9Ssthen 
557d3fecca9Ssthen 		/* see if it falls outside of array */
558d3fecca9Ssthen 		if(byte < n->offset || byte-n->offset >= n->len) {
559d3fecca9Ssthen 			/* make space in the array for it; adjusts offset */
560d3fecca9Ssthen 			if(!radnode_array_space(rt->region, n, byte)) {
561d3fecca9Ssthen 				region_recycle(rt->region, add, sizeof(*add));
562d3fecca9Ssthen 				return NULL;
563d3fecca9Ssthen 			}
564d3fecca9Ssthen 			assert(byte>=n->offset && byte-n->offset<n->len);
565d3fecca9Ssthen 			byte -= n->offset;
566d3fecca9Ssthen 			/* see if more prefix needs to be split off */
567d3fecca9Ssthen 			if(pos+1 < len) {
568d3fecca9Ssthen 				if(!radsel_str_create(rt->region, &n->array[byte],
569d3fecca9Ssthen 					k, pos+1, len)) {
570d3fecca9Ssthen 					region_recycle(rt->region, add, sizeof(*add));
571d3fecca9Ssthen 					return NULL;
572d3fecca9Ssthen 				}
573d3fecca9Ssthen 			}
574d3fecca9Ssthen 			/* insert the new node in the new bucket */
575d3fecca9Ssthen 			add->parent = n;
576d3fecca9Ssthen 			add->pidx = byte;
577d3fecca9Ssthen 			n->array[byte].node = add;
578d3fecca9Ssthen 		/* so a bucket exists and byte falls in it */
579d3fecca9Ssthen 		} else if(n->array[byte-n->offset].node == NULL) {
580d3fecca9Ssthen 			/* use existing bucket */
581d3fecca9Ssthen 			byte -= n->offset;
582d3fecca9Ssthen 			if(pos+1 < len) {
583d3fecca9Ssthen 				/* split off more prefix */
584d3fecca9Ssthen 				if(!radsel_str_create(rt->region, &n->array[byte],
585d3fecca9Ssthen 					k, pos+1, len)) {
586d3fecca9Ssthen 					region_recycle(rt->region, add, sizeof(*add));
587d3fecca9Ssthen 					return NULL;
588d3fecca9Ssthen 				}
589d3fecca9Ssthen 			}
590d3fecca9Ssthen 			/* insert the new node in the new bucket */
591d3fecca9Ssthen 			add->parent = n;
592d3fecca9Ssthen 			add->pidx = byte;
593d3fecca9Ssthen 			n->array[byte].node = add;
594d3fecca9Ssthen 		} else {
595d3fecca9Ssthen 			/* use bucket but it has a shared prefix,
596d3fecca9Ssthen 			 * split that out and create a new intermediate
597d3fecca9Ssthen 			 * node to split out between the two.
598d3fecca9Ssthen 			 * One of the two might exactmatch the new
599d3fecca9Ssthen 			 * intermediate node */
600d3fecca9Ssthen 			if(!radsel_split(rt->region, &n->array[byte-n->offset],
601d3fecca9Ssthen 				k, pos+1, len, add)) {
602d3fecca9Ssthen 				region_recycle(rt->region, add, sizeof(*add));
603d3fecca9Ssthen 				return NULL;
604d3fecca9Ssthen 			}
605d3fecca9Ssthen 		}
606d3fecca9Ssthen 	}
607d3fecca9Ssthen 
608d3fecca9Ssthen 	rt->count ++;
609d3fecca9Ssthen 	return add;
610d3fecca9Ssthen }
611d3fecca9Ssthen 
612d3fecca9Ssthen /** Delete a radnode */
radnode_delete(struct region * region,struct radnode * n)613d3fecca9Ssthen static void radnode_delete(struct region* region, struct radnode* n)
614d3fecca9Ssthen {
615d3fecca9Ssthen 	unsigned i;
616d3fecca9Ssthen 	if(!n) return;
617d3fecca9Ssthen 	for(i=0; i<n->len; i++) {
618d3fecca9Ssthen 		/* safe to free NULL str */
619d3fecca9Ssthen 		region_recycle(region, n->array[i].str, n->array[i].len);
620d3fecca9Ssthen 	}
621d3fecca9Ssthen 	region_recycle(region, n->array, n->capacity*sizeof(struct radsel));
622d3fecca9Ssthen 	region_recycle(region, n, sizeof(*n));
623d3fecca9Ssthen }
624d3fecca9Ssthen 
625d3fecca9Ssthen /** Cleanup node with one child, it is removed and joined into parent[x] str */
626d3fecca9Ssthen static int
radnode_cleanup_onechild(struct region * region,struct radnode * n,struct radnode * par)627d3fecca9Ssthen radnode_cleanup_onechild(struct region* region, struct radnode* n,
628d3fecca9Ssthen 	struct radnode* par)
629d3fecca9Ssthen {
630d3fecca9Ssthen 	uint8_t* join;
631fe5fe5f6Sflorian 	radstrlen_type joinlen;
632d3fecca9Ssthen 	uint8_t pidx = n->pidx;
633d3fecca9Ssthen 	struct radnode* child = n->array[0].node;
634d3fecca9Ssthen 	/* node had one child, merge them into the parent. */
635d3fecca9Ssthen 	/* keep the child node, so its pointers stay valid. */
636d3fecca9Ssthen 
637d3fecca9Ssthen 	/* at parent, append child->str to array str */
638d3fecca9Ssthen 	assert(pidx < par->len);
639d3fecca9Ssthen 	joinlen = par->array[pidx].len + n->array[0].len + 1;
640d3fecca9Ssthen 	join = (uint8_t*)region_alloc(region, joinlen*sizeof(uint8_t));
641d3fecca9Ssthen 	if(!join) {
642d3fecca9Ssthen 		/* cleanup failed due to out of memory */
643d3fecca9Ssthen 		/* the tree is inefficient, with node n still existing */
644d3fecca9Ssthen 		return 0;
645d3fecca9Ssthen 	}
646d3fecca9Ssthen 	/* we know that .str and join are malloced, thus aligned */
6476a6b9a23Sflorian 	if(par->array[pidx].str)
648d3fecca9Ssthen 	    memcpy(join, par->array[pidx].str, par->array[pidx].len);
649d3fecca9Ssthen 	/* the array lookup is gone, put its character in the lookup string*/
650d3fecca9Ssthen 	join[par->array[pidx].len] = child->pidx + n->offset;
651d3fecca9Ssthen 	/* but join+len may not be aligned */
6526a6b9a23Sflorian 	if(n->array[0].str)
653d3fecca9Ssthen 	    memmove(join+par->array[pidx].len+1, n->array[0].str, n->array[0].len);
654d3fecca9Ssthen 	region_recycle(region, par->array[pidx].str, par->array[pidx].len);
655d3fecca9Ssthen 	par->array[pidx].str = join;
656d3fecca9Ssthen 	par->array[pidx].len = joinlen;
657d3fecca9Ssthen 	/* and set the node to our child. */
658d3fecca9Ssthen 	par->array[pidx].node = child;
659d3fecca9Ssthen 	child->parent = par;
660d3fecca9Ssthen 	child->pidx = pidx;
661d3fecca9Ssthen 	/* we are unlinked, delete our node */
662d3fecca9Ssthen 	radnode_delete(region, n);
663d3fecca9Ssthen 	return 1;
664d3fecca9Ssthen }
665d3fecca9Ssthen 
666d3fecca9Ssthen /** remove array of nodes */
667d3fecca9Ssthen static void
radnode_array_clean_all(struct region * region,struct radnode * n)668d3fecca9Ssthen radnode_array_clean_all(struct region* region, struct radnode* n)
669d3fecca9Ssthen {
670d3fecca9Ssthen 	n->offset = 0;
671d3fecca9Ssthen 	n->len = 0;
672d3fecca9Ssthen 	/* shrink capacity */
673d3fecca9Ssthen 	region_recycle(region, n->array, n->capacity*sizeof(struct radsel));
674d3fecca9Ssthen 	n->array = NULL;
675d3fecca9Ssthen 	n->capacity = 0;
676d3fecca9Ssthen }
677d3fecca9Ssthen 
678d3fecca9Ssthen /** see if capacity can be reduced for the given node array */
679d3fecca9Ssthen static void
radnode_array_reduce_if_needed(struct region * region,struct radnode * n)680d3fecca9Ssthen radnode_array_reduce_if_needed(struct region* region, struct radnode* n)
681d3fecca9Ssthen {
682d3fecca9Ssthen 	if(n->len <= n->capacity/2 && n->len != n->capacity) {
683c939baa4Ssthen 		struct radsel* a = (struct radsel*)region_alloc_array(region,
684c939baa4Ssthen 			sizeof(*a), n->len);
685d3fecca9Ssthen 		if(!a) return;
686d3fecca9Ssthen 		memcpy(a, n->array, sizeof(*a)*n->len);
687d3fecca9Ssthen 		region_recycle(region, n->array, n->capacity*sizeof(*a));
688d3fecca9Ssthen 		n->array = a;
689d3fecca9Ssthen 		n->capacity = n->len;
690d3fecca9Ssthen 	}
691d3fecca9Ssthen }
692d3fecca9Ssthen 
693d3fecca9Ssthen /** remove NULL nodes from front of array */
694d3fecca9Ssthen static void
radnode_array_clean_front(struct region * region,struct radnode * n)695d3fecca9Ssthen radnode_array_clean_front(struct region* region, struct radnode* n)
696d3fecca9Ssthen {
697d3fecca9Ssthen 	/* move them up and adjust offset */
698d3fecca9Ssthen 	unsigned idx, shuf = 0;
699d3fecca9Ssthen 	/* remove until a nonNULL entry */
700d3fecca9Ssthen 	while(shuf < n->len && n->array[shuf].node == NULL)
701d3fecca9Ssthen 		shuf++;
702d3fecca9Ssthen 	if(shuf == 0)
703d3fecca9Ssthen 		return;
704d3fecca9Ssthen 	if(shuf == n->len) {
705d3fecca9Ssthen 		/* the array is empty, the tree is inefficient */
706d3fecca9Ssthen 		radnode_array_clean_all(region, n);
707d3fecca9Ssthen 		return;
708d3fecca9Ssthen 	}
709d3fecca9Ssthen 	assert(shuf < n->len);
710d3fecca9Ssthen 	assert((int)shuf <= 255-(int)n->offset);
711d3fecca9Ssthen 	memmove(&n->array[0], &n->array[shuf],
712d3fecca9Ssthen 		(n->len - shuf)*sizeof(struct radsel));
713d3fecca9Ssthen 	n->offset += shuf;
714d3fecca9Ssthen 	n->len -= shuf;
715d3fecca9Ssthen 	for(idx=0; idx<n->len; idx++)
716d3fecca9Ssthen 		if(n->array[idx].node)
717d3fecca9Ssthen 			n->array[idx].node->pidx = idx;
718d3fecca9Ssthen 	/* see if capacity can be reduced */
719d3fecca9Ssthen 	radnode_array_reduce_if_needed(region, n);
720d3fecca9Ssthen }
721d3fecca9Ssthen 
722d3fecca9Ssthen /** remove NULL nodes from end of array */
723d3fecca9Ssthen static void
radnode_array_clean_end(struct region * region,struct radnode * n)724d3fecca9Ssthen radnode_array_clean_end(struct region* region, struct radnode* n)
725d3fecca9Ssthen {
726d3fecca9Ssthen 	/* shorten it */
727d3fecca9Ssthen 	unsigned shuf = 0;
728d3fecca9Ssthen 	/* remove until a nonNULL entry */
729d3fecca9Ssthen 	while(shuf < n->len && n->array[n->len-1-shuf].node == NULL)
730d3fecca9Ssthen 		shuf++;
731d3fecca9Ssthen 	if(shuf == 0)
732d3fecca9Ssthen 		return;
733d3fecca9Ssthen 	if(shuf == n->len) {
734d3fecca9Ssthen 		/* the array is empty, the tree is inefficient */
735d3fecca9Ssthen 		radnode_array_clean_all(region, n);
736d3fecca9Ssthen 		return;
737d3fecca9Ssthen 	}
738d3fecca9Ssthen 	assert(shuf < n->len);
739d3fecca9Ssthen 	n->len -= shuf;
740d3fecca9Ssthen 	/* array elements can stay where they are */
741d3fecca9Ssthen 	/* see if capacity can be reduced */
742d3fecca9Ssthen 	radnode_array_reduce_if_needed(region, n);
743d3fecca9Ssthen }
744d3fecca9Ssthen 
745d3fecca9Ssthen /** clean up radnode leaf, where we know it has a parent */
746d3fecca9Ssthen static void
radnode_cleanup_leaf(struct region * region,struct radnode * n,struct radnode * par)747d3fecca9Ssthen radnode_cleanup_leaf(struct region* region, struct radnode* n,
748d3fecca9Ssthen 	struct radnode* par)
749d3fecca9Ssthen {
750d3fecca9Ssthen 	uint8_t pidx;
751d3fecca9Ssthen 	/* node was a leaf */
752d3fecca9Ssthen 	/* delete leaf node, but store parent+idx */
753d3fecca9Ssthen 	pidx = n->pidx;
754d3fecca9Ssthen 	radnode_delete(region, n);
755d3fecca9Ssthen 
756d3fecca9Ssthen 	/* set parent+idx entry to NULL str and node.*/
757d3fecca9Ssthen 	assert(pidx < par->len);
758d3fecca9Ssthen 	region_recycle(region, par->array[pidx].str, par->array[pidx].len);
759d3fecca9Ssthen 	par->array[pidx].str = NULL;
760d3fecca9Ssthen 	par->array[pidx].len = 0;
761d3fecca9Ssthen 	par->array[pidx].node = NULL;
762d3fecca9Ssthen 
763d3fecca9Ssthen 	/* see if par offset or len must be adjusted */
764d3fecca9Ssthen 	if(par->len == 1) {
765d3fecca9Ssthen 		/* removed final element from array */
766d3fecca9Ssthen 		radnode_array_clean_all(region, par);
767d3fecca9Ssthen 	} else if(pidx == 0) {
768d3fecca9Ssthen 		/* removed first element from array */
769d3fecca9Ssthen 		radnode_array_clean_front(region, par);
770d3fecca9Ssthen 	} else if(pidx == par->len-1) {
771d3fecca9Ssthen 		/* removed last element from array */
772d3fecca9Ssthen 		radnode_array_clean_end(region, par);
773d3fecca9Ssthen 	}
774d3fecca9Ssthen }
775d3fecca9Ssthen 
776d3fecca9Ssthen /**
777d3fecca9Ssthen  * Cleanup a radix node that was made smaller, see if it can
778d3fecca9Ssthen  * be merged with others.
779d3fecca9Ssthen  * @param rt: tree to remove root if needed.
780d3fecca9Ssthen  * @param n: node to cleanup
781d3fecca9Ssthen  * @return false on alloc failure.
782d3fecca9Ssthen  */
783d3fecca9Ssthen static int
radnode_cleanup(struct radtree * rt,struct radnode * n)784d3fecca9Ssthen radnode_cleanup(struct radtree* rt, struct radnode* n)
785d3fecca9Ssthen {
786d3fecca9Ssthen 	while(n) {
787d3fecca9Ssthen 		if(n->elem) {
788d3fecca9Ssthen 			/* cannot delete node with a data element */
789d3fecca9Ssthen 			return 1;
790d3fecca9Ssthen 		} else if(n->len == 1 && n->parent) {
791d3fecca9Ssthen 			return radnode_cleanup_onechild(rt->region, n, n->parent);
792d3fecca9Ssthen 		} else if(n->len == 0) {
793d3fecca9Ssthen 			struct radnode* par = n->parent;
794d3fecca9Ssthen 			if(!par) {
795d3fecca9Ssthen 				/* root deleted */
796d3fecca9Ssthen 				radnode_delete(rt->region, n);
797d3fecca9Ssthen 				rt->root = NULL;
798d3fecca9Ssthen 				return 1;
799d3fecca9Ssthen 			}
800d3fecca9Ssthen 			/* remove and delete the leaf node */
801d3fecca9Ssthen 			radnode_cleanup_leaf(rt->region, n, par);
802d3fecca9Ssthen 			/* see if parent can now be cleaned up */
803d3fecca9Ssthen 			n = par;
804d3fecca9Ssthen 		} else {
805d3fecca9Ssthen 			/* node cannot be cleaned up */
806d3fecca9Ssthen 			return 1;
807d3fecca9Ssthen 		}
808d3fecca9Ssthen 	}
809d3fecca9Ssthen 	/* ENOTREACH */
810d3fecca9Ssthen 	return 1;
811d3fecca9Ssthen }
812d3fecca9Ssthen 
radix_delete(struct radtree * rt,struct radnode * n)813d3fecca9Ssthen void radix_delete(struct radtree* rt, struct radnode* n)
814d3fecca9Ssthen {
815d3fecca9Ssthen 	if(!n) return;
816d3fecca9Ssthen 	n->elem = NULL;
817d3fecca9Ssthen 	rt->count --;
818d3fecca9Ssthen 	if(!radnode_cleanup(rt, n)) {
819d3fecca9Ssthen 		/* out of memory in cleanup.  the elem ptr is NULL, but
820d3fecca9Ssthen 		 * the radix tree could be inefficient. */
821d3fecca9Ssthen 	}
822d3fecca9Ssthen }
823d3fecca9Ssthen 
radix_search(struct radtree * rt,uint8_t * k,radstrlen_type len)824fe5fe5f6Sflorian struct radnode* radix_search(struct radtree* rt, uint8_t* k,
825fe5fe5f6Sflorian 	radstrlen_type len)
826d3fecca9Ssthen {
827d3fecca9Ssthen 	struct radnode* n = rt->root;
828fe5fe5f6Sflorian 	radstrlen_type pos = 0;
829d3fecca9Ssthen 	uint8_t byte;
830d3fecca9Ssthen 	while(n) {
831d3fecca9Ssthen 		if(pos == len)
832d3fecca9Ssthen 			return n->elem?n:NULL;
833d3fecca9Ssthen 		byte = k[pos];
834d3fecca9Ssthen 		if(byte < n->offset)
835d3fecca9Ssthen 			return NULL;
836d3fecca9Ssthen 		byte -= n->offset;
837d3fecca9Ssthen 		if(byte >= n->len)
838d3fecca9Ssthen 			return NULL;
839d3fecca9Ssthen 		pos++;
840d3fecca9Ssthen 		if(n->array[byte].len != 0) {
841d3fecca9Ssthen 			/* must match additional string */
842d3fecca9Ssthen 			if(pos+n->array[byte].len > len)
843d3fecca9Ssthen 				return NULL; /* no match */
844d3fecca9Ssthen 			if(memcmp(&k[pos], n->array[byte].str,
845d3fecca9Ssthen 				n->array[byte].len) != 0)
846d3fecca9Ssthen 				return NULL; /* no match */
847d3fecca9Ssthen 			pos += n->array[byte].len;
848d3fecca9Ssthen 		}
849d3fecca9Ssthen 		n = n->array[byte].node;
850d3fecca9Ssthen 	}
851d3fecca9Ssthen 	return NULL;
852d3fecca9Ssthen }
853d3fecca9Ssthen 
854d3fecca9Ssthen /** return self or a previous element */
ret_self_or_prev(struct radnode * n,struct radnode ** result)855d3fecca9Ssthen static int ret_self_or_prev(struct radnode* n, struct radnode** result)
856d3fecca9Ssthen {
857d3fecca9Ssthen 	if(n->elem)
858d3fecca9Ssthen 		*result = n;
859d3fecca9Ssthen 	else	*result = radix_prev(n);
860d3fecca9Ssthen 	return 0;
861d3fecca9Ssthen }
862d3fecca9Ssthen 
radix_find_less_equal(struct radtree * rt,uint8_t * k,radstrlen_type len,struct radnode ** result)863fe5fe5f6Sflorian int radix_find_less_equal(struct radtree* rt, uint8_t* k, radstrlen_type len,
864d3fecca9Ssthen         struct radnode** result)
865d3fecca9Ssthen {
866d3fecca9Ssthen 	struct radnode* n = rt->root;
867fe5fe5f6Sflorian 	radstrlen_type pos = 0;
868d3fecca9Ssthen 	uint8_t byte;
869d3fecca9Ssthen 	int r;
870d3fecca9Ssthen 	if(!n) {
871d3fecca9Ssthen 		/* empty tree */
872d3fecca9Ssthen 		*result = NULL;
873d3fecca9Ssthen 		return 0;
874d3fecca9Ssthen 	}
875d3fecca9Ssthen 	while(pos < len) {
876d3fecca9Ssthen 		byte = k[pos];
877d3fecca9Ssthen 		if(byte < n->offset) {
878d3fecca9Ssthen 			/* so the previous is the element itself */
879d3fecca9Ssthen 			/* or something before this element */
880d3fecca9Ssthen 			return ret_self_or_prev(n, result);
881d3fecca9Ssthen 		}
882d3fecca9Ssthen 		byte -= n->offset;
883d3fecca9Ssthen 		if(byte >= n->len) {
884d3fecca9Ssthen 			/* so, the previous is the last of array, or itself */
885d3fecca9Ssthen 			/* or something before this element */
886d3fecca9Ssthen 			if((*result=radnode_last_in_subtree_incl_self(n))==0)
887d3fecca9Ssthen 				*result = radix_prev(n);
888d3fecca9Ssthen 			return 0;
889d3fecca9Ssthen 		}
890d3fecca9Ssthen 		pos++;
891d3fecca9Ssthen 		if(!n->array[byte].node) {
892d3fecca9Ssthen 			/* no match */
893d3fecca9Ssthen 			/* Find an entry in arrays from byte-1 to 0 */
894d3fecca9Ssthen 			*result = radnode_find_prev_from_idx(n, byte);
895d3fecca9Ssthen 			if(*result)
896d3fecca9Ssthen 				return 0;
897d3fecca9Ssthen 			/* this entry or something before it */
898d3fecca9Ssthen 			return ret_self_or_prev(n, result);
899d3fecca9Ssthen 		}
900d3fecca9Ssthen 		if(n->array[byte].len != 0) {
901d3fecca9Ssthen 			/* must match additional string */
902d3fecca9Ssthen 			if(pos+n->array[byte].len > len) {
903d3fecca9Ssthen 				/* the additional string is longer than key*/
904d3fecca9Ssthen 				if( (memcmp(&k[pos], n->array[byte].str,
905d3fecca9Ssthen 					len-pos)) <= 0) {
906d3fecca9Ssthen 				  /* and the key is before this node */
907d3fecca9Ssthen 				  *result = radix_prev(n->array[byte].node);
908d3fecca9Ssthen 				} else {
909d3fecca9Ssthen 					/* the key is after the additional
910d3fecca9Ssthen 					 * string, thus everything in that
911d3fecca9Ssthen 					 * subtree is smaller. */
912d3fecca9Ssthen 				  	*result=radnode_last_in_subtree_incl_self(n->array[byte].node);
913d3fecca9Ssthen 					/* if somehow that is NULL,
914d3fecca9Ssthen 					 * then we have an inefficient tree:
915d3fecca9Ssthen 					 * byte+1 is larger than us, so find
916d3fecca9Ssthen 					 * something in byte-1 and before */
917d3fecca9Ssthen 					if(!*result)
918d3fecca9Ssthen 						*result = radix_prev(n->array[byte].node);
919d3fecca9Ssthen 				}
920d3fecca9Ssthen 				return 0; /* no match */
921d3fecca9Ssthen 			}
922d3fecca9Ssthen 			if( (r=memcmp(&k[pos], n->array[byte].str,
923d3fecca9Ssthen 				n->array[byte].len)) < 0) {
924d3fecca9Ssthen 				*result = radix_prev(n->array[byte].node);
925d3fecca9Ssthen 				return 0; /* no match */
926d3fecca9Ssthen 			} else if(r > 0) {
927d3fecca9Ssthen 				/* the key is larger than the additional
928d3fecca9Ssthen 				 * string, thus everything in that subtree
929d3fecca9Ssthen 				 * is smaller */
930d3fecca9Ssthen 				*result=radnode_last_in_subtree_incl_self(n->array[byte].node);
931d3fecca9Ssthen 				/* if we have an inefficient tree */
932d3fecca9Ssthen 				if(!*result) *result = radix_prev(n->array[byte].node);
933d3fecca9Ssthen 				return 0; /* no match */
934d3fecca9Ssthen 			}
935d3fecca9Ssthen 			pos += n->array[byte].len;
936d3fecca9Ssthen 		}
937d3fecca9Ssthen 		n = n->array[byte].node;
938d3fecca9Ssthen 	}
939d3fecca9Ssthen 	if(n->elem) {
940d3fecca9Ssthen 		/* exact match */
941d3fecca9Ssthen 		*result = n;
942d3fecca9Ssthen 		return 1;
943d3fecca9Ssthen 	}
944d3fecca9Ssthen 	/* there is a node which is an exact match, but it has no element */
945d3fecca9Ssthen 	*result = radix_prev(n);
946d3fecca9Ssthen 	return 0;
947d3fecca9Ssthen }
948d3fecca9Ssthen 
949d3fecca9Ssthen 
radix_first(struct radtree * rt)950d3fecca9Ssthen struct radnode* radix_first(struct radtree* rt)
951d3fecca9Ssthen {
952d3fecca9Ssthen 	struct radnode* n;
953d3fecca9Ssthen 	if(!rt || !rt->root) return NULL;
954d3fecca9Ssthen 	n = rt->root;
955d3fecca9Ssthen 	if(n->elem) return n;
956d3fecca9Ssthen 	return radix_next(n);
957d3fecca9Ssthen }
958d3fecca9Ssthen 
radix_last(struct radtree * rt)959d3fecca9Ssthen struct radnode* radix_last(struct radtree* rt)
960d3fecca9Ssthen {
961d3fecca9Ssthen 	if(!rt || !rt->root) return NULL;
962d3fecca9Ssthen 	return radnode_last_in_subtree_incl_self(rt->root);
963d3fecca9Ssthen }
964d3fecca9Ssthen 
radix_next(struct radnode * n)965d3fecca9Ssthen struct radnode* radix_next(struct radnode* n)
966d3fecca9Ssthen {
967c939baa4Ssthen 	if(!n) return NULL;
968d3fecca9Ssthen 	if(n->len) {
969d3fecca9Ssthen 		/* go down */
970d3fecca9Ssthen 		struct radnode* s = radnode_first_in_subtree(n);
971d3fecca9Ssthen 		if(s) return s;
972d3fecca9Ssthen 	}
973d3fecca9Ssthen 	/* go up - the parent->elem is not useful, because it is before us */
974d3fecca9Ssthen 	while(n->parent) {
975d3fecca9Ssthen 		unsigned idx = n->pidx;
976d3fecca9Ssthen 		n = n->parent;
977d3fecca9Ssthen 		idx++;
978d3fecca9Ssthen 		for(; idx < n->len; idx++) {
979d3fecca9Ssthen 			/* go down the next branch */
980d3fecca9Ssthen 			if(n->array[idx].node) {
981d3fecca9Ssthen 				struct radnode* s;
982d3fecca9Ssthen 				/* node itself */
983d3fecca9Ssthen 				if(n->array[idx].node->elem)
984d3fecca9Ssthen 					return n->array[idx].node;
985d3fecca9Ssthen 				/* or subtree */
986d3fecca9Ssthen 				s = radnode_first_in_subtree(
987d3fecca9Ssthen 					n->array[idx].node);
988d3fecca9Ssthen 				if(s) return s;
989d3fecca9Ssthen 			}
990d3fecca9Ssthen 		}
991d3fecca9Ssthen 	}
992d3fecca9Ssthen 	return NULL;
993d3fecca9Ssthen }
994d3fecca9Ssthen 
radix_prev(struct radnode * n)995d3fecca9Ssthen struct radnode* radix_prev(struct radnode* n)
996d3fecca9Ssthen {
997c939baa4Ssthen 	if(!n) return NULL;
998d3fecca9Ssthen 	/* must go up, since all array nodes are after this node */
999d3fecca9Ssthen 	while(n->parent) {
1000d3fecca9Ssthen 		uint8_t idx = n->pidx;
1001d3fecca9Ssthen 		struct radnode* s;
1002d3fecca9Ssthen 		n = n->parent;
1003d3fecca9Ssthen 		assert(n->len > 0); /* since we are a child */
1004d3fecca9Ssthen 		/* see if there are elements in previous branches there */
1005d3fecca9Ssthen 		s = radnode_find_prev_from_idx(n, idx);
1006d3fecca9Ssthen 		if(s) return s;
1007d3fecca9Ssthen 		/* the current node is before the array */
1008d3fecca9Ssthen 		if(n->elem)
1009d3fecca9Ssthen 			return n;
1010d3fecca9Ssthen 	}
1011d3fecca9Ssthen 	return NULL;
1012d3fecca9Ssthen }
1013d3fecca9Ssthen 
1014d3fecca9Ssthen /** convert one character from domain-name to radname */
char_d2r(uint8_t c)1015d3fecca9Ssthen static uint8_t char_d2r(uint8_t c)
1016d3fecca9Ssthen {
1017d3fecca9Ssthen 	if(c < 'A') return c+1; /* make space for 00 */
1018d3fecca9Ssthen 	else if(c <= 'Z') return c-'A'+'a'; /* lowercase */
1019d3fecca9Ssthen 	else return c;
1020d3fecca9Ssthen }
1021d3fecca9Ssthen 
1022d3fecca9Ssthen /** convert one character from radname to domain-name (still lowercased) */
char_r2d(uint8_t c)1023d3fecca9Ssthen static uint8_t char_r2d(uint8_t c)
1024d3fecca9Ssthen {
1025d3fecca9Ssthen 	assert(c != 0); /* end of label */
1026d3fecca9Ssthen 	if(c <= 'A') return c-1;
1027d3fecca9Ssthen 	else return c;
1028d3fecca9Ssthen }
1029d3fecca9Ssthen 
1030d3fecca9Ssthen /** copy and convert a range of characters */
cpy_d2r(uint8_t * to,const uint8_t * from,int len)1031d3fecca9Ssthen static void cpy_d2r(uint8_t* to, const uint8_t* from, int len)
1032d3fecca9Ssthen {
1033d3fecca9Ssthen 	int i;
1034d3fecca9Ssthen 	for(i=0; i<len; i++)
1035d3fecca9Ssthen 		to[i] = char_d2r(from[i]);
1036d3fecca9Ssthen }
1037d3fecca9Ssthen 
1038d3fecca9Ssthen /** copy and convert a range of characters */
cpy_r2d(uint8_t * to,uint8_t * from,uint8_t len)1039d3fecca9Ssthen static void cpy_r2d(uint8_t* to, uint8_t* from, uint8_t len)
1040d3fecca9Ssthen {
1041d3fecca9Ssthen 	uint8_t i;
1042d3fecca9Ssthen 	for(i=0; i<len; i++)
1043d3fecca9Ssthen 		to[i] = char_r2d(from[i]);
1044d3fecca9Ssthen }
1045d3fecca9Ssthen 
1046d3fecca9Ssthen /* radname code: domain to radix-bstring */
radname_d2r(uint8_t * k,radstrlen_type * len,const uint8_t * dname,size_t dlen)1047fe5fe5f6Sflorian void radname_d2r(uint8_t* k, radstrlen_type* len, const uint8_t* dname,
1048d3fecca9Ssthen 	size_t dlen)
1049d3fecca9Ssthen {
1050d3fecca9Ssthen 	/* the domain name is converted as follows,
1051d3fecca9Ssthen 	 * to preserve the normal (NSEC) ordering of domain names.
1052d3fecca9Ssthen 	 * lowercased, and 'end-of-label' is a '00' byte,
1053d3fecca9Ssthen 	 * bytes 00-'A' are +1 moved to make space for 00 byte.
1054d3fecca9Ssthen 	 * final root label is not appended (string ends).
1055d3fecca9Ssthen 	 * because the only allowed empty label is the final root label,
1056d3fecca9Ssthen 	 * we can also remove the last 00 label-end.
1057d3fecca9Ssthen 	 * The total result length is one-or-two less than the dname.
1058d3fecca9Ssthen 	 *
1059d3fecca9Ssthen 	 * examples (numbers are bytes, letters are ascii):
1060d3fecca9Ssthen 	 * - root: dname: 0, radname: ''
1061d3fecca9Ssthen 	 * - nl.:  dname: 3nl0, radname: 'nl'
1062d3fecca9Ssthen 	 * - labs.nl: dname 4labs3nl0, radname: 'nl0labs'
1063d3fecca9Ssthen 	 * - x.labs.nl: dname 1x4labs3nl0, radname: 'nl0labs0x'
1064d3fecca9Ssthen 	 */
1065d3fecca9Ssthen 
1066d3fecca9Ssthen 	/* conversion by putting the label starts on a stack */
1067d3fecca9Ssthen 	const uint8_t* labstart[130];
1068d3fecca9Ssthen 	unsigned int lab = 0, kpos, dpos = 0;
1069d3fecca9Ssthen 	/* sufficient space */
1070d3fecca9Ssthen 	assert(k && dname);
1071d3fecca9Ssthen 	assert(dlen <= 256); /* and therefore not more than 128 labels */
1072d3fecca9Ssthen 	assert(*len >= dlen);
1073d3fecca9Ssthen 	assert(dlen > 0); /* even root label has dlen=1 */
1074d3fecca9Ssthen 
1075d3fecca9Ssthen 	/* root */
1076d3fecca9Ssthen 	if(dlen == 1) {
1077d3fecca9Ssthen 		assert(dname[0] == 0);
1078d3fecca9Ssthen 		*len = 0;
1079d3fecca9Ssthen 		return;
1080d3fecca9Ssthen 	}
1081d3fecca9Ssthen 
1082d3fecca9Ssthen 	/* walk through domain name and remember label positions */
1083d3fecca9Ssthen 	do {
1084d3fecca9Ssthen 		/* compression pointers not allowed */
1085d3fecca9Ssthen 		if((dname[dpos] & 0xc0)) {
1086d3fecca9Ssthen 			*len = 0;
1087d3fecca9Ssthen 			return; /* format error */
1088d3fecca9Ssthen 		}
1089d3fecca9Ssthen 		labstart[lab++] = &dname[dpos];
1090d3fecca9Ssthen 		if(dpos + dname[dpos] + 1 >= dlen) {
1091d3fecca9Ssthen 			*len = 0;
1092d3fecca9Ssthen 			return; /* format error */
1093d3fecca9Ssthen 		}
1094d3fecca9Ssthen 		/* skip the label contents */
1095d3fecca9Ssthen 		dpos += dname[dpos];
1096d3fecca9Ssthen 		dpos ++;
1097d3fecca9Ssthen 	} while(dname[dpos] != 0);
1098d3fecca9Ssthen 	/* exit condition makes root label not in labelstart stack */
1099d3fecca9Ssthen 	/* because the root was handled before, we know there is some text */
1100d3fecca9Ssthen 	assert(lab > 0);
1101d3fecca9Ssthen 	lab-=1;
1102d3fecca9Ssthen 	kpos = *labstart[lab];
1103d3fecca9Ssthen 	cpy_d2r(k, labstart[lab]+1, kpos);
1104d3fecca9Ssthen 	/* if there are more labels, copy them over */
1105d3fecca9Ssthen 	while(lab) {
1106d3fecca9Ssthen 		/* put 'end-of-label' 00 to end previous label */
1107d3fecca9Ssthen 		k[kpos++]=0;
1108d3fecca9Ssthen 		/* append the label */
1109d3fecca9Ssthen 		lab--;
1110d3fecca9Ssthen 		cpy_d2r(k+kpos, labstart[lab]+1, *labstart[lab]);
1111d3fecca9Ssthen 		kpos += *labstart[lab];
1112d3fecca9Ssthen 	}
1113d3fecca9Ssthen 	/* done */
1114d3fecca9Ssthen 	assert(kpos == dlen-2); /* no rootlabel, one less label-marker */
1115d3fecca9Ssthen 	*len = kpos;
1116d3fecca9Ssthen }
1117d3fecca9Ssthen 
1118d3fecca9Ssthen /* radname code: radix-bstring to domain */
radname_r2d(uint8_t * k,radstrlen_type len,uint8_t * dname,size_t * dlen)1119fe5fe5f6Sflorian void radname_r2d(uint8_t* k, radstrlen_type len, uint8_t* dname, size_t* dlen)
1120d3fecca9Ssthen {
1121d3fecca9Ssthen 	/* find labels and push on stack */
1122d3fecca9Ssthen 	uint8_t* labstart[130];
1123d3fecca9Ssthen 	uint8_t lablen[130];
1124d3fecca9Ssthen 	unsigned int lab = 0, dpos, kpos = 0;
1125d3fecca9Ssthen 	/* sufficient space */
1126d3fecca9Ssthen 	assert(k && dname);
1127d3fecca9Ssthen 	assert((size_t)*dlen >= (size_t)len+2);
1128d3fecca9Ssthen 	assert(len <= 256);
1129d3fecca9Ssthen 	/* root label */
1130d3fecca9Ssthen 	if(len == 0) {
1131d3fecca9Ssthen 		assert(*dlen > 0);
1132d3fecca9Ssthen 		dname[0]=0;
1133d3fecca9Ssthen 		*dlen=1;
1134d3fecca9Ssthen 		return;
1135d3fecca9Ssthen 	}
1136d3fecca9Ssthen 	/* find labels */
1137d3fecca9Ssthen 	while(kpos < len) {
1138d3fecca9Ssthen 		lablen[lab]=0;
1139d3fecca9Ssthen 			labstart[lab]=&k[kpos];
1140d3fecca9Ssthen 		/* skip to next label */
1141d3fecca9Ssthen 		while(kpos < len && k[kpos] != 0) {
1142d3fecca9Ssthen 			lablen[lab]++;
1143d3fecca9Ssthen 			kpos++;
1144d3fecca9Ssthen 		}
1145d3fecca9Ssthen 		lab++;
1146d3fecca9Ssthen 		/* skip 00 byte for label-end */
1147d3fecca9Ssthen 		if(kpos < len) {
1148d3fecca9Ssthen 			assert(k[kpos] == 0);
1149d3fecca9Ssthen 			kpos++;
1150d3fecca9Ssthen 		}
1151d3fecca9Ssthen 	}
1152d3fecca9Ssthen 	/* copy the labels over to the domain name */
1153d3fecca9Ssthen 	dpos = 0;
1154d3fecca9Ssthen 	while(lab) {
1155d3fecca9Ssthen 		lab--;
1156d3fecca9Ssthen 		/* label length */
1157d3fecca9Ssthen 		dname[dpos++] = lablen[lab];
1158d3fecca9Ssthen 		/* label content */
1159d3fecca9Ssthen 		cpy_r2d(dname+dpos, labstart[lab], lablen[lab]);
1160d3fecca9Ssthen 		dpos += lablen[lab];
1161d3fecca9Ssthen 	}
1162d3fecca9Ssthen 	/* append root label */
1163d3fecca9Ssthen 	dname[dpos++] = 0;
1164d3fecca9Ssthen 	/* assert the domain name is wellformed */
1165d3fecca9Ssthen 	assert((int)dpos == (int)len+2);
1166d3fecca9Ssthen 	assert(dname[dpos-1] == 0); /* ends with root label */
1167d3fecca9Ssthen 	*dlen = dpos;
1168d3fecca9Ssthen }
1169d3fecca9Ssthen 
1170d3fecca9Ssthen /** insert by domain name */
1171d3fecca9Ssthen struct radnode*
radname_insert(struct radtree * rt,const uint8_t * d,size_t max,void * elem)1172d3fecca9Ssthen radname_insert(struct radtree* rt, const uint8_t* d, size_t max, void* elem)
1173d3fecca9Ssthen {
1174d3fecca9Ssthen 	/* convert and insert */
1175d3fecca9Ssthen 	uint8_t radname[300];
1176fe5fe5f6Sflorian 	radstrlen_type len = (radstrlen_type)sizeof(radname);
1177d3fecca9Ssthen 	if(max > sizeof(radname))
1178d3fecca9Ssthen 		return NULL; /* too long */
1179d3fecca9Ssthen 	radname_d2r(radname, &len, d, max);
1180d3fecca9Ssthen 	return radix_insert(rt, radname, len, elem);
1181d3fecca9Ssthen }
1182d3fecca9Ssthen 
1183d3fecca9Ssthen /** delete by domain name */
1184d3fecca9Ssthen void
radname_delete(struct radtree * rt,const uint8_t * d,size_t max)1185d3fecca9Ssthen radname_delete(struct radtree* rt, const uint8_t* d, size_t max)
1186d3fecca9Ssthen {
1187d3fecca9Ssthen 	/* search and remove */
1188d3fecca9Ssthen 	struct radnode* n = radname_search(rt, d, max);
1189d3fecca9Ssthen 	if(n) radix_delete(rt, n);
1190d3fecca9Ssthen }
1191d3fecca9Ssthen 
1192d3fecca9Ssthen /* search for exact match of domain name, converted to radname in tree */
radname_search(struct radtree * rt,const uint8_t * d,size_t max)1193d3fecca9Ssthen struct radnode* radname_search(struct radtree* rt, const uint8_t* d,
1194d3fecca9Ssthen 	size_t max)
1195d3fecca9Ssthen {
1196d3fecca9Ssthen 	/* stack of labels in the domain name */
1197d3fecca9Ssthen 	const uint8_t* labstart[130];
1198d3fecca9Ssthen 	unsigned int lab, dpos, lpos;
1199d3fecca9Ssthen 	struct radnode* n = rt->root;
1200d3fecca9Ssthen 	uint8_t byte;
1201fe5fe5f6Sflorian 	radstrlen_type i;
1202d3fecca9Ssthen 	uint8_t b;
1203d3fecca9Ssthen 
1204d3fecca9Ssthen 	/* search for root? it is '' */
1205d3fecca9Ssthen 	if(max < 1)
1206d3fecca9Ssthen 		return NULL;
1207d3fecca9Ssthen 	if(d[0] == 0) {
1208d3fecca9Ssthen 		if(!n) return NULL;
1209d3fecca9Ssthen 		return n->elem?n:NULL;
1210d3fecca9Ssthen 	}
1211d3fecca9Ssthen 
1212d3fecca9Ssthen 	/* find labels stack in domain name */
1213d3fecca9Ssthen 	lab = 0;
1214d3fecca9Ssthen 	dpos = 0;
1215d3fecca9Ssthen 	/* must have one label, since root is specialcased */
1216d3fecca9Ssthen 	do {
1217d3fecca9Ssthen 		if((d[dpos] & 0xc0))
1218d3fecca9Ssthen 			return NULL; /* compression ptrs not allowed error */
1219d3fecca9Ssthen 		labstart[lab++] = &d[dpos];
1220d3fecca9Ssthen 		if(dpos + d[dpos] + 1 >= max)
1221d3fecca9Ssthen 			return NULL; /* format error: outside of bounds */
1222d3fecca9Ssthen 		/* skip the label contents */
1223d3fecca9Ssthen 		dpos += d[dpos];
1224d3fecca9Ssthen 		dpos ++;
1225d3fecca9Ssthen 	} while(d[dpos] != 0);
1226d3fecca9Ssthen 	/* exit condition makes that root label is not in the labstarts */
1227d3fecca9Ssthen 	/* now: dpos+1 is length of domain name. lab is number of labels-1 */
1228d3fecca9Ssthen 
1229d3fecca9Ssthen 	/* start processing at the last label */
1230d3fecca9Ssthen 	lab-=1;
1231d3fecca9Ssthen 	lpos = 0;
1232d3fecca9Ssthen 	while(n) {
1233d3fecca9Ssthen 		/* fetch next byte this label */
1234d3fecca9Ssthen 		if(lpos < *labstart[lab])
1235d3fecca9Ssthen 			/* lpos+1 to skip labelstart, lpos++ to move forward */
1236d3fecca9Ssthen 			byte = char_d2r(labstart[lab][++lpos]);
1237d3fecca9Ssthen 		else {
1238d3fecca9Ssthen 			if(lab == 0) /* last label - we're done */
1239d3fecca9Ssthen 				return n->elem?n:NULL;
1240d3fecca9Ssthen 			/* next label, search for byte 00 */
1241d3fecca9Ssthen 			lpos = 0;
1242d3fecca9Ssthen 			lab--;
1243d3fecca9Ssthen 			byte = 0;
1244d3fecca9Ssthen 		}
1245d3fecca9Ssthen 		/* find that byte in the array */
1246d3fecca9Ssthen 		if(byte < n->offset)
1247d3fecca9Ssthen 			return NULL;
1248d3fecca9Ssthen 		byte -= n->offset;
1249d3fecca9Ssthen 		if(byte >= n->len)
1250d3fecca9Ssthen 			return NULL;
1251d3fecca9Ssthen 		if(n->array[byte].len != 0) {
1252d3fecca9Ssthen 			/* must match additional string */
1253d3fecca9Ssthen 			/* see how many bytes we need and start matching them*/
1254d3fecca9Ssthen 			for(i=0; i<n->array[byte].len; i++) {
1255d3fecca9Ssthen 				/* next byte to match */
1256d3fecca9Ssthen 				if(lpos < *labstart[lab])
1257d3fecca9Ssthen 					b = char_d2r(labstart[lab][++lpos]);
1258d3fecca9Ssthen 				else {
1259d3fecca9Ssthen 					/* if last label, no match since
1260d3fecca9Ssthen 					 * we are in the additional string */
1261d3fecca9Ssthen 					if(lab == 0)
1262d3fecca9Ssthen 						return NULL;
1263d3fecca9Ssthen 					/* next label, search for byte 00 */
1264d3fecca9Ssthen 					lpos = 0;
1265d3fecca9Ssthen 					lab--;
1266d3fecca9Ssthen 					b = 0;
1267d3fecca9Ssthen 				}
1268d3fecca9Ssthen 				if(n->array[byte].str[i] != b)
1269d3fecca9Ssthen 					return NULL; /* not matched */
1270d3fecca9Ssthen 			}
1271d3fecca9Ssthen 		}
1272d3fecca9Ssthen 		n = n->array[byte].node;
1273d3fecca9Ssthen 	}
1274d3fecca9Ssthen 	return NULL;
1275d3fecca9Ssthen }
1276d3fecca9Ssthen 
1277d3fecca9Ssthen /* find domain name or smaller or equal domain name in radix tree */
radname_find_less_equal(struct radtree * rt,const uint8_t * d,size_t max,struct radnode ** result)1278d3fecca9Ssthen int radname_find_less_equal(struct radtree* rt, const uint8_t* d, size_t max,
1279d3fecca9Ssthen         struct radnode** result)
1280d3fecca9Ssthen {
1281d3fecca9Ssthen 	/* stack of labels in the domain name */
1282d3fecca9Ssthen 	const uint8_t* labstart[130];
1283d3fecca9Ssthen 	unsigned int lab, dpos, lpos;
1284d3fecca9Ssthen 	struct radnode* n = rt->root;
1285d3fecca9Ssthen 	uint8_t byte;
1286fe5fe5f6Sflorian 	radstrlen_type i;
1287d3fecca9Ssthen 	uint8_t b;
1288d3fecca9Ssthen 
1289d3fecca9Ssthen 	/* empty tree */
1290d3fecca9Ssthen 	if(!n) {
1291d3fecca9Ssthen 		*result = NULL;
1292d3fecca9Ssthen 		return 0;
1293d3fecca9Ssthen 	}
1294d3fecca9Ssthen 
1295d3fecca9Ssthen 	/* search for root? it is '' */
1296d3fecca9Ssthen 	if(max < 1) {
1297d3fecca9Ssthen 		*result = NULL;
1298d3fecca9Ssthen 		return 0; /* parse error, out of bounds */
1299d3fecca9Ssthen 	}
1300d3fecca9Ssthen 	if(d[0] == 0) {
1301d3fecca9Ssthen 		if(n->elem) {
1302d3fecca9Ssthen 			*result = n;
1303d3fecca9Ssthen 			return 1;
1304d3fecca9Ssthen 		}
1305d3fecca9Ssthen 		/* no smaller element than the root */
1306d3fecca9Ssthen 		*result = NULL;
1307d3fecca9Ssthen 		return 0;
1308d3fecca9Ssthen 	}
1309d3fecca9Ssthen 
1310d3fecca9Ssthen 	/* find labels stack in domain name */
1311d3fecca9Ssthen 	lab = 0;
1312d3fecca9Ssthen 	dpos = 0;
1313d3fecca9Ssthen 	/* must have one label, since root is specialcased */
1314d3fecca9Ssthen 	do {
1315d3fecca9Ssthen 		if((d[dpos] & 0xc0)) {
1316d3fecca9Ssthen 			*result = NULL;
1317d3fecca9Ssthen 			return 0; /* compression ptrs not allowed error */
1318d3fecca9Ssthen 		}
1319d3fecca9Ssthen 		labstart[lab++] = &d[dpos];
1320d3fecca9Ssthen 		if(dpos + d[dpos] + 1 >= max) {
1321d3fecca9Ssthen 			*result = NULL; /* format error: outside of bounds */
1322d3fecca9Ssthen 			return 0;
1323d3fecca9Ssthen 		}
1324d3fecca9Ssthen 		/* skip the label contents */
1325d3fecca9Ssthen 		dpos += d[dpos];
1326d3fecca9Ssthen 		dpos ++;
1327d3fecca9Ssthen 	} while(d[dpos] != 0);
1328d3fecca9Ssthen 	/* exit condition makes that root label is not in the labstarts */
1329d3fecca9Ssthen 	/* now: dpos+1 is length of domain name. lab is number of labels-1 */
1330d3fecca9Ssthen 
1331d3fecca9Ssthen 	/* start processing at the last label */
1332d3fecca9Ssthen 	lab-=1;
1333d3fecca9Ssthen 	lpos = 0;
1334d3fecca9Ssthen 	while(1) {
1335d3fecca9Ssthen 		/* fetch next byte this label */
1336d3fecca9Ssthen 		if(lpos < *labstart[lab])
1337d3fecca9Ssthen 			/* lpos+1 to skip labelstart, lpos++ to move forward */
1338d3fecca9Ssthen 			byte = char_d2r(labstart[lab][++lpos]);
1339d3fecca9Ssthen 		else {
1340d3fecca9Ssthen 			if(lab == 0) {
1341d3fecca9Ssthen 				/* last label - we're done */
1342d3fecca9Ssthen 				/* exact match */
1343d3fecca9Ssthen 				if(n->elem) {
1344d3fecca9Ssthen 					*result = n;
1345d3fecca9Ssthen 					return 1;
1346d3fecca9Ssthen 				}
1347d3fecca9Ssthen 				/* there is a node which is an exact match,
1348d3fecca9Ssthen 				 * but there no element in it */
1349d3fecca9Ssthen 				*result = radix_prev(n);
1350d3fecca9Ssthen 				return 0;
1351d3fecca9Ssthen 			}
1352d3fecca9Ssthen 			/* next label, search for byte 0 the label separator */
1353d3fecca9Ssthen 			lpos = 0;
1354d3fecca9Ssthen 			lab--;
1355d3fecca9Ssthen 			byte = 0;
1356d3fecca9Ssthen 		}
1357d3fecca9Ssthen 		/* find that byte in the array */
1358d3fecca9Ssthen 		if(byte < n->offset)
1359d3fecca9Ssthen 			/* so the previous is the element itself */
1360d3fecca9Ssthen 			/* or something before this element */
1361d3fecca9Ssthen 			return ret_self_or_prev(n, result);
1362d3fecca9Ssthen 		byte -= n->offset;
1363d3fecca9Ssthen 		if(byte >= n->len) {
1364d3fecca9Ssthen 			/* so, the previous is the last of array, or itself */
1365d3fecca9Ssthen 			/* or something before this element */
1366d3fecca9Ssthen 			*result = radnode_last_in_subtree_incl_self(n);
1367d3fecca9Ssthen 			if(!*result)
1368d3fecca9Ssthen 				*result = radix_prev(n);
1369d3fecca9Ssthen 			return 0;
1370d3fecca9Ssthen 		}
1371d3fecca9Ssthen 		if(!n->array[byte].node) {
1372d3fecca9Ssthen 			/* no match */
1373d3fecca9Ssthen 			/* Find an entry in arrays from byte-1 to 0 */
1374d3fecca9Ssthen 			*result = radnode_find_prev_from_idx(n, byte);
1375d3fecca9Ssthen 			if(*result)
1376d3fecca9Ssthen 				return 0;
1377d3fecca9Ssthen 			/* this entry or something before it */
1378d3fecca9Ssthen 			return ret_self_or_prev(n, result);
1379d3fecca9Ssthen 		}
1380d3fecca9Ssthen 		if(n->array[byte].len != 0) {
1381d3fecca9Ssthen 			/* must match additional string */
1382d3fecca9Ssthen 			/* see how many bytes we need and start matching them*/
1383d3fecca9Ssthen 			for(i=0; i<n->array[byte].len; i++) {
1384d3fecca9Ssthen 				/* next byte to match */
1385d3fecca9Ssthen 				if(lpos < *labstart[lab])
1386d3fecca9Ssthen 					b = char_d2r(labstart[lab][++lpos]);
1387d3fecca9Ssthen 				else {
1388d3fecca9Ssthen 					/* if last label, no match since
1389d3fecca9Ssthen 					 * we are in the additional string */
1390d3fecca9Ssthen 					if(lab == 0) {
1391d3fecca9Ssthen 						/* dname ended, thus before
1392d3fecca9Ssthen 						 * this array element */
1393d3fecca9Ssthen 						*result =radix_prev(
1394d3fecca9Ssthen 							n->array[byte].node);
1395d3fecca9Ssthen 						return 0;
1396d3fecca9Ssthen 					}
1397d3fecca9Ssthen 					/* next label, search for byte 00 */
1398d3fecca9Ssthen 					lpos = 0;
1399d3fecca9Ssthen 					lab--;
1400d3fecca9Ssthen 					b = 0;
1401d3fecca9Ssthen 				}
1402d3fecca9Ssthen 				if(b < n->array[byte].str[i]) {
1403d3fecca9Ssthen 					*result =radix_prev(
1404d3fecca9Ssthen 						n->array[byte].node);
1405d3fecca9Ssthen 					return 0;
1406d3fecca9Ssthen 				} else if(b > n->array[byte].str[i]) {
1407d3fecca9Ssthen 					/* the key is after the additional,
1408d3fecca9Ssthen 					 * so everything in its subtree is
1409d3fecca9Ssthen 					 * smaller */
1410d3fecca9Ssthen 					*result = radnode_last_in_subtree_incl_self(n->array[byte].node);
1411d3fecca9Ssthen 					/* if that is NULL, we have an
1412d3fecca9Ssthen 					 * inefficient tree, find in byte-1*/
1413d3fecca9Ssthen 					if(!*result)
1414d3fecca9Ssthen 						*result = radix_prev(n->array[byte].node);
1415d3fecca9Ssthen 					return 0;
1416d3fecca9Ssthen 				}
1417d3fecca9Ssthen 			}
1418d3fecca9Ssthen 		}
1419d3fecca9Ssthen 		n = n->array[byte].node;
1420d3fecca9Ssthen 	}
1421d3fecca9Ssthen 	/* ENOTREACH */
1422d3fecca9Ssthen 	return 0;
1423d3fecca9Ssthen }
1424d3fecca9Ssthen 
1425