return (DNS_R_DELEGATION);
}
+typedef enum { FORWARD, BACK } direction_t;
+
+/*
+ * Step backwards or forwards through the database until we find a
+ * node with data in it for the desired version. If 'nextname' is not NULL,
+ * and we found a predecessor or successor, save the name we found in it.
+ * Return true if we found a predecessor or successor.
+ */
static bool
-activeempty(rbtdb_search_t *search, dns_rbtnodechain_t *chain,
- const dns_name_t *name) {
- dns_fixedname_t fnext;
+step(rbtdb_search_t *search, dns_rbtnodechain_t *chain, direction_t direction,
+ dns_name_t *nextname) {
dns_fixedname_t forigin;
- dns_name_t *next = NULL;
dns_name_t *origin = NULL;
dns_name_t prefix;
dns_rbtdb_t *rbtdb = NULL;
dns_rbtnode_t *node = NULL;
- isc_result_t result;
- bool answer = false;
+ isc_result_t result = ISC_R_SUCCESS;
dns_slabheader_t *header = NULL;
rbtdb = search->rbtdb;
dns_name_init(&prefix, NULL);
- next = dns_fixedname_initname(&fnext);
origin = dns_fixedname_initname(&forigin);
- result = dns_rbtnodechain_next(chain, NULL, NULL);
while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
node = NULL;
if (header != NULL) {
break;
}
- result = dns_rbtnodechain_next(chain, NULL, NULL);
+ if (direction == FORWARD) {
+ result = dns_rbtnodechain_next(chain, NULL, NULL);
+ } else {
+ result = dns_rbtnodechain_prev(chain, NULL, NULL);
+ }
+ };
+ if (result == ISC_R_SUCCESS) {
+ result = dns_name_concatenate(&prefix, origin, nextname, NULL);
}
if (result == ISC_R_SUCCESS) {
- result = dns_name_concatenate(&prefix, origin, next, NULL);
+ return (true);
}
- if (result == ISC_R_SUCCESS && dns_name_issubdomain(next, name)) {
- answer = true;
+ return (false);
+}
+
+/*
+ * Use step() to find the successor to the current name, and then
+ * check to see whether it's a subdomain of the current name. If so,
+ * then this is an empty non-terminal in the currently active version
+ * of the database.
+ */
+static bool
+activeempty(rbtdb_search_t *search, dns_rbtnodechain_t *chain,
+ const dns_name_t *current) {
+ isc_result_t result;
+ dns_fixedname_t fnext;
+ dns_name_t *next = dns_fixedname_initname(&fnext);
+
+ result = dns_rbtnodechain_next(chain, NULL, NULL);
+ if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+ return (false);
}
- return (answer);
+ return (step(search, chain, FORWARD, next) &&
+ dns_name_issubdomain(next, current));
}
static bool
-activeemptynode(rbtdb_search_t *search, const dns_name_t *qname,
- dns_name_t *wname) {
+wildcard_blocked(rbtdb_search_t *search, const dns_name_t *qname,
+ dns_name_t *wname) {
+ isc_result_t result;
dns_fixedname_t fnext;
- dns_fixedname_t forigin;
dns_fixedname_t fprev;
- dns_name_t *next = NULL;
- dns_name_t *origin = NULL;
- dns_name_t *prev = NULL;
+ dns_name_t *next = NULL, *prev = NULL;
dns_name_t name;
dns_name_t rname;
dns_name_t tname;
- dns_rbtdb_t *rbtdb = NULL;
- dns_rbtnode_t *node = NULL;
dns_rbtnodechain_t chain;
- bool check_next = true;
- bool check_prev = true;
- bool answer = false;
- isc_result_t result;
- dns_slabheader_t *header = NULL;
+ bool check_next = false;
+ bool check_prev = false;
unsigned int n;
- rbtdb = search->rbtdb;
-
dns_name_init(&name, NULL);
dns_name_init(&tname, NULL);
dns_name_init(&rname, NULL);
next = dns_fixedname_initname(&fnext);
prev = dns_fixedname_initname(&fprev);
- origin = dns_fixedname_initname(&forigin);
/*
- * Find if qname is at or below a empty node.
- * Use our own copy of the chain.
+ * The qname seems to have matched a wildcard, but we
+ * need to find out if there's an empty nonterminal node
+ * between the wildcard level and the qname.
+ *
+ * search->chain should now be pointing at the predecessor
+ * of the searched-for name. We are using a local copy of the
+ * chain so as not to change the state of search->chain.
+ * step() will walk backward until we find a predecessor with
+ * data.
*/
-
chain = search->chain;
- do {
- isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
- node = NULL;
- result = dns_rbtnodechain_current(&chain, &name, origin, &node);
- if (result != ISC_R_SUCCESS) {
- break;
- }
- NODE_RDLOCK(&(rbtdb->node_locks[node->locknum].lock),
- &nlocktype);
- for (header = node->data; header != NULL; header = header->next)
- {
- if (header->serial <= search->serial &&
- !IGNORE(header) && EXISTS(header))
- {
- break;
- }
- }
- NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
- &nlocktype);
- if (header != NULL) {
- break;
- }
- result = dns_rbtnodechain_prev(&chain, NULL, NULL);
- } while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN);
- if (result == ISC_R_SUCCESS) {
- result = dns_name_concatenate(&name, origin, prev, NULL);
- }
- if (result != ISC_R_SUCCESS) {
- check_prev = false;
- }
+ check_prev = step(search, &chain, BACK, prev);
+ /* Now reset the chain and look for a successor with data. */
+ chain = search->chain;
result = dns_rbtnodechain_next(&chain, NULL, NULL);
- while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
- isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
- node = NULL;
- result = dns_rbtnodechain_current(&chain, &name, origin, &node);
- if (result != ISC_R_SUCCESS) {
- break;
- }
- NODE_RDLOCK(&(rbtdb->node_locks[node->locknum].lock),
- &nlocktype);
- for (header = node->data; header != NULL; header = header->next)
- {
- if (header->serial <= search->serial &&
- !IGNORE(header) && EXISTS(header))
- {
- break;
- }
- }
- NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
- &nlocktype);
- if (header != NULL) {
- break;
- }
- result = dns_rbtnodechain_next(&chain, NULL, NULL);
- }
if (result == ISC_R_SUCCESS) {
- result = dns_name_concatenate(&name, origin, next, NULL);
+ check_next = step(search, &chain, FORWARD, next);
}
- if (result != ISC_R_SUCCESS) {
- check_next = false;
+
+ if (!check_prev && !check_next) {
+ /* No predecessor or successor was found at all? */
+ return (false);
}
dns_name_clone(qname, &rname);
if ((check_prev && dns_name_issubdomain(prev, &rname)) ||
(check_next && dns_name_issubdomain(next, &rname)))
{
- answer = true;
- break;
+ return (true);
}
+
/*
- * Remove the left hand label.
+ * Remove the leftmost label from the qname and check again.
*/
n = dns_name_countlabels(&rname);
dns_name_getlabelsequence(&rname, 1, n - 1, &rname);
} while (!dns_name_equal(&rname, &tname));
- return (answer);
+
+ return (false);
}
static isc_result_t
if (header != NULL ||
activeempty(search, &wchain, wname))
{
- if (activeemptynode(search, qname,
- wname))
+ if (wildcard_blocked(search, qname,
+ wname))
{
return (ISC_R_NOTFOUND);
}