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