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