rbt.c revision 5d79b60fc5e4dad4f04da39570517d20a2425f8b
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews/*
7d32c065c7bb56f281651ae3dd2888f32ce4f1d9Bob Halley * Copyright (C) 2004, 2005, 2007-2009, 2011-2015 Internet Systems Consortium, Inc. ("ISC")
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Copyright (C) 1999-2003 Internet Software Consortium.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews *
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Permission to use, copy, modify, and/or distribute this software for any
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * purpose with or without fee is hereby granted, provided that the above
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * copyright notice and this permission notice appear in all copies.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews *
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * PERFORMANCE OF THIS SOFTWARE.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence/*! \file */
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff/* Principal Authors: DCL */
de153390f5a1f6d4fa86af91d4cae772d9846ca0Mark Andrews
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff#include <config.h>
822f6cdabb1edd44472c7a758b5cae71376fa9beBrian Wellington
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#include <sys/stat.h>
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#ifdef HAVE_INTTYPES_H
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence#include <inttypes.h> /* uintptr_t */
973a19342597823f111fce6a8cd5adfd0e2e7c0dMark Andrews#endif
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#include <isc/crc64.h>
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#include <isc/file.h>
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#include <isc/hex.h>
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#include <isc/mem.h>
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#include <isc/platform.h>
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#include <isc/print.h>
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews#include <isc/refcount.h>
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#include <isc/socket.h>
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews#include <isc/stdio.h>
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#include <isc/string.h>
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews#include <isc/util.h>
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson/*%
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson * This define is so dns/name.h (included by dns/fixedname.h) uses more
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * efficient macro calls instead of functions for a few operations.
eb6bd543c7d072efdca509eb17f8f301c1467b53Mark Andrews */
600cfa2ba4c50017581b6c14e3a688a82ecebbe0David Lawrence#define DNS_NAME_USEINLINE 1
600cfa2ba4c50017581b6c14e3a688a82ecebbe0David Lawrence
600cfa2ba4c50017581b6c14e3a688a82ecebbe0David Lawrence#include <dns/fixedname.h>
eb6bd543c7d072efdca509eb17f8f301c1467b53Mark Andrews#include <dns/log.h>
deaaf94332abbfdb3aff53675546acfed16e5eb6Mark Andrews#include <dns/rbt.h>
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#include <dns/result.h>
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#include <dns/version.h>
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#include <unistd.h>
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#define CHECK(x) \
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence do { \
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence result = (x); \
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence if (result != ISC_R_SUCCESS) \
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence goto cleanup; \
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence } while (0)
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#define RBT_MAGIC ISC_MAGIC('R', 'B', 'T', '+')
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#define VALID_RBT(rbt) ISC_MAGIC_VALID(rbt, RBT_MAGIC)
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence/*
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * XXXDCL Since parent pointers were added in again, I could remove all of the
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode,
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * _lastnode. This would involve pretty major change to the API.
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#define CHAIN_MAGIC ISC_MAGIC('0', '-', '0', '-')
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#define VALID_CHAIN(chain) ISC_MAGIC_VALID(chain, CHAIN_MAGIC)
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#define RBT_HASH_SIZE 64
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#ifdef RBT_MEM_TEST
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#undef RBT_HASH_SIZE
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson#endif
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafssonstruct dns_rbt {
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson unsigned int magic;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson isc_mem_t * mctx;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson dns_rbtnode_t * root;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson void (*data_deleter)(void *, void *);
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson void * deleter_arg;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson unsigned int nodecount;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence size_t hashsize;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson dns_rbtnode_t ** hashtable;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson void * mmap_location;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence};
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence#define RED 0
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence#define BLACK 1
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence/*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * This is the header for map-format RBT images. It is populated,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * and then written, as the LAST thing done to the file before returning.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * Writing this last (with zeros in the header area initially) will ensure
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * that the header is only valid when the RBT image is also valid.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencetypedef struct file_header file_header_t;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence/* Pad to 32 bytes */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencestatic char FILE_VERSION[32] = "\0";
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence/* Header length, always the same size regardless of structure size */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence#define HEADER_LENGTH 1024
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencestruct file_header {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence char version1[32];
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_uint64_t first_node_offset; /* usually 1024 */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * information about the system on which the map file was generated
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * will be used to tell if we can load the map file or not
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_uint32_t ptrsize;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence unsigned int bigendian:1; /* big or little endian system */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence unsigned int rdataset_fixed:1; /* compiled with --enable-rrset-fixed */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence unsigned int nodecount; /* shadow from rbt structure */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_uint64_t crc;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence char version2[32]; /* repeated; must match version1 */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence};
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence/*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * The following declarations are for the serialization of an RBT:
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence *
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * step one: write out a zeroed header of 1024 bytes
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * step two: walk the tree in a depth-first, left-right-down order, writing
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * out the nodes, reserving space as we go, correcting addresses to point
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * at the proper offset in the file, and setting a flag for each pointer to
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * indicate that it is a reference to a location in the file, rather than in
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * memory.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * step three: write out the header, adding the information that will be
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * needed to re-create the tree object itself.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence *
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * The RBTDB object will do this three times, once for each of the three
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * RBT objects it contains.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence *
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * Note: 'file' must point an actual open file that can be mmapped
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * and fseeked, not to a pipe or stream
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencestatic isc_result_t
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencedns_rbt_zero_header(FILE *file);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencestatic isc_result_t
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencewrite_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_uint64_t crc);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencestatic isc_result_t
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrenceserialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence uintptr_t right, uintptr_t down, uintptr_t parent,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence uintptr_t data, isc_uint64_t *crc);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencestatic isc_result_t
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrenceserialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence dns_rbtdatawriter_t datawriter, void *writer_arg,
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence uintptr_t *where, isc_uint64_t *crc);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence/*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * The following functions allow you to get the actual address of a pointer
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * without having to use an if statement to check to see if that address is
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * relative or not
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencestatic inline dns_rbtnode_t *
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencegetparent(dns_rbtnode_t *node, file_header_t *header) {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence char *adjusted_address = (char *)(node->parent);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence adjusted_address += node->parent_is_relative * (uintptr_t)header;
7ab0e69f61e61e81d489c95c7ebd981e74e7ef16Andreas Gustafsson
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews return ((dns_rbtnode_t *)adjusted_address);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews}
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsstatic inline dns_rbtnode_t *
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsgetleft(dns_rbtnode_t *node, file_header_t *header) {
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews char *adjusted_address = (char *)(node->left);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews adjusted_address += node->left_is_relative * (uintptr_t)header;
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews return ((dns_rbtnode_t *)adjusted_address);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews}
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsstatic inline dns_rbtnode_t *
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsgetright(dns_rbtnode_t *node, file_header_t *header) {
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews char *adjusted_address = (char *)(node->right);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews adjusted_address += node->right_is_relative * (uintptr_t)header;
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews return ((dns_rbtnode_t *)adjusted_address);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews}
f6407f9a0b890bebbfd5f738d9c4aef3d3315fe9Michael Graff
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsstatic inline dns_rbtnode_t *
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsgetdown(dns_rbtnode_t *node, file_header_t *header) {
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews char *adjusted_address = (char *)(node->down);
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews adjusted_address += node->down_is_relative * (uintptr_t)header;
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return ((dns_rbtnode_t *)adjusted_address);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
bed8e84810a80dad3d37870be927d1dfd015f480Mark Andrewsstatic inline dns_rbtnode_t *
bed8e84810a80dad3d37870be927d1dfd015f480Mark Andrewsgetdata(dns_rbtnode_t *node, file_header_t *header) {
bed8e84810a80dad3d37870be927d1dfd015f480Mark Andrews char *adjusted_address = (char *)(node->data);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews adjusted_address += node->data_is_relative * (uintptr_t)header;
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews return ((dns_rbtnode_t *)adjusted_address);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews}
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews/*%
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews * Elements of the rbtnode structure.
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews */
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#define PARENT(node) ((node)->parent)
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#define LEFT(node) ((node)->left)
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#define RIGHT(node) ((node)->right)
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#define DOWN(node) ((node)->down)
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#ifdef DNS_RBT_USEHASH
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#define UPPERNODE(node) ((node)->uppernode)
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#endif /* DNS_RBT_USEHASH */
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#define DATA(node) ((node)->data)
613991eef6bb79b9703382aff26cddd0281da915Bob Halley#define IS_EMPTY(node) ((node)->data == NULL)
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#define HASHNEXT(node) ((node)->hashnext)
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#define HASHVAL(node) ((node)->hashval)
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#define COLOR(node) ((node)->color)
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#define NAMELEN(node) ((node)->namelen)
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#define OLDNAMELEN(node) ((node)->oldnamelen)
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#define OFFSETLEN(node) ((node)->offsetlen)
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#define ATTRS(node) ((node)->attributes)
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#define IS_ROOT(node) ISC_TF((node)->is_root == 1)
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#define FINDCALLBACK(node) ISC_TF((node)->find_callback == 1)
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington/*%
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington * Structure elements from the rbtdb.c, not
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews * used as part of the rbt.c algorithms.
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews */
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews#define DIRTY(node) ((node)->dirty)
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews#define WILD(node) ((node)->wild)
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews#define LOCKNUM(node) ((node)->locknum)
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews/*%
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews * The variable length stuff stored after the node has the following
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * structure.
bcd7fdf06ca76eb2f6eb157f56b612c503e062a7Mark Andrews *
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews * <name_data>{1..255}<oldoffsetlen>{1}<offsets>{1..128}
bcd7fdf06ca76eb2f6eb157f56b612c503e062a7Mark Andrews *
bcd7fdf06ca76eb2f6eb157f56b612c503e062a7Mark Andrews * <name_data> contains the name of the node when it was created.
bcd7fdf06ca76eb2f6eb157f56b612c503e062a7Mark Andrews * <oldoffsetlen> contains the length of <offsets> when the node was created.
bcd7fdf06ca76eb2f6eb157f56b612c503e062a7Mark Andrews * <offsets> contains the offets into name for each label when the node was
bcd7fdf06ca76eb2f6eb157f56b612c503e062a7Mark Andrews * created.
bcd7fdf06ca76eb2f6eb157f56b612c503e062a7Mark Andrews */
bcd7fdf06ca76eb2f6eb157f56b612c503e062a7Mark Andrews
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews#define NAME(node) ((unsigned char *)((node) + 1))
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews#define OFFSETS(node) (NAME(node) + OLDNAMELEN(node) + 1)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#define OLDOFFSETLEN(node) (OFFSETS(node)[-1])
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#define NODE_SIZE(node) (sizeof(*node) + \
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson OLDNAMELEN(node) + OLDOFFSETLEN(node) + 1)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson/*%
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Color management.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson */
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#define IS_RED(node) ((node) != NULL && (node)->color == RED)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#define IS_BLACK(node) ((node) == NULL || (node)->color == BLACK)
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews#define MAKE_RED(node) ((node)->color = RED)
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff#define MAKE_BLACK(node) ((node)->color = BLACK)
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence/*%
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * Chain management.
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff *
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff * The "ancestors" member of chains were removed, with their job now
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington * being wholly handled by parent pointers (which didn't exist, because
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington * of memory concerns, when chains were first implemented).
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff */
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff#define ADD_LEVEL(chain, node) \
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff do { \
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson INSIST((chain)->level_count < DNS_RBT_LEVELBLOCK); \
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson (chain)->levels[(chain)->level_count++] = (node); \
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence } while (0)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson/*%
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * The following macros directly access normally private name variables.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * These macros are used to avoid a lot of function calls in the critical
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * path of the tree traversal code.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson */
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonstatic inline void
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas GustafssonNODENAME(dns_rbtnode_t *node, dns_name_t *name) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->length = NAMELEN(node);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->labels = OFFSETLEN(node);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->ndata = NAME(node);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->offsets = OFFSETS(node);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->attributes = ATTRS(node);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->attributes |= DNS_NAMEATTR_READONLY;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson}
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonvoid
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssondns_rbtnode_nodename(dns_rbtnode_t *node, dns_name_t *name) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->length = NAMELEN(node);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->labels = OFFSETLEN(node);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->ndata = NAME(node);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->offsets = OFFSETS(node);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->attributes = ATTRS(node);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson name->attributes |= DNS_NAMEATTR_READONLY;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson}
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssondns_rbtnode_t *
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssondns_rbt_root(dns_rbt_t *rbt) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson return rbt->root;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson}
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#ifdef DNS_RBT_USEHASH
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonstatic isc_result_t
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssoninithash(dns_rbt_t *rbt);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#endif
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#ifdef DEBUG
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#define inline
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews/*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * A little something to help out in GDB.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsdns_name_t Name(dns_rbtnode_t *node);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsdns_name_t
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark AndrewsName(dns_rbtnode_t *node) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_name_t name;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_name_init(&name, NULL);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley if (node != NULL)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews NODENAME(node, &name);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (name);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic void
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewshexdump(const char *desc, unsigned char *data, size_t size) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews char hexdump[BUFSIZ * 2 + 1];
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_buffer_t b;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_region_t r;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_result_t result;
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews size_t bytes;
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews fprintf(stderr, "%s: ", desc);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews do {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_buffer_init(&b, hexdump, sizeof(hexdump));
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews r.base = data;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews r.length = bytes = (size > BUFSIZ) ? BUFSIZ : size;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = isc_hex_totext(&r, 0, "", &b);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley RUNTIME_CHECK(result == ISC_R_SUCCESS);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley isc_buffer_putuint8(&b, 0);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews fprintf(stderr, "%s", hexdump);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews data += bytes;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews size -= bytes;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews } while (size > 0);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews fprintf(stderr, "\n");
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews}
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews#endif /* DEBUG */
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews#ifdef DNS_RBT_USEHASH
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews/* Upper node is the parent of the root of the passed node's
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews * subtree. The passed node must not be NULL.
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic inline dns_rbtnode_t *
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsget_upper_node(dns_rbtnode_t *node) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (UPPERNODE(node));
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic void
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsfixup_uppernodes_helper(dns_rbtnode_t *node, dns_rbtnode_t *uppernode) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (node == NULL)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return;
d981ca645597116d227a48bf37cc5edc061c854dBob Halley
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews UPPERNODE(node) = uppernode;
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews fixup_uppernodes_helper(LEFT(node), uppernode);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews fixup_uppernodes_helper(RIGHT(node), uppernode);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews fixup_uppernodes_helper(DOWN(node), node);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews/*
d981ca645597116d227a48bf37cc5edc061c854dBob Halley * This function is used to fixup uppernode members of all dns_rbtnodes
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * after deserialization.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic void
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsfixup_uppernodes(dns_rbt_t *rbt) {
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence fixup_uppernodes_helper(rbt->root, NULL);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews}
19d365e4448f1782611280b020987988b7ac3210Mark Andrews
19d365e4448f1782611280b020987988b7ac3210Mark Andrews#else
19d365e4448f1782611280b020987988b7ac3210Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews/* The passed node must not be NULL. */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic inline dns_rbtnode_t *
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsget_subtree_root(dns_rbtnode_t *node) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews while (!IS_ROOT(node)) {
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff node = PARENT(node);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley }
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews return (node);
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews}
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff/* Upper node is the parent of the root of the passed node's
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * subtree. The passed node must not be NULL.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic inline dns_rbtnode_t *
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrewsget_upper_node(dns_rbtnode_t *node) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_rbtnode_t *root = get_subtree_root(node);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews
19d365e4448f1782611280b020987988b7ac3210Mark Andrews /*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Return the node in the level above the argument node that points
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * to the level the argument node is in. If the argument node is in
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews * the top level, the return value is NULL.
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (PARENT(root));
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews#endif /* DNS_RBT_USEHASH */
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewssize_t
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencedns__rbtnode_getdistance(dns_rbtnode_t *node) {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence size_t nodes = 1;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff while (node != NULL) {
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews if (IS_ROOT(node))
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews break;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff nodes++;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews node = PARENT(node);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (nodes);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews/*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Forward declarations.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic isc_result_t
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewscreate_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#ifdef DNS_RBT_USEHASH
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrewsstatic inline void
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrewshash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graffstatic inline void
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrewsunhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node);
f0a5bb8f86631ce638cb2b6c65bbb9bcf9b0cdc0Bob Halleystatic void
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrewsrehash(dns_rbt_t *rbt, unsigned int newcount);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#else
19d365e4448f1782611280b020987988b7ac3210Mark Andrews#define hash_node(rbt, node, name)
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence#define unhash_node(rbt, node)
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews#define rehash(rbt, newcount)
19d365e4448f1782611280b020987988b7ac3210Mark Andrews#endif
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic inline void
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrewsrotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrencestatic inline void
f0a5bb8f86631ce638cb2b6c65bbb9bcf9b0cdc0Bob Halleyrotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
f0a5bb8f86631ce638cb2b6c65bbb9bcf9b0cdc0Bob Halleystatic void
f0a5bb8f86631ce638cb2b6c65bbb9bcf9b0cdc0Bob Halleyaddonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff dns_rbtnode_t **rootp);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graffstatic void
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrewsdeletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp);
7c0378745269fe49a05904935afc42b85528f53aDavid Lawrence
7c0378745269fe49a05904935afc42b85528f53aDavid Lawrencestatic isc_result_t
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrewstreefix(dns_rbt_t *rbt, void *base, size_t size,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_rbtnode_t *n, dns_name_t *name,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_rbtdatafixer_t datafixer, void *fixer_arg,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_uint64_t *crc);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff
d981ca645597116d227a48bf37cc5edc061c854dBob Halleystatic void
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrewsdeletetreeflat(dns_rbt_t *rbt, unsigned int quantum, isc_boolean_t unhash,
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews dns_rbtnode_t **nodep);
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrewsstatic void
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graffprintnodename(dns_rbtnode_t *node, isc_boolean_t quoted, FILE *f);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic void
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrewsfreenode(dns_rbt_t *rbt, dns_rbtnode_t **nodep);
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
f305d86668bfd4d4727c3e0f70e7e97a2fa1b772Bob Halleystatic isc_result_t
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafssondns_rbt_zero_header(FILE *file) {
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews /*
20b20b23948b90cb2f7d7f402da99d09f837efd0David Lawrence * Write out a zeroed header as a placeholder. Doing this ensures
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * that the file will not read while it is partially written, should
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews * writing fail or be interrupted.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence char buffer[HEADER_LENGTH];
19d365e4448f1782611280b020987988b7ac3210Mark Andrews isc_result_t result;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff memset(buffer, 0, HEADER_LENGTH);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = isc_stdio_write(buffer, 1, HEADER_LENGTH, file, NULL);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (result != ISC_R_SUCCESS)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (result);
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews result = fflush(file);
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews if (result != ISC_R_SUCCESS)
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews return (result);
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews return (ISC_R_SUCCESS);
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews}
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews/*
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * Write out the real header, including NodeDump version information
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews * and the offset of the first node.
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews *
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews * Any information stored in the rbt object itself should be stored
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * here.
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews */
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrewsstatic isc_result_t
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrewswrite_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset,
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews isc_uint64_t crc)
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews{
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews file_header_t header;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff isc_result_t result;
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews off_t location;
035504dbd8ca5949e8380b860873b3385a4e61e5Mark Andrews
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff if (FILE_VERSION[0] == '\0') {
035504dbd8ca5949e8380b860873b3385a4e61e5Mark Andrews memset(FILE_VERSION, 0, sizeof(FILE_VERSION));
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews snprintf(FILE_VERSION, sizeof(FILE_VERSION),
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff "RBT Image %s %s", dns_major, dns_mapapi);
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews }
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews memset(&header, 0, sizeof(file_header_t));
c0d0a59d1b665423b8a0d1829d0f0da121cb3473Andreas Gustafsson memmove(header.version1, FILE_VERSION, sizeof(header.version1));
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews memmove(header.version2, FILE_VERSION, sizeof(header.version2));
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff header.first_node_offset = first_node_offset;
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews header.ptrsize = (isc_uint32_t) sizeof(void *);
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews header.bigendian = (1 == htonl(1)) ? 1 : 0;
fdd04623a6a36aad8449ef0877d8801a558873b8Mark Andrews
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews#ifdef DNS_RDATASET_FIXED
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews header.rdataset_fixed = 1;
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews#else
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews header.rdataset_fixed = 0;
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews#endif
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff header.nodecount = rbt->nodecount;
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews header.crc = crc;
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews CHECK(isc_stdio_tell(file, &location));
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews location = dns_rbt_serialize_align(location);
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews CHECK(isc_stdio_seek(file, location, SEEK_SET));
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff CHECK(isc_stdio_write(&header, 1, sizeof(file_header_t), file, NULL));
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews CHECK(fflush(file));
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews /* Ensure we are always at the end of the file. */
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews CHECK(isc_stdio_seek(file, 0, SEEK_END));
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews cleanup:
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (result);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
d981ca645597116d227a48bf37cc5edc061c854dBob Halleystatic isc_result_t
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsserialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left,
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff uintptr_t right, uintptr_t down, uintptr_t parent,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews uintptr_t data, isc_uint64_t *crc)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews{
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_rbtnode_t temp_node;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews off_t file_position;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews unsigned char *node_data;
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff size_t datasize;
ae70d32b67cf30e06553c01479e71c87b21d984cBob Halley isc_result_t result;
ae70d32b67cf30e06553c01479e71c87b21d984cBob Halley#ifdef DEBUG
19d365e4448f1782611280b020987988b7ac3210Mark Andrews dns_name_t nodename;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff#endif
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews INSIST(node != NULL);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence CHECK(isc_stdio_tell(file, &file_position));
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence file_position = dns_rbt_serialize_align(file_position);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews CHECK(isc_stdio_seek(file, file_position, SEEK_SET));
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence temp_node = *node;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence temp_node.down_is_relative = 0;
f8aae502686e2448c48f56697c212a50e2a1cbaeAndreas Gustafsson temp_node.left_is_relative = 0;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff temp_node.right_is_relative = 0;
f8aae502686e2448c48f56697c212a50e2a1cbaeAndreas Gustafsson temp_node.parent_is_relative = 0;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews temp_node.data_is_relative = 0;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews temp_node.is_mmapped = 1;
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews /*
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews * If the next node is not NULL, calculate the next node's location
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * in the file. Note that this will have to change when the data
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * structure changes, and it also assumes that we always write the
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * nodes out in list order (which we currently do.)
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence if (temp_node.parent != NULL) {
7ab0e69f61e61e81d489c95c7ebd981e74e7ef16Andreas Gustafsson temp_node.parent = (dns_rbtnode_t *)(parent);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence temp_node.parent_is_relative = 1;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence }
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence if (temp_node.left != NULL) {
7ab0e69f61e61e81d489c95c7ebd981e74e7ef16Andreas Gustafsson temp_node.left = (dns_rbtnode_t *)(left);
7ab0e69f61e61e81d489c95c7ebd981e74e7ef16Andreas Gustafsson temp_node.left_is_relative = 1;
7ab0e69f61e61e81d489c95c7ebd981e74e7ef16Andreas Gustafsson }
7ab0e69f61e61e81d489c95c7ebd981e74e7ef16Andreas Gustafsson if (temp_node.right != NULL) {
7ab0e69f61e61e81d489c95c7ebd981e74e7ef16Andreas Gustafsson temp_node.right = (dns_rbtnode_t *)(right);
ae70d32b67cf30e06553c01479e71c87b21d984cBob Halley temp_node.right_is_relative = 1;
7ab0e69f61e61e81d489c95c7ebd981e74e7ef16Andreas Gustafsson }
7ab0e69f61e61e81d489c95c7ebd981e74e7ef16Andreas Gustafsson if (temp_node.down != NULL) {
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff temp_node.down = (dns_rbtnode_t *)(down);
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson temp_node.down_is_relative = 1;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson }
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson if (temp_node.data != NULL) {
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson temp_node.data = (dns_rbtnode_t *)(data);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence temp_node.data_is_relative = 1;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence }
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson node_data = (unsigned char *) node + sizeof(dns_rbtnode_t);
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson datasize = NODE_SIZE(node) - sizeof(dns_rbtnode_t);
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson CHECK(isc_stdio_write(&temp_node, 1, sizeof(dns_rbtnode_t),
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson file, NULL));
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson CHECK(isc_stdio_write(node_data, 1, datasize, file, NULL));
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson#ifdef DEBUG
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson dns_name_init(&nodename, NULL);
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson NODENAME(node, &nodename);
ae70d32b67cf30e06553c01479e71c87b21d984cBob Halley fprintf(stderr, "serialize ");
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson dns_name_print(&nodename, stderr);
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson fprintf(stderr, "\n");
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff hexdump("node header", (unsigned char*) &temp_node,
d981ca645597116d227a48bf37cc5edc061c854dBob Halley sizeof(dns_rbtnode_t));
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews hexdump("node data", node_data, datasize);
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews#endif
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff isc_crc64_update(crc, (const isc_uint8_t *) &temp_node,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews sizeof(dns_rbtnode_t));
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_crc64_update(crc, (const isc_uint8_t *) node_data, datasize);
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews cleanup:
19d365e4448f1782611280b020987988b7ac3210Mark Andrews return (result);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews}
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic isc_result_t
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsserialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_rbtdatawriter_t datawriter, void *writer_arg,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews uintptr_t *where, isc_uint64_t *crc)
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews{
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews uintptr_t left = 0, right = 0, down = 0, data = 0;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews off_t location = 0, offset_adjust;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff isc_result_t result;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
d981ca645597116d227a48bf37cc5edc061c854dBob Halley if (node == NULL) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (where != NULL)
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff *where = 0;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (ISC_R_SUCCESS);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /* Reserve space for current node. */
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff CHECK(isc_stdio_tell(file, &location));
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews location = dns_rbt_serialize_align(location);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff CHECK(isc_stdio_seek(file, location, SEEK_SET));
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews offset_adjust = dns_rbt_serialize_align(location + NODE_SIZE(node));
19d365e4448f1782611280b020987988b7ac3210Mark Andrews CHECK(isc_stdio_seek(file, offset_adjust, SEEK_SET));
19d365e4448f1782611280b020987988b7ac3210Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Serialize the rest of the tree.
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews *
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews * WARNING: A change in the order (from left, right, down)
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews * will break the way the crc hash is computed.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews CHECK(serialize_nodes(file, getleft(node, NULL), location,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews datawriter, writer_arg, &left, crc));
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews CHECK(serialize_nodes(file, getright(node, NULL), location,
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews datawriter, writer_arg, &right, crc));
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews CHECK(serialize_nodes(file, getdown(node, NULL), location,
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews datawriter, writer_arg, &down, crc));
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews if (node->data != NULL) {
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews off_t ret;
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff CHECK(isc_stdio_tell(file, &ret));
d981ca645597116d227a48bf37cc5edc061c854dBob Halley ret = dns_rbt_serialize_align(ret);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley CHECK(isc_stdio_seek(file, ret, SEEK_SET));
d981ca645597116d227a48bf37cc5edc061c854dBob Halley data = ret;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
d981ca645597116d227a48bf37cc5edc061c854dBob Halley datawriter(file, node->data, writer_arg, crc);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley }
d981ca645597116d227a48bf37cc5edc061c854dBob Halley
d981ca645597116d227a48bf37cc5edc061c854dBob Halley /* Seek back to reserved space. */
d981ca645597116d227a48bf37cc5edc061c854dBob Halley CHECK(isc_stdio_seek(file, location, SEEK_SET));
d981ca645597116d227a48bf37cc5edc061c854dBob Halley
d981ca645597116d227a48bf37cc5edc061c854dBob Halley /* Serialize the current node. */
d981ca645597116d227a48bf37cc5edc061c854dBob Halley CHECK(serialize_node(file, node, left, right, down, parent, data, crc));
d981ca645597116d227a48bf37cc5edc061c854dBob Halley
d981ca645597116d227a48bf37cc5edc061c854dBob Halley /* Ensure we are always at the end of the file. */
d981ca645597116d227a48bf37cc5edc061c854dBob Halley CHECK(isc_stdio_seek(file, 0, SEEK_END));
d981ca645597116d227a48bf37cc5edc061c854dBob Halley
d981ca645597116d227a48bf37cc5edc061c854dBob Halley if (where != NULL)
d981ca645597116d227a48bf37cc5edc061c854dBob Halley *where = (uintptr_t) location;
d981ca645597116d227a48bf37cc5edc061c854dBob Halley
d981ca645597116d227a48bf37cc5edc061c854dBob Halley cleanup:
d981ca645597116d227a48bf37cc5edc061c854dBob Halley return (result);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley}
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halleyoff_t
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graffdns_rbt_serialize_align(off_t target) {
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley off_t offset = target % 8;
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley if (offset == 0)
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley return (target);
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley else
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley return (target + 8 - offset);
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley}
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halleyisc_result_t
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halleydns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt,
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley dns_rbtdatawriter_t datawriter,
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley void *writer_arg, off_t *offset)
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley{
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley isc_result_t result;
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley off_t header_position, node_position, end_position;
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley isc_uint64_t crc;
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff REQUIRE(file != NULL);
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff CHECK(isc_file_isplainfilefd(fileno(file)));
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff isc_crc64_init(&crc);
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff CHECK(isc_stdio_tell(file, &header_position));
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff /* Write dummy header */
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson CHECK(dns_rbt_zero_header(file));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff /* Serialize nodes */
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson CHECK(isc_stdio_tell(file, &node_position));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson CHECK(serialize_nodes(file, rbt->root, 0, datawriter,
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson writer_arg, NULL, &crc));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson CHECK(isc_stdio_tell(file, &end_position));
88ba491496daf4463a2c898be8a6c47775a6d048Mark Andrews if (node_position == end_position) {
88ba491496daf4463a2c898be8a6c47775a6d048Mark Andrews CHECK(isc_stdio_seek(file, header_position, SEEK_SET));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson *offset = 0;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson return (ISC_R_SUCCESS);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson }
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_crc64_final(&crc);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#ifdef DEBUG
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson hexdump("serializing CRC", (unsigned char *)&crc, sizeof(crc));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#endif
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson /* Serialize header */
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson CHECK(isc_stdio_seek(file, header_position, SEEK_SET));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson CHECK(write_header(file, rbt, HEADER_LENGTH, crc));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson /* Ensure we are always at the end of the file. */
34b394b43e2207e8f8f3703f0402422121455638David Lawrence CHECK(isc_stdio_seek(file, 0, SEEK_END));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson *offset = dns_rbt_serialize_align(header_position);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson cleanup:
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence return (result);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence}
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#define CONFIRM(a) do { \
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (! (a)) { \
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson result = ISC_R_INVALIDFILE; \
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson goto cleanup; \
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson } \
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson} while(0);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonstatic isc_result_t
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Grafftreefix(dns_rbt_t *rbt, void *base, size_t filesize, dns_rbtnode_t *n,
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson dns_name_t *name, dns_rbtdatafixer_t datafixer,
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson void *fixer_arg, isc_uint64_t *crc)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson{
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_result_t result = ISC_R_SUCCESS;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson dns_fixedname_t fixed;
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff dns_name_t nodename, *fullname;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson unsigned char *node_data;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson dns_rbtnode_t header;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson size_t datasize, nodemax = filesize - sizeof(dns_rbtnode_t);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (n == NULL)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson return (ISC_R_SUCCESS);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson CONFIRM((void *) n >= base);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson CONFIRM((char *) n - (char *) base <= (int) nodemax);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson CONFIRM(DNS_RBTNODE_VALID(n));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson dns_name_init(&nodename, NULL);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson NODENAME(n, &nodename);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson fullname = &nodename;
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(dns_name_isvalid(fullname));
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff if (!dns_name_isabsolute(&nodename)) {
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff dns_fixedname_init(&fixed);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff fullname = dns_fixedname_name(&fixed);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff CHECK(dns_name_concatenate(&nodename, name, fullname, NULL));
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence }
16996a04884731d647f43a5eb54f678581f09f68David Lawrence
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews /* memorize header contents prior to fixup */
16996a04884731d647f43a5eb54f678581f09f68David Lawrence memmove(&header, n, sizeof(header));
16996a04884731d647f43a5eb54f678581f09f68David Lawrence
16996a04884731d647f43a5eb54f678581f09f68David Lawrence if (n->left_is_relative) {
ed019cabc1cc75d4412010c331876e4ae5080a4dDavid Lawrence CONFIRM(n->left <= (dns_rbtnode_t *) nodemax);
ed019cabc1cc75d4412010c331876e4ae5080a4dDavid Lawrence n->left = getleft(n, rbt->mmap_location);
16996a04884731d647f43a5eb54f678581f09f68David Lawrence n->left_is_relative = 0;
600cfa2ba4c50017581b6c14e3a688a82ecebbe0David Lawrence CONFIRM(DNS_RBTNODE_VALID(n->left));
600cfa2ba4c50017581b6c14e3a688a82ecebbe0David Lawrence } else
600cfa2ba4c50017581b6c14e3a688a82ecebbe0David Lawrence CONFIRM(n->left == NULL);
600cfa2ba4c50017581b6c14e3a688a82ecebbe0David Lawrence
16996a04884731d647f43a5eb54f678581f09f68David Lawrence if (n->right_is_relative) {
16996a04884731d647f43a5eb54f678581f09f68David Lawrence CONFIRM(n->right <= (dns_rbtnode_t *) nodemax);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff n->right = getright(n, rbt->mmap_location);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff n->right_is_relative = 0;
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(DNS_RBTNODE_VALID(n->right));
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff } else
fc024be774c7cdee938da018aa3994be746e36deDavid Lawrence CONFIRM(n->right == NULL);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff if (n->down_is_relative) {
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(n->down <= (dns_rbtnode_t *) nodemax);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff n->down = getdown(n, rbt->mmap_location);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff n->down_is_relative = 0;
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(n->down > (dns_rbtnode_t *) n);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(DNS_RBTNODE_VALID(n->down));
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff } else
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(n->down == NULL);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff if (n->parent_is_relative) {
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(n->parent <= (dns_rbtnode_t *) nodemax);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff n->parent = getparent(n, rbt->mmap_location);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff n->parent_is_relative = 0;
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(n->parent < (dns_rbtnode_t *) n);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(DNS_RBTNODE_VALID(n->parent));
16996a04884731d647f43a5eb54f678581f09f68David Lawrence } else
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(n->parent == NULL);
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff if (n->data_is_relative) {
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CONFIRM(n->data <= (void *) filesize);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff n->data = getdata(n, rbt->mmap_location);
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews n->data_is_relative = 0;
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews CONFIRM(n->data > (void *) n);
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews } else
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff CONFIRM(n->data == NULL);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
16996a04884731d647f43a5eb54f678581f09f68David Lawrence hash_node(rbt, n, fullname);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff /* a change in the order (from left, right, down) will break hashing*/
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff if (n->left != NULL)
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CHECK(treefix(rbt, base, filesize, n->left, name,
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff datafixer, fixer_arg, crc));
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff if (n->right != NULL)
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CHECK(treefix(rbt, base, filesize, n->right, name,
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff datafixer, fixer_arg, crc));
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff if (n->down != NULL)
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CHECK(treefix(rbt, base, filesize, n->down, fullname,
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff datafixer, fixer_arg, crc));
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff if (datafixer != NULL && n->data != NULL)
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff CHECK(datafixer(n, base, filesize, fixer_arg, crc));
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff rbt->nodecount++;
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff node_data = (unsigned char *) n + sizeof(dns_rbtnode_t);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff datasize = NODE_SIZE(n) - sizeof(dns_rbtnode_t);
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff#ifdef DEBUG
79eec6934923f97a61edb8dbe2641ce56dc30085Bob Halley fprintf(stderr, "deserialize ");
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff dns_name_print(&nodename, stderr);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence fprintf(stderr, "\n");
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff hexdump("node header", (unsigned char *) &header,
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews sizeof(dns_rbtnode_t));
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff hexdump("node data", node_data, datasize);
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff#endif
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff isc_crc64_update(crc, (const isc_uint8_t *) &header,
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff sizeof(dns_rbtnode_t));
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff isc_crc64_update(crc, (const isc_uint8_t *) node_data,
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff datasize);
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence cleanup:
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence return (result);
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff}
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graffisc_result_t
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graffdns_rbt_deserialize_tree(void *base_address, size_t filesize,
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff off_t header_offset, isc_mem_t *mctx,
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff dns_rbtdeleter_t deleter, void *deleter_arg,
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff dns_rbtdatafixer_t datafixer, void *fixer_arg,
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff dns_rbtnode_t **originp, dns_rbt_t **rbtp)
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff{
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews isc_result_t result = ISC_R_SUCCESS;
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews file_header_t *header;
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews dns_rbt_t *rbt = NULL;
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews isc_uint64_t crc;
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence REQUIRE(originp == NULL || *originp == NULL);
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff REQUIRE(rbtp != NULL && *rbtp == NULL);
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff isc_crc64_init(&crc);
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff CHECK(dns_rbt_create(mctx, deleter, deleter_arg, &rbt));
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff rbt->mmap_location = base_address;
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews header = (file_header_t *)((char *)base_address + header_offset);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews
79eec6934923f97a61edb8dbe2641ce56dc30085Bob Halley#ifdef DNS_RDATASET_FIXED
79eec6934923f97a61edb8dbe2641ce56dc30085Bob Halley if (header->rdataset_fixed != 1) {
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff result = ISC_R_INVALIDFILE;
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews goto cleanup;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington }
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#else
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington if (header->rdataset_fixed != 0) {
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews result = ISC_R_INVALIDFILE;
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews goto cleanup;
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff }
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#endif
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews if (header->ptrsize != (isc_uint32_t) sizeof(void *)) {
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews result = ISC_R_INVALIDFILE;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington goto cleanup;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington }
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington if (header->bigendian != (1 == htonl(1)) ? 1 : 0) {
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington result = ISC_R_INVALIDFILE;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington goto cleanup;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington }
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington /* Copy other data items from the header into our rbt. */
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington rbt->root = (dns_rbtnode_t *)((char *)base_address +
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington header_offset + header->first_node_offset);
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington if ((header->nodecount * sizeof(dns_rbtnode_t)) > filesize) {
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington result = ISC_R_INVALIDFILE;
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff goto cleanup;
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews }
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson rehash(rbt, header->nodecount);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson CHECK(treefix(rbt, base_address, filesize, rbt->root,
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff dns_rootname, datafixer, fixer_arg, &crc));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews isc_crc64_final(&crc);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff#ifdef DEBUG
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson hexdump("deserializing CRC", (unsigned char *)&crc, sizeof(crc));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#endif
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews /* Check file hash */
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff if (header->crc != crc) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson result = ISC_R_INVALIDFILE;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson goto cleanup;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson }
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff if (header->nodecount != rbt->nodecount) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson result = ISC_R_INVALIDFILE;
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews goto cleanup;
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff }
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#ifdef DNS_RBT_USEHASH
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews fixup_uppernodes(rbt);
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews#endif /* DNS_RBT_USEHASH */
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson *rbtp = rbt;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (originp != NULL)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson *originp = rbt->root;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff cleanup:
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (result != ISC_R_SUCCESS && rbt != NULL) {
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews rbt->root = NULL;
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff rbt->nodecount = 0;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson dns_rbt_destroy(&rbt);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson }
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews return (result);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff}
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson/*
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Initialize a red/black tree of trees.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson */
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonisc_result_t
88ba491496daf4463a2c898be8a6c47775a6d048Mark Andrewsdns_rbt_create(isc_mem_t *mctx, dns_rbtdeleter_t deleter,
88ba491496daf4463a2c898be8a6c47775a6d048Mark Andrews void *deleter_arg, dns_rbt_t **rbtp)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson{
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#ifdef DNS_RBT_USEHASH
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_result_t result;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#endif
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson dns_rbt_t *rbt;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson REQUIRE(mctx != NULL);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson REQUIRE(rbtp != NULL && *rbtp == NULL);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson REQUIRE(deleter == NULL ? deleter_arg == NULL : 1);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (rbt == NULL)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson return (ISC_R_NOMEMORY);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
34b394b43e2207e8f8f3703f0402422121455638David Lawrence rbt->mctx = NULL;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_mem_attach(mctx, &rbt->mctx);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff rbt->data_deleter = deleter;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson rbt->deleter_arg = deleter_arg;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson rbt->root = NULL;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson rbt->nodecount = 0;
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews rbt->hashtable = NULL;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson rbt->hashsize = 0;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson rbt->mmap_location = NULL;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#ifdef DNS_RBT_USEHASH
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson result = inithash(rbt);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (result != ISC_R_SUCCESS) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson return (result);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson }
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson#endif
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson rbt->magic = RBT_MAGIC;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson *rbtp = rbt;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews return (ISC_R_SUCCESS);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson}
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson/*
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Deallocate a red/black tree of trees.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson */
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonvoid
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssondns_rbt_destroy(dns_rbt_t **rbtp) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson RUNTIME_CHECK(dns_rbt_destroy2(rbtp, 0) == ISC_R_SUCCESS);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson}
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonisc_result_t
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrewsdns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson dns_rbt_t *rbt;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews REQUIRE(rbtp != NULL && VALID_RBT(*rbtp));
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence rbt = *rbtp;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence deletetreeflat(rbt, quantum, ISC_FALSE, &rbt->root);
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews if (rbt->root != NULL)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (ISC_R_QUOTA);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews INSIST(rbt->nodecount == 0);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews rbt->mmap_location = NULL;
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (rbt->hashtable != NULL)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_mem_put(rbt->mctx, rbt->hashtable,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews rbt->hashsize * sizeof(dns_rbtnode_t *));
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
fe47f41b13620bfafc4f8cf65d5df24f1e568764Bob Halley rbt->magic = 0;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence *rbtp = NULL;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (ISC_R_SUCCESS);
fe47f41b13620bfafc4f8cf65d5df24f1e568764Bob Halley}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsunsigned int
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsdns_rbt_nodecount(dns_rbt_t *rbt) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews REQUIRE(VALID_RBT(rbt));
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (rbt->nodecount);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewssize_t
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsdns_rbt_hashsize(dns_rbt_t *rbt) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews REQUIRE(VALID_RBT(rbt));
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (rbt->hashsize);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic inline isc_result_t
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewschain_name(dns_rbtnodechain_t *chain, dns_name_t *name,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_boolean_t include_chain_end)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews{
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff dns_name_t nodename;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_result_t result = ISC_R_SUCCESS;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews int i;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_name_init(&nodename, NULL);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (include_chain_end && chain->end != NULL) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews NODENAME(chain->end, &nodename);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = dns_name_copy(&nodename, name, NULL);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (result != ISC_R_SUCCESS)
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff return (result);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews } else
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_name_reset(name);
fe47f41b13620bfafc4f8cf65d5df24f1e568764Bob Halley
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews for (i = (int)chain->level_count - 1; i >= 0; i--) {
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff NODENAME(chain->levels[i], &nodename);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = dns_name_concatenate(name, &nodename, name, NULL);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff if (result != ISC_R_SUCCESS)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (result);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews }
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews return (result);
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews}
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrewsstatic inline isc_result_t
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrewsmove_chain_to_last(dns_rbtnodechain_t *chain, dns_rbtnode_t *node) {
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews do {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /*
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence * Go as far right and then down as much as possible,
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews * as long as the rightmost node has a down pointer.
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews */
f0ff273b530afa730025e1c5ad311950f7ff4328Mark Andrews while (RIGHT(node) != NULL)
f0ff273b530afa730025e1c5ad311950f7ff4328Mark Andrews node = RIGHT(node);
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews if (DOWN(node) == NULL)
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff break;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence ADD_LEVEL(chain, node);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence node = DOWN(node);
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews } while (1);
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence chain->end = node;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence return (ISC_R_SUCCESS);
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews}
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews/*
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews * Add 'name' to tree, initializing its data pointer with 'data'.
7c0378745269fe49a05904935afc42b85528f53aDavid Lawrence */
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrewsisc_result_t
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrewsdns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) {
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews /*
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews * Does this thing have too many variables or what?
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews */
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews dns_rbtnode_t **root, *parent, *child, *current, *new_current;
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews dns_name_t *add_name, *new_name, current_name, *prefix, *suffix;
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix, fnewname;
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews dns_offsets_t current_offsets;
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews dns_namereln_t compared;
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews isc_result_t result = ISC_R_SUCCESS;
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews dns_rbtnodechain_t chain;
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews unsigned int common_labels;
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews unsigned int nlabels, hlabels;
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews int order;
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews REQUIRE(VALID_RBT(rbt));
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews REQUIRE(dns_name_isabsolute(name));
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews REQUIRE(nodep != NULL && *nodep == NULL);
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews /*
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews * Create a copy of the name so the original name structure is
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * not modified.
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews */
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews dns_fixedname_init(&fixedcopy);
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews add_name = dns_fixedname_name(&fixedcopy);
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews dns_name_clone(name, add_name);
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews if (rbt->root == NULL) {
7d62ddffbb4d1cc97b8d80b7ee4944554a57523eMark Andrews result = create_node(rbt->mctx, add_name, &new_current);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff if (result == ISC_R_SUCCESS) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews rbt->nodecount++;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews new_current->is_root = 1;
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff#ifdef DNS_RBT_USEHASH
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews UPPERNODE(new_current) = NULL;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#endif /* DNS_RBT_USEHASH */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews rbt->root = new_current;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews *nodep = new_current;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews hash_node(rbt, new_current, name);
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence }
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews return (result);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_rbtnodechain_init(&chain, rbt->mctx);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_fixedname_init(&fixedprefix);
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence dns_fixedname_init(&fixedsuffix);
bfb2a81b65579882a80855c279cedc45aebd62e8Mark Andrews prefix = dns_fixedname_name(&fixedprefix);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff suffix = dns_fixedname_name(&fixedsuffix);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews root = &rbt->root;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews INSIST(IS_ROOT(*root));
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews parent = NULL;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff current = NULL;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews child = *root;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_name_init(&current_name, current_offsets);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_fixedname_init(&fnewname);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews new_name = dns_fixedname_name(&fnewname);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews nlabels = dns_name_countlabels(name);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews hlabels = 0;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews do {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews current = child;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews NODENAME(current, &current_name);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews compared = dns_name_fullcompare(add_name, &current_name,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews &order, &common_labels);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (compared == dns_namereln_equal) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews *nodep = current;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = ISC_R_EXISTS;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews break;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (compared == dns_namereln_none) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (order < 0) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews parent = current;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews child = LEFT(current);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews } else if (order > 0) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews parent = current;
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff child = RIGHT(current);
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews } else {
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence /*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * This name has some suffix in common with the
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * name at the current node. If the name at
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * the current node is shorter, that means the
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * new name should be in a subtree. If the
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * name at the current node is longer, that means
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * the down pointer to this tree should point
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * to a new tree that has the common suffix, and
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * the non-common parts of these two names should
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * start a new tree.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews hlabels += common_labels;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (compared == dns_namereln_subdomain) {
26b0f58b6c4d65bc8b131debf40b8c376c2978bfBob Halley /*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * All of the existing labels are in common,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * so the new name is in a subtree.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Whack off the common labels for the
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence * not-in-common part to be searched for
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence * in the next level.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews dns_name_split(add_name, common_labels,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews add_name, NULL);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff /*
15330e4fa27c82ac04cc2ce234ec930e4b6b42d3Mark Andrews * Follow the down pointer (possibly NULL).
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews root = &DOWN(current);
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews INSIST(*root == NULL ||
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff (IS_ROOT(*root) &&
e4653123ecc6cdbfc0b9eda6e98e44af3b1f9a08Mark Andrews PARENT(*root) == current));
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews parent = NULL;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews child = DOWN(current);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff ADD_LEVEL(&chain, current);
15330e4fa27c82ac04cc2ce234ec930e4b6b42d3Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews } else {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /*
1c3191528684f3dd93ebb122298c2f8ebfc6d397Mark Andrews * The number of labels in common is fewer
34b394b43e2207e8f8f3703f0402422121455638David Lawrence * than the number of labels at the current
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence * node, so the current node must be adjusted
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * to have just the common suffix, and a down
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * pointer made to a new tree.
7c0378745269fe49a05904935afc42b85528f53aDavid Lawrence */
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews INSIST(compared == dns_namereln_commonancestor
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews || compared == dns_namereln_contains);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson /*
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson * Ensure the number of levels in the tree
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson * does not exceed the number of logical
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson * levels allowed by DNSSEC.
34b394b43e2207e8f8f3703f0402422121455638David Lawrence *
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence * XXXDCL need a better error result?
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson *
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * XXXDCL Since chain ancestors were removed,
7c0378745269fe49a05904935afc42b85528f53aDavid Lawrence * no longer used by addonlevel(),
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * this is the only real use of chains in the
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson * function. It could be done instead with
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson * a simple integer variable, but I am pressed
5466ce3f279d9fa83ce826bcdc9482bc591152aeAndreas Gustafsson * for time.
5466ce3f279d9fa83ce826bcdc9482bc591152aeAndreas Gustafsson */
5466ce3f279d9fa83ce826bcdc9482bc591152aeAndreas Gustafsson if (chain.level_count ==
5466ce3f279d9fa83ce826bcdc9482bc591152aeAndreas Gustafsson (sizeof(chain.levels) /
5466ce3f279d9fa83ce826bcdc9482bc591152aeAndreas Gustafsson sizeof(*chain.levels))) {
5466ce3f279d9fa83ce826bcdc9482bc591152aeAndreas Gustafsson result = ISC_R_NOSPACE;
5466ce3f279d9fa83ce826bcdc9482bc591152aeAndreas Gustafsson break;
15330e4fa27c82ac04cc2ce234ec930e4b6b42d3Mark Andrews }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Split the name into two parts, a prefix
035504dbd8ca5949e8380b860873b3385a4e61e5Mark Andrews * which is the not-in-common parts of the
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * two names and a suffix that is the common
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * parts of them.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews dns_name_split(&current_name, common_labels,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews prefix, suffix);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = create_node(rbt->mctx, suffix,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews &new_current);
15330e4fa27c82ac04cc2ce234ec930e4b6b42d3Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (result != ISC_R_SUCCESS)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews break;
035504dbd8ca5949e8380b860873b3385a4e61e5Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Reproduce the tree attributes of the
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * current node.
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews */
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson new_current->is_root = current->is_root;
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson if (current->nsec == DNS_RBT_NSEC_HAS_NSEC)
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson new_current->nsec = DNS_RBT_NSEC_NORMAL;
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson else
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson new_current->nsec = current->nsec;
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson PARENT(new_current) = PARENT(current);
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson LEFT(new_current) = LEFT(current);
5a219d878f0bd786e86da2c9b92999260dda3f8dAndreas Gustafsson RIGHT(new_current) = RIGHT(current);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff COLOR(new_current) = COLOR(current);
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews /*
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews * Fix pointers that were to the current node.
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews */
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson if (parent != NULL) {
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews if (LEFT(parent) == current)
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews LEFT(parent) = new_current;
2192b4497348ccab94ca6f3f779cec399c72a8efMark Andrews else
2192b4497348ccab94ca6f3f779cec399c72a8efMark Andrews RIGHT(parent) = new_current;
25870d4a37ab4bc8e675502b08335200167cc044Bob Halley }
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews if (LEFT(new_current) != NULL)
25870d4a37ab4bc8e675502b08335200167cc044Bob Halley PARENT(LEFT(new_current)) =
25870d4a37ab4bc8e675502b08335200167cc044Bob Halley new_current;
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews if (RIGHT(new_current) != NULL)
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews PARENT(RIGHT(new_current)) =
035504dbd8ca5949e8380b860873b3385a4e61e5Mark Andrews new_current;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff if (*root == current)
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews *root = new_current;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews NAMELEN(current) = prefix->length;
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews OFFSETLEN(current) = prefix->labels;
c0d0a59d1b665423b8a0d1829d0f0da121cb3473Andreas Gustafsson
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews /*
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * Set up the new root of the next level.
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * By definition it will not be the top
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews * level tree, so clear DNS_NAMEATTR_ABSOLUTE.
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews */
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff current->is_root = 1;
2192b4497348ccab94ca6f3f779cec399c72a8efMark Andrews PARENT(current) = new_current;
2192b4497348ccab94ca6f3f779cec399c72a8efMark Andrews DOWN(new_current) = current;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff root = &DOWN(new_current);
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews#ifdef DNS_RBT_USEHASH
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews UPPERNODE(new_current) = UPPERNODE(current);
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews UPPERNODE(current) = new_current;
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews#endif /* DNS_RBT_USEHASH */
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff ADD_LEVEL(&chain, new_current);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews LEFT(current) = NULL;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff RIGHT(current) = NULL;
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews MAKE_BLACK(current);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff ATTRS(current) &= ~DNS_NAMEATTR_ABSOLUTE;
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews rbt->nodecount++;
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews dns_name_getlabelsequence(name,
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence nlabels - hlabels,
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews hlabels, new_name);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff hash_node(rbt, new_current, new_name);
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews if (common_labels ==
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff dns_name_countlabels(add_name)) {
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews /*
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews * The name has been added by pushing
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews * the not-in-common parts down to
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews * a new level.
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews */
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews *nodep = new_current;
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews return (ISC_R_SUCCESS);
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews } else {
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews /*
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews * The current node has no data,
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews * because it is just a placeholder.
904294c0c952227f7778fd0ba2ccea08c097b872Mark Andrews * Its data pointer is already NULL
904294c0c952227f7778fd0ba2ccea08c097b872Mark Andrews * from create_node()), so there's
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews * nothing more to do to it.
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews */
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews /*
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews * The not-in-common parts of the new
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence * name will be inserted into the new
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence * level following this loop (unless
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence * result != ISC_R_SUCCESS, which
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence * is tested after the loop ends).
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence */
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews dns_name_split(add_name, common_labels,
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence add_name, NULL);
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews break;
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews }
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews }
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews
8a17d1e7cdba9fdcf71fb2f821a954a251204105Mark Andrews }
8a17d1e7cdba9fdcf71fb2f821a954a251204105Mark Andrews
8a17d1e7cdba9fdcf71fb2f821a954a251204105Mark Andrews } while (child != NULL);
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence if (result == ISC_R_SUCCESS)
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence result = create_node(rbt->mctx, add_name, &new_current);
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence if (result == ISC_R_SUCCESS) {
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence#ifdef DNS_RBT_USEHASH
8a17d1e7cdba9fdcf71fb2f821a954a251204105Mark Andrews if (*root == NULL)
8a17d1e7cdba9fdcf71fb2f821a954a251204105Mark Andrews UPPERNODE(new_current) = current;
8a17d1e7cdba9fdcf71fb2f821a954a251204105Mark Andrews else
8a17d1e7cdba9fdcf71fb2f821a954a251204105Mark Andrews UPPERNODE(new_current) = PARENT(*root);
8a17d1e7cdba9fdcf71fb2f821a954a251204105Mark Andrews#endif /* DNS_RBT_USEHASH */
8a17d1e7cdba9fdcf71fb2f821a954a251204105Mark Andrews addonlevel(new_current, current, order, root);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews rbt->nodecount++;
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence *nodep = new_current;
47b26abe77184f9bedc68e36bdad03332cf67570David Lawrence hash_node(rbt, new_current, name);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews }
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews return (result);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews}
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews/*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * Add a name to the tree of trees, associating it with some data.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrewsisc_result_t
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrewsdns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data) {
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews isc_result_t result;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_rbtnode_t *node;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews REQUIRE(VALID_RBT(rbt));
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews REQUIRE(dns_name_isabsolute(name));
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
15330e4fa27c82ac04cc2ce234ec930e4b6b42d3Mark Andrews node = NULL;
15330e4fa27c82ac04cc2ce234ec930e4b6b42d3Mark Andrews
15330e4fa27c82ac04cc2ce234ec930e4b6b42d3Mark Andrews result = dns_rbt_addnode(rbt, name, &node);
15330e4fa27c82ac04cc2ce234ec930e4b6b42d3Mark Andrews
15330e4fa27c82ac04cc2ce234ec930e4b6b42d3Mark Andrews /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * dns_rbt_addnode will report the node exists even when
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * it does not have data associated with it, but the
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * dns_rbt_*name functions all behave depending on whether
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * there is data associated with a node.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews if (result == ISC_R_SUCCESS ||
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews (result == ISC_R_EXISTS && DATA(node) == NULL)) {
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews DATA(node) = data;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews result = ISC_R_SUCCESS;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews }
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews return (result);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff}
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews/*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * Find the node for "name" in the tree of trees.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrenceisc_result_t
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrewsdns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews unsigned int options, dns_rbtfindcallback_t callback,
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews void *callback_arg)
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews{
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_rbtnode_t *current, *last_compared, *current_root;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_rbtnodechain_t localchain;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_name_t *search_name, current_name, *callback_name;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_fixedname_t fixedcallbackname, fixedsearchname;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_namereln_t compared;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews isc_result_t result, saved_result;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews unsigned int common_labels;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews unsigned int hlabels = 0;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews int order;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews REQUIRE(VALID_RBT(rbt));
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews REQUIRE(dns_name_isabsolute(name));
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews REQUIRE(node != NULL && *node == NULL);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews REQUIRE((options & (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR))
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews != (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR));
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * If there is a chain it needs to appear to be in a sane state,
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * otherwise a chain is still needed to generate foundname and
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * callback_name.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews if (chain == NULL) {
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews options |= DNS_RBTFIND_NOPREDECESSOR;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews chain = &localchain;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_rbtnodechain_init(chain, rbt->mctx);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews } else
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_rbtnodechain_reset(chain);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff if (rbt->root == NULL)
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews return (ISC_R_NOTFOUND);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * Appease GCC about variables it incorrectly thinks are
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * possibly used uninitialized.
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews compared = dns_namereln_none;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews last_compared = NULL;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews order = 0;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_fixedname_init(&fixedcallbackname);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews callback_name = dns_fixedname_name(&fixedcallbackname);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * search_name is the name segment being sought in each tree level.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * By using a fixedname, the search_name will definitely have offsets
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * for use by any splitting.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * By using dns_name_clone, no name data should be copied thanks to
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * the lack of bitstring labels.
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_fixedname_init(&fixedsearchname);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff search_name = dns_fixedname_name(&fixedsearchname);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_name_clone(name, search_name);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff dns_name_init(&current_name, NULL);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews saved_result = ISC_R_SUCCESS;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence current = rbt->root;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence current_root = rbt->root;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence while (current != NULL) {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence NODENAME(current, &current_name);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence compared = dns_name_fullcompare(search_name, &current_name,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence &order, &common_labels);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * last_compared is used as a shortcut to start (or
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * continue rather) finding the stop-node of the search
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * when hashing was used (see much below in this
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * function).
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff last_compared = current;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
df8c9ee4819c97089664ccc035eb2aa7569034fdDavid Lawrence if (compared == dns_namereln_equal)
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews break;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews if (compared == dns_namereln_none) {
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews#ifdef DNS_RBT_USEHASH
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * Here, current is pointing at a subtree root
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * node. We try to find a matching node using
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * the hashtable. We can get one of 3 results
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * here: (a) we locate the matching node, (b) we
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * find a node to which the current node has a
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * subdomain relation, (c) we fail to find (a)
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * or (b).
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_name_t hash_name;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_rbtnode_t *hnode;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence dns_rbtnode_t *up_current;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence unsigned int nlabels;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence unsigned int tlabels = 1;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews unsigned int hash;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * The case of current != current_root, that
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * means a left or right pointer was followed,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * only happens when the algorithm fell through to
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * the traditional binary search because of a
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * bitstring label. Since we dropped the bitstring
df8c9ee4819c97089664ccc035eb2aa7569034fdDavid Lawrence * support, this should not happen.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews INSIST(current == current_root);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence nlabels = dns_name_countlabels(search_name);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * current_root is the root of the current level, so
df8c9ee4819c97089664ccc035eb2aa7569034fdDavid Lawrence * its parent is the same as its "up" pointer.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews up_current = PARENT(current_root);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_name_init(&hash_name, NULL);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence hashagain:
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * Compute the hash over the full absolute
df8c9ee4819c97089664ccc035eb2aa7569034fdDavid Lawrence * name. Look for the smallest suffix match at
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * this tree level (hlevel), and then at every
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * iteration, look for the next smallest suffix
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * match (add another subdomain label to the
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * absolute name being hashed).
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff dns_name_getlabelsequence(name,
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews nlabels - tlabels,
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews hlabels + tlabels,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence &hash_name);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence hash = dns_name_fullhash(&hash_name, ISC_FALSE);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence dns_name_getlabelsequence(search_name,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence nlabels - tlabels,
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff tlabels, &hash_name);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * Walk all the nodes in the hash bucket pointed
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence * by the computed hash value.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews for (hnode = rbt->hashtable[hash % rbt->hashsize];
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews hnode != NULL;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews hnode = hnode->hashnext)
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews {
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_name_t hnode_name;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews if (hash != HASHVAL(hnode))
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews continue;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * This checks that the hashed label
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * sequence being looked up is at the
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * same tree level, so that we don't
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * match a labelsequence from some other
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * subdomain.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff if (get_upper_node(hnode) != up_current)
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews continue;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews dns_name_init(&hnode_name, NULL);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews NODENAME(hnode, &hnode_name);
15330e4fa27c82ac04cc2ce234ec930e4b6b42d3Mark Andrews if (dns_name_equal(&hnode_name, &hash_name))
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews break;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews }
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence if (hnode != NULL) {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence current = hnode;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews /*
83ac7ce833930a5c6cb92ad9c04a58e775579e73Bob Halley * This is an optimization. If hashing found
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * the right node, the next call to
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * dns_name_fullcompare() would obviously
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * return _equal or _subdomain. Determine
83ac7ce833930a5c6cb92ad9c04a58e775579e73Bob Halley * which of those would be the case by
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * checking if the full name was hashed. Then
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * make it look like dns_name_fullcompare
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * was called and jump to the right place.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
83ac7ce833930a5c6cb92ad9c04a58e775579e73Bob Halley if (tlabels == nlabels) {
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews compared = dns_namereln_equal;
83ac7ce833930a5c6cb92ad9c04a58e775579e73Bob Halley break;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews } else {
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews common_labels = tlabels;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews compared = dns_namereln_subdomain;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews goto subdomain;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews }
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews }
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews if (tlabels++ < nlabels)
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews goto hashagain;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * All of the labels have been tried against the hash
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * table. Since we dropped the support of bitstring
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * labels, the name isn't in the table.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews current = NULL;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews continue;
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews#else /* DNS_RBT_USEHASH */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews /*
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff * Standard binary search tree movement.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews if (order < 0)
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews current = LEFT(current);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews else
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews current = RIGHT(current);
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews#endif /* DNS_RBT_USEHASH */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews } else {
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews /*
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * The names have some common suffix labels.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews *
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * If the number in common are equal in length to
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * the current node's name length, then follow the
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews * down pointer and search in the new tree.
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews */
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews if (compared == dns_namereln_subdomain) {
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews#ifdef DNS_RBT_USEHASH
3a4ec3da9fa14511cbc3660f75817cfacb3f4d1eMark Andrews subdomain:
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews#endif
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews /*
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * Whack off the current node's common parts
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * for the name to search in the next level.
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence dns_name_split(search_name, common_labels,
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews search_name, NULL);
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews hlabels += common_labels;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * This might be the closest enclosing name.
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews */
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews if (DATA(current) != NULL ||
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews (options & DNS_RBTFIND_EMPTYDATA) != 0)
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews *node = current;
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews /*
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * Point the chain to the next level. This
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * needs to be done before 'current' is pointed
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * there because the callback in the next
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * block of code needs the current 'current',
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * but in the event the callback requests that
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * the search be stopped then the
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * DNS_R_PARTIALMATCH code at the end of this
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * function needs the chain pointed to the
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * next level.
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews */
20b20b23948b90cb2f7d7f402da99d09f837efd0David Lawrence ADD_LEVEL(chain, current);
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews /*
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * The caller may want to interrupt the
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * downward search when certain special nodes
20b20b23948b90cb2f7d7f402da99d09f837efd0David Lawrence * are traversed. If this is a special node,
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * the callback is used to learn what the
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * caller wants to do.
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews */
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews if (callback != NULL &&
20b20b23948b90cb2f7d7f402da99d09f837efd0David Lawrence FINDCALLBACK(current)) {
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews result = chain_name(chain,
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews callback_name,
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews ISC_FALSE);
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews if (result != ISC_R_SUCCESS) {
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews dns_rbtnodechain_reset(chain);
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews return (result);
20b20b23948b90cb2f7d7f402da99d09f837efd0David Lawrence }
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews result = (callback)(current,
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews callback_name,
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews callback_arg);
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews if (result != DNS_R_CONTINUE) {
20b20b23948b90cb2f7d7f402da99d09f837efd0David Lawrence saved_result = result;
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews /*
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * Treat this node as if it
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * had no down pointer.
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews */
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews current = NULL;
20b20b23948b90cb2f7d7f402da99d09f837efd0David Lawrence break;
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews }
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews }
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson /*
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley * Finally, head to the next tree level.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence */
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley current = DOWN(current);
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley current_root = current;
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley
ebd68da027cfa8da0fb536c3db11bb88292f41c7Andreas Gustafsson } else {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff * Though there are labels in common, the
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff * entire name at this node is not common
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff * with the search name so the search
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff * name does not exist in the tree.
ebd68da027cfa8da0fb536c3db11bb88292f41c7Andreas Gustafsson */
ebd68da027cfa8da0fb536c3db11bb88292f41c7Andreas Gustafsson INSIST(compared == dns_namereln_commonancestor
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence || compared == dns_namereln_contains);
3bb3b7ac462a90c2b8b1fb783324d800e2ba748cMichael Graff
3bb3b7ac462a90c2b8b1fb783324d800e2ba748cMichael Graff current = NULL;
3bb3b7ac462a90c2b8b1fb783324d800e2ba748cMichael Graff }
3bb3b7ac462a90c2b8b1fb783324d800e2ba748cMichael Graff }
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff }
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff /*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * If current is not NULL, NOEXACT is not disallowing exact matches,
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff * and either the node has data or an empty node is ok, return
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff * ISC_R_SUCCESS to indicate an exact match.
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff */
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff if (current != NULL && (options & DNS_RBTFIND_NOEXACT) == 0 &&
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff (DATA(current) != NULL ||
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff (options & DNS_RBTFIND_EMPTYDATA) != 0)) {
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff /*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * Found an exact match.
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff */
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff chain->end = current;
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff chain->level_matches = chain->level_count;
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff if (foundname != NULL)
3bb3b7ac462a90c2b8b1fb783324d800e2ba748cMichael Graff result = chain_name(chain, foundname, ISC_TRUE);
3bb3b7ac462a90c2b8b1fb783324d800e2ba748cMichael Graff else
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence result = ISC_R_SUCCESS;
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff if (result == ISC_R_SUCCESS) {
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff *node = current;
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff result = saved_result;
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff } else
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff *node = NULL;
7ec579cd5d07228c0d6cece58b80694ad8d59de9Michael Graff } else {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
f8aae502686e2448c48f56697c212a50e2a1cbaeAndreas Gustafsson * Did not find an exact match (or did not want one).
b469f0321d2bcea3914c57d26fd43319e506c313Andreas Gustafsson */
b469f0321d2bcea3914c57d26fd43319e506c313Andreas Gustafsson if (*node != NULL) {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff * ... but found a partially matching superdomain.
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff * Unwind the chain to the partial match node
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff * to set level_matches to the level above the node,
b469f0321d2bcea3914c57d26fd43319e506c313Andreas Gustafsson * and then to derive the name.
b469f0321d2bcea3914c57d26fd43319e506c313Andreas Gustafsson *
b469f0321d2bcea3914c57d26fd43319e506c313Andreas Gustafsson * chain->level_count is guaranteed to be at least 1
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * here because by definition of finding a superdomain,
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff * the chain is pointed to at least the first subtree.
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff */
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff chain->level_matches = chain->level_count - 1;
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff while (chain->levels[chain->level_matches] != *node) {
b469f0321d2bcea3914c57d26fd43319e506c313Andreas Gustafsson INSIST(chain->level_matches > 0);
014892d86d30b7eceb0003d51788f9b5cadfc1bfAndreas Gustafsson chain->level_matches--;
014892d86d30b7eceb0003d51788f9b5cadfc1bfAndreas Gustafsson }
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
014892d86d30b7eceb0003d51788f9b5cadfc1bfAndreas Gustafsson if (foundname != NULL) {
014892d86d30b7eceb0003d51788f9b5cadfc1bfAndreas Gustafsson unsigned int saved_count = chain->level_count;
014892d86d30b7eceb0003d51788f9b5cadfc1bfAndreas Gustafsson
014892d86d30b7eceb0003d51788f9b5cadfc1bfAndreas Gustafsson chain->level_count = chain->level_matches + 1;
014892d86d30b7eceb0003d51788f9b5cadfc1bfAndreas Gustafsson
014892d86d30b7eceb0003d51788f9b5cadfc1bfAndreas Gustafsson result = chain_name(chain, foundname,
ISC_FALSE);
chain->level_count = saved_count;
} else
result = ISC_R_SUCCESS;
if (result == ISC_R_SUCCESS)
result = DNS_R_PARTIALMATCH;
} else
result = ISC_R_NOTFOUND;
if (current != NULL) {
/*
* There was an exact match but either
* DNS_RBTFIND_NOEXACT was set, or
* DNS_RBTFIND_EMPTYDATA was set and the node had no
* data. A policy decision was made to set the
* chain to the exact match, but this is subject
* to change if it becomes apparent that something
* else would be more useful. It is important that
* this case is handled here, because the predecessor
* setting code below assumes the match was not exact.
*/
INSIST(((options & DNS_RBTFIND_NOEXACT) != 0) ||
((options & DNS_RBTFIND_EMPTYDATA) == 0 &&
DATA(current) == NULL));
chain->end = current;
} else if ((options & DNS_RBTFIND_NOPREDECESSOR) != 0) {
/*
* Ensure the chain points nowhere.
*/
chain->end = NULL;
} else {
/*
* Since there was no exact match, the chain argument
* needs to be pointed at the DNSSEC predecessor of
* the search name.
*/
if (compared == dns_namereln_subdomain) {
/*
* Attempted to follow a down pointer that was
* NULL, which means the searched for name was
* a subdomain of a terminal name in the tree.
* Since there are no existing subdomains to
* order against, the terminal name is the
* predecessor.
*/
INSIST(chain->level_count > 0);
INSIST(chain->level_matches <
chain->level_count);
chain->end =
chain->levels[--chain->level_count];
} else {
isc_result_t result2;
/*
* Point current to the node that stopped
* the search.
*
* With the hashing modification that has been
* added to the algorithm, the stop node of a
* standard binary search is not known. So it
* has to be found. There is probably a more
* clever way of doing this.
*
* The assignment of current to NULL when
* the relationship is *not* dns_namereln_none,
* even though it later gets set to the same
* last_compared anyway, is simply to not push
* the while loop in one more level of
* indentation.
*/
if (compared == dns_namereln_none)
current = last_compared;
else
current = NULL;
while (current != NULL) {
NODENAME(current, &current_name);
compared = dns_name_fullcompare(
search_name,
&current_name,
&order,
&common_labels);
POST(compared);
last_compared = current;
/*
* Standard binary search movement.
*/
if (order < 0)
current = LEFT(current);
else
current = RIGHT(current);
}
current = last_compared;
/*
* Reached a point within a level tree that
* positively indicates the name is not
* present, but the stop node could be either
* less than the desired name (order > 0) or
* greater than the desired name (order < 0).
*
* If the stop node is less, it is not
* necessarily the predecessor. If the stop
* node has a down pointer, then the real
* predecessor is at the end of a level below
* (not necessarily the next level).
* Move down levels until the rightmost node
* does not have a down pointer.
*
* When the stop node is greater, it is
* the successor. All the logic for finding
* the predecessor is handily encapsulated
* in dns_rbtnodechain_prev. In the event
* that the search name is less than anything
* else in the tree, the chain is reset.
* XXX DCL What is the best way for the caller
* to know that the search name has
* no predecessor?
*/
if (order > 0) {
if (DOWN(current) != NULL) {
ADD_LEVEL(chain, current);
result2 =
move_chain_to_last(chain,
DOWN(current));
if (result2 != ISC_R_SUCCESS)
result = result2;
} else
/*
* Ah, the pure and simple
* case. The stop node is the
* predecessor.
*/
chain->end = current;
} else {
INSIST(order < 0);
chain->end = current;
result2 = dns_rbtnodechain_prev(chain,
NULL,
NULL);
if (result2 == ISC_R_SUCCESS ||
result2 == DNS_R_NEWORIGIN)
; /* Nothing. */
else if (result2 == ISC_R_NOMORE)
/*
* There is no predecessor.
*/
dns_rbtnodechain_reset(chain);
else
result = result2;
}
}
}
}
ENSURE(*node == NULL || DNS_RBTNODE_VALID(*node));
return (result);
}
/*
* Get the data pointer associated with 'name'.
*/
isc_result_t
dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
dns_name_t *foundname, void **data) {
dns_rbtnode_t *node = NULL;
isc_result_t result;
REQUIRE(data != NULL && *data == NULL);
result = dns_rbt_findnode(rbt, name, foundname, &node, NULL,
options, NULL, NULL);
if (node != NULL &&
(DATA(node) != NULL || (options & DNS_RBTFIND_EMPTYDATA) != 0))
*data = DATA(node);
else
result = ISC_R_NOTFOUND;
return (result);
}
/*
* Delete a name from the tree of trees.
*/
isc_result_t
dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse) {
dns_rbtnode_t *node = NULL;
isc_result_t result;
REQUIRE(VALID_RBT(rbt));
REQUIRE(dns_name_isabsolute(name));
/*
* First, find the node.
*
* When searching, the name might not have an exact match:
* consider a.b.a.com, b.b.a.com and c.b.a.com as the only
* elements of a tree, which would make layer 1 a single
* node tree of "b.a.com" and layer 2 a three node tree of
* a, b, and c. Deleting a.com would find only a partial depth
* match in the first layer. Should it be a requirement that
* that the name to be deleted have data? For now, it is.
*
* ->dirty, ->locknum and ->references are ignored; they are
* solely the province of rbtdb.c.
*/
result = dns_rbt_findnode(rbt, name, NULL, &node, NULL,
DNS_RBTFIND_NOOPTIONS, NULL, NULL);
if (result == ISC_R_SUCCESS) {
if (DATA(node) != NULL)
result = dns_rbt_deletenode(rbt, node, recurse);
else
result = ISC_R_NOTFOUND;
} else if (result == DNS_R_PARTIALMATCH)
result = ISC_R_NOTFOUND;
return (result);
}
/*
* Remove a node from the tree of trees.
*
* NOTE WELL: deletion is *not* symmetric with addition; that is, reversing
* a sequence of additions to be deletions will not generally get the
* tree back to the state it started in. For example, if the addition
* of "b.c" caused the node "a.b.c" to be split, pushing "a" to its own level,
* then the subsequent deletion of "b.c" will not cause "a" to be pulled up,
* restoring "a.b.c". The RBT *used* to do this kind of rejoining, but it
* turned out to be a bad idea because it could corrupt an active nodechain
* that had "b.c" as one of its levels -- and the RBT has no idea what
* nodechains are in use by callers, so it can't even *try* to helpfully
* fix them up (which would probably be doomed to failure anyway).
*
* Similarly, it is possible to leave the tree in a state where a supposedly
* deleted node still exists. The first case of this is obvious; take
* the tree which has "b.c" on one level, pointing to "a". Now deleted "b.c".
* It was just established in the previous paragraph why we can't pull "a"
* back up to its parent level. But what happens when "a" then gets deleted?
* "b.c" is left hanging around without data or children. This condition
* is actually pretty easy to detect, but ... should it really be removed?
* Is a chain pointing to it? An iterator? Who knows! (Note that the
* references structure member cannot be looked at because it is private to
* rbtdb.) This is ugly and makes me unhappy, but after hours of trying to
* make it more aesthetically proper and getting nowhere, this is the way it
* is going to stay until such time as it proves to be a *real* problem.
*
* Finally, for reference, note that the original routine that did node
* joining was called join_nodes(). It has been excised, living now only
* in the CVS history, but comments have been left behind that point to it just
* in case someone wants to muck with this some more.
*
* The one positive aspect of all of this is that joining used to have a
* case where it might fail. Without trying to join, now this function always
* succeeds. It still returns isc_result_t, though, so the API wouldn't change.
*/
isc_result_t
dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse)
{
dns_rbtnode_t *parent;
REQUIRE(VALID_RBT(rbt));
REQUIRE(DNS_RBTNODE_VALID(node));
INSIST(rbt->nodecount != 0);
if (DOWN(node) != NULL) {
if (recurse) {
PARENT(DOWN(node)) = NULL;
deletetreeflat(rbt, 0, ISC_TRUE, &DOWN(node));
} else {
if (DATA(node) != NULL && rbt->data_deleter != NULL)
rbt->data_deleter(DATA(node), rbt->deleter_arg);
DATA(node) = NULL;
/*
* Since there is at least one node below this one and
* no recursion was requested, the deletion is
* complete. The down node from this node might be all
* by itself on a single level, so join_nodes() could
* be used to collapse the tree (with all the caveats
* of the comment at the start of this function).
* But join_nodes() function has now been removed.
*/
return (ISC_R_SUCCESS);
}
}
/*
* Note the node that points to the level of the node that is being
* deleted. If the deleted node is the top level, parent will be set
* to NULL.
*/
parent = get_upper_node(node);
/*
* This node now has no down pointer (either because it didn't
* have one to start, or because it was recursively removed).
* So now the node needs to be removed from this level.
*/
deletefromlevel(node, parent == NULL ? &rbt->root : &DOWN(parent));
if (DATA(node) != NULL && rbt->data_deleter != NULL)
rbt->data_deleter(DATA(node), rbt->deleter_arg);
unhash_node(rbt, node);
#if DNS_RBT_USEMAGIC
node->magic = 0;
#endif
dns_rbtnode_refdestroy(node);
freenode(rbt, &node);
/*
* There are now two special cases that can exist that would
* not have existed if the tree had been created using only
* the names that now exist in it. (This is all related to
* join_nodes() as described in this function's introductory comment.)
* Both cases exist when the deleted node's parent (the node
* that pointed to the deleted node's level) is not null but
* it has no data: parent != NULL && DATA(parent) == NULL.
*
* The first case is that the deleted node was the last on its level:
* DOWN(parent) == NULL. This case can only exist if the parent was
* previously deleted -- and so now, apparently, the parent should go
* away. That can't be done though because there might be external
* references to it, such as through a nodechain.
*
* The other case also involves a parent with no data, but with the
* deleted node being the next-to-last node instead of the last:
* LEFT(DOWN(parent)) == NULL && RIGHT(DOWN(parent)) == NULL.
* Presumably now the remaining node on the level should be joined
* with the parent, but it's already been described why that can't be
* done.
*/
/*
* This function never fails.
*/
return (ISC_R_SUCCESS);
}
void
dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name) {
REQUIRE(DNS_RBTNODE_VALID(node));
REQUIRE(name != NULL);
REQUIRE(name->offsets == NULL);
NODENAME(node, name);
}
isc_result_t
dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) {
dns_name_t current;
isc_result_t result;
REQUIRE(DNS_RBTNODE_VALID(node));
REQUIRE(name != NULL);
REQUIRE(name->buffer != NULL);
dns_name_init(&current, NULL);
dns_name_reset(name);
do {
INSIST(node != NULL);
NODENAME(node, &current);
result = dns_name_concatenate(name, &current, name, NULL);
if (result != ISC_R_SUCCESS)
break;
node = get_upper_node(node);
} while (! dns_name_isabsolute(name));
return (result);
}
char *
dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size)
{
dns_fixedname_t fixedname;
dns_name_t *name;
isc_result_t result;
REQUIRE(DNS_RBTNODE_VALID(node));
REQUIRE(printname != NULL);
dns_fixedname_init(&fixedname);
name = dns_fixedname_name(&fixedname);
result = dns_rbt_fullnamefromnode(node, name);
if (result == ISC_R_SUCCESS)
dns_name_format(name, printname, size);
else
snprintf(printname, size, "<error building name: %s>",
dns_result_totext(result));
return (printname);
}
static isc_result_t
create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) {
dns_rbtnode_t *node;
isc_region_t region;
unsigned int labels;
size_t nodelen;
REQUIRE(name->offsets != NULL);
dns_name_toregion(name, &region);
labels = dns_name_countlabels(name);
ENSURE(labels > 0);
/*
* Allocate space for the node structure, the name, and the offsets.
*/
nodelen = sizeof(dns_rbtnode_t) + region.length + labels + 1;
node = (dns_rbtnode_t *)isc_mem_get(mctx, nodelen);
if (node == NULL)
return (ISC_R_NOMEMORY);
memset(node, 0, nodelen);
node->is_root = 0;
PARENT(node) = NULL;
RIGHT(node) = NULL;
LEFT(node) = NULL;
DOWN(node) = NULL;
DATA(node) = NULL;
node->is_mmapped = 0;
node->down_is_relative = 0;
node->left_is_relative = 0;
node->right_is_relative = 0;
node->parent_is_relative = 0;
node->data_is_relative = 0;
node->rpz = 0;
#ifdef DNS_RBT_USEHASH
HASHNEXT(node) = NULL;
HASHVAL(node) = 0;
#endif
ISC_LINK_INIT(node, deadlink);
LOCKNUM(node) = 0;
WILD(node) = 0;
DIRTY(node) = 0;
dns_rbtnode_refinit(node, 0);
node->find_callback = 0;
node->nsec = DNS_RBT_NSEC_NORMAL;
MAKE_BLACK(node);
/*
* The following is stored to make reconstructing a name from the
* stored value in the node easy: the length of the name, the number
* of labels, whether the name is absolute or not, the name itself,
* and the name's offsets table.
*
* XXX RTH
* The offsets table could be made smaller by eliminating the
* first offset, which is always 0. This requires changes to
* lib/dns/name.c.
*
* Note: OLDOFFSETLEN *must* be assigned *after* OLDNAMELEN is assigned
* as it uses OLDNAMELEN.
*/
OLDNAMELEN(node) = NAMELEN(node) = region.length;
OLDOFFSETLEN(node) = OFFSETLEN(node) = labels;
ATTRS(node) = name->attributes;
memmove(NAME(node), region.base, region.length);
memmove(OFFSETS(node), name->offsets, labels);
#if DNS_RBT_USEMAGIC
node->magic = DNS_RBTNODE_MAGIC;
#endif
*nodep = node;
return (ISC_R_SUCCESS);
}
#ifdef DNS_RBT_USEHASH
static inline void
hash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
unsigned int hash;
REQUIRE(name != NULL);
HASHVAL(node) = dns_name_fullhash(name, ISC_FALSE);
hash = HASHVAL(node) % rbt->hashsize;
HASHNEXT(node) = rbt->hashtable[hash];
rbt->hashtable[hash] = node;
}
static isc_result_t
inithash(dns_rbt_t *rbt) {
unsigned int bytes;
rbt->hashsize = RBT_HASH_SIZE;
bytes = rbt->hashsize * sizeof(dns_rbtnode_t *);
rbt->hashtable = isc_mem_get(rbt->mctx, bytes);
if (rbt->hashtable == NULL)
return (ISC_R_NOMEMORY);
memset(rbt->hashtable, 0, bytes);
return (ISC_R_SUCCESS);
}
static void
rehash(dns_rbt_t *rbt, unsigned int newcount) {
unsigned int oldsize;
dns_rbtnode_t **oldtable;
dns_rbtnode_t *node;
dns_rbtnode_t *nextnode;
unsigned int hash;
unsigned int i;
oldsize = rbt->hashsize;
oldtable = rbt->hashtable;
do {
INSIST((rbt->hashsize * 2 + 1) > rbt->hashsize);
rbt->hashsize = rbt->hashsize * 2 + 1;
} while (newcount >= (rbt->hashsize * 3));
rbt->hashtable = isc_mem_get(rbt->mctx,
rbt->hashsize * sizeof(dns_rbtnode_t *));
if (rbt->hashtable == NULL) {
rbt->hashtable = oldtable;
rbt->hashsize = oldsize;
return;
}
for (i = 0; i < rbt->hashsize; i++)
rbt->hashtable[i] = NULL;
for (i = 0; i < oldsize; i++) {
for (node = oldtable[i]; node != NULL; node = nextnode) {
hash = HASHVAL(node) % rbt->hashsize;
nextnode = HASHNEXT(node);
HASHNEXT(node) = rbt->hashtable[hash];
rbt->hashtable[hash] = node;
}
}
isc_mem_put(rbt->mctx, oldtable, oldsize * sizeof(dns_rbtnode_t *));
}
static inline void
hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
REQUIRE(DNS_RBTNODE_VALID(node));
if (rbt->nodecount >= (rbt->hashsize * 3))
rehash(rbt, rbt->nodecount);
hash_add_node(rbt, node, name);
}
static inline void
unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {
unsigned int bucket;
dns_rbtnode_t *bucket_node;
REQUIRE(DNS_RBTNODE_VALID(node));
bucket = HASHVAL(node) % rbt->hashsize;
bucket_node = rbt->hashtable[bucket];
if (bucket_node == node) {
rbt->hashtable[bucket] = HASHNEXT(node);
} else {
while (HASHNEXT(bucket_node) != node) {
INSIST(HASHNEXT(bucket_node) != NULL);
bucket_node = HASHNEXT(bucket_node);
}
HASHNEXT(bucket_node) = HASHNEXT(node);
}
}
#endif /* DNS_RBT_USEHASH */
static inline void
rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
dns_rbtnode_t *child;
REQUIRE(DNS_RBTNODE_VALID(node));
REQUIRE(rootp != NULL);
child = RIGHT(node);
INSIST(child != NULL);
RIGHT(node) = LEFT(child);
if (LEFT(child) != NULL)
PARENT(LEFT(child)) = node;
LEFT(child) = node;
PARENT(child) = PARENT(node);
if (IS_ROOT(node)) {
*rootp = child;
child->is_root = 1;
node->is_root = 0;
} else {
if (LEFT(PARENT(node)) == node)
LEFT(PARENT(node)) = child;
else
RIGHT(PARENT(node)) = child;
}
PARENT(node) = child;
}
static inline void
rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
dns_rbtnode_t *child;
REQUIRE(DNS_RBTNODE_VALID(node));
REQUIRE(rootp != NULL);
child = LEFT(node);
INSIST(child != NULL);
LEFT(node) = RIGHT(child);
if (RIGHT(child) != NULL)
PARENT(RIGHT(child)) = node;
RIGHT(child) = node;
PARENT(child) = PARENT(node);
if (IS_ROOT(node)) {
*rootp = child;
child->is_root = 1;
node->is_root = 0;
} else {
if (LEFT(PARENT(node)) == node)
LEFT(PARENT(node)) = child;
else
RIGHT(PARENT(node)) = child;
}
PARENT(node) = child;
}
/*
* This is the real workhorse of the insertion code, because it does the
* true red/black tree on a single level.
*/
static void
addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
dns_rbtnode_t **rootp)
{
dns_rbtnode_t *child, *root, *parent, *grandparent;
dns_name_t add_name, current_name;
dns_offsets_t add_offsets, current_offsets;
REQUIRE(rootp != NULL);
REQUIRE(DNS_RBTNODE_VALID(node) && LEFT(node) == NULL &&
RIGHT(node) == NULL);
REQUIRE(current != NULL);
root = *rootp;
if (root == NULL) {
/*
* First node of a level.
*/
MAKE_BLACK(node);
node->is_root = 1;
PARENT(node) = current;
*rootp = node;
return;
}
child = root;
POST(child);
dns_name_init(&add_name, add_offsets);
NODENAME(node, &add_name);
dns_name_init(&current_name, current_offsets);
NODENAME(current, &current_name);
if (order < 0) {
INSIST(LEFT(current) == NULL);
LEFT(current) = node;
} else {
INSIST(RIGHT(current) == NULL);
RIGHT(current) = node;
}
INSIST(PARENT(node) == NULL);
PARENT(node) = current;
MAKE_RED(node);
while (node != root && IS_RED(PARENT(node))) {
/*
* XXXDCL could do away with separate parent and grandparent
* variables. They are vestiges of the days before parent
* pointers. However, they make the code a little clearer.
*/
parent = PARENT(node);
grandparent = PARENT(parent);
if (parent == LEFT(grandparent)) {
child = RIGHT(grandparent);
if (child != NULL && IS_RED(child)) {
MAKE_BLACK(parent);
MAKE_BLACK(child);
MAKE_RED(grandparent);
node = grandparent;
} else {
if (node == RIGHT(parent)) {
rotate_left(parent, &root);
node = parent;
parent = PARENT(node);
grandparent = PARENT(parent);
}
MAKE_BLACK(parent);
MAKE_RED(grandparent);
rotate_right(grandparent, &root);
}
} else {
child = LEFT(grandparent);
if (child != NULL && IS_RED(child)) {
MAKE_BLACK(parent);
MAKE_BLACK(child);
MAKE_RED(grandparent);
node = grandparent;
} else {
if (node == LEFT(parent)) {
rotate_right(parent, &root);
node = parent;
parent = PARENT(node);
grandparent = PARENT(parent);
}
MAKE_BLACK(parent);
MAKE_RED(grandparent);
rotate_left(grandparent, &root);
}
}
}
MAKE_BLACK(root);
ENSURE(IS_ROOT(root));
*rootp = root;
return;
}
/*
* This is the real workhorse of the deletion code, because it does the
* true red/black tree on a single level.
*/
static void
deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) {
dns_rbtnode_t *child, *sibling, *parent;
dns_rbtnode_t *successor;
REQUIRE(delete != NULL);
/*
* Verify that the parent history is (apparently) correct.
*/
INSIST((IS_ROOT(delete) && *rootp == delete) ||
(! IS_ROOT(delete) &&
(LEFT(PARENT(delete)) == delete ||
RIGHT(PARENT(delete)) == delete)));
child = NULL;
if (LEFT(delete) == NULL) {
if (RIGHT(delete) == NULL) {
if (IS_ROOT(delete)) {
/*
* This is the only item in the tree.
*/
*rootp = NULL;
return;
}
} else
/*
* This node has one child, on the right.
*/
child = RIGHT(delete);
} else if (RIGHT(delete) == NULL)
/*
* This node has one child, on the left.
*/
child = LEFT(delete);
else {
dns_rbtnode_t holder, *tmp = &holder;
/*
* This node has two children, so it cannot be directly
* deleted. Find its immediate in-order successor and
* move it to this location, then do the deletion at the
* old site of the successor.
*/
successor = RIGHT(delete);
while (LEFT(successor) != NULL)
successor = LEFT(successor);
/*
* The successor cannot possibly have a left child;
* if there is any child, it is on the right.
*/
if (RIGHT(successor) != NULL)
child = RIGHT(successor);
/*
* Swap the two nodes; it would be simpler to just replace
* the value being deleted with that of the successor,
* but this rigamarole is done so the caller has complete
* control over the pointers (and memory allocation) of
* all of nodes. If just the key value were removed from
* the tree, the pointer to the node would be unchanged.
*/
/*
* First, put the successor in the tree location of the
* node to be deleted. Save its existing tree pointer
* information, which will be needed when linking up
* delete to the successor's old location.
*/
memmove(tmp, successor, sizeof(dns_rbtnode_t));
if (IS_ROOT(delete)) {
*rootp = successor;
successor->is_root = ISC_TRUE;
delete->is_root = ISC_FALSE;
} else
if (LEFT(PARENT(delete)) == delete)
LEFT(PARENT(delete)) = successor;
else
RIGHT(PARENT(delete)) = successor;
PARENT(successor) = PARENT(delete);
LEFT(successor) = LEFT(delete);
RIGHT(successor) = RIGHT(delete);
COLOR(successor) = COLOR(delete);
if (LEFT(successor) != NULL)
PARENT(LEFT(successor)) = successor;
if (RIGHT(successor) != successor)
PARENT(RIGHT(successor)) = successor;
/*
* Now relink the node to be deleted into the
* successor's previous tree location. PARENT(tmp)
* is the successor's original parent.
*/
INSIST(! IS_ROOT(delete));
if (PARENT(tmp) == delete) {
/*
* Node being deleted was successor's parent.
*/
RIGHT(successor) = delete;
PARENT(delete) = successor;
} else {
LEFT(PARENT(tmp)) = delete;
PARENT(delete) = PARENT(tmp);
}
/*
* Original location of successor node has no left.
*/
LEFT(delete) = NULL;
RIGHT(delete) = RIGHT(tmp);
COLOR(delete) = COLOR(tmp);
}
/*
* Remove the node by removing the links from its parent.
*/
if (! IS_ROOT(delete)) {
if (LEFT(PARENT(delete)) == delete)
LEFT(PARENT(delete)) = child;
else
RIGHT(PARENT(delete)) = child;
if (child != NULL)
PARENT(child) = PARENT(delete);
} else {
/*
* This is the root being deleted, and at this point
* it is known to have just one child.
*/
*rootp = child;
child->is_root = 1;
PARENT(child) = PARENT(delete);
}
/*
* Fix color violations.
*/
if (IS_BLACK(delete)) {
parent = PARENT(delete);
while (child != *rootp && IS_BLACK(child)) {
INSIST(child == NULL || ! IS_ROOT(child));
if (LEFT(parent) == child) {
sibling = RIGHT(parent);
if (IS_RED(sibling)) {
MAKE_BLACK(sibling);
MAKE_RED(parent);
rotate_left(parent, rootp);
sibling = RIGHT(parent);
}
INSIST(sibling != NULL);
if (IS_BLACK(LEFT(sibling)) &&
IS_BLACK(RIGHT(sibling))) {
MAKE_RED(sibling);
child = parent;
} else {
if (IS_BLACK(RIGHT(sibling))) {
MAKE_BLACK(LEFT(sibling));
MAKE_RED(sibling);
rotate_right(sibling, rootp);
sibling = RIGHT(parent);
}
COLOR(sibling) = COLOR(parent);
MAKE_BLACK(parent);
INSIST(RIGHT(sibling) != NULL);
MAKE_BLACK(RIGHT(sibling));
rotate_left(parent, rootp);
child = *rootp;
}
} else {
/*
* Child is parent's right child.
* Everything is done the same as above,
* except mirrored.
*/
sibling = LEFT(parent);
if (IS_RED(sibling)) {
MAKE_BLACK(sibling);
MAKE_RED(parent);
rotate_right(parent, rootp);
sibling = LEFT(parent);
}
INSIST(sibling != NULL);
if (IS_BLACK(LEFT(sibling)) &&
IS_BLACK(RIGHT(sibling))) {
MAKE_RED(sibling);
child = parent;
} else {
if (IS_BLACK(LEFT(sibling))) {
MAKE_BLACK(RIGHT(sibling));
MAKE_RED(sibling);
rotate_left(sibling, rootp);
sibling = LEFT(parent);
}
COLOR(sibling) = COLOR(parent);
MAKE_BLACK(parent);
INSIST(LEFT(sibling) != NULL);
MAKE_BLACK(LEFT(sibling));
rotate_right(parent, rootp);
child = *rootp;
}
}
parent = PARENT(child);
}
if (IS_RED(child))
MAKE_BLACK(child);
}
}
static void
freenode(dns_rbt_t *rbt, dns_rbtnode_t **nodep) {
dns_rbtnode_t *node = *nodep;
if (node->is_mmapped == 0) {
isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
}
*nodep = NULL;
rbt->nodecount--;
}
static void
deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, isc_boolean_t unhash,
dns_rbtnode_t **nodep)
{
dns_rbtnode_t *root = *nodep;
while (root != NULL) {
/*
* If there is a left, right or down node, walk into it
* and iterate.
*/
if (LEFT(root) != NULL) {
dns_rbtnode_t *node = root;
root = LEFT(root);
LEFT(node) = NULL;
} else if (RIGHT(root) != NULL) {
dns_rbtnode_t *node = root;
root = RIGHT(root);
RIGHT(node) = NULL;
} else if (DOWN(root) != NULL) {
dns_rbtnode_t *node = root;
root = DOWN(root);
DOWN(node) = NULL;
} else {
/*
* There are no left, right or down nodes, so we
* can free this one and go back to its parent.
*/
dns_rbtnode_t *node = root;
root = PARENT(root);
if (DATA(node) != NULL && rbt->data_deleter != NULL)
rbt->data_deleter(DATA(node),
rbt->deleter_arg);
if (unhash)
unhash_node(rbt, node);
/*
* Note: we don't call unhash_node() here as we
* are destroying the complete RBT tree.
*/
#if DNS_RBT_USEMAGIC
node->magic = 0;
#endif
freenode(rbt, &node);
if (quantum != 0 && --quantum == 0)
break;
}
}
*nodep = root;
}
static size_t
getheight_helper(dns_rbtnode_t *node) {
size_t dl, dr;
size_t this_height, down_height;
if (node == NULL)
return (0);
dl = getheight_helper(LEFT(node));
dr = getheight_helper(RIGHT(node));
this_height = ISC_MAX(dl + 1, dr + 1);
down_height = getheight_helper(DOWN(node));
return (ISC_MAX(this_height, down_height));
}
size_t
dns__rbt_getheight(dns_rbt_t *rbt) {
return (getheight_helper(rbt->root));
}
static isc_boolean_t
check_properties_helper(dns_rbtnode_t *node) {
if (node == NULL)
return (ISC_TRUE);
if (IS_RED(node)) {
/* Root nodes must be BLACK. */
if (IS_ROOT(node))
return (ISC_FALSE);
/* Both children of RED nodes must be BLACK. */
if (IS_RED(LEFT(node)) || IS_RED(RIGHT(node)))
return (ISC_FALSE);
}
/* If node is assigned to the down_ pointer of its parent, it is
* a subtree root and must have the flag set.
*/
if (((!PARENT(node)) ||
(DOWN(PARENT(node)) == node)) &&
(!IS_ROOT(node)))
{
return (ISC_FALSE);
}
/* Repeat tests with this node's children. */
return (check_properties_helper(LEFT(node)) &&
check_properties_helper(RIGHT(node)) &&
check_properties_helper(DOWN(node)));
}
static isc_boolean_t
check_black_distance_helper(dns_rbtnode_t *node, size_t *distance) {
size_t dl, dr, dd;
if (node == NULL) {
*distance = 1;
return (ISC_TRUE);
}
if (!check_black_distance_helper(LEFT(node), &dl))
return (ISC_FALSE);
if (!check_black_distance_helper(RIGHT(node), &dr))
return (ISC_FALSE);
if (!check_black_distance_helper(DOWN(node), &dd))
return (ISC_FALSE);
/* Left and right side black node counts must match. */
if (dl != dr)
return (ISC_FALSE);
if (IS_BLACK(node))
dl++;
*distance = dl;
return (ISC_TRUE);
}
isc_boolean_t
dns__rbt_checkproperties(dns_rbt_t *rbt) {
size_t dd;
if (!check_properties_helper(rbt->root))
return (ISC_FALSE);
/* Path from a given node to all its leaves must contain the
* same number of BLACK child nodes. This is done separately
* here instead of inside check_properties_helper() as
* it would take (n log n) complexity otherwise.
*/
return (check_black_distance_helper(rbt->root, &dd));
}
static void
dns_rbt_indent(FILE *f, int depth) {
int i;
fprintf(f, "%4d ", depth);
for (i = 0; i < depth; i++)
fprintf(f, "- ");
}
void
dns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f) {
fprintf(f, "Node info for nodename: ");
printnodename(n, ISC_TRUE, f);
fprintf(f, "\n");
fprintf(f, "n = %p\n", n);
fprintf(f, "Relative pointers: %s%s%s%s%s\n",
(n->parent_is_relative == 1 ? " P" : ""),
(n->right_is_relative == 1 ? " R" : ""),
(n->left_is_relative == 1 ? " L" : ""),
(n->down_is_relative == 1 ? " D" : ""),
(n->data_is_relative == 1 ? " T" : ""));
fprintf(f, "node lock address = %d\n", n->locknum);
fprintf(f, "Parent: %p\n", n->parent);
fprintf(f, "Right: %p\n", n->right);
fprintf(f, "Left: %p\n", n->left);
fprintf(f, "Down: %p\n", n->down);
fprintf(f, "daTa: %p\n", n->data);
}
static void
printnodename(dns_rbtnode_t *node, isc_boolean_t quoted, FILE *f) {
isc_region_t r;
dns_name_t name;
char buffer[DNS_NAME_FORMATSIZE];
dns_offsets_t offsets;
r.length = NAMELEN(node);
r.base = NAME(node);
dns_name_init(&name, offsets);
dns_name_fromregion(&name, &r);
dns_name_format(&name, buffer, sizeof(buffer));
if (quoted)
fprintf(f, "\"%s\"", buffer);
else
fprintf(f, "%s", buffer);
}
static void
print_text_helper(dns_rbtnode_t *root, dns_rbtnode_t *parent,
int depth, const char *direction,
void (*data_printer)(FILE *, void *), FILE *f)
{
dns_rbt_indent(f, depth);
if (root != NULL) {
printnodename(root, ISC_TRUE, f);
fprintf(f, " (%s, %s", direction,
IS_RED(root) ? "RED" : "BLACK");
if ((! IS_ROOT(root) && PARENT(root) != parent) ||
( IS_ROOT(root) && depth > 0 &&
DOWN(PARENT(root)) != root)) {
fprintf(f, " (BAD parent pointer! -> ");
if (PARENT(root) != NULL)
printnodename(PARENT(root), ISC_TRUE, f);
else
fprintf(f, "NULL");
fprintf(f, ")");
}
fprintf(f, ")");
if (root->data != NULL && data_printer != NULL) {
fprintf(f, " data@%p: ", root->data);
data_printer(f, root->data);
}
fprintf(f, "\n");
depth++;
if (IS_RED(root) && IS_RED(LEFT(root)))
fprintf(f, "** Red/Red color violation on left\n");
print_text_helper(LEFT(root), root, depth, "left",
data_printer, f);
if (IS_RED(root) && IS_RED(RIGHT(root)))
fprintf(f, "** Red/Red color violation on right\n");
print_text_helper(RIGHT(root), root, depth, "right",
data_printer, f);
print_text_helper(DOWN(root), NULL, depth, "down",
data_printer, f);
} else {
fprintf(f, "NULL (%s)\n", direction);
}
}
void
dns_rbt_printtext(dns_rbt_t *rbt,
void (*data_printer)(FILE *, void *), FILE *f)
{
REQUIRE(VALID_RBT(rbt));
print_text_helper(rbt->root, NULL, 0, "root", data_printer, f);
}
static int
print_dot_helper(dns_rbtnode_t *node, unsigned int *nodecount,
isc_boolean_t show_pointers, FILE *f)
{
unsigned int l, r, d;
if (node == NULL)
return (0);
l = print_dot_helper(LEFT(node), nodecount, show_pointers, f);
r = print_dot_helper(RIGHT(node), nodecount, show_pointers, f);
d = print_dot_helper(DOWN(node), nodecount, show_pointers, f);
*nodecount += 1;
fprintf(f, "node%u[label = \"<f0> |<f1> ", *nodecount);
printnodename(node, ISC_FALSE, f);
fprintf(f, "|<f2>");
if (show_pointers)
fprintf(f, "|<f3> n=%p|<f4> p=%p", node, PARENT(node));
fprintf(f, "\"] [");
if (IS_RED(node))
fprintf(f, "color=red");
else
fprintf(f, "color=black");
/* XXXMUKS: verify that IS_ROOT() indicates subtree root and not
* forest root.
*/
if (IS_ROOT(node))
fprintf(f, ",penwidth=3");
if (IS_EMPTY(node))
fprintf(f, ",style=filled,fillcolor=lightgrey");
fprintf(f, "];\n");
if (LEFT(node) != NULL)
fprintf(f, "\"node%u\":f0 -> \"node%u\":f1;\n", *nodecount, l);
if (DOWN(node) != NULL)
fprintf(f, "\"node%u\":f1 -> \"node%u\":f1 [penwidth=5];\n",
*nodecount, d);
if (RIGHT(node) != NULL)
fprintf(f, "\"node%u\":f2 -> \"node%u\":f1;\n", *nodecount, r);
return (*nodecount);
}
void
dns_rbt_printdot(dns_rbt_t *rbt, isc_boolean_t show_pointers, FILE *f) {
unsigned int nodecount = 0;
REQUIRE(VALID_RBT(rbt));
fprintf(f, "digraph g {\n");
fprintf(f, "node [shape = record,height=.1];\n");
print_dot_helper(rbt->root, &nodecount, show_pointers, f);
fprintf(f, "}\n");
}
/*
* Chain Functions
*/
void
dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx) {
REQUIRE(chain != NULL);
/*
* Initialize 'chain'.
*/
chain->mctx = mctx;
chain->end = NULL;
chain->level_count = 0;
chain->level_matches = 0;
memset(chain->levels, 0, sizeof(chain->levels));
chain->magic = CHAIN_MAGIC;
}
isc_result_t
dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
dns_name_t *origin, dns_rbtnode_t **node)
{
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(VALID_CHAIN(chain));
if (node != NULL)
*node = chain->end;
if (chain->end == NULL)
return (ISC_R_NOTFOUND);
if (name != NULL) {
NODENAME(chain->end, name);
if (chain->level_count == 0) {
/*
* Names in the top level tree are all absolute.
* Always make 'name' relative.
*/
INSIST(dns_name_isabsolute(name));
/*
* This is cheaper than dns_name_getlabelsequence().
*/
name->labels--;
name->length--;
name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
}
}
if (origin != NULL) {
if (chain->level_count > 0)
result = chain_name(chain, origin, ISC_FALSE);
else
result = dns_name_copy(dns_rootname, origin, NULL);
}
return (result);
}
isc_result_t
dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
dns_name_t *origin)
{
dns_rbtnode_t *current, *previous, *predecessor;
isc_result_t result = ISC_R_SUCCESS;
isc_boolean_t new_origin = ISC_FALSE;
REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
predecessor = NULL;
current = chain->end;
if (LEFT(current) != NULL) {
/*
* Moving left one then right as far as possible is the
* previous node, at least for this level.
*/
current = LEFT(current);
while (RIGHT(current) != NULL)
current = RIGHT(current);
predecessor = current;
} else {
/*
* No left links, so move toward the root. If at any point on
* the way there the link from parent to child is a right
* link, then the parent is the previous node, at least
* for this level.
*/
while (! IS_ROOT(current)) {
previous = current;
current = PARENT(current);
if (RIGHT(current) == previous) {
predecessor = current;
break;
}
}
}
if (predecessor != NULL) {
/*
* Found a predecessor node in this level. It might not
* really be the predecessor, however.
*/
if (DOWN(predecessor) != NULL) {
/*
* The predecessor is really down at least one level.
* Go down and as far right as possible, and repeat
* as long as the rightmost node has a down pointer.
*/
do {
/*
* XXX DCL Need to do something about origins
* here. See whether to go down, and if so
* whether it is truly what Bob calls a
* new origin.
*/
ADD_LEVEL(chain, predecessor);
predecessor = DOWN(predecessor);
/* XXX DCL duplicated from above; clever
* way to unduplicate? */
while (RIGHT(predecessor) != NULL)
predecessor = RIGHT(predecessor);
} while (DOWN(predecessor) != NULL);
/* XXX DCL probably needs work on the concept */
if (origin != NULL)
new_origin = ISC_TRUE;
}
} else if (chain->level_count > 0) {
/*
* Dang, didn't find a predecessor in this level.
* Got to the root of this level without having traversed
* any right links. Ascend the tree one level; the
* node that points to this tree is the predecessor.
*/
INSIST(chain->level_count > 0 && IS_ROOT(current));
predecessor = chain->levels[--chain->level_count];
/* XXX DCL probably needs work on the concept */
/*
* Don't declare an origin change when the new origin is "."
* at the top level tree, because "." is declared as the origin
* for the second level tree.
*/
if (origin != NULL &&
(chain->level_count > 0 || OFFSETLEN(predecessor) > 1))
new_origin = ISC_TRUE;
}
if (predecessor != NULL) {
chain->end = predecessor;
if (new_origin) {
result = dns_rbtnodechain_current(chain, name, origin,
NULL);
if (result == ISC_R_SUCCESS)
result = DNS_R_NEWORIGIN;
} else
result = dns_rbtnodechain_current(chain, name, NULL,
NULL);
} else
result = ISC_R_NOMORE;
return (result);
}
isc_result_t
dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name,
dns_name_t *origin)
{
dns_rbtnode_t *current, *successor;
isc_result_t result = ISC_R_SUCCESS;
isc_boolean_t new_origin = ISC_FALSE;
REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
successor = NULL;
current = chain->end;
if (DOWN(current) != NULL) {
/*
* Don't declare an origin change when the new origin is "."
* at the second level tree, because "." is already declared
* as the origin for the top level tree.
*/
if (chain->level_count > 0 ||
OFFSETLEN(current) > 1)
new_origin = ISC_TRUE;
ADD_LEVEL(chain, current);
current = DOWN(current);
while (LEFT(current) != NULL)
current = LEFT(current);
successor = current;
}
if (successor != NULL) {
chain->end = successor;
/*
* It is not necessary to use dns_rbtnodechain_current like
* the other functions because this function will never
* find a node in the topmost level. This is because the
* root level will never be more than one name, and everything
* in the megatree is a successor to that node, down at
* the second level or below.
*/
if (name != NULL)
NODENAME(chain->end, name);
if (new_origin) {
if (origin != NULL)
result = chain_name(chain, origin, ISC_FALSE);
if (result == ISC_R_SUCCESS)
result = DNS_R_NEWORIGIN;
} else
result = ISC_R_SUCCESS;
} else
result = ISC_R_NOMORE;
return (result);
}
isc_result_t
dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name) {
dns_rbtnode_t *current, *previous, *successor;
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
successor = NULL;
current = chain->end;
if (RIGHT(current) == NULL) {
while (! IS_ROOT(current)) {
previous = current;
current = PARENT(current);
if (LEFT(current) == previous) {
successor = current;
break;
}
}
} else {
current = RIGHT(current);
while (LEFT(current) != NULL)
current = LEFT(current);
successor = current;
}
if (successor != NULL) {
chain->end = successor;
if (name != NULL)
NODENAME(chain->end, name);
result = ISC_R_SUCCESS;
} else
result = ISC_R_NOMORE;
return (result);
}
isc_result_t
dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
dns_name_t *origin)
{
dns_rbtnode_t *current, *previous, *successor;
isc_result_t result = ISC_R_SUCCESS;
isc_boolean_t new_origin = ISC_FALSE;
REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
successor = NULL;
current = chain->end;
/*
* If there is a level below this node, the next node is the leftmost
* node of the next level.
*/
if (DOWN(current) != NULL) {
/*
* Don't declare an origin change when the new origin is "."
* at the second level tree, because "." is already declared
* as the origin for the top level tree.
*/
if (chain->level_count > 0 ||
OFFSETLEN(current) > 1)
new_origin = ISC_TRUE;
ADD_LEVEL(chain, current);
current = DOWN(current);
while (LEFT(current) != NULL)
current = LEFT(current);
successor = current;
} else if (RIGHT(current) == NULL) {
/*
* The successor is up, either in this level or a previous one.
* Head back toward the root of the tree, looking for any path
* that was via a left link; the successor is the node that has
* that left link. In the event the root of the level is
* reached without having traversed any left links, ascend one
* level and look for either a right link off the point of
* ascent, or search for a left link upward again, repeating
* ascends until either case is true.
*/
do {
while (! IS_ROOT(current)) {
previous = current;
current = PARENT(current);
if (LEFT(current) == previous) {
successor = current;
break;
}
}
if (successor == NULL) {
/*
* Reached the root without having traversed
* any left pointers, so this level is done.
*/
if (chain->level_count == 0)
break;
current = chain->levels[--chain->level_count];
new_origin = ISC_TRUE;
if (RIGHT(current) != NULL)
break;
}
} while (successor == NULL);
}
if (successor == NULL && RIGHT(current) != NULL) {
current = RIGHT(current);
while (LEFT(current) != NULL)
current = LEFT(current);
successor = current;
}
if (successor != NULL) {
chain->end = successor;
/*
* It is not necessary to use dns_rbtnodechain_current like
* the other functions because this function will never
* find a node in the topmost level. This is because the
* root level will never be more than one name, and everything
* in the megatree is a successor to that node, down at
* the second level or below.
*/
if (name != NULL)
NODENAME(chain->end, name);
if (new_origin) {
if (origin != NULL)
result = chain_name(chain, origin, ISC_FALSE);
if (result == ISC_R_SUCCESS)
result = DNS_R_NEWORIGIN;
} else
result = ISC_R_SUCCESS;
} else
result = ISC_R_NOMORE;
return (result);
}
isc_result_t
dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
dns_name_t *name, dns_name_t *origin)
{
isc_result_t result;
REQUIRE(VALID_RBT(rbt));
REQUIRE(VALID_CHAIN(chain));
dns_rbtnodechain_reset(chain);
chain->end = rbt->root;
result = dns_rbtnodechain_current(chain, name, origin, NULL);
if (result == ISC_R_SUCCESS)
result = DNS_R_NEWORIGIN;
return (result);
}
isc_result_t
dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
dns_name_t *name, dns_name_t *origin)
{
isc_result_t result;
REQUIRE(VALID_RBT(rbt));
REQUIRE(VALID_CHAIN(chain));
dns_rbtnodechain_reset(chain);
result = move_chain_to_last(chain, rbt->root);
if (result != ISC_R_SUCCESS)
return (result);
result = dns_rbtnodechain_current(chain, name, origin, NULL);
if (result == ISC_R_SUCCESS)
result = DNS_R_NEWORIGIN;
return (result);
}
void
dns_rbtnodechain_reset(dns_rbtnodechain_t *chain) {
REQUIRE(VALID_CHAIN(chain));
/*
* Free any dynamic storage associated with 'chain', and then
* reinitialize 'chain'.
*/
chain->end = NULL;
chain->level_count = 0;
chain->level_matches = 0;
}
void
dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain) {
/*
* Free any dynamic storage associated with 'chain', and then
* invalidate 'chain'.
*/
dns_rbtnodechain_reset(chain);
chain->magic = 0;
}
/* XXXMUKS:
*
* - worth removing inline as static functions are inlined automatically
* where suitable by modern compilers.
* - bump the size of dns_rbt.nodecount to size_t.
* - the dumpfile header also contains a nodecount that is unsigned
* int. If large files (> 2^32 nodes) are to be supported, the
* allocation for this field should be increased.
*/