00001 /* 00002 * Copyright (C) 2004-2009, 2012-2015 Internet Systems Consortium, Inc. ("ISC") 00003 * Copyright (C) 1999-2002 Internet Software Consortium. 00004 * 00005 * Permission to use, copy, modify, and/or distribute this software for any 00006 * purpose with or without fee is hereby granted, provided that the above 00007 * copyright notice and this permission notice appear in all copies. 00008 * 00009 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 00010 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00011 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 00012 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00013 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 00014 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00015 * PERFORMANCE OF THIS SOFTWARE. 00016 */ 00017 00018 /* $Id: rbt.h,v 1.77.666.4 2012/02/08 19:53:30 each Exp $ */ 00019 00020 #ifndef DNS_RBT_H 00021 #define DNS_RBT_H 1 00022 00023 /*! \file dns/rbt.h */ 00024 00025 #include <isc/crc64.h> 00026 #include <isc/lang.h> 00027 #include <isc/magic.h> 00028 #include <isc/refcount.h> 00029 00030 #include <dns/types.h> 00031 00032 ISC_LANG_BEGINDECLS 00033 00034 #define DNS_RBT_USEHASH 1 00035 00036 /*@{*/ 00037 /*% 00038 * Option values for dns_rbt_findnode() and dns_rbt_findname(). 00039 * These are used to form a bitmask. 00040 */ 00041 #define DNS_RBTFIND_NOOPTIONS 0x00 00042 #define DNS_RBTFIND_EMPTYDATA 0x01 00043 #define DNS_RBTFIND_NOEXACT 0x02 00044 #define DNS_RBTFIND_NOPREDECESSOR 0x04 00045 /*@}*/ 00046 00047 #ifndef DNS_RBT_USEISCREFCOUNT 00048 #ifdef ISC_REFCOUNT_HAVEATOMIC 00049 #define DNS_RBT_USEISCREFCOUNT 1 00050 #endif 00051 #endif 00052 00053 #define DNS_RBT_USEMAGIC 1 00054 00055 /* 00056 * These should add up to 30. 00057 */ 00058 #define DNS_RBT_LOCKLENGTH 10 00059 #define DNS_RBT_REFLENGTH 20 00060 00061 #define DNS_RBTNODE_MAGIC ISC_MAGIC('R','B','N','O') 00062 #if DNS_RBT_USEMAGIC 00063 #define DNS_RBTNODE_VALID(n) ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC) 00064 #else 00065 #define DNS_RBTNODE_VALID(n) ISC_TRUE 00066 #endif 00067 00068 /*% 00069 * This is the structure that is used for each node in the red/black 00070 * tree of trees. NOTE WELL: the implementation manages this as a variable 00071 * length structure, with the actual wire-format name and other data 00072 * appended to this structure. Allocating a contiguous block of memory for 00073 * multiple dns_rbtnode structures will not work. 00074 */ 00075 typedef struct dns_rbtnode dns_rbtnode_t; 00076 enum { 00077 DNS_RBT_NSEC_NORMAL=0, /* in main tree */ 00078 DNS_RBT_NSEC_HAS_NSEC=1, /* also has node in nsec tree */ 00079 DNS_RBT_NSEC_NSEC=2, /* in nsec tree */ 00080 DNS_RBT_NSEC_NSEC3=3 /* in nsec3 tree */ 00081 }; 00082 struct dns_rbtnode { 00083 #if DNS_RBT_USEMAGIC 00084 unsigned int magic; 00085 #endif 00086 dns_rbtnode_t *parent; 00087 dns_rbtnode_t *left; 00088 dns_rbtnode_t *right; 00089 dns_rbtnode_t *down; 00090 #ifdef DNS_RBT_USEHASH 00091 dns_rbtnode_t *hashnext; 00092 #endif 00093 00094 /*% 00095 * Used for LRU cache. This linked list is used to mark nodes which 00096 * have no data any longer, but we cannot unlink at that exact moment 00097 * because we did not or could not obtain a write lock on the tree. 00098 */ 00099 ISC_LINK(dns_rbtnode_t) deadlink; 00100 00101 /*@{*/ 00102 /*! 00103 * The following bitfields add up to a total bitwidth of 32. 00104 * The range of values necessary for each item is indicated, 00105 * but in the case of "attributes" the field is wider to accommodate 00106 * possible future expansion. 00107 * 00108 * In each case below the "range" indicated is what's _necessary_ for 00109 * the bitfield to hold, not what it actually _can_ hold. 00110 */ 00111 unsigned int is_root : 1; /*%< range is 0..1 */ 00112 unsigned int color : 1; /*%< range is 0..1 */ 00113 unsigned int find_callback : 1; /*%< range is 0..1 */ 00114 unsigned int attributes : 3; /*%< range is 0..2 */ 00115 unsigned int nsec : 2; /*%< range is 0..3 */ 00116 unsigned int namelen : 8; /*%< range is 1..255 */ 00117 unsigned int offsetlen : 8; /*%< range is 1..128 */ 00118 unsigned int oldnamelen : 8; /*%< range is 1..255 */ 00119 /*@}*/ 00120 00121 /* flags needed for serialization to file*/ 00122 unsigned int is_mmapped : 1; 00123 unsigned int parent_is_relative : 1; 00124 unsigned int left_is_relative : 1; 00125 unsigned int right_is_relative : 1; 00126 unsigned int down_is_relative : 1; 00127 unsigned int data_is_relative : 1; 00128 00129 /* node needs to be cleaned from rpz */ 00130 unsigned int rpz : 1; 00131 00132 #ifdef DNS_RBT_USEHASH 00133 unsigned int hashval; 00134 #endif 00135 00136 /*@{*/ 00137 /*! 00138 * These values are used in the RBT DB implementation. The appropriate 00139 * node lock must be held before accessing them. 00140 */ 00141 void *data; 00142 unsigned int dirty:1; 00143 unsigned int wild:1; 00144 unsigned int locknum:DNS_RBT_LOCKLENGTH; 00145 #ifndef DNS_RBT_USEISCREFCOUNT 00146 unsigned int references:DNS_RBT_REFLENGTH; 00147 #else 00148 isc_refcount_t references; /* note that this is not in the bitfield */ 00149 #endif 00150 /*@}*/ 00151 }; 00152 00153 typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node, 00154 dns_name_t *name, 00155 void *callback_arg); 00156 00157 typedef isc_result_t (*dns_rbtdatawriter_t)(FILE *file, 00158 unsigned char *data, 00159 void *arg, 00160 isc_uint64_t *crc); 00161 00162 typedef isc_result_t (*dns_rbtdatafixer_t)(dns_rbtnode_t *rbtnode, 00163 void *base, size_t offset, 00164 void *arg, isc_uint64_t *crc); 00165 00166 typedef void (*dns_rbtdeleter_t)(void *, void *); 00167 00168 /***** 00169 ***** Chain Info 00170 *****/ 00171 00172 /*! 00173 * A chain is used to keep track of the sequence of nodes to reach any given 00174 * node from the root of the tree. Originally nodes did not have parent 00175 * pointers in them (for memory usage reasons) so there was no way to find 00176 * the path back to the root from any given node. Now that nodes have parent 00177 * pointers, chains might be going away in a future release, though the 00178 * movement functionality would remain. 00179 * 00180 * In any event, parent information, whether via parent pointers or chains, is 00181 * necessary information for iterating through the tree or for basic internal 00182 * tree maintenance issues (ie, the rotations that are done to rebalance the 00183 * tree when a node is added). The obvious implication of this is that for a 00184 * chain to remain valid, the tree has to be locked down against writes for the 00185 * duration of the useful life of the chain, because additions or removals can 00186 * change the path from the root to the node the chain has targeted. 00187 * 00188 * The dns_rbtnodechain_ functions _first, _last, _prev and _next all take 00189 * dns_name_t parameters for the name and the origin, which can be NULL. If 00190 * non-NULL, 'name' will end up pointing to the name data and offsets that are 00191 * stored at the node (and thus it will be read-only), so it should be a 00192 * regular dns_name_t that has been initialized with dns_name_init. When 00193 * 'origin' is non-NULL, it will get the name of the origin stored in it, so it 00194 * needs to have its own buffer space and offsets, which is most easily 00195 * accomplished with a dns_fixedname_t. It is _not_ necessary to reinitialize 00196 * either 'name' or 'origin' between calls to the chain functions. 00197 * 00198 * NOTE WELL: even though the name data at the root of the tree of trees will 00199 * be absolute (typically just "."), it will will be made into a relative name 00200 * with an origin of "." -- an empty name when the node is ".". This is 00201 * because a common on operation on 'name' and 'origin' is to use 00202 * dns_name_concatenate() on them to generate the complete name. An empty name 00203 * can be detected when dns_name_countlabels == 0, and is printed by 00204 * dns_name_totext()/dns_name_format() as "@", consistent with RFC1035's 00205 * definition of "@" as the current origin. 00206 * 00207 * dns_rbtnodechain_current is similar to the _first, _last, _prev and _next 00208 * functions but additionally can provide the node to which the chain points. 00209 */ 00210 00211 /*% 00212 * The number of level blocks to allocate at a time. Currently the maximum 00213 * number of levels is allocated directly in the structure, but future 00214 * revisions of this code might have a static initial block with dynamic 00215 * growth. Allocating space for 256 levels when the tree is almost never that 00216 * deep is wasteful, but it's not clear that it matters, since the waste is 00217 * only 2MB for 1000 concurrently active chains on a system with 64-bit 00218 * pointers. 00219 */ 00220 #define DNS_RBT_LEVELBLOCK 254 00221 00222 typedef struct dns_rbtnodechain { 00223 unsigned int magic; 00224 isc_mem_t * mctx; 00225 /*% 00226 * The terminal node of the chain. It is not in levels[]. 00227 * This is ostensibly private ... but in a pinch it could be 00228 * used tell that the chain points nowhere without needing to 00229 * call dns_rbtnodechain_current(). 00230 */ 00231 dns_rbtnode_t * end; 00232 /*% 00233 * The maximum number of labels in a name is 128; bitstrings mean 00234 * a conceptually very large number (which I have not bothered to 00235 * compute) of logical levels because splitting can potentially occur 00236 * at each bit. However, DNSSEC restricts the number of "logical" 00237 * labels in a name to 255, meaning only 254 pointers are needed 00238 * in the worst case. 00239 */ 00240 dns_rbtnode_t * levels[DNS_RBT_LEVELBLOCK]; 00241 /*% 00242 * level_count indicates how deep the chain points into the 00243 * tree of trees, and is the index into the levels[] array. 00244 * Thus, levels[level_count - 1] is the last level node stored. 00245 * A chain that points to the top level of the tree of trees has 00246 * a level_count of 0, the first level has a level_count of 1, and 00247 * so on. 00248 */ 00249 unsigned int level_count; 00250 /*% 00251 * level_matches tells how many levels matched above the node 00252 * returned by dns_rbt_findnode(). A match (partial or exact) found 00253 * in the first level thus results in level_matches being set to 1. 00254 * This is used by the rbtdb to set the start point for a recursive 00255 * search of superdomains until the RR it is looking for is found. 00256 */ 00257 unsigned int level_matches; 00258 } dns_rbtnodechain_t; 00259 00260 /***** 00261 ***** Public interfaces. 00262 *****/ 00263 isc_result_t 00264 dns_rbt_create(isc_mem_t *mctx, dns_rbtdeleter_t deleter, 00265 void *deleter_arg, dns_rbt_t **rbtp); 00266 /*%< 00267 * Initialize a red-black tree of trees. 00268 * 00269 * Notes: 00270 *\li The deleter argument, if non-null, points to a function that is 00271 * responsible for cleaning up any memory associated with the data 00272 * pointer of a node when the node is deleted. It is passed the 00273 * deleted node's data pointer as its first argument and deleter_arg 00274 * as its second argument. 00275 * 00276 * Requires: 00277 * \li mctx is a pointer to a valid memory context. 00278 *\li rbtp != NULL && *rbtp == NULL 00279 *\li arg == NULL iff deleter == NULL 00280 * 00281 * Ensures: 00282 *\li If result is ISC_R_SUCCESS: 00283 * *rbtp points to a valid red-black tree manager 00284 * 00285 *\li If result is failure: 00286 * *rbtp does not point to a valid red-black tree manager. 00287 * 00288 * Returns: 00289 *\li #ISC_R_SUCCESS Success 00290 *\li #ISC_R_NOMEMORY Resource limit: Out of Memory 00291 */ 00292 00293 isc_result_t 00294 dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data); 00295 /*%< 00296 * Add 'name' to the tree of trees, associated with 'data'. 00297 * 00298 * Notes: 00299 *\li 'data' is never required to be non-NULL, but specifying it 00300 * when the name is added is faster than searching for 'name' 00301 * again and then setting the data pointer. The lack of a data pointer 00302 * for a node also has other ramifications regarding whether 00303 * dns_rbt_findname considers a node to exist, or dns_rbt_deletename 00304 * joins nodes. 00305 * 00306 * Requires: 00307 *\li rbt is a valid rbt manager. 00308 *\li dns_name_isabsolute(name) == TRUE 00309 * 00310 * Ensures: 00311 *\li 'name' is not altered in any way. 00312 * 00313 *\li Any external references to nodes in the tree are unaffected by 00314 * node splits that are necessary to insert the new name. 00315 * 00316 *\li If result is #ISC_R_SUCCESS: 00317 * 'name' is findable in the red/black tree of trees in O(log N). 00318 * The data pointer of the node for 'name' is set to 'data'. 00319 * 00320 *\li If result is #ISC_R_EXISTS or #ISC_R_NOSPACE: 00321 * The tree of trees is unaltered. 00322 * 00323 *\li If result is #ISC_R_NOMEMORY: 00324 * No guarantees. 00325 * 00326 * Returns: 00327 *\li #ISC_R_SUCCESS Success 00328 *\li #ISC_R_EXISTS The name already exists with associated data. 00329 *\li #ISC_R_NOSPACE The name had more logical labels than are allowed. 00330 *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory 00331 */ 00332 00333 isc_result_t 00334 dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep); 00335 00336 /*%< 00337 * Just like dns_rbt_addname, but returns the address of the node. 00338 * 00339 * Requires: 00340 *\li rbt is a valid rbt structure. 00341 *\li dns_name_isabsolute(name) == TRUE 00342 *\li nodep != NULL && *nodep == NULL 00343 * 00344 * Ensures: 00345 *\li 'name' is not altered in any way. 00346 * 00347 *\li Any external references to nodes in the tree are unaffected by 00348 * node splits that are necessary to insert the new name. 00349 * 00350 *\li If result is ISC_R_SUCCESS: 00351 * 'name' is findable in the red/black tree of trees in O(log N). 00352 * *nodep is the node that was added for 'name'. 00353 * 00354 *\li If result is ISC_R_EXISTS: 00355 * The tree of trees is unaltered. 00356 * *nodep is the existing node for 'name'. 00357 * 00358 *\li If result is ISC_R_NOMEMORY: 00359 * No guarantees. 00360 * 00361 * Returns: 00362 *\li #ISC_R_SUCCESS Success 00363 *\li #ISC_R_EXISTS The name already exists, possibly without data. 00364 *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory 00365 */ 00366 00367 isc_result_t 00368 dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options, 00369 dns_name_t *foundname, void **data); 00370 /*%< 00371 * Get the data pointer associated with 'name'. 00372 * 00373 * Notes: 00374 *\li When #DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is 00375 * returned (also subject to #DNS_RBTFIND_EMPTYDATA), even when there is 00376 * an exact match in the tree. 00377 * 00378 *\li A node that has no data is considered not to exist for this function, 00379 * unless the #DNS_RBTFIND_EMPTYDATA option is set. 00380 * 00381 * Requires: 00382 *\li rbt is a valid rbt manager. 00383 *\li dns_name_isabsolute(name) == TRUE 00384 *\li data != NULL && *data == NULL 00385 * 00386 * Ensures: 00387 *\li 'name' and the tree are not altered in any way. 00388 * 00389 *\li If result is ISC_R_SUCCESS: 00390 * *data is the data associated with 'name'. 00391 * 00392 *\li If result is DNS_R_PARTIALMATCH: 00393 * *data is the data associated with the deepest superdomain 00394 * of 'name' which has data. 00395 * 00396 *\li If result is ISC_R_NOTFOUND: 00397 * Neither the name nor a superdomain was found with data. 00398 * 00399 * Returns: 00400 *\li #ISC_R_SUCCESS Success 00401 *\li #DNS_R_PARTIALMATCH Superdomain found with data 00402 *\li #ISC_R_NOTFOUND No match 00403 *\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed 00404 */ 00405 00406 isc_result_t 00407 dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname, 00408 dns_rbtnode_t **node, dns_rbtnodechain_t *chain, 00409 unsigned int options, dns_rbtfindcallback_t callback, 00410 void *callback_arg); 00411 /*%< 00412 * Find the node for 'name'. 00413 * 00414 * Notes: 00415 *\li A node that has no data is considered not to exist for this function, 00416 * unless the DNS_RBTFIND_EMPTYDATA option is set. This applies to both 00417 * exact matches and partial matches. 00418 * 00419 *\li If the chain parameter is non-NULL, then the path through the tree 00420 * to the DNSSEC predecessor of the searched for name is maintained, 00421 * unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option 00422 * is used. (For more details on those options, see below.) 00423 * 00424 *\li If there is no predecessor, then the chain will point to nowhere, as 00425 * indicated by chain->end being NULL or dns_rbtnodechain_current 00426 * returning ISC_R_NOTFOUND. Note that in a normal Internet DNS RBT 00427 * there will always be a predecessor for all names except the root 00428 * name, because '.' will exist and '.' is the predecessor of 00429 * everything. But you can certainly construct a trivial tree and a 00430 * search for it that has no predecessor. 00431 * 00432 *\li Within the chain structure, the 'levels' member of the structure holds 00433 * the root node of each level except the first. 00434 * 00435 *\li The 'level_count' of the chain indicates how deep the chain to the 00436 * predecessor name is, as an index into the 'levels[]' array. It does 00437 * not count name elements, per se, but only levels of the tree of trees, 00438 * the distinction arising because multiple labels from a name can be 00439 * stored on only one level. It is also does not include the level 00440 * that has the node, since that level is not stored in levels[]. 00441 * 00442 *\li The chain's 'level_matches' is not directly related to the predecessor. 00443 * It is the number of levels above the level of the found 'node', 00444 * regardless of whether it was a partial match or exact match. When 00445 * the node is found in the top level tree, or no node is found at all, 00446 * level_matches is 0. 00447 * 00448 *\li When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is 00449 * returned (also subject to DNS_RBTFIND_EMPTYDATA), even when 00450 * there is an exact match in the tree. In this case, the chain 00451 * will not point to the DNSSEC predecessor, but will instead point 00452 * to the exact match, if there was any. Thus the preceding paragraphs 00453 * should have "exact match" substituted for "predecessor" to describe 00454 * how the various elements of the chain are set. This was done to 00455 * ensure that the chain's state was sane, and to prevent problems that 00456 * occurred when running the predecessor location code under conditions 00457 * it was not designed for. It is not clear *where* the chain should 00458 * point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain 00459 * with this option because you want a particular node, let us know 00460 * where you want the chain pointed, so this can be made more firm. 00461 * 00462 * Requires: 00463 *\li rbt is a valid rbt manager. 00464 *\li dns_name_isabsolute(name) == TRUE. 00465 *\li node != NULL && *node == NULL. 00466 *\li #DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutually 00467 * exclusive. 00468 * 00469 * Ensures: 00470 *\li 'name' and the tree are not altered in any way. 00471 * 00472 *\li If result is ISC_R_SUCCESS: 00473 *\verbatim 00474 * *node is the terminal node for 'name'. 00475 00476 * 'foundname' and 'name' represent the same name (though not 00477 * the same memory). 00478 00479 * 'chain' points to the DNSSEC predecessor, if any, of 'name'. 00480 * 00481 * chain->level_matches and chain->level_count are equal. 00482 *\endverbatim 00483 * 00484 * If result is DNS_R_PARTIALMATCH: 00485 *\verbatim 00486 * *node is the data associated with the deepest superdomain 00487 * of 'name' which has data. 00488 * 00489 * 'foundname' is the name of deepest superdomain (which has 00490 * data, unless the DNS_RBTFIND_EMPTYDATA option is set). 00491 * 00492 * 'chain' points to the DNSSEC predecessor, if any, of 'name'. 00493 *\endverbatim 00494 * 00495 *\li If result is ISC_R_NOTFOUND: 00496 *\verbatim 00497 * Neither the name nor a superdomain was found. *node is NULL. 00498 * 00499 * 'chain' points to the DNSSEC predecessor, if any, of 'name'. 00500 * 00501 * chain->level_matches is 0. 00502 *\endverbatim 00503 * 00504 * Returns: 00505 *\li #ISC_R_SUCCESS Success 00506 *\li #DNS_R_PARTIALMATCH Superdomain found with data 00507 *\li #ISC_R_NOTFOUND No match, or superdomain with no data 00508 *\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed 00509 */ 00510 00511 isc_result_t 00512 dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse); 00513 /*%< 00514 * Delete 'name' from the tree of trees. 00515 * 00516 * Notes: 00517 *\li When 'name' is removed, if recurse is ISC_TRUE then all of its 00518 * subnames are removed too. 00519 * 00520 * Requires: 00521 *\li rbt is a valid rbt manager. 00522 *\li dns_name_isabsolute(name) == TRUE 00523 * 00524 * Ensures: 00525 *\li 'name' is not altered in any way. 00526 * 00527 *\li Does NOT ensure that any external references to nodes in the tree 00528 * are unaffected by node joins. 00529 * 00530 *\li If result is ISC_R_SUCCESS: 00531 * 'name' does not appear in the tree with data; however, 00532 * the node for the name might still exist which can be 00533 * found with dns_rbt_findnode (but not dns_rbt_findname). 00534 * 00535 *\li If result is ISC_R_NOTFOUND: 00536 * 'name' does not appear in the tree with data, because 00537 * it did not appear in the tree before the function was called. 00538 * 00539 *\li If result is something else: 00540 * See result codes for dns_rbt_findnode (if it fails, the 00541 * node is not deleted) or dns_rbt_deletenode (if it fails, 00542 * the node is deleted, but the tree is not optimized when 00543 * it could have been). 00544 * 00545 * Returns: 00546 *\li #ISC_R_SUCCESS Success 00547 *\li #ISC_R_NOTFOUND No match 00548 *\li something_else Any return code from dns_rbt_findnode except 00549 * DNS_R_PARTIALMATCH (which causes ISC_R_NOTFOUND 00550 * to be returned instead), and any code from 00551 * dns_rbt_deletenode. 00552 */ 00553 00554 isc_result_t 00555 dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse); 00556 /*%< 00557 * Delete 'node' from the tree of trees. 00558 * 00559 * Notes: 00560 *\li When 'node' is removed, if recurse is ISC_TRUE then all nodes 00561 * in levels down from it are removed too. 00562 * 00563 * Requires: 00564 *\li rbt is a valid rbt manager. 00565 *\li node != NULL. 00566 * 00567 * Ensures: 00568 *\li Does NOT ensure that any external references to nodes in the tree 00569 * are unaffected by node joins. 00570 * 00571 *\li If result is ISC_R_SUCCESS: 00572 * 'node' does not appear in the tree with data; however, 00573 * the node might still exist if it serves as a pointer to 00574 * a lower tree level as long as 'recurse' was false, hence 00575 * the node could can be found with dns_rbt_findnode when 00576 * that function's empty_data_ok parameter is true. 00577 * 00578 *\li If result is ISC_R_NOMEMORY or ISC_R_NOSPACE: 00579 * The node was deleted, but the tree structure was not 00580 * optimized. 00581 * 00582 * Returns: 00583 *\li #ISC_R_SUCCESS Success 00584 *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory when joining nodes. 00585 *\li #ISC_R_NOSPACE dns_name_concatenate failed when joining nodes. 00586 */ 00587 00588 void 00589 dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name); 00590 /*%< 00591 * Convert the sequence of labels stored at 'node' into a 'name'. 00592 * 00593 * Notes: 00594 *\li This function does not return the full name, from the root, but 00595 * just the labels at the indicated node. 00596 * 00597 *\li The name data pointed to by 'name' is the information stored 00598 * in the node, not a copy. Altering the data at this pointer 00599 * will likely cause grief. 00600 * 00601 * Requires: 00602 * \li name->offsets == NULL 00603 * 00604 * Ensures: 00605 * \li 'name' is DNS_NAMEATTR_READONLY. 00606 * 00607 * \li 'name' will point directly to the labels stored after the 00608 * dns_rbtnode_t struct. 00609 * 00610 * \li 'name' will have offsets that also point to the information stored 00611 * as part of the node. 00612 */ 00613 00614 isc_result_t 00615 dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name); 00616 /*%< 00617 * Like dns_rbt_namefromnode, but returns the full name from the root. 00618 * 00619 * Notes: 00620 * \li Unlike dns_rbt_namefromnode, the name will not point directly 00621 * to node data. Rather, dns_name_concatenate will be used to copy 00622 * the name data from each node into the 'name' argument. 00623 * 00624 * Requires: 00625 * \li name != NULL 00626 * \li name has a dedicated buffer. 00627 * 00628 * Returns: 00629 * \li ISC_R_SUCCESS 00630 * \li ISC_R_NOSPACE (possible via dns_name_concatenate) 00631 * \li DNS_R_NAMETOOLONG (possible via dns_name_concatenate) 00632 */ 00633 00634 char * 00635 dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, 00636 unsigned int size); 00637 /*%< 00638 * Format the full name of a node for printing, using dns_name_format(). 00639 * 00640 * Notes: 00641 * \li 'size' is the length of the printname buffer. This should be 00642 * DNS_NAME_FORMATSIZE or larger. 00643 * 00644 * Requires: 00645 * \li node and printname are not NULL. 00646 * 00647 * Returns: 00648 * \li The 'printname' pointer. 00649 */ 00650 00651 unsigned int 00652 dns_rbt_nodecount(dns_rbt_t *rbt); 00653 /*%< 00654 * Obtain the number of nodes in the tree of trees. 00655 * 00656 * Requires: 00657 * \li rbt is a valid rbt manager. 00658 */ 00659 00660 unsigned int 00661 dns_rbt_hashsize(dns_rbt_t *rbt); 00662 /*%< 00663 * Obtain the current number of buckets in the 'rbt' hash table. 00664 * 00665 * Requires: 00666 * \li rbt is a valid rbt manager. 00667 */ 00668 00669 void 00670 dns_rbt_destroy(dns_rbt_t **rbtp); 00671 isc_result_t 00672 dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum); 00673 /*%< 00674 * Stop working with a red-black tree of trees. 00675 * If 'quantum' is zero then the entire tree will be destroyed. 00676 * If 'quantum' is non zero then up to 'quantum' nodes will be destroyed 00677 * allowing the rbt to be incrementally destroyed by repeated calls to 00678 * dns_rbt_destroy2(). Once dns_rbt_destroy2() has been called no other 00679 * operations than dns_rbt_destroy()/dns_rbt_destroy2() should be 00680 * performed on the tree of trees. 00681 * 00682 * Requires: 00683 * \li *rbt is a valid rbt manager. 00684 * 00685 * Ensures on ISC_R_SUCCESS: 00686 * \li All space allocated by the RBT library has been returned. 00687 * 00688 * \li *rbt is invalidated as an rbt manager. 00689 * 00690 * Returns: 00691 * \li ISC_R_SUCCESS 00692 * \li ISC_R_QUOTA if 'quantum' nodes have been destroyed. 00693 */ 00694 00695 off_t 00696 dns_rbt_serialize_align(off_t target); 00697 /*%< 00698 * Align the provided integer to a pointer-size boundary. 00699 * This should be used if, during serialization of data to a will-be 00700 * mmap()ed file, a pointer alignment is needed for some data. 00701 */ 00702 00703 isc_result_t 00704 dns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt, 00705 dns_rbtdatawriter_t datawriter, 00706 void *writer_arg, off_t *offset); 00707 /*%< 00708 * Write out the RBT structure and its data to a file. 00709 * 00710 * Notes: 00711 * \li The file must be an actual file which allows seek() calls, so it cannot 00712 * be a stream. Returns ISC_R_INVALIDFILE if not. 00713 */ 00714 00715 isc_result_t 00716 dns_rbt_deserialize_tree(void *base_address, size_t filesize, 00717 off_t header_offset, isc_mem_t *mctx, 00718 dns_rbtdeleter_t deleter, void *deleter_arg, 00719 dns_rbtdatafixer_t datafixer, void *fixer_arg, 00720 dns_rbtnode_t **originp, dns_rbt_t **rbtp); 00721 /*%< 00722 * Read a RBT structure and its data from a file. 00723 * 00724 * If 'originp' is not NULL, then it is pointed to the root node of the RBT. 00725 * 00726 * Notes: 00727 * \li The file must be an actual file which allows seek() calls, so it cannot 00728 * be a stream. This condition is not checked in the code. 00729 */ 00730 00731 void 00732 dns_rbt_printtext(dns_rbt_t *rbt, 00733 void (*data_printer)(FILE *, void *), FILE *f); 00734 /*%< 00735 * Print an ASCII representation of the internal structure of the red-black 00736 * tree of trees to the passed stream. 00737 * 00738 * data_printer is a callback function that is called to print the data 00739 * in a node. It should print it to the passed FILE stream. 00740 * 00741 * Notes: 00742 * \li The name stored at each node, along with the node's color, is printed. 00743 * Then the down pointer, left and right pointers are displayed 00744 * recursively in turn. NULL down pointers are silently omitted; 00745 * NULL left and right pointers are printed. 00746 */ 00747 00748 void 00749 dns_rbt_printdot(dns_rbt_t *rbt, isc_boolean_t show_pointers, FILE *f); 00750 /*%< 00751 * Print a GraphViz dot representation of the internal structure of the 00752 * red-black tree of trees to the passed stream. 00753 * 00754 * If show_pointers is TRUE, pointers are also included in the generated 00755 * graph. 00756 * 00757 * Notes: 00758 * \li The name stored at each node, along with the node's color is displayed. 00759 * Then the down pointer, left and right pointers are displayed 00760 * recursively in turn. NULL left, right and down pointers are 00761 * silently omitted. 00762 */ 00763 00764 void 00765 dns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f); 00766 /*%< 00767 * Print out various information about a node 00768 * 00769 * Requires: 00770 *\li 'n' is a valid pointer. 00771 * 00772 *\li 'f' points to a valid open FILE structure that allows writing. 00773 */ 00774 00775 00776 size_t 00777 dns__rbt_getheight(dns_rbt_t *rbt); 00778 /*%< 00779 * Return the maximum height of sub-root nodes found in the red-black 00780 * forest. 00781 * 00782 * The height of a node is defined as the number of nodes in the longest 00783 * path from the node to a leaf. For each subtree in the forest, this 00784 * function determines the height of its root node. Then it returns the 00785 * maximum such height in the forest. 00786 * 00787 * Note: This function exists for testing purposes. Non-test code must 00788 * not use it. 00789 * 00790 * Requires: 00791 * \li rbt is a valid rbt manager. 00792 */ 00793 00794 isc_boolean_t 00795 dns__rbt_checkproperties(dns_rbt_t *rbt); 00796 /*%< 00797 * Check red-black properties of the forest. 00798 * 00799 * Note: This function exists for testing purposes. Non-test code must 00800 * not use it. 00801 * 00802 * Requires: 00803 * \li rbt is a valid rbt manager. 00804 */ 00805 00806 size_t 00807 dns__rbtnode_getdistance(dns_rbtnode_t *node); 00808 /*%< 00809 * Return the distance (in nodes) from the node to its upper node of its 00810 * subtree. The root node has a distance of 1. A child of the root node 00811 * has a distance of 2. 00812 */ 00813 00814 /***** 00815 ***** Chain Functions 00816 *****/ 00817 00818 void 00819 dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx); 00820 /*%< 00821 * Initialize 'chain'. 00822 * 00823 * Requires: 00824 *\li 'chain' is a valid pointer. 00825 * 00826 *\li 'mctx' is a valid memory context. 00827 * 00828 * Ensures: 00829 *\li 'chain' is suitable for use. 00830 */ 00831 00832 void 00833 dns_rbtnodechain_reset(dns_rbtnodechain_t *chain); 00834 /*%< 00835 * Free any dynamic storage associated with 'chain', and then reinitialize 00836 * 'chain'. 00837 * 00838 * Requires: 00839 *\li 'chain' is a valid pointer. 00840 * 00841 * Ensures: 00842 *\li 'chain' is suitable for use, and uses no dynamic storage. 00843 */ 00844 00845 void 00846 dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain); 00847 /*%< 00848 * Free any dynamic storage associated with 'chain', and then invalidates it. 00849 * 00850 * Notes: 00851 *\li Future calls to any dns_rbtnodechain_ function will need to call 00852 * dns_rbtnodechain_init on the chain first (except, of course, 00853 * dns_rbtnodechain_init itself). 00854 * 00855 * Requires: 00856 *\li 'chain' is a valid chain. 00857 * 00858 * Ensures: 00859 *\li 'chain' is no longer suitable for use, and uses no dynamic storage. 00860 */ 00861 00862 isc_result_t 00863 dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name, 00864 dns_name_t *origin, dns_rbtnode_t **node); 00865 /*%< 00866 * Provide the name, origin and node to which the chain is currently pointed. 00867 * 00868 * Notes: 00869 *\li The tree need not have be locked against additions for the chain 00870 * to remain valid, however there are no guarantees if any deletion 00871 * has been made since the chain was established. 00872 * 00873 * Requires: 00874 *\li 'chain' is a valid chain. 00875 * 00876 * Ensures: 00877 *\li 'node', if non-NULL, is the node to which the chain was pointed 00878 * by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last. 00879 * If none were called for the chain since it was initialized or reset, 00880 * or if the was no predecessor to the name searched for with 00881 * dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned. 00882 * 00883 *\li 'name', if non-NULL, is the name stored at the terminal level of 00884 * the chain. This is typically a single label, like the "www" of 00885 * "www.isc.org", but need not be so. At the root of the tree of trees, 00886 * if the node is "." then 'name' is ".", otherwise it is relative to ".". 00887 * (Minimalist and atypical case: if the tree has just the name 00888 * "isc.org." then the root node's stored name is "isc.org." but 'name' 00889 * will be "isc.org".) 00890 * 00891 *\li 'origin', if non-NULL, is the sequence of labels in the levels 00892 * above the terminal level, such as "isc.org." in the above example. 00893 * 'origin' is always "." for the root node. 00894 * 00895 * 00896 * Returns: 00897 *\li #ISC_R_SUCCESS name, origin & node were successfully set. 00898 *\li #ISC_R_NOTFOUND The chain does not point to any node. 00899 *\li <something_else> Any error return from dns_name_concatenate. 00900 */ 00901 00902 isc_result_t 00903 dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt, 00904 dns_name_t *name, dns_name_t *origin); 00905 /*%< 00906 * Set the chain to the lexically first node in the tree of trees. 00907 * 00908 * Notes: 00909 *\li By the definition of ordering for DNS names, the root of the tree of 00910 * trees is the very first node, since everything else in the megatree 00911 * uses it as a common suffix. 00912 * 00913 * Requires: 00914 *\li 'chain' is a valid chain. 00915 *\li 'rbt' is a valid rbt manager. 00916 * 00917 * Ensures: 00918 *\li The chain points to the very first node of the tree. 00919 * 00920 *\li 'name' and 'origin', if non-NULL, are set as described for 00921 * dns_rbtnodechain_current. Thus 'origin' will always be ".". 00922 * 00923 * Returns: 00924 *\li #DNS_R_NEWORIGIN The name & origin were successfully set. 00925 *\li <something_else> Any error result from dns_rbtnodechain_current. 00926 */ 00927 00928 isc_result_t 00929 dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt, 00930 dns_name_t *name, dns_name_t *origin); 00931 /*%< 00932 * Set the chain to the lexically last node in the tree of trees. 00933 * 00934 * Requires: 00935 *\li 'chain' is a valid chain. 00936 *\li 'rbt' is a valid rbt manager. 00937 * 00938 * Ensures: 00939 *\li The chain points to the very last node of the tree. 00940 * 00941 *\li 'name' and 'origin', if non-NULL, are set as described for 00942 * dns_rbtnodechain_current. 00943 * 00944 * Returns: 00945 *\li #DNS_R_NEWORIGIN The name & origin were successfully set. 00946 *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory building chain. 00947 *\li <something_else> Any error result from dns_name_concatenate. 00948 */ 00949 00950 isc_result_t 00951 dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name, 00952 dns_name_t *origin); 00953 /*%< 00954 * Adjusts chain to point the DNSSEC predecessor of the name to which it 00955 * is currently pointed. 00956 * 00957 * Requires: 00958 *\li 'chain' is a valid chain. 00959 *\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode, 00960 * dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that 00961 * dns_rbt_findnode is not guaranteed to point the chain somewhere, 00962 * since there may have been no predecessor to the searched for name. 00963 * 00964 * Ensures: 00965 *\li The chain is pointed to the predecessor of its current target. 00966 * 00967 *\li 'name' and 'origin', if non-NULL, are set as described for 00968 * dns_rbtnodechain_current. 00969 * 00970 *\li 'origin' is only if a new origin was found. 00971 * 00972 * Returns: 00973 *\li #ISC_R_SUCCESS The predecessor was found and 'name' was set. 00974 *\li #DNS_R_NEWORIGIN The predecessor was found with a different 00975 * origin and 'name' and 'origin' were set. 00976 *\li #ISC_R_NOMORE There was no predecessor. 00977 *\li <something_else> Any error result from dns_rbtnodechain_current. 00978 */ 00979 00980 isc_result_t 00981 dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name, 00982 dns_name_t *origin); 00983 /*%< 00984 * Adjusts chain to point the DNSSEC successor of the name to which it 00985 * is currently pointed. 00986 * 00987 * Requires: 00988 *\li 'chain' is a valid chain. 00989 *\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode, 00990 * dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that 00991 * dns_rbt_findnode is not guaranteed to point the chain somewhere, 00992 * since there may have been no predecessor to the searched for name. 00993 * 00994 * Ensures: 00995 *\li The chain is pointed to the successor of its current target. 00996 * 00997 *\li 'name' and 'origin', if non-NULL, are set as described for 00998 * dns_rbtnodechain_current. 00999 * 01000 *\li 'origin' is only if a new origin was found. 01001 * 01002 * Returns: 01003 *\li #ISC_R_SUCCESS The successor was found and 'name' was set. 01004 *\li #DNS_R_NEWORIGIN The successor was found with a different 01005 * origin and 'name' and 'origin' were set. 01006 *\li #ISC_R_NOMORE There was no successor. 01007 *\li <something_else> Any error result from dns_name_concatenate. 01008 */ 01009 01010 isc_result_t 01011 dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name, 01012 dns_name_t *origin); 01013 /*%< 01014 * Descend down if possible. 01015 */ 01016 01017 isc_result_t 01018 dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name); 01019 /*%< 01020 * Find the next node at the current depth in DNSSEC order. 01021 */ 01022 01023 /* 01024 * Wrapper macros for manipulating the rbtnode reference counter: 01025 * Since we selectively use isc_refcount_t for the reference counter of 01026 * a rbtnode, operations on the counter depend on the actual type of it. 01027 * The following macros provide a common interface to these operations, 01028 * hiding the back-end. The usage is the same as that of isc_refcount_xxx(). 01029 */ 01030 #ifdef DNS_RBT_USEISCREFCOUNT 01031 #define dns_rbtnode_refinit(node, n) \ 01032 do { \ 01033 isc_refcount_init(&(node)->references, (n)); \ 01034 } while (0) 01035 #define dns_rbtnode_refdestroy(node) \ 01036 do { \ 01037 isc_refcount_destroy(&(node)->references); \ 01038 } while (0) 01039 #define dns_rbtnode_refcurrent(node) \ 01040 isc_refcount_current(&(node)->references) 01041 #define dns_rbtnode_refincrement0(node, refs) \ 01042 do { \ 01043 isc_refcount_increment0(&(node)->references, (refs)); \ 01044 } while (0) 01045 #define dns_rbtnode_refincrement(node, refs) \ 01046 do { \ 01047 isc_refcount_increment(&(node)->references, (refs)); \ 01048 } while (0) 01049 #define dns_rbtnode_refdecrement(node, refs) \ 01050 do { \ 01051 isc_refcount_decrement(&(node)->references, (refs)); \ 01052 } while (0) 01053 #else /* DNS_RBT_USEISCREFCOUNT */ 01054 #define dns_rbtnode_refinit(node, n) ((node)->references = (n)) 01055 #define dns_rbtnode_refdestroy(node) REQUIRE((node)->references == 0) 01056 #define dns_rbtnode_refcurrent(node) ((node)->references) 01057 01058 #if (__STDC_VERSION__ + 0) >= 199901L || defined __GNUC__ 01059 static inline void 01060 dns_rbtnode_refincrement0(dns_rbtnode_t *node, unsigned int *refs) { 01061 node->references++; 01062 if (refs != NULL) 01063 *refs = node->references; 01064 } 01065 01066 static inline void 01067 dns_rbtnode_refincrement(dns_rbtnode_t *node, unsigned int *refs) { 01068 REQUIRE(node->references > 0); 01069 node->references++; 01070 if (refs != NULL) 01071 *refs = node->references; 01072 } 01073 01074 static inline void 01075 dns_rbtnode_refdecrement(dns_rbtnode_t *node, unsigned int *refs) { 01076 REQUIRE(node->references > 0); 01077 node->references--; 01078 if (refs != NULL) 01079 *refs = node->references; 01080 } 01081 #else 01082 #define dns_rbtnode_refincrement0(node, refs) \ 01083 do { \ 01084 unsigned int *_tmp = (unsigned int *)(refs); \ 01085 (node)->references++; \ 01086 if ((_tmp) != NULL) \ 01087 (*_tmp) = (node)->references; \ 01088 } while (0) 01089 #define dns_rbtnode_refincrement(node, refs) \ 01090 do { \ 01091 REQUIRE((node)->references > 0); \ 01092 (node)->references++; \ 01093 if ((refs) != NULL) \ 01094 (*refs) = (node)->references; \ 01095 } while (0) 01096 #define dns_rbtnode_refdecrement(node, refs) \ 01097 do { \ 01098 REQUIRE((node)->references > 0); \ 01099 (node)->references--; \ 01100 if ((refs) != NULL) \ 01101 (*refs) = (node)->references; \ 01102 } while (0) 01103 #endif 01104 #endif /* DNS_RBT_USEISCREFCOUNT */ 01105 01106 void 01107 dns_rbtnode_nodename(dns_rbtnode_t *node, dns_name_t *name); 01108 01109 dns_rbtnode_t * 01110 dns_rbt_root(dns_rbt_t *rbt); 01111 01112 ISC_LANG_ENDDECLS 01113 01114 #endif /* DNS_RBT_H */