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