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