1 /* $NetBSD: rbt.c,v 1.5 2019/11/27 05:48:41 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14 /*! \file */ 15 16 #include <config.h> 17 18 #include <inttypes.h> 19 #include <stdbool.h> 20 #include <sys/stat.h> 21 22 #include <isc/crc64.h> 23 #include <isc/file.h> 24 #include <isc/hex.h> 25 #include <isc/mem.h> 26 #include <isc/once.h> 27 #include <isc/platform.h> 28 #include <isc/print.h> 29 #include <isc/refcount.h> 30 #include <isc/socket.h> 31 #include <isc/stdio.h> 32 #include <isc/string.h> 33 #include <isc/util.h> 34 35 /*% 36 * This define is so dns/name.h (included by dns/fixedname.h) uses more 37 * efficient macro calls instead of functions for a few operations. 38 */ 39 #define DNS_NAME_USEINLINE 1 40 41 #include <dns/fixedname.h> 42 #include <dns/log.h> 43 #include <dns/rbt.h> 44 #include <dns/result.h> 45 #include <dns/version.h> 46 47 #include <unistd.h> 48 49 #define CHECK(x) \ 50 do { \ 51 result = (x); \ 52 if (result != ISC_R_SUCCESS) \ 53 goto cleanup; \ 54 } while (/*CONSTCOND*/0) 55 56 #define RBT_MAGIC ISC_MAGIC('R', 'B', 'T', '+') 57 #define VALID_RBT(rbt) ISC_MAGIC_VALID(rbt, RBT_MAGIC) 58 59 /* 60 * XXXDCL Since parent pointers were added in again, I could remove all of the 61 * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode, 62 * _lastnode. This would involve pretty major change to the API. 63 */ 64 #define CHAIN_MAGIC ISC_MAGIC('0', '-', '0', '-') 65 #define VALID_CHAIN(chain) ISC_MAGIC_VALID(chain, CHAIN_MAGIC) 66 67 #define RBT_HASH_SIZE 64 68 69 #ifdef RBT_MEM_TEST 70 #undef RBT_HASH_SIZE 71 #define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */ 72 #endif 73 74 struct dns_rbt { 75 unsigned int magic; 76 isc_mem_t * mctx; 77 dns_rbtnode_t * root; 78 void (*data_deleter)(void *, void *); 79 void * deleter_arg; 80 unsigned int nodecount; 81 size_t hashsize; 82 dns_rbtnode_t ** hashtable; 83 void * mmap_location; 84 }; 85 86 #define RED 0 87 #define BLACK 1 88 89 /* 90 * This is the header for map-format RBT images. It is populated, 91 * and then written, as the LAST thing done to the file before returning. 92 * Writing this last (with zeros in the header area initially) will ensure 93 * that the header is only valid when the RBT image is also valid. 94 */ 95 typedef struct file_header file_header_t; 96 97 /* Pad to 32 bytes */ 98 static char FILE_VERSION[32] = "\0"; 99 100 /* Header length, always the same size regardless of structure size */ 101 #define HEADER_LENGTH 1024 102 103 struct file_header { 104 char version1[32]; 105 uint64_t first_node_offset; /* usually 1024 */ 106 /* 107 * information about the system on which the map file was generated 108 * will be used to tell if we can load the map file or not 109 */ 110 uint32_t ptrsize; 111 unsigned int bigendian:1; /* big or little endian system */ 112 unsigned int rdataset_fixed:1; /* compiled with --enable-rrset-fixed */ 113 unsigned int nodecount; /* shadow from rbt structure */ 114 uint64_t crc; 115 char version2[32]; /* repeated; must match version1 */ 116 }; 117 118 /* 119 * The following declarations are for the serialization of an RBT: 120 * 121 * step one: write out a zeroed header of 1024 bytes 122 * step two: walk the tree in a depth-first, left-right-down order, writing 123 * out the nodes, reserving space as we go, correcting addresses to point 124 * at the proper offset in the file, and setting a flag for each pointer to 125 * indicate that it is a reference to a location in the file, rather than in 126 * memory. 127 * step three: write out the header, adding the information that will be 128 * needed to re-create the tree object itself. 129 * 130 * The RBTDB object will do this three times, once for each of the three 131 * RBT objects it contains. 132 * 133 * Note: 'file' must point an actual open file that can be mmapped 134 * and fseeked, not to a pipe or stream 135 */ 136 137 static isc_result_t 138 dns_rbt_zero_header(FILE *file); 139 140 static isc_result_t 141 write_header(FILE *file, dns_rbt_t *rbt, uint64_t first_node_offset, 142 uint64_t crc); 143 144 static bool 145 match_header_version(file_header_t *header); 146 147 static isc_result_t 148 serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left, 149 uintptr_t right, uintptr_t down, uintptr_t parent, 150 uintptr_t data, uint64_t *crc); 151 152 static isc_result_t 153 serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent, 154 dns_rbtdatawriter_t datawriter, void *writer_arg, 155 uintptr_t *where, uint64_t *crc); 156 157 /* 158 * The following functions allow you to get the actual address of a pointer 159 * without having to use an if statement to check to see if that address is 160 * relative or not 161 */ 162 static inline dns_rbtnode_t * 163 getparent(dns_rbtnode_t *node, file_header_t *header) { 164 char *adjusted_address = (char *)(node->parent); 165 adjusted_address += node->parent_is_relative * (uintptr_t)header; 166 167 return ((dns_rbtnode_t *)adjusted_address); 168 } 169 170 static inline dns_rbtnode_t * 171 getleft(dns_rbtnode_t *node, file_header_t *header) { 172 char *adjusted_address = (char *)(node->left); 173 adjusted_address += node->left_is_relative * (uintptr_t)header; 174 175 return ((dns_rbtnode_t *)adjusted_address); 176 } 177 178 static inline dns_rbtnode_t * 179 getright(dns_rbtnode_t *node, file_header_t *header) { 180 char *adjusted_address = (char *)(node->right); 181 adjusted_address += node->right_is_relative * (uintptr_t)header; 182 183 return ((dns_rbtnode_t *)adjusted_address); 184 } 185 186 static inline dns_rbtnode_t * 187 getdown(dns_rbtnode_t *node, file_header_t *header) { 188 char *adjusted_address = (char *)(node->down); 189 adjusted_address += node->down_is_relative * (uintptr_t)header; 190 191 return ((dns_rbtnode_t *)adjusted_address); 192 } 193 194 static inline dns_rbtnode_t * 195 getdata(dns_rbtnode_t *node, file_header_t *header) { 196 char *adjusted_address = (char *)(node->data); 197 adjusted_address += node->data_is_relative * (uintptr_t)header; 198 199 return ((dns_rbtnode_t *)adjusted_address); 200 } 201 202 /*% 203 * Elements of the rbtnode structure. 204 */ 205 #define PARENT(node) ((node)->parent) 206 #define LEFT(node) ((node)->left) 207 #define RIGHT(node) ((node)->right) 208 #define DOWN(node) ((node)->down) 209 #define UPPERNODE(node) ((node)->uppernode) 210 #define DATA(node) ((node)->data) 211 #define IS_EMPTY(node) ((node)->data == NULL) 212 #define HASHNEXT(node) ((node)->hashnext) 213 #define HASHVAL(node) ((node)->hashval) 214 #define COLOR(node) ((node)->color) 215 #define NAMELEN(node) ((node)->namelen) 216 #define OLDNAMELEN(node) ((node)->oldnamelen) 217 #define OFFSETLEN(node) ((node)->offsetlen) 218 #define ATTRS(node) ((node)->attributes) 219 #define IS_ROOT(node) ((node)->is_root) 220 #define FINDCALLBACK(node) ((node)->find_callback) 221 222 /*% 223 * Structure elements from the rbtdb.c, not 224 * used as part of the rbt.c algorithms. 225 */ 226 #define DIRTY(node) ((node)->dirty) 227 #define WILD(node) ((node)->wild) 228 #define LOCKNUM(node) ((node)->locknum) 229 230 /*% 231 * The variable length stuff stored after the node has the following 232 * structure. 233 * 234 * <name_data>{1..255}<oldoffsetlen>{1}<offsets>{1..128} 235 * 236 * <name_data> contains the name of the node when it was created. 237 * <oldoffsetlen> contains the length of <offsets> when the node 238 * was created. 239 * <offsets> contains the offets into name for each label when the node 240 * was created. 241 */ 242 243 #define NAME(node) ((unsigned char *)((node) + 1)) 244 #define OFFSETS(node) (NAME(node) + OLDNAMELEN(node) + 1) 245 #define OLDOFFSETLEN(node) (OFFSETS(node)[-1]) 246 247 #define NODE_SIZE(node) (sizeof(*node) + \ 248 OLDNAMELEN(node) + OLDOFFSETLEN(node) + 1) 249 250 /*% 251 * Color management. 252 */ 253 #define IS_RED(node) ((node) != NULL && (node)->color == RED) 254 #define IS_BLACK(node) ((node) == NULL || (node)->color == BLACK) 255 #define MAKE_RED(node) ((node)->color = RED) 256 #define MAKE_BLACK(node) ((node)->color = BLACK) 257 258 /*% 259 * Chain management. 260 * 261 * The "ancestors" member of chains were removed, with their job now 262 * being wholly handled by parent pointers (which didn't exist, because 263 * of memory concerns, when chains were first implemented). 264 */ 265 #define ADD_LEVEL(chain, node) \ 266 do { \ 267 INSIST((chain)->level_count < DNS_RBT_LEVELBLOCK); \ 268 (chain)->levels[(chain)->level_count++] = (node); \ 269 } while (0) 270 271 /*% 272 * The following macros directly access normally private name variables. 273 * These macros are used to avoid a lot of function calls in the critical 274 * path of the tree traversal code. 275 */ 276 277 static inline void 278 NODENAME(dns_rbtnode_t *node, dns_name_t *name) { 279 name->length = NAMELEN(node); 280 name->labels = OFFSETLEN(node); 281 name->ndata = NAME(node); 282 name->offsets = OFFSETS(node); 283 name->attributes = ATTRS(node); 284 name->attributes |= DNS_NAMEATTR_READONLY; 285 } 286 287 void 288 dns_rbtnode_nodename(dns_rbtnode_t *node, dns_name_t *name) { 289 name->length = NAMELEN(node); 290 name->labels = OFFSETLEN(node); 291 name->ndata = NAME(node); 292 name->offsets = OFFSETS(node); 293 name->attributes = ATTRS(node); 294 name->attributes |= DNS_NAMEATTR_READONLY; 295 } 296 297 dns_rbtnode_t * 298 dns_rbt_root(dns_rbt_t *rbt) { 299 return (rbt->root); 300 } 301 302 #ifdef DEBUG 303 #define inline 304 /* 305 * A little something to help out in GDB. 306 */ 307 dns_name_t Name(dns_rbtnode_t *node); 308 dns_name_t 309 Name(dns_rbtnode_t *node) { 310 dns_name_t name; 311 312 dns_name_init(&name, NULL); 313 if (node != NULL) 314 NODENAME(node, &name); 315 316 return (name); 317 } 318 319 static void 320 hexdump(const char *desc, void *blob, size_t size) { 321 char hexdump[BUFSIZ * 2 + 1]; 322 isc_buffer_t b; 323 isc_region_t r; 324 isc_result_t result; 325 size_t bytes; 326 uint8_t *data = blob; 327 328 fprintf(stderr, "%s: ", desc); 329 do { 330 isc_buffer_init(&b, hexdump, sizeof(hexdump)); 331 r.base = data; 332 r.length = bytes = (size > BUFSIZ) ? BUFSIZ : size; 333 result = isc_hex_totext(&r, 0, "", &b); 334 RUNTIME_CHECK(result == ISC_R_SUCCESS); 335 isc_buffer_putuint8(&b, 0); 336 fprintf(stderr, "%s", hexdump); 337 data += bytes; 338 size -= bytes; 339 } while (size > 0); 340 fprintf(stderr, "\n"); 341 } 342 #endif /* DEBUG */ 343 344 /* 345 * Upper node is the parent of the root of the passed node's 346 * subtree. The passed node must not be NULL. 347 */ 348 static inline dns_rbtnode_t * 349 get_upper_node(dns_rbtnode_t *node) { 350 return (UPPERNODE(node)); 351 } 352 353 static void 354 fixup_uppernodes_helper(dns_rbtnode_t *node, dns_rbtnode_t *uppernode) { 355 if (node == NULL) 356 return; 357 358 UPPERNODE(node) = uppernode; 359 360 fixup_uppernodes_helper(LEFT(node), uppernode); 361 fixup_uppernodes_helper(RIGHT(node), uppernode); 362 fixup_uppernodes_helper(DOWN(node), node); 363 } 364 365 /* 366 * This function is used to fixup uppernode members of all dns_rbtnodes 367 * after deserialization. 368 */ 369 static void 370 fixup_uppernodes(dns_rbt_t *rbt) { 371 fixup_uppernodes_helper(rbt->root, NULL); 372 } 373 374 size_t 375 dns__rbtnode_getdistance(dns_rbtnode_t *node) { 376 size_t nodes = 1; 377 378 while (node != NULL) { 379 if (IS_ROOT(node)) 380 break; 381 nodes++; 382 node = PARENT(node); 383 } 384 385 return (nodes); 386 } 387 388 /* 389 * Forward declarations. 390 */ 391 static isc_result_t 392 create_node(isc_mem_t *mctx, const dns_name_t *name, dns_rbtnode_t **nodep); 393 394 static isc_result_t 395 inithash(dns_rbt_t *rbt); 396 397 static inline void 398 hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, const dns_name_t *name); 399 400 static inline void 401 unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node); 402 403 static void 404 rehash(dns_rbt_t *rbt, unsigned int newcount); 405 406 static inline void 407 rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp); 408 static inline void 409 rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp); 410 411 static void 412 addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order, 413 dns_rbtnode_t **rootp); 414 415 static void 416 deletefromlevel(dns_rbtnode_t *item, dns_rbtnode_t **rootp); 417 418 static isc_result_t 419 treefix(dns_rbt_t *rbt, void *base, size_t size, 420 dns_rbtnode_t *n, const dns_name_t *name, 421 dns_rbtdatafixer_t datafixer, void *fixer_arg, 422 uint64_t *crc); 423 424 static void 425 deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, bool unhash, 426 dns_rbtnode_t **nodep); 427 428 static void 429 printnodename(dns_rbtnode_t *node, bool quoted, FILE *f); 430 431 static void 432 freenode(dns_rbt_t *rbt, dns_rbtnode_t **nodep); 433 434 static isc_result_t 435 dns_rbt_zero_header(FILE *file) { 436 /* 437 * Write out a zeroed header as a placeholder. Doing this ensures 438 * that the file will not read while it is partially written, should 439 * writing fail or be interrupted. 440 */ 441 char buffer[HEADER_LENGTH]; 442 isc_result_t result; 443 444 memset(buffer, 0, HEADER_LENGTH); 445 result = isc_stdio_write(buffer, 1, HEADER_LENGTH, file, NULL); 446 if (result != ISC_R_SUCCESS) 447 return (result); 448 449 result = fflush(file); 450 if (result != ISC_R_SUCCESS) 451 return (result); 452 453 return (ISC_R_SUCCESS); 454 } 455 456 static isc_once_t once = ISC_ONCE_INIT; 457 458 static void 459 init_file_version(void) { 460 int n; 461 462 memset(FILE_VERSION, 0, sizeof(FILE_VERSION)); 463 n = snprintf(FILE_VERSION, sizeof(FILE_VERSION), 464 "RBT Image %s %s", dns_major, dns_mapapi); 465 INSIST(n > 0 && (unsigned int)n < sizeof(FILE_VERSION)); 466 } 467 468 /* 469 * Write out the real header, including NodeDump version information 470 * and the offset of the first node. 471 * 472 * Any information stored in the rbt object itself should be stored 473 * here. 474 */ 475 static isc_result_t 476 write_header(FILE *file, dns_rbt_t *rbt, uint64_t first_node_offset, 477 uint64_t crc) 478 { 479 file_header_t header; 480 isc_result_t result; 481 off_t location; 482 483 RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS); 484 485 memset(&header, 0, sizeof(file_header_t)); 486 memmove(header.version1, FILE_VERSION, sizeof(header.version1)); 487 memmove(header.version2, FILE_VERSION, sizeof(header.version2)); 488 header.first_node_offset = first_node_offset; 489 header.ptrsize = (uint32_t) sizeof(void *); 490 header.bigendian = (1 == htonl(1)) ? 1 : 0; 491 492 #ifdef DNS_RDATASET_FIXED 493 header.rdataset_fixed = 1; 494 #else 495 header.rdataset_fixed = 0; 496 #endif 497 498 header.nodecount = rbt->nodecount; 499 500 header.crc = crc; 501 502 CHECK(isc_stdio_tell(file, &location)); 503 location = dns_rbt_serialize_align(location); 504 CHECK(isc_stdio_seek(file, location, SEEK_SET)); 505 CHECK(isc_stdio_write(&header, 1, sizeof(file_header_t), file, NULL)); 506 CHECK(fflush(file)); 507 508 /* Ensure we are always at the end of the file. */ 509 CHECK(isc_stdio_seek(file, 0, SEEK_END)); 510 511 cleanup: 512 return (result); 513 } 514 515 static bool 516 match_header_version(file_header_t *header) { 517 RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS); 518 519 if (memcmp(header->version1, FILE_VERSION, 520 sizeof(header->version1)) != 0 || 521 memcmp(header->version2, FILE_VERSION, 522 sizeof(header->version1)) != 0) 523 { 524 return (false); 525 } 526 527 return (true); 528 } 529 530 static isc_result_t 531 serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left, 532 uintptr_t right, uintptr_t down, uintptr_t parent, 533 uintptr_t data, uint64_t *crc) 534 { 535 dns_rbtnode_t temp_node; 536 off_t file_position; 537 unsigned char *node_data; 538 size_t datasize; 539 isc_result_t result; 540 #ifdef DEBUG 541 dns_name_t nodename; 542 #endif 543 544 INSIST(node != NULL); 545 546 CHECK(isc_stdio_tell(file, &file_position)); 547 file_position = dns_rbt_serialize_align(file_position); 548 CHECK(isc_stdio_seek(file, file_position, SEEK_SET)); 549 550 temp_node = *node; 551 temp_node.down_is_relative = 0; 552 temp_node.left_is_relative = 0; 553 temp_node.right_is_relative = 0; 554 temp_node.parent_is_relative = 0; 555 temp_node.data_is_relative = 0; 556 temp_node.is_mmapped = 1; 557 558 /* 559 * If the next node is not NULL, calculate the next node's location 560 * in the file. Note that this will have to change when the data 561 * structure changes, and it also assumes that we always write the 562 * nodes out in list order (which we currently do.) 563 */ 564 if (temp_node.parent != NULL) { 565 temp_node.parent = (dns_rbtnode_t *)(parent); 566 temp_node.parent_is_relative = 1; 567 } 568 if (temp_node.left != NULL) { 569 temp_node.left = (dns_rbtnode_t *)(left); 570 temp_node.left_is_relative = 1; 571 } 572 if (temp_node.right != NULL) { 573 temp_node.right = (dns_rbtnode_t *)(right); 574 temp_node.right_is_relative = 1; 575 } 576 if (temp_node.down != NULL) { 577 temp_node.down = (dns_rbtnode_t *)(down); 578 temp_node.down_is_relative = 1; 579 } 580 if (temp_node.data != NULL) { 581 temp_node.data = (dns_rbtnode_t *)(data); 582 temp_node.data_is_relative = 1; 583 } 584 585 node_data = (unsigned char *) node + sizeof(dns_rbtnode_t); 586 datasize = NODE_SIZE(node) - sizeof(dns_rbtnode_t); 587 588 CHECK(isc_stdio_write(&temp_node, 1, sizeof(dns_rbtnode_t), 589 file, NULL)); 590 CHECK(isc_stdio_write(node_data, 1, datasize, file, NULL)); 591 592 #ifdef DEBUG 593 dns_name_init(&nodename, NULL); 594 NODENAME(node, &nodename); 595 fprintf(stderr, "serialize "); 596 dns_name_print(&nodename, stderr); 597 fprintf(stderr, "\n"); 598 hexdump("node header", &temp_node, 599 sizeof(dns_rbtnode_t)); 600 hexdump("node data", node_data, datasize); 601 #endif 602 603 isc_crc64_update(crc, (const uint8_t *) &temp_node, 604 sizeof(dns_rbtnode_t)); 605 isc_crc64_update(crc, (const uint8_t *) node_data, datasize); 606 607 cleanup: 608 return (result); 609 } 610 611 static isc_result_t 612 serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent, 613 dns_rbtdatawriter_t datawriter, void *writer_arg, 614 uintptr_t *where, uint64_t *crc) 615 { 616 uintptr_t left = 0, right = 0, down = 0, data = 0; 617 off_t location = 0, offset_adjust; 618 isc_result_t result; 619 620 if (node == NULL) { 621 if (where != NULL) 622 *where = 0; 623 return (ISC_R_SUCCESS); 624 } 625 626 /* Reserve space for current node. */ 627 CHECK(isc_stdio_tell(file, &location)); 628 location = dns_rbt_serialize_align(location); 629 CHECK(isc_stdio_seek(file, location, SEEK_SET)); 630 631 offset_adjust = dns_rbt_serialize_align(location + NODE_SIZE(node)); 632 CHECK(isc_stdio_seek(file, offset_adjust, SEEK_SET)); 633 634 /* 635 * Serialize the rest of the tree. 636 * 637 * WARNING: A change in the order (from left, right, down) 638 * will break the way the crc hash is computed. 639 */ 640 CHECK(serialize_nodes(file, getleft(node, NULL), location, 641 datawriter, writer_arg, &left, crc)); 642 CHECK(serialize_nodes(file, getright(node, NULL), location, 643 datawriter, writer_arg, &right, crc)); 644 CHECK(serialize_nodes(file, getdown(node, NULL), location, 645 datawriter, writer_arg, &down, crc)); 646 647 if (node->data != NULL) { 648 off_t ret; 649 650 CHECK(isc_stdio_tell(file, &ret)); 651 ret = dns_rbt_serialize_align(ret); 652 CHECK(isc_stdio_seek(file, ret, SEEK_SET)); 653 data = ret; 654 655 datawriter(file, node->data, writer_arg, crc); 656 } 657 658 /* Seek back to reserved space. */ 659 CHECK(isc_stdio_seek(file, location, SEEK_SET)); 660 661 /* Serialize the current node. */ 662 CHECK(serialize_node(file, node, left, right, down, parent, data, crc)); 663 664 /* Ensure we are always at the end of the file. */ 665 CHECK(isc_stdio_seek(file, 0, SEEK_END)); 666 667 if (where != NULL) 668 *where = (uintptr_t) location; 669 670 cleanup: 671 return (result); 672 } 673 674 off_t 675 dns_rbt_serialize_align(off_t target) { 676 off_t offset = target % 8; 677 678 if (offset == 0) 679 return (target); 680 else 681 return (target + 8 - offset); 682 } 683 684 isc_result_t 685 dns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt, 686 dns_rbtdatawriter_t datawriter, 687 void *writer_arg, off_t *offset) 688 { 689 isc_result_t result; 690 off_t header_position, node_position, end_position; 691 uint64_t crc; 692 693 REQUIRE(file != NULL); 694 695 CHECK(isc_file_isplainfilefd(fileno(file))); 696 697 isc_crc64_init(&crc); 698 699 CHECK(isc_stdio_tell(file, &header_position)); 700 701 /* Write dummy header */ 702 CHECK(dns_rbt_zero_header(file)); 703 704 /* Serialize nodes */ 705 CHECK(isc_stdio_tell(file, &node_position)); 706 CHECK(serialize_nodes(file, rbt->root, 0, datawriter, 707 writer_arg, NULL, &crc)); 708 709 CHECK(isc_stdio_tell(file, &end_position)); 710 if (node_position == end_position) { 711 CHECK(isc_stdio_seek(file, header_position, SEEK_SET)); 712 *offset = 0; 713 return (ISC_R_SUCCESS); 714 } 715 716 isc_crc64_final(&crc); 717 #ifdef DEBUG 718 hexdump("serializing CRC", &crc, sizeof(crc)); 719 #endif 720 721 /* Serialize header */ 722 CHECK(isc_stdio_seek(file, header_position, SEEK_SET)); 723 CHECK(write_header(file, rbt, HEADER_LENGTH, crc)); 724 725 /* Ensure we are always at the end of the file. */ 726 CHECK(isc_stdio_seek(file, 0, SEEK_END)); 727 *offset = dns_rbt_serialize_align(header_position); 728 729 cleanup: 730 return (result); 731 } 732 733 #define CONFIRM(a) do { \ 734 if (! (a)) { \ 735 result = ISC_R_INVALIDFILE; \ 736 goto cleanup; \ 737 } \ 738 } while(/*CONSTCOND*/0); 739 740 static isc_result_t 741 treefix(dns_rbt_t *rbt, void *base, size_t filesize, dns_rbtnode_t *n, 742 const dns_name_t *name, dns_rbtdatafixer_t datafixer, 743 void *fixer_arg, uint64_t *crc) 744 { 745 isc_result_t result = ISC_R_SUCCESS; 746 dns_fixedname_t fixed; 747 dns_name_t nodename, *fullname; 748 unsigned char *node_data; 749 dns_rbtnode_t header; 750 size_t datasize, nodemax = filesize - sizeof(dns_rbtnode_t); 751 752 if (n == NULL) 753 return (ISC_R_SUCCESS); 754 755 CONFIRM((void *) n >= base); 756 CONFIRM((char *) n - (char *) base <= (int) nodemax); 757 CONFIRM(DNS_RBTNODE_VALID(n)); 758 759 dns_name_init(&nodename, NULL); 760 NODENAME(n, &nodename); 761 762 fullname = &nodename; 763 CONFIRM(dns_name_isvalid(fullname)); 764 765 if (!dns_name_isabsolute(&nodename)) { 766 fullname = dns_fixedname_initname(&fixed); 767 CHECK(dns_name_concatenate(&nodename, name, fullname, NULL)); 768 } 769 770 /* memorize header contents prior to fixup */ 771 memmove(&header, n, sizeof(header)); 772 773 if (n->left_is_relative) { 774 CONFIRM(n->left <= (dns_rbtnode_t *) nodemax); 775 n->left = getleft(n, rbt->mmap_location); 776 n->left_is_relative = 0; 777 CONFIRM(DNS_RBTNODE_VALID(n->left)); 778 } else 779 CONFIRM(n->left == NULL); 780 781 if (n->right_is_relative) { 782 CONFIRM(n->right <= (dns_rbtnode_t *) nodemax); 783 n->right = getright(n, rbt->mmap_location); 784 n->right_is_relative = 0; 785 CONFIRM(DNS_RBTNODE_VALID(n->right)); 786 } else 787 CONFIRM(n->right == NULL); 788 789 if (n->down_is_relative) { 790 CONFIRM(n->down <= (dns_rbtnode_t *) nodemax); 791 n->down = getdown(n, rbt->mmap_location); 792 n->down_is_relative = 0; 793 CONFIRM(n->down > (dns_rbtnode_t *) n); 794 CONFIRM(DNS_RBTNODE_VALID(n->down)); 795 } else 796 CONFIRM(n->down == NULL); 797 798 if (n->parent_is_relative) { 799 CONFIRM(n->parent <= (dns_rbtnode_t *) nodemax); 800 n->parent = getparent(n, rbt->mmap_location); 801 n->parent_is_relative = 0; 802 CONFIRM(n->parent < (dns_rbtnode_t *) n); 803 CONFIRM(DNS_RBTNODE_VALID(n->parent)); 804 } else 805 CONFIRM(n->parent == NULL); 806 807 if (n->data_is_relative) { 808 CONFIRM(n->data <= (void *) filesize); 809 n->data = getdata(n, rbt->mmap_location); 810 n->data_is_relative = 0; 811 CONFIRM(n->data > (void *) n); 812 } else 813 CONFIRM(n->data == NULL); 814 815 hash_node(rbt, n, fullname); 816 817 /* a change in the order (from left, right, down) will break hashing*/ 818 if (n->left != NULL) 819 CHECK(treefix(rbt, base, filesize, n->left, name, 820 datafixer, fixer_arg, crc)); 821 if (n->right != NULL) 822 CHECK(treefix(rbt, base, filesize, n->right, name, 823 datafixer, fixer_arg, crc)); 824 if (n->down != NULL) 825 CHECK(treefix(rbt, base, filesize, n->down, fullname, 826 datafixer, fixer_arg, crc)); 827 828 if (datafixer != NULL && n->data != NULL) 829 CHECK(datafixer(n, base, filesize, fixer_arg, crc)); 830 831 rbt->nodecount++; 832 node_data = (unsigned char *) n + sizeof(dns_rbtnode_t); 833 datasize = NODE_SIZE(n) - sizeof(dns_rbtnode_t); 834 835 #ifdef DEBUG 836 fprintf(stderr, "deserialize "); 837 dns_name_print(&nodename, stderr); 838 fprintf(stderr, "\n"); 839 hexdump("node header", &header, 840 sizeof(dns_rbtnode_t)); 841 hexdump("node data", node_data, datasize); 842 #endif 843 isc_crc64_update(crc, (const uint8_t *) &header, 844 sizeof(dns_rbtnode_t)); 845 isc_crc64_update(crc, (const uint8_t *) node_data, 846 datasize); 847 848 cleanup: 849 return (result); 850 } 851 852 isc_result_t 853 dns_rbt_deserialize_tree(void *base_address, size_t filesize, 854 off_t header_offset, isc_mem_t *mctx, 855 dns_rbtdeleter_t deleter, void *deleter_arg, 856 dns_rbtdatafixer_t datafixer, void *fixer_arg, 857 dns_rbtnode_t **originp, dns_rbt_t **rbtp) 858 { 859 isc_result_t result = ISC_R_SUCCESS; 860 file_header_t *header; 861 dns_rbt_t *rbt = NULL; 862 uint64_t crc; 863 unsigned int host_big_endian; 864 865 REQUIRE(originp == NULL || *originp == NULL); 866 REQUIRE(rbtp != NULL && *rbtp == NULL); 867 868 isc_crc64_init(&crc); 869 870 CHECK(dns_rbt_create(mctx, deleter, deleter_arg, &rbt)); 871 872 rbt->mmap_location = base_address; 873 874 header = (file_header_t *)((char *)base_address + header_offset); 875 if (!match_header_version(header)) { 876 result = ISC_R_INVALIDFILE; 877 goto cleanup; 878 } 879 880 #ifdef DNS_RDATASET_FIXED 881 if (header->rdataset_fixed != 1) { 882 result = ISC_R_INVALIDFILE; 883 goto cleanup; 884 } 885 886 #else 887 if (header->rdataset_fixed != 0) { 888 result = ISC_R_INVALIDFILE; 889 goto cleanup; 890 } 891 #endif 892 893 if (header->ptrsize != (uint32_t) sizeof(void *)) { 894 result = ISC_R_INVALIDFILE; 895 goto cleanup; 896 } 897 898 host_big_endian = (1 == htonl(1)); 899 if (header->bigendian != host_big_endian) { 900 result = ISC_R_INVALIDFILE; 901 goto cleanup; 902 } 903 904 /* Copy other data items from the header into our rbt. */ 905 rbt->root = (dns_rbtnode_t *)((char *)base_address + 906 header_offset + header->first_node_offset); 907 908 if ((header->nodecount * sizeof(dns_rbtnode_t)) > filesize) { 909 result = ISC_R_INVALIDFILE; 910 goto cleanup; 911 } 912 rehash(rbt, header->nodecount); 913 914 CHECK(treefix(rbt, base_address, filesize, rbt->root, 915 dns_rootname, datafixer, fixer_arg, &crc)); 916 917 isc_crc64_final(&crc); 918 #ifdef DEBUG 919 hexdump("deserializing CRC", &crc, sizeof(crc)); 920 #endif 921 922 /* Check file hash */ 923 if (header->crc != crc) { 924 result = ISC_R_INVALIDFILE; 925 goto cleanup; 926 } 927 928 if (header->nodecount != rbt->nodecount) { 929 result = ISC_R_INVALIDFILE; 930 goto cleanup; 931 } 932 933 fixup_uppernodes(rbt); 934 935 *rbtp = rbt; 936 if (originp != NULL) 937 *originp = rbt->root; 938 939 cleanup: 940 if (result != ISC_R_SUCCESS && rbt != NULL) { 941 rbt->root = NULL; 942 rbt->nodecount = 0; 943 dns_rbt_destroy(&rbt); 944 } 945 946 return (result); 947 } 948 949 /* 950 * Initialize a red/black tree of trees. 951 */ 952 isc_result_t 953 dns_rbt_create(isc_mem_t *mctx, dns_rbtdeleter_t deleter, 954 void *deleter_arg, dns_rbt_t **rbtp) 955 { 956 isc_result_t result; 957 dns_rbt_t *rbt; 958 959 REQUIRE(mctx != NULL); 960 REQUIRE(rbtp != NULL && *rbtp == NULL); 961 REQUIRE(deleter == NULL ? deleter_arg == NULL : 1); 962 963 rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt)); 964 if (rbt == NULL) 965 return (ISC_R_NOMEMORY); 966 967 rbt->mctx = NULL; 968 isc_mem_attach(mctx, &rbt->mctx); 969 rbt->data_deleter = deleter; 970 rbt->deleter_arg = deleter_arg; 971 rbt->root = NULL; 972 rbt->nodecount = 0; 973 rbt->hashtable = NULL; 974 rbt->hashsize = 0; 975 rbt->mmap_location = NULL; 976 977 result = inithash(rbt); 978 if (result != ISC_R_SUCCESS) { 979 isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt)); 980 return (result); 981 } 982 983 rbt->magic = RBT_MAGIC; 984 985 *rbtp = rbt; 986 987 return (ISC_R_SUCCESS); 988 } 989 990 /* 991 * Deallocate a red/black tree of trees. 992 */ 993 void 994 dns_rbt_destroy(dns_rbt_t **rbtp) { 995 RUNTIME_CHECK(dns_rbt_destroy2(rbtp, 0) == ISC_R_SUCCESS); 996 } 997 998 isc_result_t 999 dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) { 1000 dns_rbt_t *rbt; 1001 1002 REQUIRE(rbtp != NULL && VALID_RBT(*rbtp)); 1003 1004 rbt = *rbtp; 1005 1006 deletetreeflat(rbt, quantum, false, &rbt->root); 1007 if (rbt->root != NULL) 1008 return (ISC_R_QUOTA); 1009 1010 INSIST(rbt->nodecount == 0); 1011 1012 rbt->mmap_location = NULL; 1013 1014 if (rbt->hashtable != NULL) 1015 isc_mem_put(rbt->mctx, rbt->hashtable, 1016 rbt->hashsize * sizeof(dns_rbtnode_t *)); 1017 1018 rbt->magic = 0; 1019 1020 isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt)); 1021 *rbtp = NULL; 1022 return (ISC_R_SUCCESS); 1023 } 1024 1025 unsigned int 1026 dns_rbt_nodecount(dns_rbt_t *rbt) { 1027 1028 REQUIRE(VALID_RBT(rbt)); 1029 1030 return (rbt->nodecount); 1031 } 1032 1033 size_t 1034 dns_rbt_hashsize(dns_rbt_t *rbt) { 1035 1036 REQUIRE(VALID_RBT(rbt)); 1037 1038 return (rbt->hashsize); 1039 } 1040 1041 static inline isc_result_t 1042 chain_name(dns_rbtnodechain_t *chain, dns_name_t *name, 1043 bool include_chain_end) 1044 { 1045 dns_name_t nodename; 1046 isc_result_t result = ISC_R_SUCCESS; 1047 int i; 1048 1049 dns_name_init(&nodename, NULL); 1050 1051 if (include_chain_end && chain->end != NULL) { 1052 NODENAME(chain->end, &nodename); 1053 dns_name_copynf(&nodename, name); 1054 } else 1055 dns_name_reset(name); 1056 1057 for (i = (int)chain->level_count - 1; i >= 0; i--) { 1058 NODENAME(chain->levels[i], &nodename); 1059 result = dns_name_concatenate(name, &nodename, name, NULL); 1060 1061 if (result != ISC_R_SUCCESS) 1062 return (result); 1063 } 1064 return (result); 1065 } 1066 1067 static inline isc_result_t 1068 move_chain_to_last(dns_rbtnodechain_t *chain, dns_rbtnode_t *node) { 1069 do { 1070 /* 1071 * Go as far right and then down as much as possible, 1072 * as long as the rightmost node has a down pointer. 1073 */ 1074 while (RIGHT(node) != NULL) 1075 node = RIGHT(node); 1076 1077 if (DOWN(node) == NULL) 1078 break; 1079 1080 ADD_LEVEL(chain, node); 1081 node = DOWN(node); 1082 } while (1); 1083 1084 chain->end = node; 1085 1086 return (ISC_R_SUCCESS); 1087 } 1088 1089 /* 1090 * Add 'name' to tree, initializing its data pointer with 'data'. 1091 */ 1092 1093 isc_result_t 1094 dns_rbt_addnode(dns_rbt_t *rbt, const dns_name_t *name, dns_rbtnode_t **nodep) { 1095 /* 1096 * Does this thing have too many variables or what? 1097 */ 1098 dns_rbtnode_t **root, *parent, *child, *current, *new_current; 1099 dns_name_t *add_name, *new_name, current_name, *prefix, *suffix; 1100 dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix, fnewname; 1101 dns_offsets_t current_offsets; 1102 dns_namereln_t compared; 1103 isc_result_t result = ISC_R_SUCCESS; 1104 unsigned int level_count; 1105 unsigned int common_labels; 1106 unsigned int nlabels, hlabels; 1107 int order; 1108 1109 REQUIRE(VALID_RBT(rbt)); 1110 REQUIRE(dns_name_isabsolute(name)); 1111 REQUIRE(nodep != NULL && *nodep == NULL); 1112 1113 /* 1114 * Dear future BIND developer, 1115 * 1116 * After you have tried attempting to optimize this routine by 1117 * using the hashtable and have realized your folly, please 1118 * append another cross ("X") below as a warning to the next 1119 * future BIND developer: 1120 * 1121 * Number of victim developers: X 1122 * 1123 * I wish the past developer had included such a notice. 1124 * 1125 * Long form: Unlike dns_rbt_findnode(), this function does not 1126 * lend itself to be optimized using the hashtable: 1127 * 1128 * 1. In the subtree where the insertion occurs, this function 1129 * needs to have the insertion point and the order where the 1130 * lookup terminated (i.e., at the insertion point where left or 1131 * right child is NULL). This cannot be determined from the 1132 * hashtable, so at least in that subtree, a BST O(log N) lookup 1133 * is necessary. 1134 * 1135 * 2. Our RBT nodes contain not only single labels but label 1136 * sequences to optimize space usage. So at every level, we have 1137 * to look for a match in the hashtable for all superdomains in 1138 * the rest of the name we're searching. This is an O(N) 1139 * operation at least, here N being the label size of name, each 1140 * of which is a hashtable lookup involving dns_name_equal() 1141 * comparisons. 1142 */ 1143 1144 /* 1145 * Create a copy of the name so the original name structure is 1146 * not modified. 1147 */ 1148 add_name = dns_fixedname_initname(&fixedcopy); 1149 INSIST(add_name != NULL); 1150 dns_name_clone(name, add_name); 1151 1152 if (ISC_UNLIKELY(rbt->root == NULL)) { 1153 result = create_node(rbt->mctx, add_name, &new_current); 1154 if (result == ISC_R_SUCCESS) { 1155 rbt->nodecount++; 1156 new_current->is_root = 1; 1157 1158 UPPERNODE(new_current) = NULL; 1159 1160 rbt->root = new_current; 1161 *nodep = new_current; 1162 hash_node(rbt, new_current, name); 1163 } 1164 return (result); 1165 } 1166 1167 level_count = 0; 1168 1169 prefix = dns_fixedname_initname(&fixedprefix); 1170 suffix = dns_fixedname_initname(&fixedsuffix); 1171 1172 INSIST(prefix != NULL); 1173 INSIST(suffix != NULL); 1174 1175 root = &rbt->root; 1176 INSIST(IS_ROOT(*root)); 1177 parent = NULL; 1178 current = NULL; 1179 child = *root; 1180 dns_name_init(¤t_name, current_offsets); 1181 new_name = dns_fixedname_initname(&fnewname); 1182 nlabels = dns_name_countlabels(name); 1183 hlabels = 0; 1184 1185 do { 1186 current = child; 1187 1188 NODENAME(current, ¤t_name); 1189 compared = dns_name_fullcompare(add_name, ¤t_name, 1190 &order, &common_labels); 1191 1192 if (compared == dns_namereln_equal) { 1193 *nodep = current; 1194 result = ISC_R_EXISTS; 1195 break; 1196 1197 } 1198 1199 if (compared == dns_namereln_none) { 1200 1201 if (order < 0) { 1202 parent = current; 1203 child = LEFT(current); 1204 1205 } else if (order > 0) { 1206 parent = current; 1207 child = RIGHT(current); 1208 1209 } 1210 1211 } else { 1212 /* 1213 * This name has some suffix in common with the 1214 * name at the current node. If the name at 1215 * the current node is shorter, that means the 1216 * new name should be in a subtree. If the 1217 * name at the current node is longer, that means 1218 * the down pointer to this tree should point 1219 * to a new tree that has the common suffix, and 1220 * the non-common parts of these two names should 1221 * start a new tree. 1222 */ 1223 hlabels += common_labels; 1224 if (compared == dns_namereln_subdomain) { 1225 /* 1226 * All of the existing labels are in common, 1227 * so the new name is in a subtree. 1228 * Whack off the common labels for the 1229 * not-in-common part to be searched for 1230 * in the next level. 1231 */ 1232 dns_name_split(add_name, common_labels, 1233 add_name, NULL); 1234 1235 /* 1236 * Follow the down pointer (possibly NULL). 1237 */ 1238 root = &DOWN(current); 1239 1240 INSIST(*root == NULL || 1241 (IS_ROOT(*root) && 1242 PARENT(*root) == current)); 1243 1244 parent = NULL; 1245 child = DOWN(current); 1246 1247 INSIST(level_count < DNS_RBT_LEVELBLOCK); 1248 level_count++; 1249 } else { 1250 /* 1251 * The number of labels in common is fewer 1252 * than the number of labels at the current 1253 * node, so the current node must be adjusted 1254 * to have just the common suffix, and a down 1255 * pointer made to a new tree. 1256 */ 1257 1258 INSIST(compared == dns_namereln_commonancestor 1259 || compared == dns_namereln_contains); 1260 1261 /* 1262 * Ensure the number of levels in the tree 1263 * does not exceed the number of logical 1264 * levels allowed by DNSSEC. 1265 * 1266 * XXXDCL need a better error result? 1267 */ 1268 if (level_count >= DNS_RBT_LEVELBLOCK) { 1269 result = ISC_R_NOSPACE; 1270 break; 1271 } 1272 1273 /* 1274 * Split the name into two parts, a prefix 1275 * which is the not-in-common parts of the 1276 * two names and a suffix that is the common 1277 * parts of them. 1278 */ 1279 dns_name_split(¤t_name, common_labels, 1280 prefix, suffix); 1281 result = create_node(rbt->mctx, suffix, 1282 &new_current); 1283 1284 if (result != ISC_R_SUCCESS) 1285 break; 1286 1287 /* 1288 * Reproduce the tree attributes of the 1289 * current node. 1290 */ 1291 new_current->is_root = current->is_root; 1292 if (current->nsec == DNS_RBT_NSEC_HAS_NSEC) 1293 new_current->nsec = DNS_RBT_NSEC_NORMAL; 1294 else 1295 new_current->nsec = current->nsec; 1296 PARENT(new_current) = PARENT(current); 1297 LEFT(new_current) = LEFT(current); 1298 RIGHT(new_current) = RIGHT(current); 1299 COLOR(new_current) = COLOR(current); 1300 1301 /* 1302 * Fix pointers that were to the current node. 1303 */ 1304 if (parent != NULL) { 1305 if (LEFT(parent) == current) 1306 LEFT(parent) = new_current; 1307 else 1308 RIGHT(parent) = new_current; 1309 } 1310 if (LEFT(new_current) != NULL) 1311 PARENT(LEFT(new_current)) = 1312 new_current; 1313 if (RIGHT(new_current) != NULL) 1314 PARENT(RIGHT(new_current)) = 1315 new_current; 1316 if (*root == current) 1317 *root = new_current; 1318 1319 NAMELEN(current) = prefix->length; 1320 OFFSETLEN(current) = prefix->labels; 1321 1322 /* 1323 * Set up the new root of the next level. 1324 * By definition it will not be the top 1325 * level tree, so clear DNS_NAMEATTR_ABSOLUTE. 1326 */ 1327 current->is_root = 1; 1328 PARENT(current) = new_current; 1329 DOWN(new_current) = current; 1330 root = &DOWN(new_current); 1331 1332 UPPERNODE(new_current) = UPPERNODE(current); 1333 UPPERNODE(current) = new_current; 1334 1335 INSIST(level_count < DNS_RBT_LEVELBLOCK); 1336 level_count++; 1337 1338 LEFT(current) = NULL; 1339 RIGHT(current) = NULL; 1340 1341 MAKE_BLACK(current); 1342 ATTRS(current) &= ~DNS_NAMEATTR_ABSOLUTE; 1343 1344 rbt->nodecount++; 1345 dns_name_getlabelsequence(name, 1346 nlabels - hlabels, 1347 hlabels, new_name); 1348 hash_node(rbt, new_current, new_name); 1349 1350 if (common_labels == 1351 dns_name_countlabels(add_name)) { 1352 /* 1353 * The name has been added by pushing 1354 * the not-in-common parts down to 1355 * a new level. 1356 */ 1357 *nodep = new_current; 1358 return (ISC_R_SUCCESS); 1359 1360 } else { 1361 /* 1362 * The current node has no data, 1363 * because it is just a placeholder. 1364 * Its data pointer is already NULL 1365 * from create_node()), so there's 1366 * nothing more to do to it. 1367 */ 1368 1369 /* 1370 * The not-in-common parts of the new 1371 * name will be inserted into the new 1372 * level following this loop (unless 1373 * result != ISC_R_SUCCESS, which 1374 * is tested after the loop ends). 1375 */ 1376 dns_name_split(add_name, common_labels, 1377 add_name, NULL); 1378 1379 break; 1380 } 1381 1382 } 1383 1384 } 1385 1386 } while (ISC_LIKELY(child != NULL)); 1387 1388 if (ISC_LIKELY(result == ISC_R_SUCCESS)) 1389 result = create_node(rbt->mctx, add_name, &new_current); 1390 1391 if (ISC_LIKELY(result == ISC_R_SUCCESS)) { 1392 if (*root == NULL) { 1393 UPPERNODE(new_current) = current; 1394 } else { 1395 UPPERNODE(new_current) = PARENT(*root); 1396 } 1397 1398 addonlevel(new_current, current, order, root); 1399 rbt->nodecount++; 1400 *nodep = new_current; 1401 hash_node(rbt, new_current, name); 1402 } 1403 1404 return (result); 1405 } 1406 1407 /* 1408 * Add a name to the tree of trees, associating it with some data. 1409 */ 1410 isc_result_t 1411 dns_rbt_addname(dns_rbt_t *rbt, const dns_name_t *name, void *data) { 1412 isc_result_t result; 1413 dns_rbtnode_t *node; 1414 1415 REQUIRE(VALID_RBT(rbt)); 1416 REQUIRE(dns_name_isabsolute(name)); 1417 1418 node = NULL; 1419 1420 result = dns_rbt_addnode(rbt, name, &node); 1421 1422 /* 1423 * dns_rbt_addnode will report the node exists even when 1424 * it does not have data associated with it, but the 1425 * dns_rbt_*name functions all behave depending on whether 1426 * there is data associated with a node. 1427 */ 1428 if (result == ISC_R_SUCCESS || 1429 (result == ISC_R_EXISTS && DATA(node) == NULL)) { 1430 DATA(node) = data; 1431 result = ISC_R_SUCCESS; 1432 } 1433 1434 return (result); 1435 } 1436 1437 /* 1438 * Find the node for "name" in the tree of trees. 1439 */ 1440 isc_result_t 1441 dns_rbt_findnode(dns_rbt_t *rbt, const dns_name_t *name, dns_name_t *foundname, 1442 dns_rbtnode_t **node, dns_rbtnodechain_t *chain, 1443 unsigned int options, dns_rbtfindcallback_t callback, 1444 void *callback_arg) 1445 { 1446 dns_rbtnode_t *current, *last_compared; 1447 dns_rbtnodechain_t localchain; 1448 dns_name_t *search_name, current_name, *callback_name; 1449 dns_fixedname_t fixedcallbackname, fixedsearchname; 1450 dns_namereln_t compared; 1451 isc_result_t result, saved_result; 1452 unsigned int common_labels; 1453 unsigned int hlabels = 0; 1454 int order; 1455 1456 REQUIRE(VALID_RBT(rbt)); 1457 REQUIRE(dns_name_isabsolute(name)); 1458 REQUIRE(node != NULL && *node == NULL); 1459 REQUIRE((options & (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR)) 1460 != (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR)); 1461 1462 /* 1463 * If there is a chain it needs to appear to be in a sane state, 1464 * otherwise a chain is still needed to generate foundname and 1465 * callback_name. 1466 */ 1467 if (chain == NULL) { 1468 options |= DNS_RBTFIND_NOPREDECESSOR; 1469 chain = &localchain; 1470 dns_rbtnodechain_init(chain, rbt->mctx); 1471 } else 1472 dns_rbtnodechain_reset(chain); 1473 1474 if (ISC_UNLIKELY(rbt->root == NULL)) 1475 return (ISC_R_NOTFOUND); 1476 1477 /* 1478 * Appease GCC about variables it incorrectly thinks are 1479 * possibly used uninitialized. 1480 */ 1481 compared = dns_namereln_none; 1482 last_compared = NULL; 1483 order = 0; 1484 1485 callback_name = dns_fixedname_initname(&fixedcallbackname); 1486 1487 /* 1488 * search_name is the name segment being sought in each tree level. 1489 * By using a fixedname, the search_name will definitely have offsets 1490 * for use by any splitting. 1491 * By using dns_name_clone, no name data should be copied thanks to 1492 * the lack of bitstring labels. 1493 */ 1494 search_name = dns_fixedname_initname(&fixedsearchname); 1495 INSIST(search_name != NULL); 1496 dns_name_clone(name, search_name); 1497 1498 dns_name_init(¤t_name, NULL); 1499 1500 saved_result = ISC_R_SUCCESS; 1501 current = rbt->root; 1502 1503 while (ISC_LIKELY(current != NULL)) { 1504 NODENAME(current, ¤t_name); 1505 compared = dns_name_fullcompare(search_name, ¤t_name, 1506 &order, &common_labels); 1507 /* 1508 * last_compared is used as a shortcut to start (or 1509 * continue rather) finding the stop-node of the search 1510 * when hashing was used (see much below in this 1511 * function). 1512 */ 1513 last_compared = current; 1514 1515 if (compared == dns_namereln_equal) 1516 break; 1517 1518 if (compared == dns_namereln_none) { 1519 /* 1520 * Here, current is pointing at a subtree root 1521 * node. We try to find a matching node using 1522 * the hashtable. We can get one of 3 results 1523 * here: (a) we locate the matching node, (b) we 1524 * find a node to which the current node has a 1525 * subdomain relation, (c) we fail to find (a) 1526 * or (b). 1527 */ 1528 1529 dns_name_t hash_name; 1530 dns_rbtnode_t *hnode; 1531 dns_rbtnode_t *up_current; 1532 unsigned int nlabels; 1533 unsigned int tlabels = 1; 1534 unsigned int hash; 1535 1536 /* 1537 * The case of current not being a subtree root, 1538 * that means a left or right pointer was 1539 * followed, only happens when the algorithm 1540 * fell through to the traditional binary search 1541 * because of a bitstring label. Since we 1542 * dropped the bitstring support, this should 1543 * not happen. 1544 */ 1545 INSIST(IS_ROOT(current)); 1546 1547 nlabels = dns_name_countlabels(search_name); 1548 1549 /* 1550 * current is the root of the current level, so 1551 * its parent is the same as its "up" pointer. 1552 */ 1553 up_current = PARENT(current); 1554 dns_name_init(&hash_name, NULL); 1555 1556 hashagain: 1557 /* 1558 * Compute the hash over the full absolute 1559 * name. Look for the smallest suffix match at 1560 * this tree level (hlevel), and then at every 1561 * iteration, look for the next smallest suffix 1562 * match (add another subdomain label to the 1563 * absolute name being hashed). 1564 */ 1565 dns_name_getlabelsequence(name, 1566 nlabels - tlabels, 1567 hlabels + tlabels, 1568 &hash_name); 1569 hash = dns_name_fullhash(&hash_name, false); 1570 dns_name_getlabelsequence(search_name, 1571 nlabels - tlabels, 1572 tlabels, &hash_name); 1573 1574 /* 1575 * Walk all the nodes in the hash bucket pointed 1576 * by the computed hash value. 1577 */ 1578 for (hnode = rbt->hashtable[hash % rbt->hashsize]; 1579 hnode != NULL; 1580 hnode = hnode->hashnext) 1581 { 1582 dns_name_t hnode_name; 1583 1584 if (ISC_LIKELY(hash != HASHVAL(hnode))) 1585 continue; 1586 /* 1587 * This checks that the hashed label 1588 * sequence being looked up is at the 1589 * same tree level, so that we don't 1590 * match a labelsequence from some other 1591 * subdomain. 1592 */ 1593 if (ISC_LIKELY(get_upper_node(hnode) != 1594 up_current)) 1595 { 1596 continue; 1597 } 1598 1599 dns_name_init(&hnode_name, NULL); 1600 NODENAME(hnode, &hnode_name); 1601 if (ISC_LIKELY(dns_name_equal(&hnode_name, 1602 &hash_name))) 1603 { 1604 break; 1605 } 1606 } 1607 1608 if (hnode != NULL) { 1609 current = hnode; 1610 /* 1611 * This is an optimization. If hashing found 1612 * the right node, the next call to 1613 * dns_name_fullcompare() would obviously 1614 * return _equal or _subdomain. Determine 1615 * which of those would be the case by 1616 * checking if the full name was hashed. Then 1617 * make it look like dns_name_fullcompare 1618 * was called and jump to the right place. 1619 */ 1620 if (tlabels == nlabels) { 1621 compared = dns_namereln_equal; 1622 break; 1623 } else { 1624 common_labels = tlabels; 1625 compared = dns_namereln_subdomain; 1626 goto subdomain; 1627 } 1628 } 1629 1630 if (tlabels++ < nlabels) 1631 goto hashagain; 1632 1633 /* 1634 * All of the labels have been tried against the hash 1635 * table. Since we dropped the support of bitstring 1636 * labels, the name isn't in the table. 1637 */ 1638 current = NULL; 1639 continue; 1640 } else { 1641 /* 1642 * The names have some common suffix labels. 1643 * 1644 * If the number in common are equal in length to 1645 * the current node's name length, then follow the 1646 * down pointer and search in the new tree. 1647 */ 1648 if (compared == dns_namereln_subdomain) { 1649 subdomain: 1650 /* 1651 * Whack off the current node's common parts 1652 * for the name to search in the next level. 1653 */ 1654 dns_name_split(search_name, common_labels, 1655 search_name, NULL); 1656 hlabels += common_labels; 1657 /* 1658 * This might be the closest enclosing name. 1659 */ 1660 if (DATA(current) != NULL || 1661 (options & DNS_RBTFIND_EMPTYDATA) != 0) 1662 *node = current; 1663 1664 /* 1665 * Point the chain to the next level. This 1666 * needs to be done before 'current' is pointed 1667 * there because the callback in the next 1668 * block of code needs the current 'current', 1669 * but in the event the callback requests that 1670 * the search be stopped then the 1671 * DNS_R_PARTIALMATCH code at the end of this 1672 * function needs the chain pointed to the 1673 * next level. 1674 */ 1675 ADD_LEVEL(chain, current); 1676 1677 /* 1678 * The caller may want to interrupt the 1679 * downward search when certain special nodes 1680 * are traversed. If this is a special node, 1681 * the callback is used to learn what the 1682 * caller wants to do. 1683 */ 1684 if (callback != NULL && 1685 FINDCALLBACK(current)) { 1686 result = chain_name(chain, 1687 callback_name, 1688 false); 1689 if (result != ISC_R_SUCCESS) { 1690 dns_rbtnodechain_reset(chain); 1691 return (result); 1692 } 1693 1694 result = (callback)(current, 1695 callback_name, 1696 callback_arg); 1697 if (result != DNS_R_CONTINUE) { 1698 saved_result = result; 1699 /* 1700 * Treat this node as if it 1701 * had no down pointer. 1702 */ 1703 current = NULL; 1704 break; 1705 } 1706 } 1707 1708 /* 1709 * Finally, head to the next tree level. 1710 */ 1711 current = DOWN(current); 1712 } else { 1713 /* 1714 * Though there are labels in common, the 1715 * entire name at this node is not common 1716 * with the search name so the search 1717 * name does not exist in the tree. 1718 */ 1719 INSIST(compared == dns_namereln_commonancestor 1720 || compared == dns_namereln_contains); 1721 1722 current = NULL; 1723 } 1724 } 1725 } 1726 1727 /* 1728 * If current is not NULL, NOEXACT is not disallowing exact matches, 1729 * and either the node has data or an empty node is ok, return 1730 * ISC_R_SUCCESS to indicate an exact match. 1731 */ 1732 if (current != NULL && (options & DNS_RBTFIND_NOEXACT) == 0 && 1733 (DATA(current) != NULL || 1734 (options & DNS_RBTFIND_EMPTYDATA) != 0)) { 1735 /* 1736 * Found an exact match. 1737 */ 1738 chain->end = current; 1739 chain->level_matches = chain->level_count; 1740 1741 if (foundname != NULL) 1742 result = chain_name(chain, foundname, true); 1743 else 1744 result = ISC_R_SUCCESS; 1745 1746 if (result == ISC_R_SUCCESS) { 1747 *node = current; 1748 result = saved_result; 1749 } else 1750 *node = NULL; 1751 } else { 1752 /* 1753 * Did not find an exact match (or did not want one). 1754 */ 1755 if (*node != NULL) { 1756 /* 1757 * ... but found a partially matching superdomain. 1758 * Unwind the chain to the partial match node 1759 * to set level_matches to the level above the node, 1760 * and then to derive the name. 1761 * 1762 * chain->level_count is guaranteed to be at least 1 1763 * here because by definition of finding a superdomain, 1764 * the chain is pointed to at least the first subtree. 1765 */ 1766 chain->level_matches = chain->level_count - 1; 1767 1768 while (chain->levels[chain->level_matches] != *node) { 1769 INSIST(chain->level_matches > 0); 1770 chain->level_matches--; 1771 } 1772 1773 if (foundname != NULL) { 1774 unsigned int saved_count = chain->level_count; 1775 1776 chain->level_count = chain->level_matches + 1; 1777 1778 result = chain_name(chain, foundname, 1779 false); 1780 1781 chain->level_count = saved_count; 1782 } else 1783 result = ISC_R_SUCCESS; 1784 1785 if (result == ISC_R_SUCCESS) 1786 result = DNS_R_PARTIALMATCH; 1787 1788 } else 1789 result = ISC_R_NOTFOUND; 1790 1791 if (current != NULL) { 1792 /* 1793 * There was an exact match but either 1794 * DNS_RBTFIND_NOEXACT was set, or 1795 * DNS_RBTFIND_EMPTYDATA was set and the node had no 1796 * data. A policy decision was made to set the 1797 * chain to the exact match, but this is subject 1798 * to change if it becomes apparent that something 1799 * else would be more useful. It is important that 1800 * this case is handled here, because the predecessor 1801 * setting code below assumes the match was not exact. 1802 */ 1803 INSIST(((options & DNS_RBTFIND_NOEXACT) != 0) || 1804 ((options & DNS_RBTFIND_EMPTYDATA) == 0 && 1805 DATA(current) == NULL)); 1806 chain->end = current; 1807 1808 } else if ((options & DNS_RBTFIND_NOPREDECESSOR) != 0) { 1809 /* 1810 * Ensure the chain points nowhere. 1811 */ 1812 chain->end = NULL; 1813 1814 } else { 1815 /* 1816 * Since there was no exact match, the chain argument 1817 * needs to be pointed at the DNSSEC predecessor of 1818 * the search name. 1819 */ 1820 if (compared == dns_namereln_subdomain) { 1821 /* 1822 * Attempted to follow a down pointer that was 1823 * NULL, which means the searched for name was 1824 * a subdomain of a terminal name in the tree. 1825 * Since there are no existing subdomains to 1826 * order against, the terminal name is the 1827 * predecessor. 1828 */ 1829 INSIST(chain->level_count > 0); 1830 INSIST(chain->level_matches < 1831 chain->level_count); 1832 chain->end = 1833 chain->levels[--chain->level_count]; 1834 1835 } else { 1836 isc_result_t result2; 1837 1838 /* 1839 * Point current to the node that stopped 1840 * the search. 1841 * 1842 * With the hashing modification that has been 1843 * added to the algorithm, the stop node of a 1844 * standard binary search is not known. So it 1845 * has to be found. There is probably a more 1846 * clever way of doing this. 1847 * 1848 * The assignment of current to NULL when 1849 * the relationship is *not* dns_namereln_none, 1850 * even though it later gets set to the same 1851 * last_compared anyway, is simply to not push 1852 * the while loop in one more level of 1853 * indentation. 1854 */ 1855 if (compared == dns_namereln_none) 1856 current = last_compared; 1857 else 1858 current = NULL; 1859 1860 while (current != NULL) { 1861 NODENAME(current, ¤t_name); 1862 compared = dns_name_fullcompare( 1863 search_name, 1864 ¤t_name, 1865 &order, 1866 &common_labels); 1867 POST(compared); 1868 1869 last_compared = current; 1870 1871 /* 1872 * Standard binary search movement. 1873 */ 1874 if (order < 0) 1875 current = LEFT(current); 1876 else 1877 current = RIGHT(current); 1878 1879 } 1880 1881 current = last_compared; 1882 1883 /* 1884 * Reached a point within a level tree that 1885 * positively indicates the name is not 1886 * present, but the stop node could be either 1887 * less than the desired name (order > 0) or 1888 * greater than the desired name (order < 0). 1889 * 1890 * If the stop node is less, it is not 1891 * necessarily the predecessor. If the stop 1892 * node has a down pointer, then the real 1893 * predecessor is at the end of a level below 1894 * (not necessarily the next level). 1895 * Move down levels until the rightmost node 1896 * does not have a down pointer. 1897 * 1898 * When the stop node is greater, it is 1899 * the successor. All the logic for finding 1900 * the predecessor is handily encapsulated 1901 * in dns_rbtnodechain_prev. In the event 1902 * that the search name is less than anything 1903 * else in the tree, the chain is reset. 1904 * XXX DCL What is the best way for the caller 1905 * to know that the search name has 1906 * no predecessor? 1907 */ 1908 1909 1910 if (order > 0) { 1911 if (DOWN(current) != NULL) { 1912 ADD_LEVEL(chain, current); 1913 1914 result2 = 1915 move_chain_to_last(chain, 1916 DOWN(current)); 1917 1918 if (result2 != ISC_R_SUCCESS) 1919 result = result2; 1920 } else 1921 /* 1922 * Ah, the pure and simple 1923 * case. The stop node is the 1924 * predecessor. 1925 */ 1926 chain->end = current; 1927 1928 } else { 1929 INSIST(order < 0); 1930 1931 chain->end = current; 1932 1933 result2 = dns_rbtnodechain_prev(chain, 1934 NULL, 1935 NULL); 1936 if (result2 == ISC_R_SUCCESS || 1937 result2 == DNS_R_NEWORIGIN) 1938 ; /* Nothing. */ 1939 else if (result2 == ISC_R_NOMORE) 1940 /* 1941 * There is no predecessor. 1942 */ 1943 dns_rbtnodechain_reset(chain); 1944 else 1945 result = result2; 1946 } 1947 1948 } 1949 } 1950 } 1951 1952 ENSURE(*node == NULL || DNS_RBTNODE_VALID(*node)); 1953 1954 return (result); 1955 } 1956 1957 /* 1958 * Get the data pointer associated with 'name'. 1959 */ 1960 isc_result_t 1961 dns_rbt_findname(dns_rbt_t *rbt, const dns_name_t *name, unsigned int options, 1962 dns_name_t *foundname, void **data) { 1963 dns_rbtnode_t *node = NULL; 1964 isc_result_t result; 1965 1966 REQUIRE(data != NULL && *data == NULL); 1967 1968 result = dns_rbt_findnode(rbt, name, foundname, &node, NULL, 1969 options, NULL, NULL); 1970 1971 if (node != NULL && 1972 (DATA(node) != NULL || (options & DNS_RBTFIND_EMPTYDATA) != 0)) 1973 *data = DATA(node); 1974 else 1975 result = ISC_R_NOTFOUND; 1976 1977 return (result); 1978 } 1979 1980 /* 1981 * Delete a name from the tree of trees. 1982 */ 1983 isc_result_t 1984 dns_rbt_deletename(dns_rbt_t *rbt, const dns_name_t *name, 1985 bool recurse) 1986 { 1987 dns_rbtnode_t *node = NULL; 1988 isc_result_t result; 1989 1990 REQUIRE(VALID_RBT(rbt)); 1991 REQUIRE(dns_name_isabsolute(name)); 1992 1993 /* 1994 * First, find the node. 1995 * 1996 * When searching, the name might not have an exact match: 1997 * consider a.b.a.com, b.b.a.com and c.b.a.com as the only 1998 * elements of a tree, which would make layer 1 a single 1999 * node tree of "b.a.com" and layer 2 a three node tree of 2000 * a, b, and c. Deleting a.com would find only a partial depth 2001 * match in the first layer. Should it be a requirement that 2002 * that the name to be deleted have data? For now, it is. 2003 * 2004 * ->dirty, ->locknum and ->references are ignored; they are 2005 * solely the province of rbtdb.c. 2006 */ 2007 result = dns_rbt_findnode(rbt, name, NULL, &node, NULL, 2008 DNS_RBTFIND_NOOPTIONS, NULL, NULL); 2009 2010 if (result == ISC_R_SUCCESS) { 2011 if (DATA(node) != NULL) 2012 result = dns_rbt_deletenode(rbt, node, recurse); 2013 else 2014 result = ISC_R_NOTFOUND; 2015 2016 } else if (result == DNS_R_PARTIALMATCH) 2017 result = ISC_R_NOTFOUND; 2018 2019 return (result); 2020 } 2021 2022 /* 2023 * Remove a node from the tree of trees. 2024 * 2025 * NOTE WELL: deletion is *not* symmetric with addition; that is, reversing 2026 * a sequence of additions to be deletions will not generally get the 2027 * tree back to the state it started in. For example, if the addition 2028 * of "b.c" caused the node "a.b.c" to be split, pushing "a" to its own level, 2029 * then the subsequent deletion of "b.c" will not cause "a" to be pulled up, 2030 * restoring "a.b.c". The RBT *used* to do this kind of rejoining, but it 2031 * turned out to be a bad idea because it could corrupt an active nodechain 2032 * that had "b.c" as one of its levels -- and the RBT has no idea what 2033 * nodechains are in use by callers, so it can't even *try* to helpfully 2034 * fix them up (which would probably be doomed to failure anyway). 2035 * 2036 * Similarly, it is possible to leave the tree in a state where a supposedly 2037 * deleted node still exists. The first case of this is obvious; take 2038 * the tree which has "b.c" on one level, pointing to "a". Now deleted "b.c". 2039 * It was just established in the previous paragraph why we can't pull "a" 2040 * back up to its parent level. But what happens when "a" then gets deleted? 2041 * "b.c" is left hanging around without data or children. This condition 2042 * is actually pretty easy to detect, but ... should it really be removed? 2043 * Is a chain pointing to it? An iterator? Who knows! (Note that the 2044 * references structure member cannot be looked at because it is private to 2045 * rbtdb.) This is ugly and makes me unhappy, but after hours of trying to 2046 * make it more aesthetically proper and getting nowhere, this is the way it 2047 * is going to stay until such time as it proves to be a *real* problem. 2048 * 2049 * Finally, for reference, note that the original routine that did node 2050 * joining was called join_nodes(). It has been excised, living now only 2051 * in the CVS history, but comments have been left behind that point to it just 2052 * in case someone wants to muck with this some more. 2053 * 2054 * The one positive aspect of all of this is that joining used to have a 2055 * case where it might fail. Without trying to join, now this function always 2056 * succeeds. It still returns isc_result_t, though, so the API wouldn't change. 2057 */ 2058 isc_result_t 2059 dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, bool recurse) 2060 { 2061 dns_rbtnode_t *parent; 2062 2063 REQUIRE(VALID_RBT(rbt)); 2064 REQUIRE(DNS_RBTNODE_VALID(node)); 2065 INSIST(rbt->nodecount != 0); 2066 2067 if (DOWN(node) != NULL) { 2068 if (recurse) { 2069 PARENT(DOWN(node)) = NULL; 2070 deletetreeflat(rbt, 0, true, &DOWN(node)); 2071 } else { 2072 if (DATA(node) != NULL && rbt->data_deleter != NULL) 2073 rbt->data_deleter(DATA(node), rbt->deleter_arg); 2074 DATA(node) = NULL; 2075 2076 /* 2077 * Since there is at least one node below this one and 2078 * no recursion was requested, the deletion is 2079 * complete. The down node from this node might be all 2080 * by itself on a single level, so join_nodes() could 2081 * be used to collapse the tree (with all the caveats 2082 * of the comment at the start of this function). 2083 * But join_nodes() function has now been removed. 2084 */ 2085 return (ISC_R_SUCCESS); 2086 } 2087 } 2088 2089 /* 2090 * Note the node that points to the level of the node 2091 * that is being deleted. If the deleted node is the 2092 * top level, parent will be set to NULL. 2093 */ 2094 parent = get_upper_node(node); 2095 2096 /* 2097 * This node now has no down pointer, so now it needs 2098 * to be removed from this level. 2099 */ 2100 deletefromlevel(node, parent == NULL ? &rbt->root : &DOWN(parent)); 2101 2102 if (DATA(node) != NULL && rbt->data_deleter != NULL) 2103 rbt->data_deleter(DATA(node), rbt->deleter_arg); 2104 2105 unhash_node(rbt, node); 2106 #if DNS_RBT_USEMAGIC 2107 node->magic = 0; 2108 #endif 2109 isc_refcount_destroy(&node->references); 2110 2111 freenode(rbt, &node); 2112 2113 /* 2114 * This function never fails. 2115 */ 2116 return (ISC_R_SUCCESS); 2117 } 2118 2119 void 2120 dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name) { 2121 2122 REQUIRE(DNS_RBTNODE_VALID(node)); 2123 REQUIRE(name != NULL); 2124 REQUIRE(name->offsets == NULL); 2125 2126 NODENAME(node, name); 2127 } 2128 2129 isc_result_t 2130 dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) { 2131 dns_name_t current; 2132 isc_result_t result; 2133 2134 REQUIRE(DNS_RBTNODE_VALID(node)); 2135 REQUIRE(name != NULL); 2136 REQUIRE(name->buffer != NULL); 2137 2138 dns_name_init(¤t, NULL); 2139 dns_name_reset(name); 2140 2141 do { 2142 INSIST(node != NULL); 2143 2144 NODENAME(node, ¤t); 2145 2146 result = dns_name_concatenate(name, ¤t, name, NULL); 2147 if (result != ISC_R_SUCCESS) 2148 break; 2149 2150 node = get_upper_node(node); 2151 } while (! dns_name_isabsolute(name)); 2152 2153 return (result); 2154 } 2155 2156 char * 2157 dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size) 2158 { 2159 dns_fixedname_t fixedname; 2160 dns_name_t *name; 2161 isc_result_t result; 2162 2163 REQUIRE(DNS_RBTNODE_VALID(node)); 2164 REQUIRE(printname != NULL); 2165 2166 name = dns_fixedname_initname(&fixedname); 2167 result = dns_rbt_fullnamefromnode(node, name); 2168 if (result == ISC_R_SUCCESS) 2169 dns_name_format(name, printname, size); 2170 else 2171 snprintf(printname, size, "<error building name: %s>", 2172 dns_result_totext(result)); 2173 2174 return (printname); 2175 } 2176 2177 static isc_result_t 2178 create_node(isc_mem_t *mctx, const dns_name_t *name, dns_rbtnode_t **nodep) { 2179 dns_rbtnode_t *node; 2180 isc_region_t region; 2181 unsigned int labels; 2182 size_t nodelen; 2183 2184 REQUIRE(name->offsets != NULL); 2185 2186 dns_name_toregion(name, ®ion); 2187 labels = dns_name_countlabels(name); 2188 ENSURE(labels > 0); 2189 2190 /* 2191 * Allocate space for the node structure, the name, and the offsets. 2192 */ 2193 nodelen = sizeof(dns_rbtnode_t) + region.length + labels + 1; 2194 node = (dns_rbtnode_t *)isc_mem_get(mctx, nodelen); 2195 if (node == NULL) 2196 return (ISC_R_NOMEMORY); 2197 memset(node, 0, nodelen); 2198 2199 node->is_root = 0; 2200 PARENT(node) = NULL; 2201 RIGHT(node) = NULL; 2202 LEFT(node) = NULL; 2203 DOWN(node) = NULL; 2204 DATA(node) = NULL; 2205 node->is_mmapped = 0; 2206 node->down_is_relative = 0; 2207 node->left_is_relative = 0; 2208 node->right_is_relative = 0; 2209 node->parent_is_relative = 0; 2210 node->data_is_relative = 0; 2211 node->rpz = 0; 2212 2213 HASHNEXT(node) = NULL; 2214 HASHVAL(node) = 0; 2215 2216 ISC_LINK_INIT(node, deadlink); 2217 2218 LOCKNUM(node) = 0; 2219 WILD(node) = 0; 2220 DIRTY(node) = 0; 2221 isc_refcount_init(&node->references, 0); 2222 node->find_callback = 0; 2223 node->nsec = DNS_RBT_NSEC_NORMAL; 2224 2225 MAKE_BLACK(node); 2226 2227 /* 2228 * The following is stored to make reconstructing a name from the 2229 * stored value in the node easy: the length of the name, the number 2230 * of labels, whether the name is absolute or not, the name itself, 2231 * and the name's offsets table. 2232 * 2233 * XXX RTH 2234 * The offsets table could be made smaller by eliminating the 2235 * first offset, which is always 0. This requires changes to 2236 * lib/dns/name.c. 2237 * 2238 * Note: OLDOFFSETLEN *must* be assigned *after* OLDNAMELEN is assigned 2239 * as it uses OLDNAMELEN. 2240 */ 2241 OLDNAMELEN(node) = NAMELEN(node) = region.length; 2242 OLDOFFSETLEN(node) = OFFSETLEN(node) = labels; 2243 ATTRS(node) = name->attributes; 2244 2245 memmove(NAME(node), region.base, region.length); 2246 memmove(OFFSETS(node), name->offsets, labels); 2247 2248 #if DNS_RBT_USEMAGIC 2249 node->magic = DNS_RBTNODE_MAGIC; 2250 #endif 2251 *nodep = node; 2252 2253 return (ISC_R_SUCCESS); 2254 } 2255 2256 /* 2257 * Add a node to the hash table 2258 */ 2259 static inline void 2260 hash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node, const dns_name_t *name) { 2261 unsigned int hash; 2262 2263 REQUIRE(name != NULL); 2264 2265 HASHVAL(node) = dns_name_fullhash(name, false); 2266 2267 hash = HASHVAL(node) % rbt->hashsize; 2268 HASHNEXT(node) = rbt->hashtable[hash]; 2269 2270 rbt->hashtable[hash] = node; 2271 } 2272 2273 /* 2274 * Initialize hash table 2275 */ 2276 static isc_result_t 2277 inithash(dns_rbt_t *rbt) { 2278 unsigned int bytes; 2279 2280 rbt->hashsize = RBT_HASH_SIZE; 2281 bytes = (unsigned int)rbt->hashsize * sizeof(dns_rbtnode_t *); 2282 rbt->hashtable = isc_mem_get(rbt->mctx, bytes); 2283 2284 if (rbt->hashtable == NULL) 2285 return (ISC_R_NOMEMORY); 2286 2287 memset(rbt->hashtable, 0, bytes); 2288 2289 return (ISC_R_SUCCESS); 2290 } 2291 2292 /* 2293 * Rebuild the hashtable to reduce the load factor 2294 */ 2295 static void 2296 rehash(dns_rbt_t *rbt, unsigned int newcount) { 2297 unsigned int oldsize; 2298 dns_rbtnode_t **oldtable; 2299 dns_rbtnode_t *node; 2300 dns_rbtnode_t *nextnode; 2301 unsigned int hash; 2302 unsigned int i; 2303 2304 oldsize = (unsigned int)rbt->hashsize; 2305 oldtable = rbt->hashtable; 2306 do { 2307 INSIST((rbt->hashsize * 2 + 1) > rbt->hashsize); 2308 rbt->hashsize = rbt->hashsize * 2 + 1; 2309 } while (newcount >= (rbt->hashsize * 3)); 2310 rbt->hashtable = isc_mem_get(rbt->mctx, 2311 rbt->hashsize * sizeof(dns_rbtnode_t *)); 2312 if (rbt->hashtable == NULL) { 2313 rbt->hashtable = oldtable; 2314 rbt->hashsize = oldsize; 2315 return; 2316 } 2317 2318 for (i = 0; i < rbt->hashsize; i++) 2319 rbt->hashtable[i] = NULL; 2320 2321 for (i = 0; i < oldsize; i++) { 2322 for (node = oldtable[i]; node != NULL; node = nextnode) { 2323 hash = HASHVAL(node) % rbt->hashsize; 2324 nextnode = HASHNEXT(node); 2325 HASHNEXT(node) = rbt->hashtable[hash]; 2326 rbt->hashtable[hash] = node; 2327 } 2328 } 2329 2330 isc_mem_put(rbt->mctx, oldtable, oldsize * sizeof(dns_rbtnode_t *)); 2331 } 2332 2333 /* 2334 * Add a node to the hash table. Rehash the hashtable if the node count 2335 * rises above a critical level. 2336 */ 2337 static inline void 2338 hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, const dns_name_t *name) { 2339 REQUIRE(DNS_RBTNODE_VALID(node)); 2340 2341 if (rbt->nodecount >= (rbt->hashsize * 3)) 2342 rehash(rbt, rbt->nodecount); 2343 2344 hash_add_node(rbt, node, name); 2345 } 2346 2347 /* 2348 * Remove a node from the hash table 2349 */ 2350 static inline void 2351 unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) { 2352 unsigned int bucket; 2353 dns_rbtnode_t *bucket_node; 2354 2355 REQUIRE(DNS_RBTNODE_VALID(node)); 2356 2357 bucket = HASHVAL(node) % rbt->hashsize; 2358 bucket_node = rbt->hashtable[bucket]; 2359 2360 if (bucket_node == node) { 2361 rbt->hashtable[bucket] = HASHNEXT(node); 2362 } else { 2363 while (HASHNEXT(bucket_node) != node) { 2364 INSIST(HASHNEXT(bucket_node) != NULL); 2365 bucket_node = HASHNEXT(bucket_node); 2366 } 2367 HASHNEXT(bucket_node) = HASHNEXT(node); 2368 } 2369 } 2370 2371 static inline void 2372 rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp) { 2373 dns_rbtnode_t *child; 2374 2375 REQUIRE(DNS_RBTNODE_VALID(node)); 2376 REQUIRE(rootp != NULL); 2377 2378 child = RIGHT(node); 2379 INSIST(child != NULL); 2380 2381 RIGHT(node) = LEFT(child); 2382 if (LEFT(child) != NULL) 2383 PARENT(LEFT(child)) = node; 2384 LEFT(child) = node; 2385 2386 PARENT(child) = PARENT(node); 2387 2388 if (IS_ROOT(node)) { 2389 *rootp = child; 2390 child->is_root = 1; 2391 node->is_root = 0; 2392 2393 } else { 2394 if (LEFT(PARENT(node)) == node) 2395 LEFT(PARENT(node)) = child; 2396 else 2397 RIGHT(PARENT(node)) = child; 2398 } 2399 2400 PARENT(node) = child; 2401 } 2402 2403 static inline void 2404 rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) { 2405 dns_rbtnode_t *child; 2406 2407 REQUIRE(DNS_RBTNODE_VALID(node)); 2408 REQUIRE(rootp != NULL); 2409 2410 child = LEFT(node); 2411 INSIST(child != NULL); 2412 2413 LEFT(node) = RIGHT(child); 2414 if (RIGHT(child) != NULL) 2415 PARENT(RIGHT(child)) = node; 2416 RIGHT(child) = node; 2417 2418 PARENT(child) = PARENT(node); 2419 2420 if (IS_ROOT(node)) { 2421 *rootp = child; 2422 child->is_root = 1; 2423 node->is_root = 0; 2424 2425 } else { 2426 if (LEFT(PARENT(node)) == node) 2427 LEFT(PARENT(node)) = child; 2428 else 2429 RIGHT(PARENT(node)) = child; 2430 } 2431 2432 PARENT(node) = child; 2433 } 2434 2435 /* 2436 * This is the real workhorse of the insertion code, because it does the 2437 * true red/black tree on a single level. 2438 */ 2439 static void 2440 addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order, 2441 dns_rbtnode_t **rootp) 2442 { 2443 dns_rbtnode_t *child, *root, *parent, *grandparent; 2444 dns_name_t add_name, current_name; 2445 dns_offsets_t add_offsets, current_offsets; 2446 2447 REQUIRE(rootp != NULL); 2448 REQUIRE(DNS_RBTNODE_VALID(node) && LEFT(node) == NULL && 2449 RIGHT(node) == NULL); 2450 REQUIRE(current != NULL); 2451 2452 root = *rootp; 2453 if (root == NULL) { 2454 /* 2455 * First node of a level. 2456 */ 2457 MAKE_BLACK(node); 2458 node->is_root = 1; 2459 PARENT(node) = current; 2460 *rootp = node; 2461 return; 2462 } 2463 2464 child = root; 2465 POST(child); 2466 2467 dns_name_init(&add_name, add_offsets); 2468 NODENAME(node, &add_name); 2469 2470 dns_name_init(¤t_name, current_offsets); 2471 NODENAME(current, ¤t_name); 2472 2473 if (order < 0) { 2474 INSIST(LEFT(current) == NULL); 2475 LEFT(current) = node; 2476 } else { 2477 INSIST(RIGHT(current) == NULL); 2478 RIGHT(current) = node; 2479 } 2480 2481 INSIST(PARENT(node) == NULL); 2482 PARENT(node) = current; 2483 2484 MAKE_RED(node); 2485 2486 while (node != root && IS_RED(PARENT(node))) { 2487 /* 2488 * XXXDCL could do away with separate parent and grandparent 2489 * variables. They are vestiges of the days before parent 2490 * pointers. However, they make the code a little clearer. 2491 */ 2492 2493 parent = PARENT(node); 2494 grandparent = PARENT(parent); 2495 2496 if (parent == LEFT(grandparent)) { 2497 child = RIGHT(grandparent); 2498 if (child != NULL && IS_RED(child)) { 2499 MAKE_BLACK(parent); 2500 MAKE_BLACK(child); 2501 MAKE_RED(grandparent); 2502 node = grandparent; 2503 } else { 2504 if (node == RIGHT(parent)) { 2505 rotate_left(parent, &root); 2506 node = parent; 2507 parent = PARENT(node); 2508 grandparent = PARENT(parent); 2509 } 2510 MAKE_BLACK(parent); 2511 MAKE_RED(grandparent); 2512 rotate_right(grandparent, &root); 2513 } 2514 } else { 2515 child = LEFT(grandparent); 2516 if (child != NULL && IS_RED(child)) { 2517 MAKE_BLACK(parent); 2518 MAKE_BLACK(child); 2519 MAKE_RED(grandparent); 2520 node = grandparent; 2521 } else { 2522 if (node == LEFT(parent)) { 2523 rotate_right(parent, &root); 2524 node = parent; 2525 parent = PARENT(node); 2526 grandparent = PARENT(parent); 2527 } 2528 MAKE_BLACK(parent); 2529 MAKE_RED(grandparent); 2530 rotate_left(grandparent, &root); 2531 } 2532 } 2533 } 2534 2535 MAKE_BLACK(root); 2536 ENSURE(IS_ROOT(root)); 2537 *rootp = root; 2538 2539 return; 2540 } 2541 2542 /* 2543 * This is the real workhorse of the deletion code, because it does the 2544 * true red/black tree on a single level. 2545 */ 2546 static void 2547 deletefromlevel(dns_rbtnode_t *item, dns_rbtnode_t **rootp) { 2548 dns_rbtnode_t *child, *sibling, *parent; 2549 dns_rbtnode_t *successor; 2550 2551 REQUIRE(item != NULL); 2552 2553 /* 2554 * Verify that the parent history is (apparently) correct. 2555 */ 2556 INSIST((IS_ROOT(item) && *rootp == item) || 2557 (! IS_ROOT(item) && 2558 (LEFT(PARENT(item)) == item || 2559 RIGHT(PARENT(item)) == item))); 2560 2561 child = NULL; 2562 2563 if (LEFT(item) == NULL) { 2564 if (RIGHT(item) == NULL) { 2565 if (IS_ROOT(item)) { 2566 /* 2567 * This is the only item in the tree. 2568 */ 2569 *rootp = NULL; 2570 return; 2571 } 2572 } else 2573 /* 2574 * This node has one child, on the right. 2575 */ 2576 child = RIGHT(item); 2577 2578 } else if (RIGHT(item) == NULL) 2579 /* 2580 * This node has one child, on the left. 2581 */ 2582 child = LEFT(item); 2583 else { 2584 dns_rbtnode_t holder, *tmp = &holder; 2585 2586 /* 2587 * This node has two children, so it cannot be directly 2588 * deleted. Find its immediate in-order successor and 2589 * move it to this location, then do the deletion at the 2590 * old site of the successor. 2591 */ 2592 successor = RIGHT(item); 2593 while (LEFT(successor) != NULL) 2594 successor = LEFT(successor); 2595 2596 /* 2597 * The successor cannot possibly have a left child; 2598 * if there is any child, it is on the right. 2599 */ 2600 if (RIGHT(successor) != NULL) 2601 child = RIGHT(successor); 2602 2603 /* 2604 * Swap the two nodes; it would be simpler to just replace 2605 * the value being deleted with that of the successor, 2606 * but this rigamarole is done so the caller has complete 2607 * control over the pointers (and memory allocation) of 2608 * all of nodes. If just the key value were removed from 2609 * the tree, the pointer to the node would be unchanged. 2610 */ 2611 2612 /* 2613 * First, put the successor in the tree location of the 2614 * node to be deleted. Save its existing tree pointer 2615 * information, which will be needed when linking up 2616 * delete to the successor's old location. 2617 */ 2618 memmove(tmp, successor, sizeof(dns_rbtnode_t)); 2619 2620 if (IS_ROOT(item)) { 2621 *rootp = successor; 2622 successor->is_root = true; 2623 item->is_root = false; 2624 2625 } else 2626 if (LEFT(PARENT(item)) == item) 2627 LEFT(PARENT(item)) = successor; 2628 else 2629 RIGHT(PARENT(item)) = successor; 2630 2631 PARENT(successor) = PARENT(item); 2632 LEFT(successor) = LEFT(item); 2633 RIGHT(successor) = RIGHT(item); 2634 COLOR(successor) = COLOR(item); 2635 2636 if (LEFT(successor) != NULL) 2637 PARENT(LEFT(successor)) = successor; 2638 if (RIGHT(successor) != successor) 2639 PARENT(RIGHT(successor)) = successor; 2640 2641 /* 2642 * Now relink the node to be deleted into the 2643 * successor's previous tree location. PARENT(tmp) 2644 * is the successor's original parent. 2645 */ 2646 INSIST(! IS_ROOT(item)); 2647 2648 if (PARENT(tmp) == item) { 2649 /* 2650 * Node being deleted was successor's parent. 2651 */ 2652 RIGHT(successor) = item; 2653 PARENT(item) = successor; 2654 2655 } else { 2656 LEFT(PARENT(tmp)) = item; 2657 PARENT(item) = PARENT(tmp); 2658 } 2659 2660 /* 2661 * Original location of successor node has no left. 2662 */ 2663 LEFT(item) = NULL; 2664 RIGHT(item) = RIGHT(tmp); 2665 COLOR(item) = COLOR(tmp); 2666 } 2667 2668 /* 2669 * Remove the node by removing the links from its parent. 2670 */ 2671 if (! IS_ROOT(item)) { 2672 if (LEFT(PARENT(item)) == item) 2673 LEFT(PARENT(item)) = child; 2674 else 2675 RIGHT(PARENT(item)) = child; 2676 2677 if (child != NULL) 2678 PARENT(child) = PARENT(item); 2679 2680 } else { 2681 /* 2682 * This is the root being deleted, and at this point 2683 * it is known to have just one child. 2684 */ 2685 *rootp = child; 2686 child->is_root = 1; 2687 PARENT(child) = PARENT(item); 2688 } 2689 2690 /* 2691 * Fix color violations. 2692 */ 2693 if (IS_BLACK(item)) { 2694 /* cppcheck-suppress nullPointerRedundantCheck symbolName=item */ 2695 parent = PARENT(item); 2696 2697 while (child != *rootp && IS_BLACK(child)) { 2698 INSIST(child == NULL || ! IS_ROOT(child)); 2699 2700 if (LEFT(parent) == child) { 2701 sibling = RIGHT(parent); 2702 2703 if (IS_RED(sibling)) { 2704 MAKE_BLACK(sibling); 2705 MAKE_RED(parent); 2706 rotate_left(parent, rootp); 2707 sibling = RIGHT(parent); 2708 } 2709 2710 INSIST(sibling != NULL); 2711 2712 /* cppcheck-suppress nullPointerRedundantCheck symbolName=sibling */ 2713 if (IS_BLACK(LEFT(sibling)) && 2714 IS_BLACK(RIGHT(sibling))) { 2715 MAKE_RED(sibling); 2716 child = parent; 2717 2718 } else { 2719 2720 if (IS_BLACK(RIGHT(sibling))) { 2721 MAKE_BLACK(LEFT(sibling)); 2722 MAKE_RED(sibling); 2723 rotate_right(sibling, rootp); 2724 sibling = RIGHT(parent); 2725 } 2726 2727 COLOR(sibling) = COLOR(parent); 2728 MAKE_BLACK(parent); 2729 INSIST(RIGHT(sibling) != NULL); 2730 MAKE_BLACK(RIGHT(sibling)); 2731 rotate_left(parent, rootp); 2732 child = *rootp; 2733 } 2734 2735 } else { 2736 /* 2737 * Child is parent's right child. 2738 * Everything is done the same as above, 2739 * except mirrored. 2740 */ 2741 sibling = LEFT(parent); 2742 2743 if (IS_RED(sibling)) { 2744 MAKE_BLACK(sibling); 2745 MAKE_RED(parent); 2746 rotate_right(parent, rootp); 2747 sibling = LEFT(parent); 2748 } 2749 2750 INSIST(sibling != NULL); 2751 2752 /* cppcheck-suppress nullPointerRedundantCheck symbolName=sibling */ 2753 if (IS_BLACK(LEFT(sibling)) && 2754 IS_BLACK(RIGHT(sibling))) { 2755 MAKE_RED(sibling); 2756 child = parent; 2757 2758 } else { 2759 if (IS_BLACK(LEFT(sibling))) { 2760 MAKE_BLACK(RIGHT(sibling)); 2761 MAKE_RED(sibling); 2762 rotate_left(sibling, rootp); 2763 sibling = LEFT(parent); 2764 } 2765 2766 COLOR(sibling) = COLOR(parent); 2767 MAKE_BLACK(parent); 2768 INSIST(LEFT(sibling) != NULL); 2769 MAKE_BLACK(LEFT(sibling)); 2770 rotate_right(parent, rootp); 2771 child = *rootp; 2772 } 2773 } 2774 2775 parent = PARENT(child); 2776 } 2777 2778 if (IS_RED(child)) 2779 MAKE_BLACK(child); 2780 } 2781 } 2782 2783 static void 2784 freenode(dns_rbt_t *rbt, dns_rbtnode_t **nodep) { 2785 dns_rbtnode_t *node = *nodep; 2786 2787 if (node->is_mmapped == 0) { 2788 isc_mem_put(rbt->mctx, node, NODE_SIZE(node)); 2789 } 2790 *nodep = NULL; 2791 2792 rbt->nodecount--; 2793 } 2794 2795 static void 2796 deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, bool unhash, 2797 dns_rbtnode_t **nodep) 2798 { 2799 dns_rbtnode_t *root = *nodep; 2800 2801 while (root != NULL) { 2802 /* 2803 * If there is a left, right or down node, walk into it 2804 * and iterate. 2805 */ 2806 if (LEFT(root) != NULL) { 2807 dns_rbtnode_t *node = root; 2808 root = LEFT(root); 2809 LEFT(node) = NULL; 2810 } else if (RIGHT(root) != NULL) { 2811 dns_rbtnode_t *node = root; 2812 root = RIGHT(root); 2813 RIGHT(node) = NULL; 2814 } else if (DOWN(root) != NULL) { 2815 dns_rbtnode_t *node = root; 2816 root = DOWN(root); 2817 DOWN(node) = NULL; 2818 } else { 2819 /* 2820 * There are no left, right or down nodes, so we 2821 * can free this one and go back to its parent. 2822 */ 2823 dns_rbtnode_t *node = root; 2824 root = PARENT(root); 2825 2826 if (DATA(node) != NULL && rbt->data_deleter != NULL) 2827 rbt->data_deleter(DATA(node), 2828 rbt->deleter_arg); 2829 if (unhash) 2830 unhash_node(rbt, node); 2831 /* 2832 * Note: we don't call unhash_node() here as we 2833 * are destroying the complete RBT tree. 2834 */ 2835 #if DNS_RBT_USEMAGIC 2836 node->magic = 0; 2837 #endif 2838 freenode(rbt, &node); 2839 if (quantum != 0 && --quantum == 0) 2840 break; 2841 } 2842 } 2843 2844 *nodep = root; 2845 } 2846 2847 static size_t 2848 getheight_helper(dns_rbtnode_t *node) { 2849 size_t dl, dr; 2850 size_t this_height, down_height; 2851 2852 if (node == NULL) 2853 return (0); 2854 2855 dl = getheight_helper(LEFT(node)); 2856 dr = getheight_helper(RIGHT(node)); 2857 2858 this_height = ISC_MAX(dl + 1, dr + 1); 2859 down_height = getheight_helper(DOWN(node)); 2860 2861 return (ISC_MAX(this_height, down_height)); 2862 } 2863 2864 size_t 2865 dns__rbt_getheight(dns_rbt_t *rbt) { 2866 return (getheight_helper(rbt->root)); 2867 } 2868 2869 static bool 2870 check_properties_helper(dns_rbtnode_t *node) { 2871 if (node == NULL) 2872 return (true); 2873 2874 if (IS_RED(node)) { 2875 /* Root nodes must be BLACK. */ 2876 if (IS_ROOT(node)) 2877 return (false); 2878 2879 /* Both children of RED nodes must be BLACK. */ 2880 if (IS_RED(LEFT(node)) || IS_RED(RIGHT(node))) 2881 return (false); 2882 } 2883 2884 /* cppcheck-suppress nullPointerRedundantCheck symbolName=node */ 2885 if ((DOWN(node) != NULL) && (!IS_ROOT(DOWN(node)))) 2886 return (false); 2887 2888 if (IS_ROOT(node)) { 2889 if ((PARENT(node) != NULL) && 2890 (DOWN(PARENT(node)) != node)) 2891 return (false); 2892 2893 if (get_upper_node(node) != PARENT(node)) 2894 return (false); 2895 } 2896 2897 /* If node is assigned to the down_ pointer of its parent, it is 2898 * a subtree root and must have the flag set. 2899 */ 2900 if (((!PARENT(node)) || 2901 (DOWN(PARENT(node)) == node)) && 2902 (!IS_ROOT(node))) 2903 { 2904 return (false); 2905 } 2906 2907 /* Repeat tests with this node's children. */ 2908 return (check_properties_helper(LEFT(node)) && 2909 check_properties_helper(RIGHT(node)) && 2910 check_properties_helper(DOWN(node))); 2911 } 2912 2913 static bool 2914 check_black_distance_helper(dns_rbtnode_t *node, size_t *distance) { 2915 size_t dl, dr, dd; 2916 2917 if (node == NULL) { 2918 *distance = 1; 2919 return (true); 2920 } 2921 2922 /* cppcheck-suppress nullPointerRedundantCheck symbolName=node */ 2923 if (!check_black_distance_helper(LEFT(node), &dl)) 2924 return (false); 2925 2926 /* cppcheck-suppress nullPointerRedundantCheck symbolName=node */ 2927 if (!check_black_distance_helper(RIGHT(node), &dr)) 2928 return (false); 2929 2930 /* cppcheck-suppress nullPointerRedundantCheck symbolName=node */ 2931 if (!check_black_distance_helper(DOWN(node), &dd)) 2932 return (false); 2933 2934 /* Left and right side black node counts must match. */ 2935 if (dl != dr) 2936 return (false); 2937 2938 if (IS_BLACK(node)) 2939 dl++; 2940 2941 *distance = dl; 2942 2943 return (true); 2944 } 2945 2946 bool 2947 dns__rbt_checkproperties(dns_rbt_t *rbt) { 2948 size_t dd; 2949 2950 if (!check_properties_helper(rbt->root)) 2951 return (false); 2952 2953 /* Path from a given node to all its leaves must contain the 2954 * same number of BLACK child nodes. This is done separately 2955 * here instead of inside check_properties_helper() as 2956 * it would take (n log n) complexity otherwise. 2957 */ 2958 return (check_black_distance_helper(rbt->root, &dd)); 2959 } 2960 2961 static void 2962 dns_rbt_indent(FILE *f, int depth) { 2963 int i; 2964 2965 fprintf(f, "%4d ", depth); 2966 2967 for (i = 0; i < depth; i++) 2968 fprintf(f, "- "); 2969 } 2970 2971 void 2972 dns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f) { 2973 2974 if (n == NULL) { 2975 fprintf(f, "Null node\n"); 2976 return; 2977 } 2978 2979 fprintf(f, "Node info for nodename: "); 2980 printnodename(n, true, f); 2981 fprintf(f, "\n"); 2982 2983 fprintf(f, "n = %p\n", n); 2984 2985 fprintf(f, "Relative pointers: %s%s%s%s%s\n", 2986 (n->parent_is_relative == 1 ? " P" : ""), 2987 (n->right_is_relative == 1 ? " R" : ""), 2988 (n->left_is_relative == 1 ? " L" : ""), 2989 (n->down_is_relative == 1 ? " D" : ""), 2990 (n->data_is_relative == 1 ? " T" : "")); 2991 2992 fprintf(f, "node lock address = %u\n", n->locknum); 2993 2994 fprintf(f, "Parent: %p\n", n->parent); 2995 fprintf(f, "Right: %p\n", n->right); 2996 fprintf(f, "Left: %p\n", n->left); 2997 fprintf(f, "Down: %p\n", n->down); 2998 fprintf(f, "Data: %p\n", n->data); 2999 } 3000 3001 static void 3002 printnodename(dns_rbtnode_t *node, bool quoted, FILE *f) { 3003 isc_region_t r; 3004 dns_name_t name; 3005 char buffer[DNS_NAME_FORMATSIZE]; 3006 dns_offsets_t offsets; 3007 3008 r.length = NAMELEN(node); 3009 r.base = NAME(node); 3010 3011 dns_name_init(&name, offsets); 3012 dns_name_fromregion(&name, &r); 3013 3014 dns_name_format(&name, buffer, sizeof(buffer)); 3015 3016 if (quoted) 3017 fprintf(f, "\"%s\"", buffer); 3018 else 3019 fprintf(f, "%s", buffer); 3020 } 3021 3022 static void 3023 print_text_helper(dns_rbtnode_t *root, dns_rbtnode_t *parent, 3024 int depth, const char *direction, 3025 void (*data_printer)(FILE *, void *), FILE *f) 3026 { 3027 dns_rbt_indent(f, depth); 3028 3029 if (root != NULL) { 3030 printnodename(root, true, f); 3031 /* 3032 * Don't use IS_RED(root) as it tests for 'root != NULL' 3033 * and cppcheck produces false positives. 3034 */ 3035 fprintf(f, " (%s, %s", direction, 3036 COLOR(root) == RED ? "RED" : "BLACK"); 3037 3038 if ((! IS_ROOT(root) && PARENT(root) != parent) || 3039 ( IS_ROOT(root) && depth > 0 && 3040 DOWN(PARENT(root)) != root)) { 3041 3042 fprintf(f, " (BAD parent pointer! -> "); 3043 if (PARENT(root) != NULL) 3044 printnodename(PARENT(root), true, f); 3045 else 3046 fprintf(f, "NULL"); 3047 fprintf(f, ")"); 3048 } 3049 3050 fprintf(f, ")"); 3051 3052 if (root->data != NULL && data_printer != NULL) { 3053 fprintf(f, " data@%p: ", root->data); 3054 data_printer(f, root->data); 3055 } 3056 fprintf(f, "\n"); 3057 3058 depth++; 3059 3060 /* 3061 * Don't use IS_RED(root) as it tests for 'root != NULL' 3062 * and cppcheck produces false positives. 3063 */ 3064 if (COLOR(root) == RED && IS_RED(LEFT(root))) { 3065 fprintf(f, "** Red/Red color violation on left\n"); 3066 } 3067 print_text_helper(LEFT(root), root, depth, "left", 3068 data_printer, f); 3069 3070 /* 3071 * Don't use IS_RED(root) as cppcheck produces false positives. 3072 */ 3073 if (COLOR(root) == RED && IS_RED(RIGHT(root))) { 3074 fprintf(f, "** Red/Red color violation on right\n"); 3075 } 3076 print_text_helper(RIGHT(root), root, depth, "right", 3077 data_printer, f); 3078 3079 print_text_helper(DOWN(root), NULL, depth, "down", 3080 data_printer, f); 3081 } else { 3082 fprintf(f, "NULL (%s)\n", direction); 3083 } 3084 } 3085 3086 void 3087 dns_rbt_printtext(dns_rbt_t *rbt, 3088 void (*data_printer)(FILE *, void *), FILE *f) 3089 { 3090 REQUIRE(VALID_RBT(rbt)); 3091 3092 print_text_helper(rbt->root, NULL, 0, "root", data_printer, f); 3093 } 3094 3095 static int 3096 print_dot_helper(dns_rbtnode_t *node, unsigned int *nodecount, 3097 bool show_pointers, FILE *f) 3098 { 3099 unsigned int l, r, d; 3100 3101 if (node == NULL) 3102 return (0); 3103 3104 l = print_dot_helper(LEFT(node), nodecount, show_pointers, f); 3105 r = print_dot_helper(RIGHT(node), nodecount, show_pointers, f); 3106 d = print_dot_helper(DOWN(node), nodecount, show_pointers, f); 3107 3108 *nodecount += 1; 3109 3110 fprintf(f, "node%u[label = \"<f0> |<f1> ", *nodecount); 3111 printnodename(node, false, f); 3112 fprintf(f, "|<f2>"); 3113 3114 if (show_pointers) 3115 fprintf(f, "|<f3> n=%p|<f4> p=%p", node, PARENT(node)); 3116 3117 fprintf(f, "\"] ["); 3118 3119 if (IS_RED(node)) 3120 fprintf(f, "color=red"); 3121 else 3122 fprintf(f, "color=black"); 3123 3124 /* XXXMUKS: verify that IS_ROOT() indicates subtree root and not 3125 * forest root. 3126 */ 3127 if (IS_ROOT(node)) 3128 fprintf(f, ",penwidth=3"); 3129 3130 if (IS_EMPTY(node)) 3131 fprintf(f, ",style=filled,fillcolor=lightgrey"); 3132 3133 fprintf(f, "];\n"); 3134 3135 if (LEFT(node) != NULL) 3136 fprintf(f, "\"node%u\":f0 -> \"node%u\":f1;\n", *nodecount, l); 3137 3138 if (DOWN(node) != NULL) 3139 fprintf(f, "\"node%u\":f1 -> \"node%u\":f1 [penwidth=5];\n", 3140 *nodecount, d); 3141 3142 if (RIGHT(node) != NULL) 3143 fprintf(f, "\"node%u\":f2 -> \"node%u\":f1;\n", *nodecount, r); 3144 3145 return (*nodecount); 3146 } 3147 3148 void 3149 dns_rbt_printdot(dns_rbt_t *rbt, bool show_pointers, FILE *f) { 3150 unsigned int nodecount = 0; 3151 3152 REQUIRE(VALID_RBT(rbt)); 3153 3154 fprintf(f, "digraph g {\n"); 3155 fprintf(f, "node [shape = record,height=.1];\n"); 3156 print_dot_helper(rbt->root, &nodecount, show_pointers, f); 3157 fprintf(f, "}\n"); 3158 } 3159 3160 /* 3161 * Chain Functions 3162 */ 3163 3164 void 3165 dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx) { 3166 3167 REQUIRE(chain != NULL); 3168 3169 /* 3170 * Initialize 'chain'. 3171 */ 3172 chain->mctx = mctx; 3173 chain->end = NULL; 3174 chain->level_count = 0; 3175 chain->level_matches = 0; 3176 memset(chain->levels, 0, sizeof(chain->levels)); 3177 3178 chain->magic = CHAIN_MAGIC; 3179 } 3180 3181 isc_result_t 3182 dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name, 3183 dns_name_t *origin, dns_rbtnode_t **node) 3184 { 3185 isc_result_t result = ISC_R_SUCCESS; 3186 3187 REQUIRE(VALID_CHAIN(chain)); 3188 3189 if (node != NULL) 3190 *node = chain->end; 3191 3192 if (chain->end == NULL) 3193 return (ISC_R_NOTFOUND); 3194 3195 if (name != NULL) { 3196 NODENAME(chain->end, name); 3197 3198 if (chain->level_count == 0) { 3199 /* 3200 * Names in the top level tree are all absolute. 3201 * Always make 'name' relative. 3202 */ 3203 INSIST(dns_name_isabsolute(name)); 3204 3205 /* 3206 * This is cheaper than dns_name_getlabelsequence(). 3207 */ 3208 name->labels--; 3209 name->length--; 3210 name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; 3211 } 3212 } 3213 3214 if (origin != NULL) { 3215 if (chain->level_count > 0) { 3216 result = chain_name(chain, origin, false); 3217 } else { 3218 dns_name_copynf(dns_rootname, origin); 3219 } 3220 } 3221 3222 return (result); 3223 } 3224 3225 isc_result_t 3226 dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name, 3227 dns_name_t *origin) 3228 { 3229 dns_rbtnode_t *current, *previous, *predecessor; 3230 isc_result_t result = ISC_R_SUCCESS; 3231 bool new_origin = false; 3232 3233 REQUIRE(VALID_CHAIN(chain) && chain->end != NULL); 3234 3235 predecessor = NULL; 3236 3237 current = chain->end; 3238 3239 if (LEFT(current) != NULL) { 3240 /* 3241 * Moving left one then right as far as possible is the 3242 * previous node, at least for this level. 3243 */ 3244 current = LEFT(current); 3245 3246 while (RIGHT(current) != NULL) 3247 current = RIGHT(current); 3248 3249 predecessor = current; 3250 3251 } else { 3252 /* 3253 * No left links, so move toward the root. If at any point on 3254 * the way there the link from parent to child is a right 3255 * link, then the parent is the previous node, at least 3256 * for this level. 3257 */ 3258 while (! IS_ROOT(current)) { 3259 previous = current; 3260 current = PARENT(current); 3261 3262 if (RIGHT(current) == previous) { 3263 predecessor = current; 3264 break; 3265 } 3266 } 3267 } 3268 3269 if (predecessor != NULL) { 3270 /* 3271 * Found a predecessor node in this level. It might not 3272 * really be the predecessor, however. 3273 */ 3274 if (DOWN(predecessor) != NULL) { 3275 /* 3276 * The predecessor is really down at least one level. 3277 * Go down and as far right as possible, and repeat 3278 * as long as the rightmost node has a down pointer. 3279 */ 3280 do { 3281 /* 3282 * XXX DCL Need to do something about origins 3283 * here. See whether to go down, and if so 3284 * whether it is truly what Bob calls a 3285 * new origin. 3286 */ 3287 ADD_LEVEL(chain, predecessor); 3288 predecessor = DOWN(predecessor); 3289 3290 /* XXX DCL duplicated from above; clever 3291 * way to unduplicate? */ 3292 3293 while (RIGHT(predecessor) != NULL) 3294 predecessor = RIGHT(predecessor); 3295 } while (DOWN(predecessor) != NULL); 3296 3297 /* XXX DCL probably needs work on the concept */ 3298 if (origin != NULL) 3299 new_origin = true; 3300 } 3301 3302 } else if (chain->level_count > 0) { 3303 /* 3304 * Dang, didn't find a predecessor in this level. 3305 * Got to the root of this level without having traversed 3306 * any right links. Ascend the tree one level; the 3307 * node that points to this tree is the predecessor. 3308 */ 3309 INSIST(chain->level_count > 0 && IS_ROOT(current)); 3310 predecessor = chain->levels[--chain->level_count]; 3311 3312 /* XXX DCL probably needs work on the concept */ 3313 /* 3314 * Don't declare an origin change when the new origin is "." 3315 * at the top level tree, because "." is declared as the origin 3316 * for the second level tree. 3317 */ 3318 if (origin != NULL && 3319 (chain->level_count > 0 || OFFSETLEN(predecessor) > 1)) 3320 new_origin = true; 3321 } 3322 3323 if (predecessor != NULL) { 3324 chain->end = predecessor; 3325 3326 if (new_origin) { 3327 result = dns_rbtnodechain_current(chain, name, origin, 3328 NULL); 3329 if (result == ISC_R_SUCCESS) 3330 result = DNS_R_NEWORIGIN; 3331 3332 } else 3333 result = dns_rbtnodechain_current(chain, name, NULL, 3334 NULL); 3335 3336 } else 3337 result = ISC_R_NOMORE; 3338 3339 return (result); 3340 } 3341 3342 isc_result_t 3343 dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name, 3344 dns_name_t *origin) 3345 { 3346 dns_rbtnode_t *current, *successor; 3347 isc_result_t result = ISC_R_SUCCESS; 3348 bool new_origin = false; 3349 3350 REQUIRE(VALID_CHAIN(chain) && chain->end != NULL); 3351 3352 successor = NULL; 3353 3354 current = chain->end; 3355 3356 if (DOWN(current) != NULL) { 3357 /* 3358 * Don't declare an origin change when the new origin is "." 3359 * at the second level tree, because "." is already declared 3360 * as the origin for the top level tree. 3361 */ 3362 if (chain->level_count > 0 || 3363 OFFSETLEN(current) > 1) 3364 new_origin = true; 3365 3366 ADD_LEVEL(chain, current); 3367 current = DOWN(current); 3368 3369 while (LEFT(current) != NULL) 3370 current = LEFT(current); 3371 3372 successor = current; 3373 } 3374 3375 if (successor != NULL) { 3376 chain->end = successor; 3377 3378 /* 3379 * It is not necessary to use dns_rbtnodechain_current like 3380 * the other functions because this function will never 3381 * find a node in the topmost level. This is because the 3382 * root level will never be more than one name, and everything 3383 * in the megatree is a successor to that node, down at 3384 * the second level or below. 3385 */ 3386 3387 if (name != NULL) 3388 NODENAME(chain->end, name); 3389 3390 if (new_origin) { 3391 if (origin != NULL) 3392 result = chain_name(chain, origin, false); 3393 3394 if (result == ISC_R_SUCCESS) 3395 result = DNS_R_NEWORIGIN; 3396 3397 } else 3398 result = ISC_R_SUCCESS; 3399 3400 } else 3401 result = ISC_R_NOMORE; 3402 3403 return (result); 3404 } 3405 3406 isc_result_t 3407 dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name) { 3408 dns_rbtnode_t *current, *previous, *successor; 3409 isc_result_t result = ISC_R_SUCCESS; 3410 3411 REQUIRE(VALID_CHAIN(chain) && chain->end != NULL); 3412 3413 successor = NULL; 3414 3415 current = chain->end; 3416 3417 if (RIGHT(current) == NULL) { 3418 while (! IS_ROOT(current)) { 3419 previous = current; 3420 current = PARENT(current); 3421 3422 if (LEFT(current) == previous) { 3423 successor = current; 3424 break; 3425 } 3426 } 3427 } else { 3428 current = RIGHT(current); 3429 3430 while (LEFT(current) != NULL) 3431 current = LEFT(current); 3432 3433 successor = current; 3434 } 3435 3436 if (successor != NULL) { 3437 chain->end = successor; 3438 3439 if (name != NULL) 3440 NODENAME(chain->end, name); 3441 3442 result = ISC_R_SUCCESS; 3443 } else 3444 result = ISC_R_NOMORE; 3445 3446 return (result); 3447 } 3448 3449 isc_result_t 3450 dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name, 3451 dns_name_t *origin) 3452 { 3453 dns_rbtnode_t *current, *previous, *successor; 3454 isc_result_t result = ISC_R_SUCCESS; 3455 bool new_origin = false; 3456 3457 REQUIRE(VALID_CHAIN(chain) && chain->end != NULL); 3458 3459 successor = NULL; 3460 3461 current = chain->end; 3462 3463 /* 3464 * If there is a level below this node, the next node is the leftmost 3465 * node of the next level. 3466 */ 3467 if (DOWN(current) != NULL) { 3468 /* 3469 * Don't declare an origin change when the new origin is "." 3470 * at the second level tree, because "." is already declared 3471 * as the origin for the top level tree. 3472 */ 3473 if (chain->level_count > 0 || 3474 OFFSETLEN(current) > 1) 3475 new_origin = true; 3476 3477 ADD_LEVEL(chain, current); 3478 current = DOWN(current); 3479 3480 while (LEFT(current) != NULL) 3481 current = LEFT(current); 3482 3483 successor = current; 3484 3485 } else if (RIGHT(current) == NULL) { 3486 /* 3487 * The successor is up, either in this level or a previous one. 3488 * Head back toward the root of the tree, looking for any path 3489 * that was via a left link; the successor is the node that has 3490 * that left link. In the event the root of the level is 3491 * reached without having traversed any left links, ascend one 3492 * level and look for either a right link off the point of 3493 * ascent, or search for a left link upward again, repeating 3494 * ascends until either case is true. 3495 */ 3496 do { 3497 while (! IS_ROOT(current)) { 3498 previous = current; 3499 current = PARENT(current); 3500 3501 if (LEFT(current) == previous) { 3502 successor = current; 3503 break; 3504 } 3505 } 3506 3507 if (successor == NULL) { 3508 /* 3509 * Reached the root without having traversed 3510 * any left pointers, so this level is done. 3511 */ 3512 if (chain->level_count == 0) { 3513 /* 3514 * If the tree we are iterating over 3515 * was modified since this chain was 3516 * initialized in a way that caused 3517 * node splits to occur, "current" may 3518 * now be pointing to a root node which 3519 * appears to be at level 0, but still 3520 * has a parent. If that happens, 3521 * abort. Otherwise, we are done 3522 * looking for a successor as we really 3523 * reached the root node on level 0. 3524 */ 3525 INSIST(PARENT(current) == NULL); 3526 break; 3527 } 3528 3529 current = chain->levels[--chain->level_count]; 3530 new_origin = true; 3531 3532 if (RIGHT(current) != NULL) 3533 break; 3534 } 3535 } while (successor == NULL); 3536 } 3537 3538 if (successor == NULL && RIGHT(current) != NULL) { 3539 current = RIGHT(current); 3540 3541 while (LEFT(current) != NULL) 3542 current = LEFT(current); 3543 3544 successor = current; 3545 } 3546 3547 if (successor != NULL) { 3548 /* 3549 * If we determine that the current node is the successor to 3550 * itself, we will run into an infinite loop, so abort instead. 3551 */ 3552 INSIST(chain->end != successor); 3553 3554 chain->end = successor; 3555 3556 /* 3557 * It is not necessary to use dns_rbtnodechain_current like 3558 * the other functions because this function will never 3559 * find a node in the topmost level. This is because the 3560 * root level will never be more than one name, and everything 3561 * in the megatree is a successor to that node, down at 3562 * the second level or below. 3563 */ 3564 3565 if (name != NULL) 3566 NODENAME(chain->end, name); 3567 3568 if (new_origin) { 3569 if (origin != NULL) 3570 result = chain_name(chain, origin, false); 3571 3572 if (result == ISC_R_SUCCESS) 3573 result = DNS_R_NEWORIGIN; 3574 3575 } else 3576 result = ISC_R_SUCCESS; 3577 3578 } else 3579 result = ISC_R_NOMORE; 3580 3581 return (result); 3582 } 3583 3584 isc_result_t 3585 dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt, 3586 dns_name_t *name, dns_name_t *origin) 3587 3588 { 3589 isc_result_t result; 3590 3591 REQUIRE(VALID_RBT(rbt)); 3592 REQUIRE(VALID_CHAIN(chain)); 3593 3594 dns_rbtnodechain_reset(chain); 3595 3596 chain->end = rbt->root; 3597 3598 result = dns_rbtnodechain_current(chain, name, origin, NULL); 3599 3600 if (result == ISC_R_SUCCESS) 3601 result = DNS_R_NEWORIGIN; 3602 3603 return (result); 3604 } 3605 3606 isc_result_t 3607 dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt, 3608 dns_name_t *name, dns_name_t *origin) 3609 3610 { 3611 isc_result_t result; 3612 3613 REQUIRE(VALID_RBT(rbt)); 3614 REQUIRE(VALID_CHAIN(chain)); 3615 3616 dns_rbtnodechain_reset(chain); 3617 3618 result = move_chain_to_last(chain, rbt->root); 3619 if (result != ISC_R_SUCCESS) 3620 return (result); 3621 3622 result = dns_rbtnodechain_current(chain, name, origin, NULL); 3623 3624 if (result == ISC_R_SUCCESS) 3625 result = DNS_R_NEWORIGIN; 3626 3627 return (result); 3628 } 3629 3630 3631 void 3632 dns_rbtnodechain_reset(dns_rbtnodechain_t *chain) { 3633 3634 REQUIRE(VALID_CHAIN(chain)); 3635 3636 /* 3637 * Free any dynamic storage associated with 'chain', and then 3638 * reinitialize 'chain'. 3639 */ 3640 chain->end = NULL; 3641 chain->level_count = 0; 3642 chain->level_matches = 0; 3643 } 3644 3645 void 3646 dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain) { 3647 /* 3648 * Free any dynamic storage associated with 'chain', and then 3649 * invalidate 'chain'. 3650 */ 3651 3652 dns_rbtnodechain_reset(chain); 3653 3654 chain->magic = 0; 3655 } 3656 3657 /* XXXMUKS: 3658 * 3659 * - worth removing inline as static functions are inlined automatically 3660 * where suitable by modern compilers. 3661 * - bump the size of dns_rbt.nodecount to size_t. 3662 * - the dumpfile header also contains a nodecount that is unsigned 3663 * int. If large files (> 2^32 nodes) are to be supported, the 3664 * allocation for this field should be increased. 3665 */ 3666