[35904] Add various RBT unit tests
No CHANGES entry was added as this commit mainly adds tests related code. Squashed commit of the following: commit d3d44508daa128fb8b60f64b3a8c81f80602273d Author: Evan Hunt <each@isc.org> Date: Wed May 7 09:36:41 2014 -0700 [rt35904] remove private non-static names from .def file commit dbca45661c3939f21c3bb3f405d08cfe1b35d7aa Author: Mukund Sivaraman <muks@isc.org> Date: Wed May 7 21:39:32 2014 +0530 Remove test for shortcut findnode() The implementation was not included in this review branch, but the tests erroneously made it through. This functionality will be addressed in a different ticket (RT#35906). commit 94ff14576ab3407f2612d34727b7eacfefc3668c Author: Mukund Sivaraman <muks@isc.org> Date: Wed May 7 21:36:50 2014 +0530 Minor indent fix commit 50972f17697bb222996e433faa8224843366f9b2 Author: Evan Hunt <each@isc.org> Date: Tue May 6 20:05:21 2014 -0700 [rt35904] style commit 5c4d5d41fcc5bfecdeebc008896974385c841b8d Author: Mukund Sivaraman <muks@isc.org> Date: Sun May 4 19:19:36 2014 +0530 RBT related updates * Add various RBT unit tests * Add some helper methods useful in unit testing RBT code * General cleanup
This commit is contained in:
@@ -726,10 +726,14 @@ dns_rbt_deserialize_tree(void *base_address, size_t filesize,
|
||||
*/
|
||||
|
||||
void
|
||||
dns_rbt_printall(dns_rbt_t *rbt, void (*data_printer)(FILE *, void *));
|
||||
dns_rbt_printtext(dns_rbt_t *rbt,
|
||||
void (*data_printer)(FILE *, void *), FILE *f);
|
||||
/*%<
|
||||
* Print an ASCII representation of the internal structure of the red-black
|
||||
* tree of trees.
|
||||
* tree of trees to the passed stream.
|
||||
*
|
||||
* data_printer is a callback function that is called to print the data
|
||||
* in a node. It should print it to the passed FILE stream.
|
||||
*
|
||||
* Notes:
|
||||
* \li The name stored at each node, along with the node's color, is printed.
|
||||
@@ -739,9 +743,69 @@ dns_rbt_printall(dns_rbt_t *rbt, void (*data_printer)(FILE *, void *));
|
||||
*/
|
||||
|
||||
void
|
||||
dns_rbt_printnodeinfo(dns_rbtnode_t *n);
|
||||
dns_rbt_printdot(dns_rbt_t *rbt, isc_boolean_t show_pointers, FILE *f);
|
||||
/*%<
|
||||
* Print a GraphViz dot representation of the internal structure of the
|
||||
* red-black tree of trees to the passed stream.
|
||||
*
|
||||
* If show_pointers is TRUE, pointers are also included in the generated
|
||||
* graph.
|
||||
*
|
||||
* Notes:
|
||||
* \li The name stored at each node, along with the node's color is displayed.
|
||||
* Then the down pointer, left and right pointers are displayed
|
||||
* recursively in turn. NULL left, right and down pointers are
|
||||
* silently omitted.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f);
|
||||
/*%<
|
||||
* Print out various information about a node
|
||||
*
|
||||
* Requires:
|
||||
*\li 'n' is a valid pointer.
|
||||
*
|
||||
*\li 'f' points to a valid open FILE structure that allows writing.
|
||||
*/
|
||||
|
||||
|
||||
size_t
|
||||
dns__rbt_getheight(dns_rbt_t *rbt);
|
||||
/*%<
|
||||
* Return the maximum height of sub-root nodes found in the red-black
|
||||
* forest.
|
||||
*
|
||||
* The height of a node is defined as the number of nodes in the longest
|
||||
* path from the node to a leaf. For each subtree in the forest, this
|
||||
* function determines the height of its root node. Then it returns the
|
||||
* maximum such height in the forest.
|
||||
*
|
||||
* Note: This function exists for testing purposes. Non-test code must
|
||||
* not use it.
|
||||
*
|
||||
* Requires:
|
||||
* \li rbt is a valid rbt manager.
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
dns__rbt_checkproperties(dns_rbt_t *rbt);
|
||||
/*%<
|
||||
* Check red-black properties of the forest.
|
||||
*
|
||||
* Note: This function exists for testing purposes. Non-test code must
|
||||
* not use it.
|
||||
*
|
||||
* Requires:
|
||||
* \li rbt is a valid rbt manager.
|
||||
*/
|
||||
|
||||
size_t
|
||||
dns__rbtnode_getdistance(dns_rbtnode_t *node);
|
||||
/*%<
|
||||
* Return the distance (in nodes) from the node to its upper node of its
|
||||
* subtree. The root node has a distance of 1. A child of the root node
|
||||
* has a distance of 2.
|
||||
*/
|
||||
|
||||
/*****
|
||||
@@ -1036,6 +1100,12 @@ dns_rbtnode_refdecrement(dns_rbtnode_t *node, unsigned int *refs) {
|
||||
#endif
|
||||
#endif /* DNS_RBT_USEISCREFCOUNT */
|
||||
|
||||
void
|
||||
dns_rbtnode_nodename(dns_rbtnode_t *node, dns_name_t *name);
|
||||
|
||||
dns_rbtnode_t *
|
||||
dns_rbt_root(dns_rbt_t *rbt);
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* DNS_RBT_H */
|
||||
|
||||
374
lib/dns/rbt.c
374
lib/dns/rbt.c
@@ -209,6 +209,7 @@ getdata(dns_rbtnode_t *node, file_header_t *header) {
|
||||
#define RIGHT(node) ((node)->right)
|
||||
#define DOWN(node) ((node)->down)
|
||||
#define DATA(node) ((node)->data)
|
||||
#define IS_EMPTY(node) ((node)->data == NULL)
|
||||
#define HASHNEXT(node) ((node)->hashnext)
|
||||
#define HASHVAL(node) ((node)->hashval)
|
||||
#define COLOR(node) ((node)->color)
|
||||
@@ -280,6 +281,21 @@ NODENAME(dns_rbtnode_t *node, dns_name_t *name) {
|
||||
name->attributes |= DNS_NAMEATTR_READONLY;
|
||||
}
|
||||
|
||||
void
|
||||
dns_rbtnode_nodename(dns_rbtnode_t *node, dns_name_t *name) {
|
||||
name->length = NAMELEN(node);
|
||||
name->labels = OFFSETLEN(node);
|
||||
name->ndata = NAME(node);
|
||||
name->offsets = OFFSETS(node);
|
||||
name->attributes = ATTRS(node);
|
||||
name->attributes |= DNS_NAMEATTR_READONLY;
|
||||
}
|
||||
|
||||
dns_rbtnode_t *
|
||||
dns_rbt_root(dns_rbt_t *rbt) {
|
||||
return rbt->root;
|
||||
}
|
||||
|
||||
#ifdef DNS_RBT_USEHASH
|
||||
static isc_result_t
|
||||
inithash(dns_rbt_t *rbt);
|
||||
@@ -302,8 +318,6 @@ Name(dns_rbtnode_t *node) {
|
||||
return (name);
|
||||
}
|
||||
|
||||
static void printnodename(dns_rbtnode_t *node);
|
||||
|
||||
static void
|
||||
hexdump(const char *desc, unsigned char *data, size_t size) {
|
||||
char hexdump[BUFSIZ * 2 + 1];
|
||||
@@ -326,23 +340,47 @@ hexdump(const char *desc, unsigned char *data, size_t size) {
|
||||
} while (size > 0);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* The passed node must not be NULL. */
|
||||
static inline dns_rbtnode_t *
|
||||
find_up(dns_rbtnode_t *node) {
|
||||
dns_rbtnode_t *root;
|
||||
get_subtree_root(dns_rbtnode_t *node) {
|
||||
while (!IS_ROOT(node)) {
|
||||
node = PARENT(node);
|
||||
}
|
||||
|
||||
return (node);
|
||||
}
|
||||
|
||||
/* Upper node is the parent of the root of the passed node's
|
||||
* subtree. The passed node must not be NULL.
|
||||
*/
|
||||
static inline dns_rbtnode_t *
|
||||
get_upper_node(dns_rbtnode_t *node) {
|
||||
dns_rbtnode_t *root = get_subtree_root(node);
|
||||
|
||||
/*
|
||||
* Return the node in the level above the argument node that points
|
||||
* to the level the argument node is in. If the argument node is in
|
||||
* the top level, the return value is NULL.
|
||||
*/
|
||||
for (root = node; ! IS_ROOT(root); root = PARENT(root))
|
||||
; /* Nothing. */
|
||||
|
||||
return (PARENT(root));
|
||||
}
|
||||
|
||||
size_t
|
||||
dns__rbtnode_getdistance(dns_rbtnode_t *node) {
|
||||
size_t nodes = 1;
|
||||
|
||||
while (node != NULL) {
|
||||
if (IS_ROOT(node))
|
||||
break;
|
||||
nodes++;
|
||||
node = PARENT(node);
|
||||
}
|
||||
|
||||
return (nodes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
@@ -387,7 +425,7 @@ static void
|
||||
deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, dns_rbtnode_t **nodep);
|
||||
|
||||
static void
|
||||
printnodename(dns_rbtnode_t *node);
|
||||
printnodename(dns_rbtnode_t *node, isc_boolean_t quoted, FILE *f);
|
||||
|
||||
static void
|
||||
freenode(dns_rbt_t *rbt, dns_rbtnode_t **nodep);
|
||||
@@ -1371,15 +1409,14 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
|
||||
|
||||
if (rbt->root == NULL)
|
||||
return (ISC_R_NOTFOUND);
|
||||
else {
|
||||
/*
|
||||
* Appease GCC about variables it incorrectly thinks are
|
||||
* possibly used uninitialized.
|
||||
*/
|
||||
compared = dns_namereln_none;
|
||||
last_compared = NULL;
|
||||
order = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Appease GCC about variables it incorrectly thinks are
|
||||
* possibly used uninitialized.
|
||||
*/
|
||||
compared = dns_namereln_none;
|
||||
last_compared = NULL;
|
||||
order = 0;
|
||||
|
||||
dns_fixedname_init(&fixedcallbackname);
|
||||
callback_name = dns_fixedname_name(&fixedcallbackname);
|
||||
@@ -1405,6 +1442,12 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
|
||||
NODENAME(current, ¤t_name);
|
||||
compared = dns_name_fullcompare(search_name, ¤t_name,
|
||||
&order, &common_labels);
|
||||
/*
|
||||
* last_compared is used as a shortcut to start (or
|
||||
* continue rather) finding the stop-node of the search
|
||||
* when hashing was used (see much below in this
|
||||
* function).
|
||||
*/
|
||||
last_compared = current;
|
||||
|
||||
if (compared == dns_namereln_equal)
|
||||
@@ -1412,6 +1455,16 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
|
||||
|
||||
if (compared == dns_namereln_none) {
|
||||
#ifdef DNS_RBT_USEHASH
|
||||
/*
|
||||
* Here, current is pointing at a subtree root
|
||||
* node. We try to find a matching node using
|
||||
* the hashtable. We can get one of 3 results
|
||||
* here: (a) we locate the matching node, (b) we
|
||||
* find a node to which the current node has a
|
||||
* subdomain relation, (c) we fail to find (a)
|
||||
* or (b).
|
||||
*/
|
||||
|
||||
dns_name_t hash_name;
|
||||
dns_rbtnode_t *hnode;
|
||||
dns_rbtnode_t *up_current;
|
||||
@@ -1446,7 +1499,12 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
|
||||
|
||||
hashagain:
|
||||
/*
|
||||
* Hash includes tail.
|
||||
* Compute the hash over the full absolute
|
||||
* name. Look for the smallest suffix match at
|
||||
* this tree level (hlevel), and then at every
|
||||
* iteration, look for the next smallest suffix
|
||||
* match (add another subdomain label to the
|
||||
* absolute name being hashed).
|
||||
*/
|
||||
dns_name_getlabelsequence(name,
|
||||
nlabels - tlabels,
|
||||
@@ -1457,6 +1515,10 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
|
||||
nlabels - tlabels,
|
||||
tlabels, &hash_name);
|
||||
|
||||
/*
|
||||
* Walk all the nodes in the hash bucket pointed
|
||||
* by the computed hash value.
|
||||
*/
|
||||
for (hnode = rbt->hashtable[hash % rbt->hashsize];
|
||||
hnode != NULL;
|
||||
hnode = hnode->hashnext)
|
||||
@@ -1465,8 +1527,16 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
|
||||
|
||||
if (hash != HASHVAL(hnode))
|
||||
continue;
|
||||
if (find_up(hnode) != up_current)
|
||||
/*
|
||||
* This checks that the hashed label
|
||||
* sequence being looked up is at the
|
||||
* same tree level, so that we don't
|
||||
* match a labelsequence from some other
|
||||
* subdomain.
|
||||
*/
|
||||
if (get_upper_node(hnode) != up_current)
|
||||
continue;
|
||||
|
||||
dns_name_init(&hnode_name, NULL);
|
||||
NODENAME(hnode, &hnode_name);
|
||||
if (dns_name_equal(&hnode_name, &hash_name))
|
||||
@@ -1971,7 +2041,7 @@ dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse)
|
||||
* deleted. If the deleted node is the top level, parent will be set
|
||||
* to NULL.
|
||||
*/
|
||||
parent = find_up(node);
|
||||
parent = get_upper_node(node);
|
||||
|
||||
/*
|
||||
* This node now has no down pointer (either because it didn't
|
||||
@@ -2051,7 +2121,7 @@ dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) {
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
node = find_up(node);
|
||||
node = get_upper_node(node);
|
||||
} while (! dns_name_isabsolute(name));
|
||||
|
||||
return (result);
|
||||
@@ -2799,42 +2869,140 @@ deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, dns_rbtnode_t **nodep) {
|
||||
goto again;
|
||||
}
|
||||
|
||||
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(int depth) {
|
||||
dns_rbt_indent(FILE *f, int depth) {
|
||||
int i;
|
||||
|
||||
printf("%4d ", depth);
|
||||
fprintf(f, "%4d ", depth);
|
||||
|
||||
for (i = 0; i < depth; i++)
|
||||
printf("- ");
|
||||
fprintf(f, "- ");
|
||||
}
|
||||
|
||||
void
|
||||
dns_rbt_printnodeinfo(dns_rbtnode_t *n) {
|
||||
printf("Node info for nodename: ");
|
||||
printnodename(n);
|
||||
printf("\n");
|
||||
dns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f) {
|
||||
fprintf(f, "Node info for nodename: ");
|
||||
printnodename(n, ISC_TRUE, f);
|
||||
fprintf(f, "\n");
|
||||
|
||||
printf("n = %p\n", n);
|
||||
fprintf(f, "n = %p\n", n);
|
||||
|
||||
printf("Relative pointers: %s%s%s%s%s\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" : ""));
|
||||
|
||||
printf("node lock address = %d\n", n->locknum);
|
||||
fprintf(f, "node lock address = %d\n", n->locknum);
|
||||
|
||||
printf("Parent: %p\n", n->parent);
|
||||
printf("Right: %p\n", n->right);
|
||||
printf("Left: %p\n", n->left);
|
||||
printf("Down: %p\n", n->down);
|
||||
printf("daTa: %p\n", n->data);
|
||||
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) {
|
||||
printnodename(dns_rbtnode_t *node, isc_boolean_t quoted, FILE *f) {
|
||||
isc_region_t r;
|
||||
dns_name_t name;
|
||||
char buffer[DNS_NAME_FORMATSIZE];
|
||||
@@ -2848,65 +3016,135 @@ printnodename(dns_rbtnode_t *node) {
|
||||
|
||||
dns_name_format(&name, buffer, sizeof(buffer));
|
||||
|
||||
printf("\"%s\"", buffer);
|
||||
if (quoted)
|
||||
fprintf(f, "\"%s\"", buffer);
|
||||
else
|
||||
fprintf(f, "%s", buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
dns_rbt_printtree(dns_rbtnode_t *root, dns_rbtnode_t *parent,
|
||||
print_text_helper(dns_rbtnode_t *root, dns_rbtnode_t *parent,
|
||||
int depth, const char *direction,
|
||||
void (*data_printer)(FILE *, void *))
|
||||
void (*data_printer)(FILE *, void *), FILE *f)
|
||||
{
|
||||
dns_rbt_indent(depth);
|
||||
dns_rbt_indent(f, depth);
|
||||
|
||||
if (root != NULL) {
|
||||
printnodename(root);
|
||||
printf(" (%s, %s", direction, IS_RED(root) ? "RED" : "BLACK");
|
||||
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)) {
|
||||
|
||||
printf(" (BAD parent pointer! -> ");
|
||||
fprintf(f, " (BAD parent pointer! -> ");
|
||||
if (PARENT(root) != NULL)
|
||||
printnodename(PARENT(root));
|
||||
printnodename(PARENT(root), ISC_TRUE, f);
|
||||
else
|
||||
printf("NULL");
|
||||
printf(")");
|
||||
fprintf(f, "NULL");
|
||||
fprintf(f, ")");
|
||||
}
|
||||
|
||||
printf(")");
|
||||
fprintf(f, ")");
|
||||
|
||||
if (root->data != NULL && data_printer != NULL) {
|
||||
printf(" data@%p: ", root->data);
|
||||
data_printer(stdout, root->data);
|
||||
fprintf(f, " data@%p: ", root->data);
|
||||
data_printer(f, root->data);
|
||||
}
|
||||
printf("\n");
|
||||
fprintf(f, "\n");
|
||||
|
||||
depth++;
|
||||
|
||||
if (IS_RED(root) && IS_RED(LEFT(root)))
|
||||
printf("** Red/Red color violation on left\n");
|
||||
dns_rbt_printtree(LEFT(root), root, depth, "left",
|
||||
data_printer);
|
||||
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)))
|
||||
printf("** Red/Red color violation on right\n");
|
||||
dns_rbt_printtree(RIGHT(root), root, depth, "right",
|
||||
data_printer);
|
||||
fprintf(f, "** Red/Red color violation on right\n");
|
||||
print_text_helper(RIGHT(root), root, depth, "right",
|
||||
data_printer, f);
|
||||
|
||||
dns_rbt_printtree(DOWN(root), NULL, depth, "down",
|
||||
data_printer);
|
||||
print_text_helper(DOWN(root), NULL, depth, "down",
|
||||
data_printer, f);
|
||||
} else {
|
||||
printf("NULL (%s)\n", direction);
|
||||
fprintf(f, "NULL (%s)\n", direction);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dns_rbt_printall(dns_rbt_t *rbt, void (*data_printer)(FILE *, 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));
|
||||
|
||||
dns_rbt_printtree(rbt->root, NULL, 0, "root", data_printer);
|
||||
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");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3384,3 +3622,13 @@ dns_rbtnodechain_invalidate(dns_rbtnodechain_t *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.
|
||||
*/
|
||||
|
||||
@@ -49,6 +49,7 @@ SRCS = db_test.c \
|
||||
nsec3_test.c \
|
||||
private_test.c \
|
||||
rbt_test.c \
|
||||
rbt_serialize_test.c \
|
||||
rdata_test.c \
|
||||
rdataset_test.c \
|
||||
rdatasetstats_test.c \
|
||||
@@ -69,6 +70,7 @@ TARGETS = db_test@EXEEXT@ \
|
||||
nsec3_test@EXEEXT@ \
|
||||
private_test@EXEEXT@ \
|
||||
rbt_test@EXEEXT@ \
|
||||
rbt_serialize_test@EXEEXT@ \
|
||||
rdata_test@EXEEXT@ \
|
||||
rdataset_test@EXEEXT@ \
|
||||
rdatasetstats_test@EXEEXT@ \
|
||||
@@ -158,6 +160,11 @@ rbt_test@EXEEXT@: rbt_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
|
||||
rbt_test.@O@ dnstest.@O@ ${DNSLIBS} \
|
||||
${ISCLIBS} ${LIBS}
|
||||
|
||||
rbt_serialize_test@EXEEXT@: rbt_serialize_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
|
||||
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
|
||||
rbt_serialize_test.@O@ dnstest.@O@ ${DNSLIBS} \
|
||||
${ISCLIBS} ${LIBS}
|
||||
|
||||
rdata_test@EXEEXT@: rdata_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
|
||||
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
|
||||
rdata_test.@O@ ${DNSLIBS} \
|
||||
|
||||
464
lib/dns/tests/rbt_serialize_test.c
Normal file
464
lib/dns/tests/rbt_serialize_test.c
Normal file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: rbt_test.c,v 1.1.14.8 2012/02/10 16:24:37 ckb Exp $ */
|
||||
|
||||
/* ! \file */
|
||||
|
||||
#include <config.h>
|
||||
#include <atf-c.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h> /* uintptr_t */
|
||||
#endif
|
||||
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/result.h>
|
||||
#include <dns/compress.h>
|
||||
#include "dnstest.h"
|
||||
|
||||
#include <isc/app.h>
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/entropy.h>
|
||||
#include <isc/file.h>
|
||||
#include <isc/hash.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/os.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/socket.h>
|
||||
#include <isc/stdio.h>
|
||||
#include <isc/task.h>
|
||||
#include <isc/timer.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/log.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/result.h>
|
||||
|
||||
#include <dst/dst.h>
|
||||
|
||||
#ifndef MAP_FILE
|
||||
#define MAP_FILE 0
|
||||
#endif
|
||||
|
||||
typedef struct data_holder {
|
||||
int len;
|
||||
const char *data;
|
||||
} data_holder_t;
|
||||
|
||||
typedef struct rbt_testdata {
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
data_holder_t data;
|
||||
} rbt_testdata_t;
|
||||
|
||||
#define DATA_ITEM(name) { (name), sizeof(name) - 1, { sizeof(name), (name) } }
|
||||
|
||||
rbt_testdata_t testdata[] = {
|
||||
DATA_ITEM("first.com."),
|
||||
DATA_ITEM("one.net."),
|
||||
DATA_ITEM("two.com."),
|
||||
DATA_ITEM("three.org."),
|
||||
DATA_ITEM("asdf.com."),
|
||||
DATA_ITEM("ghjkl.com."),
|
||||
DATA_ITEM("1.edu."),
|
||||
DATA_ITEM("2.edu."),
|
||||
DATA_ITEM("3.edu."),
|
||||
DATA_ITEM("123.edu."),
|
||||
DATA_ITEM("1236.com."),
|
||||
DATA_ITEM("and_so_forth.com."),
|
||||
DATA_ITEM("thisisalongname.com."),
|
||||
DATA_ITEM("a.b."),
|
||||
DATA_ITEM("test.net."),
|
||||
DATA_ITEM("whoknows.org."),
|
||||
DATA_ITEM("blargh.com."),
|
||||
DATA_ITEM("www.joe.com."),
|
||||
DATA_ITEM("test.com."),
|
||||
DATA_ITEM("isc.org."),
|
||||
DATA_ITEM("uiop.mil."),
|
||||
DATA_ITEM("last.fm."),
|
||||
{ NULL, 0, { 0, NULL } }
|
||||
};
|
||||
|
||||
static void
|
||||
delete_data(void *data, void *arg) {
|
||||
UNUSED(arg);
|
||||
UNUSED(data);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
write_data(FILE *file, unsigned char *datap, void *arg, isc_uint64_t *crc) {
|
||||
isc_result_t result;
|
||||
size_t ret = 0;
|
||||
data_holder_t *data = (data_holder_t *)datap;
|
||||
data_holder_t temp;
|
||||
off_t where;
|
||||
|
||||
UNUSED(arg);
|
||||
|
||||
REQUIRE(file != NULL);
|
||||
REQUIRE(crc != NULL);
|
||||
REQUIRE(data != NULL);
|
||||
REQUIRE((data->len == 0 && data->data == NULL) ||
|
||||
(data->len != 0 && data->data != NULL));
|
||||
|
||||
result = isc_stdio_tell(file, &where);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
temp = *data;
|
||||
temp.data = (data->len == 0
|
||||
? NULL
|
||||
: (char *)((uintptr_t)where + sizeof(data_holder_t)));
|
||||
|
||||
isc_crc64_update(crc, (void *)&temp, sizeof(temp));
|
||||
ret = fwrite(&temp, sizeof(data_holder_t), 1, file);
|
||||
if (ret != 1)
|
||||
return (ISC_R_FAILURE);
|
||||
if (data->len > 0) {
|
||||
isc_crc64_update(crc, (const void *)data->data, data->len);
|
||||
ret = fwrite(data->data, data->len, 1, file);
|
||||
if (ret != 1)
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
fix_data(dns_rbtnode_t *p, void *base, size_t max, void *arg,
|
||||
isc_uint64_t *crc)
|
||||
{
|
||||
data_holder_t *data = p->data;
|
||||
size_t size;
|
||||
|
||||
UNUSED(base);
|
||||
UNUSED(max);
|
||||
UNUSED(arg);
|
||||
|
||||
REQUIRE(crc != NULL);
|
||||
REQUIRE(p != NULL);
|
||||
|
||||
|
||||
if (data == NULL)
|
||||
printf("fixing data: data NULL\n");
|
||||
else
|
||||
printf("fixing data: len %d, data %p\n", data->len, data->data);
|
||||
|
||||
if (data == NULL ||
|
||||
(data->len == 0 && data->data != NULL) ||
|
||||
(data->len != 0 && data->data == NULL))
|
||||
return (ISC_R_INVALIDFILE);
|
||||
|
||||
size = max - ((char *)p - (char *)base);
|
||||
|
||||
if (data->len > (int) size || data->data > (const char *) max) {
|
||||
printf("data invalid\n");
|
||||
return (ISC_R_INVALIDFILE);
|
||||
}
|
||||
|
||||
isc_crc64_update(crc, (void *)data, sizeof(*data));
|
||||
|
||||
data->data = (data->len == 0)
|
||||
? NULL
|
||||
: (char *)data + sizeof(data_holder_t);
|
||||
|
||||
if (data->len > 0)
|
||||
isc_crc64_update(crc, (const void *)data->data, data->len);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Load test data into the RBT.
|
||||
*/
|
||||
static void
|
||||
add_test_data(isc_mem_t *mctx, dns_rbt_t *rbt) {
|
||||
char buffer[1024];
|
||||
isc_buffer_t b;
|
||||
isc_result_t result;
|
||||
dns_fixedname_t fname;
|
||||
dns_name_t *name;
|
||||
dns_compress_t cctx;
|
||||
rbt_testdata_t *testdatap = testdata;
|
||||
|
||||
dns_compress_init(&cctx, -1, mctx);
|
||||
|
||||
while (testdatap->name != NULL && testdatap->data.data != NULL) {
|
||||
memmove(buffer, testdatap->name, testdatap->name_len);
|
||||
|
||||
isc_buffer_init(&b, buffer, testdatap->name_len);
|
||||
isc_buffer_add(&b, testdatap->name_len);
|
||||
dns_fixedname_init(&fname);
|
||||
name = dns_fixedname_name(&fname);
|
||||
result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
testdatap++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name != NULL) {
|
||||
result = dns_rbt_addname(rbt, name, &testdatap->data);
|
||||
ATF_CHECK_STREQ(dns_result_totext(result), "success");
|
||||
}
|
||||
testdatap++;
|
||||
}
|
||||
|
||||
dns_compress_invalidate(&cctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk the tree and ensure that all the test nodes are present.
|
||||
*/
|
||||
static void
|
||||
check_test_data(dns_rbt_t *rbt) {
|
||||
char buffer[1024];
|
||||
char *arg;
|
||||
dns_fixedname_t fname;
|
||||
dns_fixedname_t fixed;
|
||||
dns_name_t *name;
|
||||
isc_buffer_t b;
|
||||
data_holder_t *data;
|
||||
isc_result_t result;
|
||||
dns_name_t *foundname;
|
||||
rbt_testdata_t *testdatap = testdata;
|
||||
|
||||
dns_fixedname_init(&fixed);
|
||||
foundname = dns_fixedname_name(&fixed);
|
||||
|
||||
while (testdatap->name != NULL && testdatap->data.data != NULL) {
|
||||
memmove(buffer, testdatap->name, testdatap->name_len + 1);
|
||||
arg = buffer;
|
||||
|
||||
isc_buffer_init(&b, arg, testdatap->name_len);
|
||||
isc_buffer_add(&b, testdatap->name_len);
|
||||
dns_fixedname_init(&fname);
|
||||
name = dns_fixedname_name(&fname);
|
||||
result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
testdatap++;
|
||||
continue;
|
||||
}
|
||||
|
||||
data = NULL;
|
||||
result = dns_rbt_findname(rbt, name, 0, foundname,
|
||||
(void *) &data);
|
||||
ATF_CHECK_STREQ(dns_result_totext(result), "success");
|
||||
|
||||
testdatap++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
data_printer(FILE *out, void *datap)
|
||||
{
|
||||
data_holder_t *data = (data_holder_t *)datap;
|
||||
|
||||
fprintf(out, "%d bytes, %s", data->len, data->data);
|
||||
}
|
||||
|
||||
ATF_TC(serialize);
|
||||
ATF_TC_HEAD(serialize, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "Test writing an rbt to file");
|
||||
}
|
||||
ATF_TC_BODY(serialize, tc) {
|
||||
dns_rbt_t *rbt = NULL;
|
||||
isc_result_t result;
|
||||
FILE *rbtfile = NULL;
|
||||
dns_rbt_t *rbt_deserialized = NULL;
|
||||
off_t offset;
|
||||
int fd;
|
||||
off_t filesize = 0;
|
||||
char *base;
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_TRUE);
|
||||
ATF_CHECK_STREQ(dns_result_totext(result), "success");
|
||||
result = dns_rbt_create(mctx, delete_data, NULL, &rbt);
|
||||
ATF_CHECK_STREQ(dns_result_totext(result), "success");
|
||||
|
||||
add_test_data(mctx, rbt);
|
||||
|
||||
dns_rbt_printtext(rbt, data_printer, stdout);
|
||||
|
||||
/*
|
||||
* Serialize the tree.
|
||||
*/
|
||||
printf("serialization begins.\n");
|
||||
rbtfile = fopen("./zone.bin", "w+b");
|
||||
ATF_REQUIRE(rbtfile != NULL);
|
||||
result = dns_rbt_serialize_tree(rbtfile, rbt, write_data, NULL,
|
||||
&offset);
|
||||
ATF_REQUIRE(result == ISC_R_SUCCESS);
|
||||
dns_rbt_destroy(&rbt);
|
||||
|
||||
/*
|
||||
* Deserialize the tree
|
||||
*/
|
||||
printf("deserialization begins.\n");
|
||||
|
||||
/*
|
||||
* Map in the whole file in one go
|
||||
*/
|
||||
fd = open("zone.bin", O_RDWR);
|
||||
isc_file_getsizefd(fd, &filesize);
|
||||
base = mmap(NULL, filesize,
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_FILE|MAP_PRIVATE, fd, 0);
|
||||
ATF_REQUIRE(base != NULL && base != MAP_FAILED);
|
||||
close(fd);
|
||||
|
||||
result = dns_rbt_deserialize_tree(base, filesize, 0, mctx,
|
||||
delete_data, NULL, fix_data, NULL,
|
||||
NULL, &rbt_deserialized);
|
||||
|
||||
/* Test to make sure we have a valid tree */
|
||||
ATF_REQUIRE(result == ISC_R_SUCCESS);
|
||||
if (rbt_deserialized == NULL)
|
||||
atf_tc_fail("deserialized rbt is null!"); /* Abort execution. */
|
||||
|
||||
check_test_data(rbt_deserialized);
|
||||
|
||||
dns_rbt_printtext(rbt_deserialized, data_printer, stdout);
|
||||
|
||||
dns_rbt_destroy(&rbt_deserialized);
|
||||
munmap(base, filesize);
|
||||
unlink("zone.bin");
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(deserialize_corrupt);
|
||||
ATF_TC_HEAD(deserialize_corrupt, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "Test reading a corrupt map file");
|
||||
}
|
||||
ATF_TC_BODY(deserialize_corrupt, tc) {
|
||||
dns_rbt_t *rbt = NULL;
|
||||
isc_result_t result;
|
||||
FILE *rbtfile = NULL;
|
||||
off_t offset;
|
||||
int fd;
|
||||
off_t filesize = 0;
|
||||
char *base, *p, *q;
|
||||
isc_uint32_t r;
|
||||
int i;
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_TRUE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
/* Set up map file */
|
||||
result = dns_rbt_create(mctx, delete_data, NULL, &rbt);
|
||||
ATF_CHECK_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
add_test_data(mctx, rbt);
|
||||
rbtfile = fopen("./zone.bin", "w+b");
|
||||
ATF_REQUIRE(rbtfile != NULL);
|
||||
result = dns_rbt_serialize_tree(rbtfile, rbt, write_data, NULL,
|
||||
&offset);
|
||||
ATF_REQUIRE(result == ISC_R_SUCCESS);
|
||||
dns_rbt_destroy(&rbt);
|
||||
|
||||
/* Read back with random fuzzing */
|
||||
for (i = 0; i < 256; i++) {
|
||||
dns_rbt_t *rbt_deserialized = NULL;
|
||||
|
||||
fd = open("zone.bin", O_RDWR);
|
||||
isc_file_getsizefd(fd, &filesize);
|
||||
base = mmap(NULL, filesize,
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_FILE|MAP_PRIVATE, fd, 0);
|
||||
ATF_REQUIRE(base != NULL && base != MAP_FAILED);
|
||||
close(fd);
|
||||
|
||||
/* Randomly fuzz a portion of the memory */
|
||||
isc_random_get(&r);
|
||||
p = base + (r % filesize);
|
||||
q = base + filesize;
|
||||
isc_random_get(&r);
|
||||
q -= (r % (q - p));
|
||||
while (p++ < q) {
|
||||
isc_random_get(&r);
|
||||
*p = r & 0xff;
|
||||
}
|
||||
|
||||
result = dns_rbt_deserialize_tree(base, filesize, 0, mctx,
|
||||
delete_data, NULL,
|
||||
fix_data, NULL,
|
||||
NULL, &rbt_deserialized);
|
||||
printf("%d: %s\n", i, isc_result_totext(result));
|
||||
|
||||
/* Test to make sure we have a valid tree */
|
||||
ATF_REQUIRE(result == ISC_R_SUCCESS ||
|
||||
result == ISC_R_INVALIDFILE);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
ATF_REQUIRE(rbt_deserialized == NULL);
|
||||
|
||||
if (rbt_deserialized != NULL)
|
||||
dns_rbt_destroy(&rbt_deserialized);
|
||||
|
||||
munmap(base, filesize);
|
||||
}
|
||||
|
||||
unlink("zone.bin");
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
|
||||
ATF_TC(serialize_align);
|
||||
ATF_TC_HEAD(serialize_align, tc) {
|
||||
atf_tc_set_md_var(tc, "descr",
|
||||
"Test the dns_rbt_serialize_align() function.");
|
||||
}
|
||||
ATF_TC_BODY(serialize_align, tc) {
|
||||
UNUSED(tc);
|
||||
|
||||
ATF_CHECK(dns_rbt_serialize_align(0) == 0);
|
||||
ATF_CHECK(dns_rbt_serialize_align(1) == 8);
|
||||
ATF_CHECK(dns_rbt_serialize_align(2) == 8);
|
||||
ATF_CHECK(dns_rbt_serialize_align(3) == 8);
|
||||
ATF_CHECK(dns_rbt_serialize_align(4) == 8);
|
||||
ATF_CHECK(dns_rbt_serialize_align(5) == 8);
|
||||
ATF_CHECK(dns_rbt_serialize_align(6) == 8);
|
||||
ATF_CHECK(dns_rbt_serialize_align(7) == 8);
|
||||
ATF_CHECK(dns_rbt_serialize_align(8) == 8);
|
||||
ATF_CHECK(dns_rbt_serialize_align(9) == 16);
|
||||
ATF_CHECK(dns_rbt_serialize_align(0xff) == 0x100);
|
||||
ATF_CHECK(dns_rbt_serialize_align(0x301) == 0x308);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main
|
||||
*/
|
||||
ATF_TP_ADD_TCS(tp) {
|
||||
ATF_TP_ADD_TC(tp, serialize);
|
||||
ATF_TP_ADD_TC(tp, deserialize_corrupt);
|
||||
ATF_TP_ADD_TC(tp, serialize_align);
|
||||
|
||||
return (atf_no_error());
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -553,7 +553,8 @@ dns_rbt_fullnamefromnode
|
||||
dns_rbt_hashsize
|
||||
dns_rbt_namefromnode
|
||||
dns_rbt_nodecount
|
||||
dns_rbt_printall
|
||||
dns_rbt_printtext
|
||||
dns_rbt_printdot
|
||||
dns_rbt_printnodeinfo
|
||||
dns_rbt_serialize_align
|
||||
dns_rbt_serialize_tree
|
||||
|
||||
@@ -393,3 +393,17 @@ isc_hash_calc(const unsigned char *key, unsigned int keylen,
|
||||
|
||||
return (hash_calc(hash, key, keylen, case_sensitive));
|
||||
}
|
||||
|
||||
void
|
||||
isc__hash_setvec(const uint16_t *vec) {
|
||||
int i;
|
||||
hash_random_t *p;
|
||||
|
||||
if (hash == NULL)
|
||||
return;
|
||||
|
||||
p = hash->rndvector;
|
||||
for (i = 0; i < 256; i++) {
|
||||
p[i] = vec[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#ifndef ISC_HASH_H
|
||||
#define ISC_HASH_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*****
|
||||
***** Module Info
|
||||
*****/
|
||||
@@ -180,6 +182,22 @@ isc_hash_calc(const unsigned char *key, unsigned int keylen,
|
||||
*/
|
||||
/*@}*/
|
||||
|
||||
void
|
||||
isc__hash_setvec(const uint16_t *vec);
|
||||
|
||||
/*!<
|
||||
* \brief Set the contents of the random vector used in hashing.
|
||||
*
|
||||
* WARNING: This function is meant to be used only in testing code. It
|
||||
* must not be used anywhere in normally running code.
|
||||
*
|
||||
* The hash context must have been created beforehand, otherwise this
|
||||
* function is a nop.
|
||||
*
|
||||
* 'vec' is not documented here on purpose. You should know what you are
|
||||
* doing before using this function.
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* ISC_HASH_H */
|
||||
|
||||
Reference in New Issue
Block a user