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