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