2 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: rbtdb.c,v 1.196.18.53 2008/01/31 23:46:05 tbox Exp $ */
23 * Principal Author: Bob Halley
28 #include <isc/event.h>
30 #include <isc/print.h>
31 #include <isc/mutex.h>
32 #include <isc/random.h>
33 #include <isc/refcount.h>
34 #include <isc/rwlock.h>
35 #include <isc/string.h>
40 #include <dns/acache.h>
42 #include <dns/dbiterator.h>
43 #include <dns/events.h>
44 #include <dns/fixedname.h>
47 #include <dns/masterdump.h>
49 #include <dns/rdata.h>
50 #include <dns/rdataset.h>
51 #include <dns/rdatasetiter.h>
52 #include <dns/rdataslab.h>
53 #include <dns/result.h>
56 #include <dns/zonekey.h>
58 #ifdef DNS_RBTDB_VERSION64
64 #ifdef DNS_RBTDB_VERSION64
65 #define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '8')
67 #define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '4')
71 * Note that "impmagic" is not the first four bytes of the struct, so
72 * ISC_MAGIC_VALID cannot be used.
74 #define VALID_RBTDB(rbtdb) ((rbtdb) != NULL && \
75 (rbtdb)->common.impmagic == RBTDB_MAGIC)
77 #ifdef DNS_RBTDB_VERSION64
78 typedef isc_uint64_t rbtdb_serial_t;
80 * Make casting easier in symbolic debuggers by using different names
81 * for the 64 bit version.
83 #define dns_rbtdb_t dns_rbtdb64_t
84 #define rdatasetheader_t rdatasetheader64_t
85 #define rbtdb_version_t rbtdb_version64_t
87 typedef isc_uint32_t rbtdb_serial_t;
90 typedef isc_uint32_t rbtdb_rdatatype_t;
92 #define RBTDB_RDATATYPE_BASE(type) ((dns_rdatatype_t)((type) & 0xFFFF))
93 #define RBTDB_RDATATYPE_EXT(type) ((dns_rdatatype_t)((type) >> 16))
94 #define RBTDB_RDATATYPE_VALUE(b, e) (((e) << 16) | (b))
96 #define RBTDB_RDATATYPE_SIGNSEC \
97 RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec)
98 #define RBTDB_RDATATYPE_SIGNS \
99 RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ns)
100 #define RBTDB_RDATATYPE_SIGCNAME \
101 RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname)
102 #define RBTDB_RDATATYPE_SIGDNAME \
103 RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname)
104 #define RBTDB_RDATATYPE_NCACHEANY \
105 RBTDB_RDATATYPE_VALUE(0, dns_rdatatype_any)
108 * We use rwlock for DB lock only when ISC_RWLOCK_USEATOMIC is non 0.
109 * Using rwlock is effective with regard to lookup performance only when
110 * it is implemented in an efficient way.
111 * Otherwise, it is generally wise to stick to the simple locking since rwlock
112 * would require more memory or can even make lookups slower due to its own
113 * overhead (when it internally calls mutex locks).
115 #ifdef ISC_RWLOCK_USEATOMIC
116 #define DNS_RBTDB_USERWLOCK 1
118 #define DNS_RBTDB_USERWLOCK 0
121 #if DNS_RBTDB_USERWLOCK
122 #define RBTDB_INITLOCK(l) isc_rwlock_init((l), 0, 0)
123 #define RBTDB_DESTROYLOCK(l) isc_rwlock_destroy(l)
124 #define RBTDB_LOCK(l, t) RWLOCK((l), (t))
125 #define RBTDB_UNLOCK(l, t) RWUNLOCK((l), (t))
127 #define RBTDB_INITLOCK(l) isc_mutex_init(l)
128 #define RBTDB_DESTROYLOCK(l) DESTROYLOCK(l)
129 #define RBTDB_LOCK(l, t) LOCK(l)
130 #define RBTDB_UNLOCK(l, t) UNLOCK(l)
134 * Since node locking is sensitive to both performance and memory footprint,
135 * we need some trick here. If we have both high-performance rwlock and
136 * high performance and small-memory reference counters, we use rwlock for
137 * node lock and isc_refcount for node references. In this case, we don't have
138 * to protect the access to the counters by locks.
139 * Otherwise, we simply use ordinary mutex lock for node locking, and use
140 * simple integers as reference counters which is protected by the lock.
141 * In most cases, we can simply use wrapper macros such as NODE_LOCK and
142 * NODE_UNLOCK. In some other cases, however, we need to protect reference
143 * counters first and then protect other parts of a node as read-only data.
144 * Special additional macros, NODE_STRONGLOCK(), NODE_WEAKLOCK(), etc, are also
145 * provided for these special cases. When we can use the efficient backend
146 * routines, we should only protect the "other members" by NODE_WEAKLOCK(read).
147 * Otherwise, we should use NODE_STRONGLOCK() to protect the entire critical
148 * section including the access to the reference counter.
149 * Note that we cannot use NODE_LOCK()/NODE_UNLOCK() wherever the protected
150 * section is also protected by NODE_STRONGLOCK().
152 #if defined(ISC_RWLOCK_USEATOMIC) && defined(DNS_RBT_USEISCREFCOUNT)
153 typedef isc_rwlock_t nodelock_t;
155 #define NODE_INITLOCK(l) isc_rwlock_init((l), 0, 0)
156 #define NODE_DESTROYLOCK(l) isc_rwlock_destroy(l)
157 #define NODE_LOCK(l, t) RWLOCK((l), (t))
158 #define NODE_UNLOCK(l, t) RWUNLOCK((l), (t))
159 #define NODE_TRYUPGRADE(l) isc_rwlock_tryupgrade(l)
161 #define NODE_STRONGLOCK(l) ((void)0)
162 #define NODE_STRONGUNLOCK(l) ((void)0)
163 #define NODE_WEAKLOCK(l, t) NODE_LOCK(l, t)
164 #define NODE_WEAKUNLOCK(l, t) NODE_UNLOCK(l, t)
165 #define NODE_WEAKDOWNGRADE(l) isc_rwlock_downgrade(l)
167 typedef isc_mutex_t nodelock_t;
169 #define NODE_INITLOCK(l) isc_mutex_init(l)
170 #define NODE_DESTROYLOCK(l) DESTROYLOCK(l)
171 #define NODE_LOCK(l, t) LOCK(l)
172 #define NODE_UNLOCK(l, t) UNLOCK(l)
173 #define NODE_TRYUPGRADE(l) ISC_R_SUCCESS
175 #define NODE_STRONGLOCK(l) LOCK(l)
176 #define NODE_STRONGUNLOCK(l) UNLOCK(l)
177 #define NODE_WEAKLOCK(l, t) ((void)0)
178 #define NODE_WEAKUNLOCK(l, t) ((void)0)
179 #define NODE_WEAKDOWNGRADE(l) ((void)0)
182 #ifndef DNS_RDATASET_FIXED
183 #define DNS_RDATASET_FIXED 1
187 * Allow clients with a virtual time of upto 5 minutes in the past to see
188 * records that would have otherwise have expired.
190 #define RBTDB_VIRTUAL 300
198 typedef struct acachectl acachectl_t;
200 typedef struct rdatasetheader {
202 * Locked by the owning node's lock.
204 rbtdb_serial_t serial;
206 rbtdb_rdatatype_t type;
207 isc_uint16_t attributes;
209 struct noqname *noqname;
211 * We don't use the LIST macros, because the LIST structure has
212 * both head and tail pointers, and is doubly linked.
215 struct rdatasetheader *next;
217 * If this is the top header for an rdataset, 'next' points
218 * to the top header for the next rdataset (i.e., the next type).
219 * Otherwise, it points up to the header whose down pointer points
223 struct rdatasetheader *down;
225 * Points to the header for the next older version of
231 * Monotonously increased every time this rdataset is bound so that
232 * it is used as the base of the starting point in DNS responses
233 * when the "cyclic" rrset-order is required. Since the ordering
234 * should not be so crucial, no lock is set for the counter for
235 * performance reasons.
238 acachectl_t *additional_auth;
239 acachectl_t *additional_glue;
242 #define RDATASET_ATTR_NONEXISTENT 0x0001
243 #define RDATASET_ATTR_STALE 0x0002
244 #define RDATASET_ATTR_IGNORE 0x0004
245 #define RDATASET_ATTR_RETAIN 0x0008
246 #define RDATASET_ATTR_NXDOMAIN 0x0010
248 typedef struct acache_cbarg {
249 dns_rdatasetadditional_t type;
253 rdatasetheader_t *header;
257 dns_acacheentry_t *entry;
258 acache_cbarg_t *cbarg;
263 * When the cache will pre-expire data (due to memory low or other
264 * situations) before the rdataset's TTL has expired, it MUST
265 * respect the RETAIN bit and not expire the data until its TTL is
269 #undef IGNORE /* WIN32 winbase.h defines this. */
271 #define EXISTS(header) \
272 (((header)->attributes & RDATASET_ATTR_NONEXISTENT) == 0)
273 #define NONEXISTENT(header) \
274 (((header)->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
275 #define IGNORE(header) \
276 (((header)->attributes & RDATASET_ATTR_IGNORE) != 0)
277 #define RETAIN(header) \
278 (((header)->attributes & RDATASET_ATTR_RETAIN) != 0)
279 #define NXDOMAIN(header) \
280 (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
282 #define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */
283 #define DEFAULT_CACHE_NODE_LOCK_COUNT 1009 /*%< Should be prime. */
287 /* Protected in the refcount routines. */
288 isc_refcount_t references;
289 /* Locked by lock. */
290 isc_boolean_t exiting;
293 typedef struct rbtdb_changed {
294 dns_rbtnode_t * node;
296 ISC_LINK(struct rbtdb_changed) link;
299 typedef ISC_LIST(rbtdb_changed_t) rbtdb_changedlist_t;
301 typedef struct rbtdb_version {
303 rbtdb_serial_t serial;
305 * Protected in the refcount routines.
306 * XXXJT: should we change the lock policy based on the refcount
309 isc_refcount_t references;
310 /* Locked by database lock. */
311 isc_boolean_t writer;
312 isc_boolean_t commit_ok;
313 rbtdb_changedlist_t changed_list;
314 ISC_LINK(struct rbtdb_version) link;
317 typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
322 #if DNS_RBTDB_USERWLOCK
327 isc_rwlock_t tree_lock;
328 unsigned int node_lock_count;
329 rbtdb_nodelock_t * node_locks;
330 dns_rbtnode_t * origin_node;
331 /* Locked by lock. */
333 isc_refcount_t references;
334 unsigned int attributes;
335 rbtdb_serial_t current_serial;
336 rbtdb_serial_t least_serial;
337 rbtdb_serial_t next_serial;
338 rbtdb_version_t * current_version;
339 rbtdb_version_t * future_version;
340 rbtdb_versionlist_t open_versions;
341 isc_boolean_t overmem;
343 dns_dbnode_t *soanode;
344 dns_dbnode_t *nsnode;
345 /* Locked by tree_lock. */
347 isc_boolean_t secure;
350 unsigned int quantum;
353 #define RBTDB_ATTR_LOADED 0x01
354 #define RBTDB_ATTR_LOADING 0x02
361 rbtdb_version_t * rbtversion;
362 rbtdb_serial_t serial;
363 unsigned int options;
364 dns_rbtnodechain_t chain;
365 isc_boolean_t copy_name;
366 isc_boolean_t need_cleanup;
368 dns_rbtnode_t * zonecut;
369 rdatasetheader_t * zonecut_rdataset;
370 rdatasetheader_t * zonecut_sigrdataset;
371 dns_fixedname_t zonecut_name;
383 static void rdataset_disassociate(dns_rdataset_t *rdataset);
384 static isc_result_t rdataset_first(dns_rdataset_t *rdataset);
385 static isc_result_t rdataset_next(dns_rdataset_t *rdataset);
386 static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
387 static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
388 static unsigned int rdataset_count(dns_rdataset_t *rdataset);
389 static isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset,
391 dns_rdataset_t *nsec,
392 dns_rdataset_t *nsecsig);
393 static isc_result_t rdataset_getadditional(dns_rdataset_t *rdataset,
394 dns_rdatasetadditional_t type,
395 dns_rdatatype_t qtype,
396 dns_acache_t *acache,
399 dns_dbversion_t **versionp,
400 dns_dbnode_t **nodep,
404 static isc_result_t rdataset_setadditional(dns_rdataset_t *rdataset,
405 dns_rdatasetadditional_t type,
406 dns_rdatatype_t qtype,
407 dns_acache_t *acache,
410 dns_dbversion_t *version,
413 static isc_result_t rdataset_putadditional(dns_acache_t *acache,
414 dns_rdataset_t *rdataset,
415 dns_rdatasetadditional_t type,
416 dns_rdatatype_t qtype);
418 static dns_rdatasetmethods_t rdataset_methods = {
419 rdataset_disassociate,
427 rdataset_getadditional,
428 rdataset_setadditional,
429 rdataset_putadditional
432 static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
433 static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);
434 static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);
435 static void rdatasetiter_current(dns_rdatasetiter_t *iterator,
436 dns_rdataset_t *rdataset);
438 static dns_rdatasetitermethods_t rdatasetiter_methods = {
439 rdatasetiter_destroy,
445 typedef struct rbtdb_rdatasetiter {
446 dns_rdatasetiter_t common;
447 rdatasetheader_t * current;
448 } rbtdb_rdatasetiter_t;
450 static void dbiterator_destroy(dns_dbiterator_t **iteratorp);
451 static isc_result_t dbiterator_first(dns_dbiterator_t *iterator);
452 static isc_result_t dbiterator_last(dns_dbiterator_t *iterator);
453 static isc_result_t dbiterator_seek(dns_dbiterator_t *iterator,
455 static isc_result_t dbiterator_prev(dns_dbiterator_t *iterator);
456 static isc_result_t dbiterator_next(dns_dbiterator_t *iterator);
457 static isc_result_t dbiterator_current(dns_dbiterator_t *iterator,
458 dns_dbnode_t **nodep,
460 static isc_result_t dbiterator_pause(dns_dbiterator_t *iterator);
461 static isc_result_t dbiterator_origin(dns_dbiterator_t *iterator,
464 static dns_dbiteratormethods_t dbiterator_methods = {
476 #define DELETION_BATCH_MAX 64
479 * If 'paused' is ISC_TRUE, then the tree lock is not being held.
481 typedef struct rbtdb_dbiterator {
482 dns_dbiterator_t common;
483 isc_boolean_t paused;
484 isc_boolean_t new_origin;
485 isc_rwlocktype_t tree_locked;
487 dns_fixedname_t name;
488 dns_fixedname_t origin;
489 dns_rbtnodechain_t chain;
491 dns_rbtnode_t *deletions[DELETION_BATCH_MAX];
493 } rbtdb_dbiterator_t;
496 #define IS_STUB(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_STUB) != 0)
497 #define IS_CACHE(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_CACHE) != 0)
499 static void free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log,
503 * 'init_count' is used to initialize 'newheader->count' which inturn
504 * is used to determine where in the cycle rrset-order cyclic starts.
505 * We don't lock this as we don't care about simultanious updates.
508 * Both init_count and header->count can be ISC_UINT32_MAX.
509 * The count on the returned rdataset however can't be as
510 * that indicates that the database does not implement cyclic
513 static unsigned int init_count;
518 * If a routine is going to lock more than one lock in this module, then
519 * the locking must be done in the following order:
523 * Node Lock (Only one from the set may be locked at one time by
528 * Failure to follow this hierarchy can result in deadlock.
534 * Currently there is no deletion of nodes from the database, except when
535 * the database is being destroyed.
537 * If node deletion is added in the future, then for zone databases the node
538 * for the origin of the zone MUST NOT be deleted.
547 attach(dns_db_t *source, dns_db_t **targetp) {
548 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)source;
550 REQUIRE(VALID_RBTDB(rbtdb));
552 isc_refcount_increment(&rbtdb->references, NULL);
558 free_rbtdb_callback(isc_task_t *task, isc_event_t *event) {
559 dns_rbtdb_t *rbtdb = event->ev_arg;
563 free_rbtdb(rbtdb, ISC_TRUE, event);
567 * Work out how many nodes can be deleted in the time between two
568 * requests to the nameserver. Smooth the resulting number and use it
569 * as a estimate for the number of nodes to be deleted in the next
573 adjust_quantum(unsigned int old, isc_time_t *start) {
574 unsigned int pps = dns_pps; /* packets per second */
575 unsigned int interval;
584 interval = 1000000 / pps; /* interval in usec */
587 usecs = isc_time_microdiff(&end, start);
590 * We were unable to measure the amount of time taken.
591 * Double the nodes deleted next time.
598 new = old * interval;
599 new /= (unsigned int)usecs;
606 new = (new + old * 3) / 4;
608 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
609 ISC_LOG_DEBUG(1), "adjust_quantum -> %d", new);
615 free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
617 isc_ondestroy_t ondest;
619 char buf[DNS_NAME_FORMATSIZE];
622 REQUIRE(rbtdb->current_version != NULL || EMPTY(rbtdb->open_versions));
623 REQUIRE(rbtdb->future_version == NULL);
625 if (rbtdb->current_version != NULL) {
628 isc_refcount_decrement(&rbtdb->current_version->references,
631 UNLINK(rbtdb->open_versions, rbtdb->current_version, link);
632 isc_refcount_destroy(&rbtdb->current_version->references);
633 isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
634 sizeof(rbtdb_version_t));
637 rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0;
639 if (rbtdb->tree != NULL) {
640 isc_time_now(&start);
641 result = dns_rbt_destroy2(&rbtdb->tree, rbtdb->quantum);
642 if (result == ISC_R_QUOTA) {
643 INSIST(rbtdb->task != NULL);
644 if (rbtdb->quantum != 0)
645 rbtdb->quantum = adjust_quantum(rbtdb->quantum,
648 event = isc_event_allocate(rbtdb->common.mctx,
650 DNS_EVENT_FREESTORAGE,
653 sizeof(isc_event_t));
656 isc_task_send(rbtdb->task, &event);
659 INSIST(result == ISC_R_SUCCESS && rbtdb->tree == NULL);
662 isc_event_free(&event);
664 if (dns_name_dynamic(&rbtdb->common.origin))
665 dns_name_format(&rbtdb->common.origin, buf,
668 strcpy(buf, "<UNKNOWN>");
669 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
670 DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
671 "done free_rbtdb(%s)", buf);
673 if (dns_name_dynamic(&rbtdb->common.origin))
674 dns_name_free(&rbtdb->common.origin, rbtdb->common.mctx);
675 for (i = 0; i < rbtdb->node_lock_count; i++) {
676 isc_refcount_destroy(&rbtdb->node_locks[i].references);
677 NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
679 isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks,
680 rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));
681 isc_rwlock_destroy(&rbtdb->tree_lock);
682 isc_refcount_destroy(&rbtdb->references);
683 if (rbtdb->task != NULL)
684 isc_task_detach(&rbtdb->task);
685 RBTDB_DESTROYLOCK(&rbtdb->lock);
686 rbtdb->common.magic = 0;
687 rbtdb->common.impmagic = 0;
688 ondest = rbtdb->common.ondest;
689 isc_mem_putanddetach(&rbtdb->common.mctx, rbtdb, sizeof(*rbtdb));
690 isc_ondestroy_notify(&ondest, rbtdb);
694 maybe_free_rbtdb(dns_rbtdb_t *rbtdb) {
695 isc_boolean_t want_free = ISC_FALSE;
697 unsigned int inactive = 0;
699 /* XXX check for open versions here */
701 if (rbtdb->soanode != NULL)
702 dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->soanode);
703 if (rbtdb->nsnode != NULL)
704 dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->nsnode);
707 * Even though there are no external direct references, there still
708 * may be nodes in use.
710 for (i = 0; i < rbtdb->node_lock_count; i++) {
711 NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
712 rbtdb->node_locks[i].exiting = ISC_TRUE;
713 NODE_UNLOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
714 if (isc_refcount_current(&rbtdb->node_locks[i].references)
721 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
722 rbtdb->active -= inactive;
723 if (rbtdb->active == 0)
724 want_free = ISC_TRUE;
725 RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
727 char buf[DNS_NAME_FORMATSIZE];
728 if (dns_name_dynamic(&rbtdb->common.origin))
729 dns_name_format(&rbtdb->common.origin, buf,
732 strcpy(buf, "<UNKNOWN>");
733 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
734 DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
735 "calling free_rbtdb(%s)", buf);
736 free_rbtdb(rbtdb, ISC_TRUE, NULL);
742 detach(dns_db_t **dbp) {
743 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(*dbp);
746 REQUIRE(VALID_RBTDB(rbtdb));
748 isc_refcount_decrement(&rbtdb->references, &refs);
751 maybe_free_rbtdb(rbtdb);
757 currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
758 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
759 rbtdb_version_t *version;
762 REQUIRE(VALID_RBTDB(rbtdb));
764 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
765 version = rbtdb->current_version;
766 isc_refcount_increment(&version->references, &refs);
767 RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
769 *versionp = (dns_dbversion_t *)version;
772 static inline rbtdb_version_t *
773 allocate_version(isc_mem_t *mctx, rbtdb_serial_t serial,
774 unsigned int references, isc_boolean_t writer)
777 rbtdb_version_t *version;
779 version = isc_mem_get(mctx, sizeof(*version));
782 version->serial = serial;
783 result = isc_refcount_init(&version->references, references);
784 if (result != ISC_R_SUCCESS) {
785 isc_mem_put(mctx, version, sizeof(*version));
788 version->writer = writer;
789 version->commit_ok = ISC_FALSE;
790 ISC_LIST_INIT(version->changed_list);
791 ISC_LINK_INIT(version, link);
797 newversion(dns_db_t *db, dns_dbversion_t **versionp) {
798 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
799 rbtdb_version_t *version;
801 REQUIRE(VALID_RBTDB(rbtdb));
802 REQUIRE(versionp != NULL && *versionp == NULL);
803 REQUIRE(rbtdb->future_version == NULL);
805 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
806 RUNTIME_CHECK(rbtdb->next_serial != 0); /* XXX Error? */
807 version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1,
809 if (version != NULL) {
810 version->commit_ok = ISC_TRUE;
811 rbtdb->next_serial++;
812 rbtdb->future_version = version;
814 RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
817 return (ISC_R_NOMEMORY);
821 return (ISC_R_SUCCESS);
825 attachversion(dns_db_t *db, dns_dbversion_t *source,
826 dns_dbversion_t **targetp)
828 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
829 rbtdb_version_t *rbtversion = source;
832 REQUIRE(VALID_RBTDB(rbtdb));
834 isc_refcount_increment(&rbtversion->references, &refs);
837 *targetp = rbtversion;
840 static rbtdb_changed_t *
841 add_changed(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
844 rbtdb_changed_t *changed;
848 * Caller must be holding the node lock if its reference must be
849 * protected by the lock.
852 changed = isc_mem_get(rbtdb->common.mctx, sizeof(*changed));
854 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
856 REQUIRE(version->writer);
858 if (changed != NULL) {
859 dns_rbtnode_refincrement(node, &refs);
861 changed->node = node;
862 changed->dirty = ISC_FALSE;
863 ISC_LIST_INITANDAPPEND(version->changed_list, changed, link);
865 version->commit_ok = ISC_FALSE;
867 RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
873 free_acachearray(isc_mem_t *mctx, rdatasetheader_t *header,
878 unsigned char *raw; /* RDATASLAB */
881 * The caller must be holding the corresponding node lock.
887 raw = (unsigned char *)header + sizeof(*header);
888 count = raw[0] * 256 + raw[1];
891 * Sanity check: since an additional cache entry has a reference to
892 * the original DB node (in the callback arg), there should be no
893 * acache entries when the node can be freed.
895 for (i = 0; i < count; i++)
896 INSIST(array[i].entry == NULL && array[i].cbarg == NULL);
898 isc_mem_put(mctx, array, count * sizeof(acachectl_t));
902 free_noqname(isc_mem_t *mctx, struct noqname **noqname) {
904 if (dns_name_dynamic(&(*noqname)->name))
905 dns_name_free(&(*noqname)->name, mctx);
906 if ((*noqname)->nsec != NULL)
907 isc_mem_put(mctx, (*noqname)->nsec,
908 dns_rdataslab_size((*noqname)->nsec, 0));
909 if ((*noqname)->nsecsig != NULL)
910 isc_mem_put(mctx, (*noqname)->nsecsig,
911 dns_rdataslab_size((*noqname)->nsecsig, 0));
912 isc_mem_put(mctx, *noqname, sizeof(**noqname));
917 free_rdataset(isc_mem_t *mctx, rdatasetheader_t *rdataset) {
920 if (rdataset->noqname != NULL)
921 free_noqname(mctx, &rdataset->noqname);
923 free_acachearray(mctx, rdataset, rdataset->additional_auth);
924 free_acachearray(mctx, rdataset, rdataset->additional_glue);
926 if ((rdataset->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
927 size = sizeof(*rdataset);
929 size = dns_rdataslab_size((unsigned char *)rdataset,
931 isc_mem_put(mctx, rdataset, size);
935 rollback_node(dns_rbtnode_t *node, rbtdb_serial_t serial) {
936 rdatasetheader_t *header, *dcurrent;
937 isc_boolean_t make_dirty = ISC_FALSE;
940 * Caller must hold the node lock.
944 * We set the IGNORE attribute on rdatasets with serial number
945 * 'serial'. When the reference count goes to zero, these rdatasets
946 * will be cleaned up; until that time, they will be ignored.
948 for (header = node->data; header != NULL; header = header->next) {
949 if (header->serial == serial) {
950 header->attributes |= RDATASET_ATTR_IGNORE;
951 make_dirty = ISC_TRUE;
953 for (dcurrent = header->down;
955 dcurrent = dcurrent->down) {
956 if (dcurrent->serial == serial) {
957 dcurrent->attributes |= RDATASET_ATTR_IGNORE;
958 make_dirty = ISC_TRUE;
967 clean_stale_headers(isc_mem_t *mctx, rdatasetheader_t *top) {
968 rdatasetheader_t *d, *down_next;
970 for (d = top->down; d != NULL; d = down_next) {
972 free_rdataset(mctx, d);
978 clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
979 rdatasetheader_t *current, *top_prev, *top_next;
980 isc_mem_t *mctx = rbtdb->common.mctx;
983 * Caller must be holding the node lock.
987 for (current = node->data; current != NULL; current = top_next) {
988 top_next = current->next;
989 clean_stale_headers(mctx, current);
991 * If current is nonexistent or stale, we can clean it up.
993 if ((current->attributes &
994 (RDATASET_ATTR_NONEXISTENT|RDATASET_ATTR_STALE)) != 0) {
995 if (top_prev != NULL)
996 top_prev->next = current->next;
998 node->data = current->next;
999 free_rdataset(mctx, current);
1007 clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
1008 rbtdb_serial_t least_serial)
1010 rdatasetheader_t *current, *dcurrent, *down_next, *dparent;
1011 rdatasetheader_t *top_prev, *top_next;
1012 isc_mem_t *mctx = rbtdb->common.mctx;
1013 isc_boolean_t still_dirty = ISC_FALSE;
1016 * Caller must be holding the node lock.
1018 REQUIRE(least_serial != 0);
1021 for (current = node->data; current != NULL; current = top_next) {
1022 top_next = current->next;
1025 * First, we clean up any instances of multiple rdatasets
1026 * with the same serial number, or that have the IGNORE
1030 for (dcurrent = current->down;
1032 dcurrent = down_next) {
1033 down_next = dcurrent->down;
1034 INSIST(dcurrent->serial <= dparent->serial);
1035 if (dcurrent->serial == dparent->serial ||
1037 if (down_next != NULL)
1038 down_next->next = dparent;
1039 dparent->down = down_next;
1040 free_rdataset(mctx, dcurrent);
1046 * We've now eliminated all IGNORE datasets with the possible
1047 * exception of current, which we now check.
1049 if (IGNORE(current)) {
1050 down_next = current->down;
1051 if (down_next == NULL) {
1052 if (top_prev != NULL)
1053 top_prev->next = current->next;
1055 node->data = current->next;
1056 free_rdataset(mctx, current);
1058 * current no longer exists, so we can
1059 * just continue with the loop.
1064 * Pull up current->down, making it the new
1067 if (top_prev != NULL)
1068 top_prev->next = down_next;
1070 node->data = down_next;
1071 down_next->next = top_next;
1072 free_rdataset(mctx, current);
1073 current = down_next;
1078 * We now try to find the first down node less than the
1082 for (dcurrent = current->down;
1084 dcurrent = down_next) {
1085 down_next = dcurrent->down;
1086 if (dcurrent->serial < least_serial)
1092 * If there is a such an rdataset, delete it and any older
1095 if (dcurrent != NULL) {
1097 down_next = dcurrent->down;
1098 INSIST(dcurrent->serial <= least_serial);
1099 free_rdataset(mctx, dcurrent);
1100 dcurrent = down_next;
1101 } while (dcurrent != NULL);
1102 dparent->down = NULL;
1106 * Note. The serial number of 'current' might be less than
1107 * least_serial too, but we cannot delete it because it is
1108 * the most recent version, unless it is a NONEXISTENT
1111 if (current->down != NULL) {
1112 still_dirty = ISC_TRUE;
1116 * If this is a NONEXISTENT rdataset, we can delete it.
1118 if (NONEXISTENT(current)) {
1119 if (top_prev != NULL)
1120 top_prev->next = current->next;
1122 node->data = current->next;
1123 free_rdataset(mctx, current);
1133 * Caller must be holding the node lock if its reference must be protected
1137 new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
1138 unsigned int lockrefs, noderefs;
1139 isc_refcount_t *lockref;
1141 dns_rbtnode_refincrement0(node, &noderefs);
1142 if (noderefs == 1) { /* this is the first reference to the node */
1143 lockref = &rbtdb->node_locks[node->locknum].references;
1144 isc_refcount_increment0(lockref, &lockrefs);
1145 INSIST(lockrefs != 0);
1147 INSIST(noderefs != 0);
1151 * Caller must be holding the node lock; either the "strong", read or write
1152 * lock. Note that the lock must be held even when node references are
1153 * atomically modified; in that case the decrement operation itself does not
1154 * have to be protected, but we must avoid a race condition where multiple
1155 * threads are decreasing the reference to zero simultaneously and at least
1156 * one of them is going to free the node.
1157 * This function returns ISC_TRUE if and only if the node reference decreases
1160 static isc_boolean_t
1161 decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
1162 rbtdb_serial_t least_serial,
1163 isc_rwlocktype_t nlock, isc_rwlocktype_t tlock)
1165 isc_result_t result;
1166 isc_boolean_t write_locked;
1167 rbtdb_nodelock_t *nodelock;
1168 unsigned int refs, nrefs;
1170 nodelock = &rbtdb->node_locks[node->locknum];
1172 /* Handle easy and typical case first. */
1173 if (!node->dirty && (node->data != NULL || node->down != NULL)) {
1174 dns_rbtnode_refdecrement(node, &nrefs);
1175 INSIST((int)nrefs >= 0);
1177 isc_refcount_decrement(&nodelock->references, &refs);
1178 INSIST((int)refs >= 0);
1180 return ((nrefs == 0) ? ISC_TRUE : ISC_FALSE);
1183 /* Upgrade the lock? */
1184 if (nlock == isc_rwlocktype_read) {
1185 NODE_WEAKUNLOCK(&nodelock->lock, isc_rwlocktype_read);
1186 NODE_WEAKLOCK(&nodelock->lock, isc_rwlocktype_write);
1188 dns_rbtnode_refdecrement(node, &nrefs);
1189 INSIST((int)nrefs >= 0);
1191 /* Restore the lock? */
1192 if (nlock == isc_rwlocktype_read)
1193 NODE_WEAKDOWNGRADE(&nodelock->lock);
1197 if (node->dirty && dns_rbtnode_refcurrent(node) == 0) {
1198 if (IS_CACHE(rbtdb))
1199 clean_cache_node(rbtdb, node);
1201 if (least_serial == 0) {
1203 * Caller doesn't know the least serial.
1206 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
1207 least_serial = rbtdb->least_serial;
1208 RBTDB_UNLOCK(&rbtdb->lock,
1209 isc_rwlocktype_read);
1211 clean_zone_node(rbtdb, node, least_serial);
1215 isc_refcount_decrement(&nodelock->references, &refs);
1216 INSIST((int)refs >= 0);
1219 * XXXDCL should this only be done for cache zones?
1221 if (node->data != NULL || node->down != NULL) {
1222 /* Restore the lock? */
1223 if (nlock == isc_rwlocktype_read)
1224 NODE_WEAKDOWNGRADE(&nodelock->lock);
1229 * XXXDCL need to add a deferred delete method for ISC_R_LOCKBUSY.
1231 if (tlock != isc_rwlocktype_write) {
1233 * Locking hierarchy notwithstanding, we don't need to free
1234 * the node lock before acquiring the tree write lock because
1235 * we only do a trylock.
1237 if (tlock == isc_rwlocktype_read)
1238 result = isc_rwlock_tryupgrade(&rbtdb->tree_lock);
1240 result = isc_rwlock_trylock(&rbtdb->tree_lock,
1241 isc_rwlocktype_write);
1242 RUNTIME_CHECK(result == ISC_R_SUCCESS ||
1243 result == ISC_R_LOCKBUSY);
1245 write_locked = ISC_TF(result == ISC_R_SUCCESS);
1247 write_locked = ISC_TRUE;
1249 if (write_locked && dns_rbtnode_refcurrent(node) == 0) {
1251 * We can now delete the node if the reference counter is
1252 * zero. This should be typically the case, but a different
1253 * thread may still gain a (new) reference just before the
1254 * current thread locks the tree (e.g., in findnode()).
1257 if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
1258 char printname[DNS_NAME_FORMATSIZE];
1260 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1261 DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
1262 "decrement_reference: "
1263 "delete from rbt: %p %s",
1265 dns_rbt_formatnodename(node, printname,
1266 sizeof(printname)));
1269 result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE);
1270 if (result != ISC_R_SUCCESS)
1271 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1272 DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
1273 "decrement_reference: "
1274 "dns_rbt_deletenode: %s",
1275 isc_result_totext(result));
1278 /* Restore the lock? */
1279 if (nlock == isc_rwlocktype_read)
1280 NODE_WEAKDOWNGRADE(&nodelock->lock);
1283 * Relock a read lock, or unlock the write lock if no lock was held.
1285 if (tlock == isc_rwlocktype_none)
1287 RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
1289 if (tlock == isc_rwlocktype_read)
1291 isc_rwlock_downgrade(&rbtdb->tree_lock);
1297 make_least_version(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
1298 rbtdb_changedlist_t *cleanup_list)
1301 * Caller must be holding the database lock.
1304 rbtdb->least_serial = version->serial;
1305 *cleanup_list = version->changed_list;
1306 ISC_LIST_INIT(version->changed_list);
1310 cleanup_nondirty(rbtdb_version_t *version, rbtdb_changedlist_t *cleanup_list) {
1311 rbtdb_changed_t *changed, *next_changed;
1314 * If the changed record is dirty, then
1315 * an update created multiple versions of
1316 * a given rdataset. We keep this list
1317 * until we're the least open version, at
1318 * which point it's safe to get rid of any
1321 * If the changed record isn't dirty, then
1322 * we don't need it anymore since we're
1323 * committing and not rolling back.
1325 * The caller must be holding the database lock.
1327 for (changed = HEAD(version->changed_list);
1329 changed = next_changed) {
1330 next_changed = NEXT(changed, link);
1331 if (!changed->dirty) {
1332 UNLINK(version->changed_list,
1334 APPEND(*cleanup_list,
1340 static isc_boolean_t
1341 iszonesecure(dns_db_t *db, dns_dbnode_t *origin) {
1342 dns_rdataset_t keyset;
1343 dns_rdataset_t nsecset, signsecset;
1344 isc_boolean_t haszonekey = ISC_FALSE;
1345 isc_boolean_t hasnsec = ISC_FALSE;
1346 isc_result_t result;
1348 dns_rdataset_init(&keyset);
1349 result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_dnskey, 0,
1351 if (result == ISC_R_SUCCESS) {
1352 dns_rdata_t keyrdata = DNS_RDATA_INIT;
1353 result = dns_rdataset_first(&keyset);
1354 while (result == ISC_R_SUCCESS) {
1355 dns_rdataset_current(&keyset, &keyrdata);
1356 if (dns_zonekey_iszonekey(&keyrdata)) {
1357 haszonekey = ISC_TRUE;
1360 result = dns_rdataset_next(&keyset);
1362 dns_rdataset_disassociate(&keyset);
1367 dns_rdataset_init(&nsecset);
1368 dns_rdataset_init(&signsecset);
1369 result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_nsec, 0,
1370 0, &nsecset, &signsecset);
1371 if (result == ISC_R_SUCCESS) {
1372 if (dns_rdataset_isassociated(&signsecset)) {
1374 dns_rdataset_disassociate(&signsecset);
1376 dns_rdataset_disassociate(&nsecset);
1382 closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
1383 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
1384 rbtdb_version_t *version, *cleanup_version, *least_greater;
1385 isc_boolean_t rollback = ISC_FALSE;
1386 rbtdb_changedlist_t cleanup_list;
1387 rbtdb_changed_t *changed, *next_changed;
1388 rbtdb_serial_t serial, least_serial;
1389 dns_rbtnode_t *rbtnode;
1391 isc_boolean_t writer;
1393 REQUIRE(VALID_RBTDB(rbtdb));
1394 version = (rbtdb_version_t *)*versionp;
1396 cleanup_version = NULL;
1397 ISC_LIST_INIT(cleanup_list);
1399 isc_refcount_decrement(&version->references, &refs);
1400 if (refs > 0) { /* typical and easy case first */
1402 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
1403 INSIST(!version->writer);
1404 RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
1409 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
1410 serial = version->serial;
1411 writer = version->writer;
1412 if (version->writer) {
1415 rbtdb_version_t *cur_version;
1417 INSIST(version->commit_ok);
1418 INSIST(version == rbtdb->future_version);
1420 * The current version is going to be replaced.
1421 * Release the (likely last) reference to it from the
1422 * DB itself and unlink it from the open list.
1424 cur_version = rbtdb->current_version;
1425 isc_refcount_decrement(&cur_version->references,
1428 if (cur_version->serial == rbtdb->least_serial)
1429 INSIST(EMPTY(cur_version->changed_list));
1430 UNLINK(rbtdb->open_versions,
1433 if (EMPTY(rbtdb->open_versions)) {
1435 * We're going to become the least open
1438 make_least_version(rbtdb, version,
1442 * Some other open version is the
1443 * least version. We can't cleanup
1444 * records that were changed in this
1445 * version because the older versions
1446 * may still be in use by an open
1449 * We can, however, discard the
1450 * changed records for things that
1451 * we've added that didn't exist in
1454 cleanup_nondirty(version, &cleanup_list);
1457 * If the (soon to be former) current version
1458 * isn't being used by anyone, we can clean
1462 cleanup_version = cur_version;
1463 APPENDLIST(version->changed_list,
1464 cleanup_version->changed_list,
1468 * Become the current version.
1470 version->writer = ISC_FALSE;
1471 rbtdb->current_version = version;
1472 rbtdb->current_serial = version->serial;
1473 rbtdb->future_version = NULL;
1476 * Keep the current version in the open list, and
1477 * gain a reference for the DB itself (see the DB
1478 * creation function below). This must be the only
1479 * case where we need to increment the counter from
1480 * zero and need to use isc_refcount_increment0().
1482 isc_refcount_increment0(&version->references,
1484 INSIST(cur_ref == 1);
1485 PREPEND(rbtdb->open_versions,
1486 rbtdb->current_version, link);
1489 * We're rolling back this transaction.
1491 cleanup_list = version->changed_list;
1492 ISC_LIST_INIT(version->changed_list);
1493 rollback = ISC_TRUE;
1494 cleanup_version = version;
1495 rbtdb->future_version = NULL;
1498 if (version != rbtdb->current_version) {
1500 * There are no external or internal references
1501 * to this version and it can be cleaned up.
1503 cleanup_version = version;
1506 * Find the version with the least serial
1507 * number greater than ours.
1509 least_greater = PREV(version, link);
1510 if (least_greater == NULL)
1511 least_greater = rbtdb->current_version;
1513 INSIST(version->serial < least_greater->serial);
1515 * Is this the least open version?
1517 if (version->serial == rbtdb->least_serial) {
1519 * Yes. Install the new least open
1522 make_least_version(rbtdb,
1527 * Add any unexecuted cleanups to
1528 * those of the least greater version.
1530 APPENDLIST(least_greater->changed_list,
1531 version->changed_list,
1534 } else if (version->serial == rbtdb->least_serial)
1535 INSIST(EMPTY(version->changed_list));
1536 UNLINK(rbtdb->open_versions, version, link);
1538 least_serial = rbtdb->least_serial;
1539 RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
1542 * Update the zone's secure status.
1544 if (writer && commit && !IS_CACHE(rbtdb))
1545 rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
1547 if (cleanup_version != NULL) {
1548 INSIST(EMPTY(cleanup_version->changed_list));
1549 isc_mem_put(rbtdb->common.mctx, cleanup_version,
1550 sizeof(*cleanup_version));
1553 if (!EMPTY(cleanup_list)) {
1554 for (changed = HEAD(cleanup_list);
1556 changed = next_changed) {
1559 next_changed = NEXT(changed, link);
1560 rbtnode = changed->node;
1561 lock = &rbtdb->node_locks[rbtnode->locknum].lock;
1563 NODE_LOCK(lock, isc_rwlocktype_write);
1565 rollback_node(rbtnode, serial);
1566 decrement_reference(rbtdb, rbtnode, least_serial,
1567 isc_rwlocktype_write,
1568 isc_rwlocktype_none);
1569 NODE_UNLOCK(lock, isc_rwlocktype_write);
1571 isc_mem_put(rbtdb->common.mctx, changed,
1581 * Add the necessary magic for the wildcard name 'name'
1582 * to be found in 'rbtdb'.
1584 * In order for wildcard matching to work correctly in
1585 * zone_find(), we must ensure that a node for the wildcarding
1586 * level exists in the database, and has its 'find_callback'
1587 * and 'wild' bits set.
1589 * E.g. if the wildcard name is "*.sub.example." then we
1590 * must ensure that "sub.example." exists and is marked as
1594 add_wildcard_magic(dns_rbtdb_t *rbtdb, dns_name_t *name) {
1595 isc_result_t result;
1596 dns_name_t foundname;
1597 dns_offsets_t offsets;
1599 dns_rbtnode_t *node = NULL;
1601 dns_name_init(&foundname, offsets);
1602 n = dns_name_countlabels(name);
1605 dns_name_getlabelsequence(name, 1, n, &foundname);
1606 result = dns_rbt_addnode(rbtdb->tree, &foundname, &node);
1607 if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
1609 node->find_callback = 1;
1611 return (ISC_R_SUCCESS);
1615 add_empty_wildcards(dns_rbtdb_t *rbtdb, dns_name_t *name) {
1616 isc_result_t result;
1617 dns_name_t foundname;
1618 dns_offsets_t offsets;
1619 unsigned int n, l, i;
1621 dns_name_init(&foundname, offsets);
1622 n = dns_name_countlabels(name);
1623 l = dns_name_countlabels(&rbtdb->common.origin);
1626 dns_rbtnode_t *node = NULL; /* dummy */
1627 dns_name_getlabelsequence(name, n - i, i, &foundname);
1628 if (dns_name_iswildcard(&foundname)) {
1629 result = add_wildcard_magic(rbtdb, &foundname);
1630 if (result != ISC_R_SUCCESS)
1632 result = dns_rbt_addnode(rbtdb->tree, &foundname,
1634 if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
1639 return (ISC_R_SUCCESS);
1643 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
1644 dns_dbnode_t **nodep)
1646 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
1647 dns_rbtnode_t *node = NULL;
1648 dns_name_t nodename;
1649 isc_result_t result;
1650 isc_rwlocktype_t locktype = isc_rwlocktype_read;
1652 REQUIRE(VALID_RBTDB(rbtdb));
1654 dns_name_init(&nodename, NULL);
1655 RWLOCK(&rbtdb->tree_lock, locktype);
1656 result = dns_rbt_findnode(rbtdb->tree, name, NULL, &node, NULL,
1657 DNS_RBTFIND_EMPTYDATA, NULL, NULL);
1658 if (result != ISC_R_SUCCESS) {
1659 RWUNLOCK(&rbtdb->tree_lock, locktype);
1661 if (result == DNS_R_PARTIALMATCH)
1662 result = ISC_R_NOTFOUND;
1666 * It would be nice to try to upgrade the lock instead of
1667 * unlocking then relocking.
1669 locktype = isc_rwlocktype_write;
1670 RWLOCK(&rbtdb->tree_lock, locktype);
1672 result = dns_rbt_addnode(rbtdb->tree, name, &node);
1673 if (result == ISC_R_SUCCESS) {
1674 dns_rbt_namefromnode(node, &nodename);
1675 #ifdef DNS_RBT_USEHASH
1676 node->locknum = node->hashval % rbtdb->node_lock_count;
1678 node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
1679 rbtdb->node_lock_count;
1681 add_empty_wildcards(rbtdb, name);
1683 if (dns_name_iswildcard(name)) {
1684 result = add_wildcard_magic(rbtdb, name);
1685 if (result != ISC_R_SUCCESS) {
1686 RWUNLOCK(&rbtdb->tree_lock, locktype);
1690 } else if (result != ISC_R_EXISTS) {
1691 RWUNLOCK(&rbtdb->tree_lock, locktype);
1695 NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
1696 new_reference(rbtdb, node);
1697 NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
1698 RWUNLOCK(&rbtdb->tree_lock, locktype);
1700 *nodep = (dns_dbnode_t *)node;
1702 return (ISC_R_SUCCESS);
1706 zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
1707 rbtdb_search_t *search = arg;
1708 rdatasetheader_t *header, *header_next;
1709 rdatasetheader_t *dname_header, *sigdname_header, *ns_header;
1710 rdatasetheader_t *found;
1711 isc_result_t result;
1712 dns_rbtnode_t *onode;
1715 * We only want to remember the topmost zone cut, since it's the one
1716 * that counts, so we'll just continue if we've already found a
1719 if (search->zonecut != NULL)
1720 return (DNS_R_CONTINUE);
1723 result = DNS_R_CONTINUE;
1724 onode = search->rbtdb->origin_node;
1726 NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
1727 isc_rwlocktype_read);
1730 * Look for an NS or DNAME rdataset active in our version.
1733 dname_header = NULL;
1734 sigdname_header = NULL;
1735 for (header = node->data; header != NULL; header = header_next) {
1736 header_next = header->next;
1737 if (header->type == dns_rdatatype_ns ||
1738 header->type == dns_rdatatype_dname ||
1739 header->type == RBTDB_RDATATYPE_SIGDNAME) {
1741 if (header->serial <= search->serial &&
1744 * Is this a "this rdataset doesn't
1747 if (NONEXISTENT(header))
1751 header = header->down;
1752 } while (header != NULL);
1753 if (header != NULL) {
1754 if (header->type == dns_rdatatype_dname)
1755 dname_header = header;
1756 else if (header->type ==
1757 RBTDB_RDATATYPE_SIGDNAME)
1758 sigdname_header = header;
1759 else if (node != onode ||
1760 IS_STUB(search->rbtdb)) {
1762 * We've found an NS rdataset that
1763 * isn't at the origin node. We check
1764 * that they're not at the origin node,
1765 * because otherwise we'd erroneously
1766 * treat the zone top as if it were
1776 * Did we find anything?
1778 if (dname_header != NULL) {
1780 * Note that DNAME has precedence over NS if both exist.
1782 found = dname_header;
1783 search->zonecut_sigrdataset = sigdname_header;
1784 } else if (ns_header != NULL) {
1786 search->zonecut_sigrdataset = NULL;
1789 if (found != NULL) {
1791 * We increment the reference count on node to ensure that
1792 * search->zonecut_rdataset will still be valid later.
1794 new_reference(search->rbtdb, node);
1795 search->zonecut = node;
1796 search->zonecut_rdataset = found;
1797 search->need_cleanup = ISC_TRUE;
1799 * Since we've found a zonecut, anything beneath it is
1800 * glue and is not subject to wildcard matching, so we
1801 * may clear search->wild.
1803 search->wild = ISC_FALSE;
1804 if ((search->options & DNS_DBFIND_GLUEOK) == 0) {
1806 * If the caller does not want to find glue, then
1807 * this is the best answer and the search should
1810 result = DNS_R_PARTIALMATCH;
1815 * The search will continue beneath the zone cut.
1816 * This may or may not be the best match. In case it
1817 * is, we need to remember the node name.
1819 zcname = dns_fixedname_name(&search->zonecut_name);
1820 RUNTIME_CHECK(dns_name_copy(name, zcname, NULL) ==
1822 search->copy_name = ISC_TRUE;
1826 * There is no zonecut at this node which is active in this
1829 * If this is a "wild" node and the caller hasn't disabled
1830 * wildcard matching, remember that we've seen a wild node
1831 * in case we need to go searching for wildcard matches
1834 if (node->wild && (search->options & DNS_DBFIND_NOWILD) == 0)
1835 search->wild = ISC_TRUE;
1838 NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
1839 isc_rwlocktype_read);
1845 bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
1846 rdatasetheader_t *header, isc_stdtime_t now,
1847 dns_rdataset_t *rdataset)
1849 unsigned char *raw; /* RDATASLAB */
1852 * Caller must be holding the node reader lock.
1853 * XXXJT: technically, we need a writer lock, since we'll increment
1854 * the header count below. However, since the actual counter value
1855 * doesn't matter, we prioritize performance here. (We may want to
1856 * use atomic increment when available).
1859 if (rdataset == NULL)
1862 new_reference(rbtdb, node);
1864 INSIST(rdataset->methods == NULL); /* We must be disassociated. */
1866 rdataset->methods = &rdataset_methods;
1867 rdataset->rdclass = rbtdb->common.rdclass;
1868 rdataset->type = RBTDB_RDATATYPE_BASE(header->type);
1869 rdataset->covers = RBTDB_RDATATYPE_EXT(header->type);
1870 rdataset->ttl = header->ttl - now;
1871 rdataset->trust = header->trust;
1872 if (NXDOMAIN(header))
1873 rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
1874 rdataset->private1 = rbtdb;
1875 rdataset->private2 = node;
1876 raw = (unsigned char *)header + sizeof(*header);
1877 rdataset->private3 = raw;
1878 rdataset->count = header->count++;
1879 if (rdataset->count == ISC_UINT32_MAX)
1880 rdataset->count = 0;
1883 * Reset iterator state.
1885 rdataset->privateuint4 = 0;
1886 rdataset->private5 = NULL;
1889 * Add noqname proof.
1891 rdataset->private6 = header->noqname;
1892 if (rdataset->private6 != NULL)
1893 rdataset->attributes |= DNS_RDATASETATTR_NOQNAME;
1896 static inline isc_result_t
1897 setup_delegation(rbtdb_search_t *search, dns_dbnode_t **nodep,
1898 dns_name_t *foundname, dns_rdataset_t *rdataset,
1899 dns_rdataset_t *sigrdataset)
1901 isc_result_t result;
1903 rbtdb_rdatatype_t type;
1904 dns_rbtnode_t *node;
1907 * The caller MUST NOT be holding any node locks.
1910 node = search->zonecut;
1911 type = search->zonecut_rdataset->type;
1914 * If we have to set foundname, we do it before anything else.
1915 * If we were to set foundname after we had set nodep or bound the
1916 * rdataset, then we'd have to undo that work if dns_name_copy()
1917 * failed. By setting foundname first, there's nothing to undo if
1920 if (foundname != NULL && search->copy_name) {
1921 zcname = dns_fixedname_name(&search->zonecut_name);
1922 result = dns_name_copy(zcname, foundname, NULL);
1923 if (result != ISC_R_SUCCESS)
1926 if (nodep != NULL) {
1928 * Note that we don't have to increment the node's reference
1929 * count here because we're going to use the reference we
1930 * already have in the search block.
1933 search->need_cleanup = ISC_FALSE;
1935 if (rdataset != NULL) {
1936 NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
1937 isc_rwlocktype_read);
1938 bind_rdataset(search->rbtdb, node, search->zonecut_rdataset,
1939 search->now, rdataset);
1940 if (sigrdataset != NULL && search->zonecut_sigrdataset != NULL)
1941 bind_rdataset(search->rbtdb, node,
1942 search->zonecut_sigrdataset,
1943 search->now, sigrdataset);
1944 NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
1945 isc_rwlocktype_read);
1948 if (type == dns_rdatatype_dname)
1949 return (DNS_R_DNAME);
1950 return (DNS_R_DELEGATION);
1953 static inline isc_boolean_t
1954 valid_glue(rbtdb_search_t *search, dns_name_t *name, rbtdb_rdatatype_t type,
1955 dns_rbtnode_t *node)
1957 unsigned char *raw; /* RDATASLAB */
1958 unsigned int count, size;
1960 isc_boolean_t valid = ISC_FALSE;
1961 dns_offsets_t offsets;
1962 isc_region_t region;
1963 rdatasetheader_t *header;
1966 * No additional locking is required.
1970 * Valid glue types are A, AAAA, A6. NS is also a valid glue type
1971 * if it occurs at a zone cut, but is not valid below it.
1973 if (type == dns_rdatatype_ns) {
1974 if (node != search->zonecut) {
1977 } else if (type != dns_rdatatype_a &&
1978 type != dns_rdatatype_aaaa &&
1979 type != dns_rdatatype_a6) {
1983 header = search->zonecut_rdataset;
1984 raw = (unsigned char *)header + sizeof(*header);
1985 count = raw[0] * 256 + raw[1];
1986 #if DNS_RDATASET_FIXED
1987 raw += 2 + (4 * count);
1994 size = raw[0] * 256 + raw[1];
1995 #if DNS_RDATASET_FIXED
2001 region.length = size;
2004 * XXX Until we have rdata structures, we have no choice but
2005 * to directly access the rdata format.
2007 dns_name_init(&ns_name, offsets);
2008 dns_name_fromregion(&ns_name, ®ion);
2009 if (dns_name_compare(&ns_name, name) == 0) {
2018 static inline isc_boolean_t
2019 activeempty(rbtdb_search_t *search, dns_rbtnodechain_t *chain,
2022 dns_fixedname_t fnext;
2023 dns_fixedname_t forigin;
2028 dns_rbtnode_t *node;
2029 isc_result_t result;
2030 isc_boolean_t answer = ISC_FALSE;
2031 rdatasetheader_t *header;
2033 rbtdb = search->rbtdb;
2035 dns_name_init(&prefix, NULL);
2036 dns_fixedname_init(&fnext);
2037 next = dns_fixedname_name(&fnext);
2038 dns_fixedname_init(&forigin);
2039 origin = dns_fixedname_name(&forigin);
2041 result = dns_rbtnodechain_next(chain, NULL, NULL);
2042 while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
2044 result = dns_rbtnodechain_current(chain, &prefix,
2046 if (result != ISC_R_SUCCESS)
2048 NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
2049 isc_rwlocktype_read);
2050 for (header = node->data;
2052 header = header->next) {
2053 if (header->serial <= search->serial &&
2054 !IGNORE(header) && EXISTS(header))
2057 NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
2058 isc_rwlocktype_read);
2061 result = dns_rbtnodechain_next(chain, NULL, NULL);
2063 if (result == ISC_R_SUCCESS)
2064 result = dns_name_concatenate(&prefix, origin, next, NULL);
2065 if (result == ISC_R_SUCCESS && dns_name_issubdomain(next, name))
2070 static inline isc_boolean_t
2071 activeemtpynode(rbtdb_search_t *search, dns_name_t *qname, dns_name_t *wname) {
2072 dns_fixedname_t fnext;
2073 dns_fixedname_t forigin;
2074 dns_fixedname_t fprev;
2082 dns_rbtnode_t *node;
2083 dns_rbtnodechain_t chain;
2084 isc_boolean_t check_next = ISC_TRUE;
2085 isc_boolean_t check_prev = ISC_TRUE;
2086 isc_boolean_t answer = ISC_FALSE;
2087 isc_result_t result;
2088 rdatasetheader_t *header;
2091 rbtdb = search->rbtdb;
2093 dns_name_init(&name, NULL);
2094 dns_name_init(&tname, NULL);
2095 dns_name_init(&rname, NULL);
2096 dns_fixedname_init(&fnext);
2097 next = dns_fixedname_name(&fnext);
2098 dns_fixedname_init(&fprev);
2099 prev = dns_fixedname_name(&fprev);
2100 dns_fixedname_init(&forigin);
2101 origin = dns_fixedname_name(&forigin);
2104 * Find if qname is at or below a empty node.
2105 * Use our own copy of the chain.
2108 chain = search->chain;
2111 result = dns_rbtnodechain_current(&chain, &name,
2113 if (result != ISC_R_SUCCESS)
2115 NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
2116 isc_rwlocktype_read);
2117 for (header = node->data;
2119 header = header->next) {
2120 if (header->serial <= search->serial &&
2121 !IGNORE(header) && EXISTS(header))
2124 NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
2125 isc_rwlocktype_read);
2128 result = dns_rbtnodechain_prev(&chain, NULL, NULL);
2129 } while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN);
2130 if (result == ISC_R_SUCCESS)
2131 result = dns_name_concatenate(&name, origin, prev, NULL);
2132 if (result != ISC_R_SUCCESS)
2133 check_prev = ISC_FALSE;
2135 result = dns_rbtnodechain_next(&chain, NULL, NULL);
2136 while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
2138 result = dns_rbtnodechain_current(&chain, &name,
2140 if (result != ISC_R_SUCCESS)
2142 NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
2143 isc_rwlocktype_read);
2144 for (header = node->data;
2146 header = header->next) {
2147 if (header->serial <= search->serial &&
2148 !IGNORE(header) && EXISTS(header))
2151 NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
2152 isc_rwlocktype_read);
2155 result = dns_rbtnodechain_next(&chain, NULL, NULL);
2157 if (result == ISC_R_SUCCESS)
2158 result = dns_name_concatenate(&name, origin, next, NULL);
2159 if (result != ISC_R_SUCCESS)
2160 check_next = ISC_FALSE;
2162 dns_name_clone(qname, &rname);
2165 * Remove the wildcard label to find the terminal name.
2167 n = dns_name_countlabels(wname);
2168 dns_name_getlabelsequence(wname, 1, n - 1, &tname);
2171 if ((check_prev && dns_name_issubdomain(prev, &rname)) ||
2172 (check_next && dns_name_issubdomain(next, &rname))) {
2177 * Remove the left hand label.
2179 n = dns_name_countlabels(&rname);
2180 dns_name_getlabelsequence(&rname, 1, n - 1, &rname);
2181 } while (!dns_name_equal(&rname, &tname));
2185 static inline isc_result_t
2186 find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
2190 dns_rbtnode_t *node, *level_node, *wnode;
2191 rdatasetheader_t *header;
2192 isc_result_t result = ISC_R_NOTFOUND;
2195 dns_fixedname_t fwname;
2197 isc_boolean_t done, wild, active;
2198 dns_rbtnodechain_t wchain;
2201 * Caller must be holding the tree lock and MUST NOT be holding
2206 * Examine each ancestor level. If the level's wild bit
2207 * is set, then construct the corresponding wildcard name and
2208 * search for it. If the wildcard node exists, and is active in
2209 * this version, we're done. If not, then we next check to see
2210 * if the ancestor is active in this version. If so, then there
2211 * can be no possible wildcard match and again we're done. If not,
2212 * continue the search.
2215 rbtdb = search->rbtdb;
2216 i = search->chain.level_matches;
2220 NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
2221 isc_rwlocktype_read);
2224 * First we try to figure out if this node is active in
2225 * the search's version. We do this now, even though we
2226 * may not need the information, because it simplifies the
2227 * locking and code flow.
2229 for (header = node->data;
2231 header = header->next) {
2232 if (header->serial <= search->serial &&
2233 !IGNORE(header) && EXISTS(header))
2246 NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
2247 isc_rwlocktype_read);
2251 * Construct the wildcard name for this level.
2253 dns_name_init(&name, NULL);
2254 dns_rbt_namefromnode(node, &name);
2255 dns_fixedname_init(&fwname);
2256 wname = dns_fixedname_name(&fwname);
2257 result = dns_name_concatenate(dns_wildcardname, &name,
2260 while (result == ISC_R_SUCCESS && j != 0) {
2262 level_node = search->chain.levels[j];
2263 dns_name_init(&name, NULL);
2264 dns_rbt_namefromnode(level_node, &name);
2265 result = dns_name_concatenate(wname,
2270 if (result != ISC_R_SUCCESS)
2274 dns_rbtnodechain_init(&wchain, NULL);
2275 result = dns_rbt_findnode(rbtdb->tree, wname,
2276 NULL, &wnode, &wchain,
2277 DNS_RBTFIND_EMPTYDATA,
2279 if (result == ISC_R_SUCCESS) {
2283 * We have found the wildcard node. If it
2284 * is active in the search's version, we're
2287 lock = &rbtdb->node_locks[wnode->locknum].lock;
2288 NODE_LOCK(lock, isc_rwlocktype_read);
2289 for (header = wnode->data;
2291 header = header->next) {
2292 if (header->serial <= search->serial &&
2293 !IGNORE(header) && EXISTS(header))
2296 NODE_UNLOCK(lock, isc_rwlocktype_read);
2297 if (header != NULL ||
2298 activeempty(search, &wchain, wname)) {
2299 if (activeemtpynode(search, qname,
2301 return (ISC_R_NOTFOUND);
2304 * The wildcard node is active!
2306 * Note: result is still ISC_R_SUCCESS
2307 * so we don't have to set it.
2312 } else if (result != ISC_R_NOTFOUND &&
2313 result != DNS_R_PARTIALMATCH) {
2315 * An error has occurred. Bail out.
2323 * The level node is active. Any wildcarding
2324 * present at higher levels has no
2325 * effect and we're done.
2327 result = ISC_R_NOTFOUND;
2333 node = search->chain.levels[i];
2341 static inline isc_result_t
2342 find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
2343 dns_name_t *foundname, dns_rdataset_t *rdataset,
2344 dns_rdataset_t *sigrdataset, isc_boolean_t need_sig)
2346 dns_rbtnode_t *node;
2347 rdatasetheader_t *header, *header_next, *found, *foundsig;
2348 isc_boolean_t empty_node;
2349 isc_result_t result;
2350 dns_fixedname_t fname, forigin;
2351 dns_name_t *name, *origin;
2355 dns_fixedname_init(&fname);
2356 name = dns_fixedname_name(&fname);
2357 dns_fixedname_init(&forigin);
2358 origin = dns_fixedname_name(&forigin);
2359 result = dns_rbtnodechain_current(&search->chain, name,
2361 if (result != ISC_R_SUCCESS)
2363 NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
2364 isc_rwlocktype_read);
2367 empty_node = ISC_TRUE;
2368 for (header = node->data;
2370 header = header_next) {
2371 header_next = header->next;
2373 * Look for an active, extant NSEC or RRSIG NSEC.
2376 if (header->serial <= search->serial &&
2379 * Is this a "this rdataset doesn't
2382 if (NONEXISTENT(header))
2386 header = header->down;
2387 } while (header != NULL);
2388 if (header != NULL) {
2390 * We now know that there is at least one
2391 * active rdataset at this node.
2393 empty_node = ISC_FALSE;
2394 if (header->type == dns_rdatatype_nsec) {
2396 if (foundsig != NULL)
2398 } else if (header->type ==
2399 RBTDB_RDATATYPE_SIGNSEC) {
2407 if (found != NULL &&
2408 (foundsig != NULL || !need_sig))
2411 * We've found the right NSEC record.
2413 * Note: for this to really be the right
2414 * NSEC record, it's essential that the NSEC
2415 * records of any nodes obscured by a zone
2416 * cut have been removed; we assume this is
2419 result = dns_name_concatenate(name, origin,
2421 if (result == ISC_R_SUCCESS) {
2422 if (nodep != NULL) {
2423 new_reference(search->rbtdb,
2427 bind_rdataset(search->rbtdb, node,
2430 if (foundsig != NULL)
2431 bind_rdataset(search->rbtdb,
2437 } else if (found == NULL && foundsig == NULL) {
2439 * This node is active, but has no NSEC or
2440 * RRSIG NSEC. That means it's glue or
2441 * other obscured zone data that isn't
2442 * relevant for our search. Treat the
2443 * node as if it were empty and keep looking.
2445 empty_node = ISC_TRUE;
2446 result = dns_rbtnodechain_prev(&search->chain,
2450 * We found an active node, but either the
2451 * NSEC or the RRSIG NSEC is missing. This
2454 result = DNS_R_BADDB;
2458 * This node isn't active. We've got to keep
2461 result = dns_rbtnodechain_prev(&search->chain, NULL,
2464 NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
2465 isc_rwlocktype_read);
2466 } while (empty_node && result == ISC_R_SUCCESS);
2469 * If the result is ISC_R_NOMORE, then we got to the beginning of
2470 * the database and didn't find a NSEC record. This shouldn't
2473 if (result == ISC_R_NOMORE)
2474 result = DNS_R_BADDB;
2480 zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
2481 dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
2482 dns_dbnode_t **nodep, dns_name_t *foundname,
2483 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
2485 dns_rbtnode_t *node = NULL;
2486 isc_result_t result;
2487 rbtdb_search_t search;
2488 isc_boolean_t cname_ok = ISC_TRUE;
2489 isc_boolean_t close_version = ISC_FALSE;
2490 isc_boolean_t maybe_zonecut = ISC_FALSE;
2491 isc_boolean_t at_zonecut = ISC_FALSE;
2493 isc_boolean_t empty_node;
2494 rdatasetheader_t *header, *header_next, *found, *nsecheader;
2495 rdatasetheader_t *foundsig, *cnamesig, *nsecsig;
2496 rbtdb_rdatatype_t sigtype;
2497 isc_boolean_t active;
2498 dns_rbtnodechain_t chain;
2502 search.rbtdb = (dns_rbtdb_t *)db;
2504 REQUIRE(VALID_RBTDB(search.rbtdb));
2507 * We don't care about 'now'.
2512 * If the caller didn't supply a version, attach to the current
2515 if (version == NULL) {
2516 currentversion(db, &version);
2517 close_version = ISC_TRUE;
2520 search.rbtversion = version;
2521 search.serial = search.rbtversion->serial;
2522 search.options = options;
2523 search.copy_name = ISC_FALSE;
2524 search.need_cleanup = ISC_FALSE;
2525 search.wild = ISC_FALSE;
2526 search.zonecut = NULL;
2527 dns_fixedname_init(&search.zonecut_name);
2528 dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
2532 * 'wild' will be true iff. we've matched a wildcard.
2536 RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
2539 * Search down from the root of the tree. If, while going down, we
2540 * encounter a callback node, zone_zonecut_callback() will search the
2541 * rdatasets at the zone cut for active DNAME or NS rdatasets.
2543 result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
2544 &search.chain, DNS_RBTFIND_EMPTYDATA,
2545 zone_zonecut_callback, &search);
2547 if (result == DNS_R_PARTIALMATCH) {
2549 if (search.zonecut != NULL) {
2550 result = setup_delegation(&search, nodep, foundname,
2551 rdataset, sigrdataset);
2557 * At least one of the levels in the search chain
2558 * potentially has a wildcard. For each such level,
2559 * we must see if there's a matching wildcard active
2560 * in the current version.
2562 result = find_wildcard(&search, &node, name);
2563 if (result == ISC_R_SUCCESS) {
2564 result = dns_name_copy(name, foundname, NULL);
2565 if (result != ISC_R_SUCCESS)
2570 else if (result != ISC_R_NOTFOUND)
2574 chain = search.chain;
2575 active = activeempty(&search, &chain, name);
2578 * If we're here, then the name does not exist, is not
2579 * beneath a zonecut, and there's no matching wildcard.
2581 if (search.rbtdb->secure ||
2582 (search.options & DNS_DBFIND_FORCENSEC) != 0)
2584 result = find_closest_nsec(&search, nodep, foundname,
2585 rdataset, sigrdataset,
2586 search.rbtdb->secure);
2587 if (result == ISC_R_SUCCESS)
2588 result = active ? DNS_R_EMPTYNAME :
2591 result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN;
2593 } else if (result != ISC_R_SUCCESS)
2598 * We have found a node whose name is the desired name, or we
2599 * have matched a wildcard.
2602 if (search.zonecut != NULL) {
2604 * If we're beneath a zone cut, we don't want to look for
2605 * CNAMEs because they're not legitimate zone glue.
2607 cname_ok = ISC_FALSE;
2610 * The node may be a zone cut itself. If it might be one,
2611 * make sure we check for it later.
2613 if (node->find_callback &&
2614 (node != search.rbtdb->origin_node ||
2615 IS_STUB(search.rbtdb)) &&
2616 !dns_rdatatype_atparent(type))
2617 maybe_zonecut = ISC_TRUE;
2621 * Certain DNSSEC types are not subject to CNAME matching
2622 * (RFC4035, section 2.5 and RFC3007).
2624 * We don't check for RRSIG, because we don't store RRSIG records
2627 if (type == dns_rdatatype_key || type == dns_rdatatype_nsec)
2628 cname_ok = ISC_FALSE;
2631 * We now go looking for rdata...
2634 NODE_LOCK(&(search.rbtdb->node_locks[node->locknum].lock),
2635 isc_rwlocktype_read);
2639 sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
2643 empty_node = ISC_TRUE;
2644 for (header = node->data; header != NULL; header = header_next) {
2645 header_next = header->next;
2647 * Look for an active, extant rdataset.
2650 if (header->serial <= search.serial &&
2653 * Is this a "this rdataset doesn't
2656 if (NONEXISTENT(header))
2660 header = header->down;
2661 } while (header != NULL);
2662 if (header != NULL) {
2664 * We now know that there is at least one active
2665 * rdataset at this node.
2667 empty_node = ISC_FALSE;
2670 * Do special zone cut handling, if requested.
2672 if (maybe_zonecut &&
2673 header->type == dns_rdatatype_ns) {
2675 * We increment the reference count on node to
2676 * ensure that search->zonecut_rdataset will
2677 * still be valid later.
2679 new_reference(search.rbtdb, node);
2680 search.zonecut = node;
2681 search.zonecut_rdataset = header;
2682 search.zonecut_sigrdataset = NULL;
2683 search.need_cleanup = ISC_TRUE;
2684 maybe_zonecut = ISC_FALSE;
2685 at_zonecut = ISC_TRUE;
2687 * It is not clear if KEY should still be
2688 * allowed at the parent side of the zone
2689 * cut or not. It is needed for RFC3007
2690 * validated updates.
2692 if ((search.options & DNS_DBFIND_GLUEOK) == 0
2693 && type != dns_rdatatype_nsec
2694 && type != dns_rdatatype_key) {
2696 * Glue is not OK, but any answer we
2697 * could return would be glue. Return
2703 if (found != NULL && foundsig != NULL)
2708 * If we found a type we were looking for,
2711 if (header->type == type ||
2712 type == dns_rdatatype_any ||
2713 (header->type == dns_rdatatype_cname &&
2716 * We've found the answer!
2719 if (header->type == dns_rdatatype_cname &&
2722 * We may be finding a CNAME instead
2723 * of the desired type.
2725 * If we've already got the CNAME RRSIG,
2726 * use it, otherwise change sigtype
2727 * so that we find it.
2729 if (cnamesig != NULL)
2730 foundsig = cnamesig;
2733 RBTDB_RDATATYPE_SIGCNAME;
2736 * If we've got all we need, end the search.
2738 if (!maybe_zonecut && foundsig != NULL)
2740 } else if (header->type == sigtype) {
2742 * We've found the RRSIG rdataset for our
2743 * target type. Remember it.
2747 * If we've got all we need, end the search.
2749 if (!maybe_zonecut && found != NULL)
2751 } else if (header->type == dns_rdatatype_nsec) {
2753 * Remember a NSEC rdataset even if we're
2754 * not specifically looking for it, because
2755 * we might need it later.
2757 nsecheader = header;
2758 } else if (header->type == RBTDB_RDATATYPE_SIGNSEC) {
2760 * If we need the NSEC rdataset, we'll also
2761 * need its signature.
2764 } else if (cname_ok &&
2765 header->type == RBTDB_RDATATYPE_SIGCNAME) {
2767 * If we get a CNAME match, we'll also need
2777 * We have an exact match for the name, but there are no
2778 * active rdatasets in the desired version. That means that
2779 * this node doesn't exist in the desired version, and that
2780 * we really have a partial match.
2783 lock = &search.rbtdb->node_locks[node->locknum].lock;
2784 NODE_UNLOCK(lock, isc_rwlocktype_read);
2790 * If we didn't find what we were looking for...
2792 if (found == NULL) {
2793 if (search.zonecut != NULL) {
2795 * We were trying to find glue at a node beneath a
2796 * zone cut, but didn't.
2798 * Return the delegation.
2800 lock = &search.rbtdb->node_locks[node->locknum].lock;
2801 NODE_UNLOCK(lock, isc_rwlocktype_read);
2802 result = setup_delegation(&search, nodep, foundname,
2803 rdataset, sigrdataset);
2807 * The desired type doesn't exist.
2809 result = DNS_R_NXRRSET;
2810 if (search.rbtdb->secure &&
2811 (nsecheader == NULL || nsecsig == NULL)) {
2813 * The zone is secure but there's no NSEC,
2814 * or the NSEC has no signature!
2817 result = DNS_R_BADDB;
2821 lock = &search.rbtdb->node_locks[node->locknum].lock;
2822 NODE_UNLOCK(lock, isc_rwlocktype_read);
2823 result = find_closest_nsec(&search, nodep, foundname,
2824 rdataset, sigrdataset,
2825 search.rbtdb->secure);
2826 if (result == ISC_R_SUCCESS)
2827 result = DNS_R_EMPTYWILD;
2830 if ((search.options & DNS_DBFIND_FORCENSEC) != 0 &&
2834 * There's no NSEC record, and we were told
2837 result = DNS_R_BADDB;
2840 if (nodep != NULL) {
2841 new_reference(search.rbtdb, node);
2844 if (search.rbtdb->secure ||
2845 (search.options & DNS_DBFIND_FORCENSEC) != 0)
2847 bind_rdataset(search.rbtdb, node, nsecheader,
2849 if (nsecsig != NULL)
2850 bind_rdataset(search.rbtdb, node,
2851 nsecsig, 0, sigrdataset);
2854 foundname->attributes |= DNS_NAMEATTR_WILDCARD;
2859 * We found what we were looking for, or we found a CNAME.
2862 if (type != found->type &&
2863 type != dns_rdatatype_any &&
2864 found->type == dns_rdatatype_cname) {
2866 * We weren't doing an ANY query and we found a CNAME instead
2867 * of the type we were looking for, so we need to indicate
2868 * that result to the caller.
2870 result = DNS_R_CNAME;
2871 } else if (search.zonecut != NULL) {
2873 * If we're beneath a zone cut, we must indicate that the
2874 * result is glue, unless we're actually at the zone cut
2875 * and the type is NSEC or KEY.
2877 if (search.zonecut == node) {
2879 * It is not clear if KEY should still be
2880 * allowed at the parent side of the zone
2881 * cut or not. It is needed for RFC3007
2882 * validated updates.
2884 if (type == dns_rdatatype_nsec ||
2885 type == dns_rdatatype_key)
2886 result = ISC_R_SUCCESS;
2887 else if (type == dns_rdatatype_any)
2888 result = DNS_R_ZONECUT;
2890 result = DNS_R_GLUE;
2892 result = DNS_R_GLUE;
2894 * We might have found data that isn't glue, but was occluded
2895 * by a dynamic update. If the caller cares about this, they
2896 * will have told us to validate glue.
2898 * XXX We should cache the glue validity state!
2900 if (result == DNS_R_GLUE &&
2901 (search.options & DNS_DBFIND_VALIDATEGLUE) != 0 &&
2902 !valid_glue(&search, foundname, type, node)) {
2903 lock = &search.rbtdb->node_locks[node->locknum].lock;
2904 NODE_UNLOCK(lock, isc_rwlocktype_read);
2905 result = setup_delegation(&search, nodep, foundname,
2906 rdataset, sigrdataset);
2911 * An ordinary successful query!
2913 result = ISC_R_SUCCESS;
2916 if (nodep != NULL) {
2918 new_reference(search.rbtdb, node);
2920 search.need_cleanup = ISC_FALSE;
2924 if (type != dns_rdatatype_any) {
2925 bind_rdataset(search.rbtdb, node, found, 0, rdataset);
2926 if (foundsig != NULL)
2927 bind_rdataset(search.rbtdb, node, foundsig, 0,
2932 foundname->attributes |= DNS_NAMEATTR_WILDCARD;
2935 NODE_UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock),
2936 isc_rwlocktype_read);
2939 RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
2942 * If we found a zonecut but aren't going to use it, we have to
2945 if (search.need_cleanup) {
2946 node = search.zonecut;
2947 lock = &(search.rbtdb->node_locks[node->locknum].lock);
2949 NODE_LOCK(lock, isc_rwlocktype_read);
2950 decrement_reference(search.rbtdb, node, 0,
2951 isc_rwlocktype_read, isc_rwlocktype_none);
2952 NODE_UNLOCK(lock, isc_rwlocktype_read);
2956 closeversion(db, &version, ISC_FALSE);
2958 dns_rbtnodechain_reset(&search.chain);
2964 zone_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
2965 isc_stdtime_t now, dns_dbnode_t **nodep,
2966 dns_name_t *foundname,
2967 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
2976 UNUSED(sigrdataset);
2978 FATAL_ERROR(__FILE__, __LINE__, "zone_findzonecut() called!");
2980 return (ISC_R_NOTIMPLEMENTED);
2984 cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
2985 rbtdb_search_t *search = arg;
2986 rdatasetheader_t *header, *header_prev, *header_next;
2987 rdatasetheader_t *dname_header, *sigdname_header;
2988 isc_result_t result;
2990 isc_rwlocktype_t locktype;
2994 REQUIRE(search->zonecut == NULL);
2997 * Keep compiler silent.
3001 lock = &(search->rbtdb->node_locks[node->locknum].lock);
3002 locktype = isc_rwlocktype_read;
3003 NODE_LOCK(lock, locktype);
3006 * Look for a DNAME or RRSIG DNAME rdataset.
3008 dname_header = NULL;
3009 sigdname_header = NULL;
3011 for (header = node->data; header != NULL; header = header_next) {
3012 header_next = header->next;
3013 if (header->ttl <= search->now) {
3015 * This rdataset is stale. If no one else is
3016 * using the node, we can clean it up right
3017 * now, otherwise we mark it as stale, and
3018 * the node as dirty, so it will get cleaned
3021 if ((header->ttl <= search->now - RBTDB_VIRTUAL) &&
3022 (locktype == isc_rwlocktype_write ||
3023 NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
3025 * We update the node's status only when we
3026 * can get write access; otherwise, we leave
3027 * others to this work. Periodical cleaning
3028 * will eventually take the job as the last
3030 * We won't downgrade the lock, since other
3031 * rdatasets are probably stale, too.
3033 locktype = isc_rwlocktype_write;
3035 if (dns_rbtnode_refcurrent(node) == 0) {
3039 * header->down can be non-NULL if the
3040 * refcount has just decremented to 0
3041 * but decrement_reference() has not
3042 * performed clean_cache_node(), in
3043 * which case we need to purge the
3044 * stale headers first.
3046 mctx = search->rbtdb->common.mctx;
3047 clean_stale_headers(mctx, header);
3048 if (header_prev != NULL)
3052 node->data = header->next;
3053 free_rdataset(mctx, header);
3055 header->attributes |=
3056 RDATASET_ATTR_STALE;
3058 header_prev = header;
3061 header_prev = header;
3062 } else if (header->type == dns_rdatatype_dname &&
3064 dname_header = header;
3065 header_prev = header;
3066 } else if (header->type == RBTDB_RDATATYPE_SIGDNAME &&
3068 sigdname_header = header;
3069 header_prev = header;
3071 header_prev = header;
3074 if (dname_header != NULL &&
3075 (dname_header->trust != dns_trust_pending ||
3076 (search->options & DNS_DBFIND_PENDINGOK) != 0)) {
3078 * We increment the reference count on node to ensure that
3079 * search->zonecut_rdataset will still be valid later.
3081 new_reference(search->rbtdb, node);
3082 search->zonecut = node;
3083 search->zonecut_rdataset = dname_header;
3084 search->zonecut_sigrdataset = sigdname_header;
3085 search->need_cleanup = ISC_TRUE;
3086 result = DNS_R_PARTIALMATCH;
3088 result = DNS_R_CONTINUE;
3090 NODE_UNLOCK(lock, locktype);
3095 static inline isc_result_t
3096 find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
3097 dns_dbnode_t **nodep, dns_name_t *foundname,
3098 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
3101 dns_rbtnode_t *level_node;
3102 rdatasetheader_t *header, *header_prev, *header_next;
3103 rdatasetheader_t *found, *foundsig;
3104 isc_result_t result = ISC_R_NOTFOUND;
3109 isc_rwlocktype_t locktype;
3112 * Caller must be holding the tree lock.
3115 rbtdb = search->rbtdb;
3116 i = search->chain.level_matches;
3119 locktype = isc_rwlocktype_read;
3120 lock = &rbtdb->node_locks[node->locknum].lock;
3121 NODE_LOCK(lock, locktype);
3124 * Look for NS and RRSIG NS rdatasets.
3129 for (header = node->data;
3131 header = header_next) {
3132 header_next = header->next;
3133 if (header->ttl <= search->now) {
3135 * This rdataset is stale. If no one else is
3136 * using the node, we can clean it up right
3137 * now, otherwise we mark it as stale, and
3138 * the node as dirty, so it will get cleaned
3141 if ((header->ttl <= search->now -
3143 (locktype == isc_rwlocktype_write ||
3144 NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
3146 * We update the node's status only
3147 * when we can get write access.
3149 locktype = isc_rwlocktype_write;
3151 if (dns_rbtnode_refcurrent(node)
3155 m = search->rbtdb->common.mctx;
3156 clean_stale_headers(m, header);
3157 if (header_prev != NULL)
3163 free_rdataset(m, header);
3165 header->attributes |=
3166 RDATASET_ATTR_STALE;
3168 header_prev = header;
3171 header_prev = header;
3172 } else if (EXISTS(header)) {
3174 * We've found an extant rdataset. See if
3175 * we're interested in it.
3177 if (header->type == dns_rdatatype_ns) {
3179 if (foundsig != NULL)
3181 } else if (header->type ==
3182 RBTDB_RDATATYPE_SIGNS) {
3187 header_prev = header;
3189 header_prev = header;
3192 if (found != NULL) {
3194 * If we have to set foundname, we do it before
3195 * anything else. If we were to set foundname after
3196 * we had set nodep or bound the rdataset, then we'd
3197 * have to undo that work if dns_name_concatenate()
3198 * failed. By setting foundname first, there's
3199 * nothing to undo if we have trouble.
3201 if (foundname != NULL) {
3202 dns_name_init(&name, NULL);
3203 dns_rbt_namefromnode(node, &name);
3204 result = dns_name_copy(&name, foundname, NULL);
3205 while (result == ISC_R_SUCCESS && i > 0) {
3207 level_node = search->chain.levels[i];
3208 dns_name_init(&name, NULL);
3209 dns_rbt_namefromnode(level_node,
3212 dns_name_concatenate(foundname,
3217 if (result != ISC_R_SUCCESS) {
3222 result = DNS_R_DELEGATION;
3223 if (nodep != NULL) {
3224 new_reference(search->rbtdb, node);
3227 bind_rdataset(search->rbtdb, node, found, search->now,
3229 if (foundsig != NULL)
3230 bind_rdataset(search->rbtdb, node, foundsig,
3231 search->now, sigrdataset);
3235 NODE_UNLOCK(lock, locktype);
3237 if (found == NULL && i > 0) {
3239 node = search->chain.levels[i];
3249 find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
3250 isc_stdtime_t now, dns_name_t *foundname,
3251 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
3253 dns_rbtnode_t *node;
3254 rdatasetheader_t *header, *header_next, *header_prev;
3255 rdatasetheader_t *found, *foundsig;
3256 isc_boolean_t empty_node;
3257 isc_result_t result;
3258 dns_fixedname_t fname, forigin;
3259 dns_name_t *name, *origin;
3260 rbtdb_rdatatype_t matchtype, sigmatchtype;
3262 isc_rwlocktype_t locktype;
3264 matchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_nsec, 0);
3265 sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig,
3266 dns_rdatatype_nsec);
3270 dns_fixedname_init(&fname);
3271 name = dns_fixedname_name(&fname);
3272 dns_fixedname_init(&forigin);
3273 origin = dns_fixedname_name(&forigin);
3274 result = dns_rbtnodechain_current(&search->chain, name,
3276 if (result != ISC_R_SUCCESS)
3278 locktype = isc_rwlocktype_read;
3279 lock = &(search->rbtdb->node_locks[node->locknum].lock);
3280 NODE_LOCK(lock, locktype);
3283 empty_node = ISC_TRUE;
3285 for (header = node->data;
3287 header = header_next) {
3288 header_next = header->next;
3289 if (header->ttl <= now) {
3291 * This rdataset is stale. If no one else is
3292 * using the node, we can clean it up right
3293 * now, otherwise we mark it as stale, and the
3294 * node as dirty, so it will get cleaned up
3297 if ((header->ttl <= now - RBTDB_VIRTUAL) &&
3298 (locktype == isc_rwlocktype_write ||
3299 NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
3301 * We update the node's status only
3302 * when we can get write access.
3304 locktype = isc_rwlocktype_write;
3306 if (dns_rbtnode_refcurrent(node)
3310 m = search->rbtdb->common.mctx;
3311 clean_stale_headers(m, header);
3312 if (header_prev != NULL)
3316 node->data = header->next;
3317 free_rdataset(m, header);
3319 header->attributes |=
3320 RDATASET_ATTR_STALE;
3322 header_prev = header;
3325 header_prev = header;
3328 if (NONEXISTENT(header) ||
3329 RBTDB_RDATATYPE_BASE(header->type) == 0) {
3330 header_prev = header;
3333 empty_node = ISC_FALSE;
3334 if (header->type == matchtype)
3336 else if (header->type == sigmatchtype)
3338 header_prev = header;
3340 if (found != NULL) {
3341 result = dns_name_concatenate(name, origin,
3343 if (result != ISC_R_SUCCESS)
3345 bind_rdataset(search->rbtdb, node, found,
3347 if (foundsig != NULL)
3348 bind_rdataset(search->rbtdb, node, foundsig,
3350 new_reference(search->rbtdb, node);
3352 result = DNS_R_COVERINGNSEC;
3353 } else if (!empty_node) {
3354 result = ISC_R_NOTFOUND;
3356 result = dns_rbtnodechain_prev(&search->chain, NULL,
3359 NODE_UNLOCK(lock, locktype);
3360 } while (empty_node && result == ISC_R_SUCCESS);
3365 cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
3366 dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
3367 dns_dbnode_t **nodep, dns_name_t *foundname,
3368 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
3370 dns_rbtnode_t *node = NULL;
3371 isc_result_t result;
3372 rbtdb_search_t search;
3373 isc_boolean_t cname_ok = ISC_TRUE;
3374 isc_boolean_t empty_node;
3376 isc_rwlocktype_t locktype;
3377 rdatasetheader_t *header, *header_prev, *header_next;
3378 rdatasetheader_t *found, *nsheader;
3379 rdatasetheader_t *foundsig, *nssig, *cnamesig;
3380 rbtdb_rdatatype_t sigtype, negtype;
3384 search.rbtdb = (dns_rbtdb_t *)db;
3386 REQUIRE(VALID_RBTDB(search.rbtdb));
3387 REQUIRE(version == NULL);
3390 isc_stdtime_get(&now);
3392 search.rbtversion = NULL;
3394 search.options = options;
3395 search.copy_name = ISC_FALSE;
3396 search.need_cleanup = ISC_FALSE;
3397 search.wild = ISC_FALSE;
3398 search.zonecut = NULL;
3399 dns_fixedname_init(&search.zonecut_name);
3400 dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
3403 RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
3406 * Search down from the root of the tree. If, while going down, we
3407 * encounter a callback node, cache_zonecut_callback() will search the
3408 * rdatasets at the zone cut for a DNAME rdataset.
3410 result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
3411 &search.chain, DNS_RBTFIND_EMPTYDATA,
3412 cache_zonecut_callback, &search);
3414 if (result == DNS_R_PARTIALMATCH) {
3415 if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) {
3416 result = find_coveringnsec(&search, nodep, now,
3417 foundname, rdataset,
3419 if (result == DNS_R_COVERINGNSEC)
3422 if (search.zonecut != NULL) {
3423 result = setup_delegation(&search, nodep, foundname,
3424 rdataset, sigrdataset);
3428 result = find_deepest_zonecut(&search, node, nodep,
3429 foundname, rdataset,
3433 } else if (result != ISC_R_SUCCESS)
3437 * Certain DNSSEC types are not subject to CNAME matching
3438 * (RFC4035, section 2.5 and RFC3007).
3440 * We don't check for RRSIG, because we don't store RRSIG records
3443 if (type == dns_rdatatype_key || type == dns_rdatatype_nsec)
3444 cname_ok = ISC_FALSE;
3447 * We now go looking for rdata...
3450 lock = &(search.rbtdb->node_locks[node->locknum].lock);
3451 locktype = isc_rwlocktype_read;
3452 NODE_LOCK(lock, locktype);
3456 sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
3457 negtype = RBTDB_RDATATYPE_VALUE(0, type);
3461 empty_node = ISC_TRUE;
3463 for (header = node->data; header != NULL; header = header_next) {
3464 header_next = header->next;
3465 if (header->ttl <= now) {
3467 * This rdataset is stale. If no one else is using the
3468 * node, we can clean it up right now, otherwise we
3469 * mark it as stale, and the node as dirty, so it will
3470 * get cleaned up later.
3472 if ((header->ttl <= now - RBTDB_VIRTUAL) &&
3473 (locktype == isc_rwlocktype_write ||
3474 NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
3476 * We update the node's status only when we
3477 * can get write access.
3479 locktype = isc_rwlocktype_write;
3481 if (dns_rbtnode_refcurrent(node) == 0) {
3484 mctx = search.rbtdb->common.mctx;
3485 clean_stale_headers(mctx, header);
3486 if (header_prev != NULL)
3490 node->data = header->next;
3491 free_rdataset(mctx, header);
3493 header->attributes |=
3494 RDATASET_ATTR_STALE;
3496 header_prev = header;
3499 header_prev = header;
3500 } else if (EXISTS(header)) {
3502 * We now know that there is at least one active
3503 * non-stale rdataset at this node.
3505 empty_node = ISC_FALSE;
3508 * If we found a type we were looking for, remember
3511 if (header->type == type ||
3512 (type == dns_rdatatype_any &&
3513 RBTDB_RDATATYPE_BASE(header->type) != 0) ||
3514 (cname_ok && header->type ==
3515 dns_rdatatype_cname)) {
3517 * We've found the answer.
3520 if (header->type == dns_rdatatype_cname &&
3524 * If we've already got the CNAME RRSIG,
3525 * use it, otherwise change sigtype
3526 * so that we find it.
3528 if (cnamesig != NULL)
3529 foundsig = cnamesig;
3532 RBTDB_RDATATYPE_SIGCNAME;
3533 foundsig = cnamesig;
3535 } else if (header->type == sigtype) {
3537 * We've found the RRSIG rdataset for our
3538 * target type. Remember it.
3541 } else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
3542 header->type == negtype) {
3544 * We've found a negative cache entry.
3547 } else if (header->type == dns_rdatatype_ns) {
3549 * Remember a NS rdataset even if we're
3550 * not specifically looking for it, because
3551 * we might need it later.
3554 } else if (header->type == RBTDB_RDATATYPE_SIGNS) {
3556 * If we need the NS rdataset, we'll also
3557 * need its signature.
3560 } else if (cname_ok &&
3561 header->type == RBTDB_RDATATYPE_SIGCNAME) {
3563 * If we get a CNAME match, we'll also need
3568 header_prev = header;
3570 header_prev = header;
3575 * We have an exact match for the name, but there are no
3576 * extant rdatasets. That means that this node doesn't
3577 * meaningfully exist, and that we really have a partial match.
3579 NODE_UNLOCK(lock, locktype);
3584 * If we didn't find what we were looking for...
3586 if (found == NULL ||
3587 (found->trust == dns_trust_glue &&
3588 ((options & DNS_DBFIND_GLUEOK) == 0)) ||
3589 (found->trust == dns_trust_pending &&
3590 ((options & DNS_DBFIND_PENDINGOK) == 0))) {
3592 * If there is an NS rdataset at this node, then this is the
3595 if (nsheader != NULL) {
3596 if (nodep != NULL) {
3597 new_reference(search.rbtdb, node);
3600 bind_rdataset(search.rbtdb, node, nsheader, search.now,
3603 bind_rdataset(search.rbtdb, node, nssig,
3604 search.now, sigrdataset);
3605 result = DNS_R_DELEGATION;
3610 * Go find the deepest zone cut.
3612 NODE_UNLOCK(lock, locktype);
3617 * We found what we were looking for, or we found a CNAME.
3620 if (nodep != NULL) {
3621 new_reference(search.rbtdb, node);
3625 if (RBTDB_RDATATYPE_BASE(found->type) == 0) {
3627 * We found a negative cache entry.
3629 if (NXDOMAIN(found))
3630 result = DNS_R_NCACHENXDOMAIN;
3632 result = DNS_R_NCACHENXRRSET;
3633 } else if (type != found->type &&
3634 type != dns_rdatatype_any &&
3635 found->type == dns_rdatatype_cname) {
3637 * We weren't doing an ANY query and we found a CNAME instead
3638 * of the type we were looking for, so we need to indicate
3639 * that result to the caller.
3641 result = DNS_R_CNAME;
3644 * An ordinary successful query!
3646 result = ISC_R_SUCCESS;
3649 if (type != dns_rdatatype_any || result == DNS_R_NCACHENXDOMAIN ||
3650 result == DNS_R_NCACHENXRRSET) {
3651 bind_rdataset(search.rbtdb, node, found, search.now,
3653 if (foundsig != NULL)
3654 bind_rdataset(search.rbtdb, node, foundsig, search.now,
3659 NODE_UNLOCK(lock, locktype);
3662 RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
3665 * If we found a zonecut but aren't going to use it, we have to
3668 if (search.need_cleanup) {
3669 node = search.zonecut;
3670 lock = &(search.rbtdb->node_locks[node->locknum].lock);
3672 NODE_LOCK(lock, isc_rwlocktype_read);
3673 decrement_reference(search.rbtdb, node, 0,
3674 isc_rwlocktype_read, isc_rwlocktype_none);
3675 NODE_UNLOCK(lock, isc_rwlocktype_read);
3678 dns_rbtnodechain_reset(&search.chain);
3684 cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
3685 isc_stdtime_t now, dns_dbnode_t **nodep,
3686 dns_name_t *foundname,
3687 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
3689 dns_rbtnode_t *node = NULL;
3691 isc_result_t result;
3692 rbtdb_search_t search;
3693 rdatasetheader_t *header, *header_prev, *header_next;
3694 rdatasetheader_t *found, *foundsig;
3695 unsigned int rbtoptions = DNS_RBTFIND_EMPTYDATA;
3696 isc_rwlocktype_t locktype;
3698 search.rbtdb = (dns_rbtdb_t *)db;
3700 REQUIRE(VALID_RBTDB(search.rbtdb));
3703 isc_stdtime_get(&now);
3705 search.rbtversion = NULL;
3707 search.options = options;
3708 search.copy_name = ISC_FALSE;
3709 search.need_cleanup = ISC_FALSE;
3710 search.wild = ISC_FALSE;
3711 search.zonecut = NULL;
3712 dns_fixedname_init(&search.zonecut_name);
3713 dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
3716 if ((options & DNS_DBFIND_NOEXACT) != 0)
3717 rbtoptions |= DNS_RBTFIND_NOEXACT;
3719 RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
3722 * Search down from the root of the tree.
3724 result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
3725 &search.chain, rbtoptions, NULL, &search);
3727 if (result == DNS_R_PARTIALMATCH) {
3729 result = find_deepest_zonecut(&search, node, nodep, foundname,
3730 rdataset, sigrdataset);
3732 } else if (result != ISC_R_SUCCESS)
3736 * We now go looking for an NS rdataset at the node.
3739 lock = &(search.rbtdb->node_locks[node->locknum].lock);
3740 locktype = isc_rwlocktype_read;
3741 NODE_LOCK(lock, locktype);
3746 for (header = node->data; header != NULL; header = header_next) {
3747 header_next = header->next;
3748 if (header->ttl <= now) {
3750 * This rdataset is stale. If no one else is using the
3751 * node, we can clean it up right now, otherwise we
3752 * mark it as stale, and the node as dirty, so it will
3753 * get cleaned up later.
3755 if ((header->ttl <= now - RBTDB_VIRTUAL) &&
3756 (locktype == isc_rwlocktype_write ||
3757 NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
3759 * We update the node's status only when we
3760 * can get write access.
3762 locktype = isc_rwlocktype_write;
3764 if (dns_rbtnode_refcurrent(node) == 0) {
3767 mctx = search.rbtdb->common.mctx;
3768 clean_stale_headers(mctx, header);
3769 if (header_prev != NULL)
3773 node->data = header->next;
3774 free_rdataset(mctx, header);
3776 header->attributes |=
3777 RDATASET_ATTR_STALE;
3779 header_prev = header;
3782 header_prev = header;
3783 } else if (EXISTS(header)) {
3785 * If we found a type we were looking for, remember
3788 if (header->type == dns_rdatatype_ns) {
3790 * Remember a NS rdataset even if we're
3791 * not specifically looking for it, because
3792 * we might need it later.
3795 } else if (header->type == RBTDB_RDATATYPE_SIGNS) {
3797 * If we need the NS rdataset, we'll also
3798 * need its signature.
3802 header_prev = header;
3804 header_prev = header;
3807 if (found == NULL) {
3809 * No NS records here.
3811 NODE_UNLOCK(lock, locktype);
3815 if (nodep != NULL) {
3816 new_reference(search.rbtdb, node);
3820 bind_rdataset(search.rbtdb, node, found, search.now, rdataset);
3821 if (foundsig != NULL)
3822 bind_rdataset(search.rbtdb, node, foundsig, search.now,
3825 NODE_UNLOCK(lock, locktype);
3828 RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
3830 INSIST(!search.need_cleanup);
3832 dns_rbtnodechain_reset(&search.chain);
3834 if (result == DNS_R_DELEGATION)
3835 result = ISC_R_SUCCESS;
3841 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
3842 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
3843 dns_rbtnode_t *node = (dns_rbtnode_t *)source;
3846 REQUIRE(VALID_RBTDB(rbtdb));
3847 REQUIRE(targetp != NULL && *targetp == NULL);
3849 NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
3850 dns_rbtnode_refincrement(node, &refs);
3852 NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
3858 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
3859 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
3860 dns_rbtnode_t *node;
3861 isc_boolean_t want_free = ISC_FALSE;
3862 isc_boolean_t inactive = ISC_FALSE;
3863 rbtdb_nodelock_t *nodelock;
3865 REQUIRE(VALID_RBTDB(rbtdb));
3866 REQUIRE(targetp != NULL && *targetp != NULL);
3868 node = (dns_rbtnode_t *)(*targetp);
3869 nodelock = &rbtdb->node_locks[node->locknum];
3871 NODE_LOCK(&nodelock->lock, isc_rwlocktype_read);
3873 if (decrement_reference(rbtdb, node, 0, isc_rwlocktype_read,
3874 isc_rwlocktype_none)) {
3875 if (isc_refcount_current(&nodelock->references) == 0 &&
3876 nodelock->exiting) {
3877 inactive = ISC_TRUE;
3881 NODE_UNLOCK(&nodelock->lock, isc_rwlocktype_read);
3886 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
3888 if (rbtdb->active == 0)
3889 want_free = ISC_TRUE;
3890 RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
3892 char buf[DNS_NAME_FORMATSIZE];
3893 if (dns_name_dynamic(&rbtdb->common.origin))
3894 dns_name_format(&rbtdb->common.origin, buf,
3897 strcpy(buf, "<UNKNOWN>");
3898 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
3899 DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
3900 "calling free_rbtdb(%s)", buf);
3901 free_rbtdb(rbtdb, ISC_TRUE, NULL);
3907 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
3908 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
3909 dns_rbtnode_t *rbtnode = node;
3910 rdatasetheader_t *header;
3911 isc_boolean_t force_expire = ISC_FALSE;
3913 * These are the category and module used by the cache cleaner.
3915 isc_boolean_t log = ISC_FALSE;
3916 isc_logcategory_t *category = DNS_LOGCATEGORY_DATABASE;
3917 isc_logmodule_t *module = DNS_LOGMODULE_CACHE;
3918 int level = ISC_LOG_DEBUG(2);
3919 char printname[DNS_NAME_FORMATSIZE];
3921 REQUIRE(VALID_RBTDB(rbtdb));
3924 * Caller must hold a tree lock.
3928 isc_stdtime_get(&now);
3930 if (rbtdb->overmem) {
3933 isc_random_get(&val);
3935 * XXXDCL Could stand to have a better policy, like LRU.
3937 force_expire = ISC_TF(rbtnode->down == NULL && val % 4 == 0);
3940 * Note that 'log' can be true IFF rbtdb->overmem is also true.
3941 * rbtdb->ovemem can currently only be true for cache databases
3942 * -- hence all of the "overmem cache" log strings.
3944 log = ISC_TF(isc_log_wouldlog(dns_lctx, level));
3946 isc_log_write(dns_lctx, category, module, level,
3947 "overmem cache: %s %s",
3948 force_expire ? "FORCE" : "check",
3949 dns_rbt_formatnodename(rbtnode,
3951 sizeof(printname)));
3955 * We may not need write access, but this code path is not performance
3956 * sensitive, so it should be okay to always lock as a writer.
3958 NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
3959 isc_rwlocktype_write);
3961 for (header = rbtnode->data; header != NULL; header = header->next)
3962 if (header->ttl <= now - RBTDB_VIRTUAL) {
3964 * We don't check if refcurrent(rbtnode) == 0 and try
3965 * to free like we do in cache_find(), because
3966 * refcurrent(rbtnode) must be non-zero. This is so
3967 * because 'node' is an argument to the function.
3969 header->attributes |= RDATASET_ATTR_STALE;
3972 isc_log_write(dns_lctx, category, module,
3973 level, "overmem cache: stale %s",
3975 } else if (force_expire) {
3976 if (! RETAIN(header)) {
3978 header->attributes |= RDATASET_ATTR_STALE;
3981 isc_log_write(dns_lctx, category, module,
3982 level, "overmem cache: "
3983 "reprieve by RETAIN() %s",
3986 } else if (rbtdb->overmem && log)
3987 isc_log_write(dns_lctx, category, module, level,
3988 "overmem cache: saved %s", printname);
3990 NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
3991 isc_rwlocktype_write);
3993 return (ISC_R_SUCCESS);
3997 overmem(dns_db_t *db, isc_boolean_t overmem) {
3998 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
4000 if (IS_CACHE(rbtdb)) {
4001 rbtdb->overmem = overmem;
4006 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
4007 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
4008 dns_rbtnode_t *rbtnode = node;
4009 isc_boolean_t first;
4011 REQUIRE(VALID_RBTDB(rbtdb));
4013 NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
4014 isc_rwlocktype_read);
4016 fprintf(out, "node %p, %u references, locknum = %u\n",
4017 rbtnode, dns_rbtnode_refcurrent(rbtnode),
4019 if (rbtnode->data != NULL) {
4020 rdatasetheader_t *current, *top_next;
4022 for (current = rbtnode->data; current != NULL;
4023 current = top_next) {
4024 top_next = current->next;
4026 fprintf(out, "\ttype %u", current->type);
4032 "\tserial = %lu, ttl = %u, "
4033 "trust = %u, attributes = %u\n",
4034 (unsigned long)current->serial,
4037 current->attributes);
4038 current = current->down;
4039 } while (current != NULL);
4042 fprintf(out, "(empty)\n");
4044 NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
4045 isc_rwlocktype_read);
4049 createiterator(dns_db_t *db, isc_boolean_t relative_names,
4050 dns_dbiterator_t **iteratorp)
4052 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
4053 rbtdb_dbiterator_t *rbtdbiter;
4055 REQUIRE(VALID_RBTDB(rbtdb));
4057 rbtdbiter = isc_mem_get(rbtdb->common.mctx, sizeof(*rbtdbiter));
4058 if (rbtdbiter == NULL)
4059 return (ISC_R_NOMEMORY);
4061 rbtdbiter->common.methods = &dbiterator_methods;
4062 rbtdbiter->common.db = NULL;
4063 dns_db_attach(db, &rbtdbiter->common.db);
4064 rbtdbiter->common.relative_names = relative_names;
4065 rbtdbiter->common.magic = DNS_DBITERATOR_MAGIC;
4066 rbtdbiter->common.cleaning = ISC_FALSE;
4067 rbtdbiter->paused = ISC_TRUE;
4068 rbtdbiter->tree_locked = isc_rwlocktype_none;
4069 rbtdbiter->result = ISC_R_SUCCESS;
4070 dns_fixedname_init(&rbtdbiter->name);
4071 dns_fixedname_init(&rbtdbiter->origin);
4072 rbtdbiter->node = NULL;
4073 rbtdbiter->delete = 0;
4074 memset(rbtdbiter->deletions, 0, sizeof(rbtdbiter->deletions));
4075 dns_rbtnodechain_init(&rbtdbiter->chain, db->mctx);
4077 *iteratorp = (dns_dbiterator_t *)rbtdbiter;
4079 return (ISC_R_SUCCESS);
4083 zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
4084 dns_rdatatype_t type, dns_rdatatype_t covers,
4085 isc_stdtime_t now, dns_rdataset_t *rdataset,
4086 dns_rdataset_t *sigrdataset)
4088 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
4089 dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
4090 rdatasetheader_t *header, *header_next, *found, *foundsig;
4091 rbtdb_serial_t serial;
4092 rbtdb_version_t *rbtversion = version;
4093 isc_boolean_t close_version = ISC_FALSE;
4094 rbtdb_rdatatype_t matchtype, sigmatchtype;
4096 REQUIRE(VALID_RBTDB(rbtdb));
4097 REQUIRE(type != dns_rdatatype_any);
4099 if (rbtversion == NULL) {
4100 currentversion(db, (dns_dbversion_t **) (void *)(&rbtversion));
4101 close_version = ISC_TRUE;
4103 serial = rbtversion->serial;
4106 NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
4107 isc_rwlocktype_read);
4111 matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
4113 sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
4117 for (header = rbtnode->data; header != NULL; header = header_next) {
4118 header_next = header->next;
4120 if (header->serial <= serial &&
4123 * Is this a "this rdataset doesn't
4126 if (NONEXISTENT(header))
4130 header = header->down;
4131 } while (header != NULL);
4132 if (header != NULL) {
4134 * We have an active, extant rdataset. If it's a
4135 * type we're looking for, remember it.
4137 if (header->type == matchtype) {
4139 if (foundsig != NULL)
4141 } else if (header->type == sigmatchtype) {
4148 if (found != NULL) {
4149 bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
4150 if (foundsig != NULL)
4151 bind_rdataset(rbtdb, rbtnode, foundsig, now,
4155 NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
4156 isc_rwlocktype_read);
4159 closeversion(db, (dns_dbversion_t **) (void *)(&rbtversion),
4163 return (ISC_R_NOTFOUND);
4165 return (ISC_R_SUCCESS);
4169 cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
4170 dns_rdatatype_t type, dns_rdatatype_t covers,
4171 isc_stdtime_t now, dns_rdataset_t *rdataset,
4172 dns_rdataset_t *sigrdataset)
4174 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
4175 dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
4176 rdatasetheader_t *header, *header_next, *found, *foundsig;
4177 rbtdb_rdatatype_t matchtype, sigmatchtype, negtype;
4178 isc_result_t result;
4180 isc_rwlocktype_t locktype;
4182 REQUIRE(VALID_RBTDB(rbtdb));
4183 REQUIRE(type != dns_rdatatype_any);
4187 result = ISC_R_SUCCESS;
4190 isc_stdtime_get(&now);
4192 lock = &rbtdb->node_locks[rbtnode->locknum].lock;
4193 locktype = isc_rwlocktype_read;
4194 NODE_LOCK(lock, locktype);
4198 matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
4199 negtype = RBTDB_RDATATYPE_VALUE(0, type);
4201 sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
4205 for (header = rbtnode->data; header != NULL; header = header_next) {
4206 header_next = header->next;
4207 if (header->ttl <= now) {
4208 if ((header->ttl <= now - RBTDB_VIRTUAL) &&
4209 (locktype == isc_rwlocktype_write ||
4210 NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
4212 * We update the node's status only when we
4213 * can get write access.
4215 locktype = isc_rwlocktype_write;
4218 * We don't check if refcurrent(rbtnode) == 0
4219 * and try to free like we do in cache_find(),
4220 * because refcurrent(rbtnode) must be
4221 * non-zero. This is so because 'node' is an
4222 * argument to the function.
4224 header->attributes |= RDATASET_ATTR_STALE;
4227 } else if (EXISTS(header)) {
4228 if (header->type == matchtype)
4230 else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
4231 header->type == negtype)
4233 else if (header->type == sigmatchtype)
4237 if (found != NULL) {
4238 bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
4239 if (foundsig != NULL)
4240 bind_rdataset(rbtdb, rbtnode, foundsig, now,
4244 NODE_UNLOCK(lock, locktype);
4247 return (ISC_R_NOTFOUND);
4249 if (RBTDB_RDATATYPE_BASE(found->type) == 0) {
4251 * We found a negative cache entry.
4253 if (NXDOMAIN(found))
4254 result = DNS_R_NCACHENXDOMAIN;
4256 result = DNS_R_NCACHENXRRSET;
4263 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
4264 isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
4266 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
4267 dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
4268 rbtdb_version_t *rbtversion = version;
4269 rbtdb_rdatasetiter_t *iterator;
4272 REQUIRE(VALID_RBTDB(rbtdb));
4274 iterator = isc_mem_get(rbtdb->common.mctx, sizeof(*iterator));
4275 if (iterator == NULL)
4276 return (ISC_R_NOMEMORY);
4278 if ((db->attributes & DNS_DBATTR_CACHE) == 0) {
4280 if (rbtversion == NULL)
4282 (dns_dbversion_t **) (void *)(&rbtversion));
4286 isc_refcount_increment(&rbtversion->references,
4292 isc_stdtime_get(&now);
4296 iterator->common.magic = DNS_RDATASETITER_MAGIC;
4297 iterator->common.methods = &rdatasetiter_methods;
4298 iterator->common.db = db;
4299 iterator->common.node = node;
4300 iterator->common.version = (dns_dbversion_t *)rbtversion;
4301 iterator->common.now = now;
4303 NODE_STRONGLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
4305 dns_rbtnode_refincrement(rbtnode, &refs);
4308 iterator->current = NULL;
4310 NODE_STRONGUNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
4312 *iteratorp = (dns_rdatasetiter_t *)iterator;
4314 return (ISC_R_SUCCESS);
4317 static isc_boolean_t
4318 cname_and_other_data(dns_rbtnode_t *node, rbtdb_serial_t serial) {
4319 rdatasetheader_t *header, *header_next;
4320 isc_boolean_t cname, other_data;
4321 dns_rdatatype_t rdtype;
4324 * The caller must hold the node lock.
4328 * Look for CNAME and "other data" rdatasets active in our version.
4331 other_data = ISC_FALSE;
4332 for (header = node->data; header != NULL; header = header_next) {
4333 header_next = header->next;
4334 if (header->type == dns_rdatatype_cname) {
4336 * Look for an active extant CNAME.
4339 if (header->serial <= serial &&
4342 * Is this a "this rdataset doesn't
4345 if (NONEXISTENT(header))
4349 header = header->down;
4350 } while (header != NULL);
4355 * Look for active extant "other data".
4357 * "Other data" is any rdataset whose type is not
4358 * KEY, RRSIG KEY, NSEC, RRSIG NSEC or RRSIG CNAME.
4360 rdtype = RBTDB_RDATATYPE_BASE(header->type);
4361 if (rdtype == dns_rdatatype_rrsig ||
4362 rdtype == dns_rdatatype_sig)
4363 rdtype = RBTDB_RDATATYPE_EXT(header->type);
4364 if (rdtype != dns_rdatatype_nsec &&
4365 rdtype != dns_rdatatype_key &&
4366 rdtype != dns_rdatatype_cname) {
4368 * We've found a type that isn't
4369 * NSEC, KEY, CNAME, or one of their
4370 * signatures. Is it active and extant?
4373 if (header->serial <= serial &&
4376 * Is this a "this rdataset
4377 * doesn't exist" record?
4379 if (NONEXISTENT(header))
4383 header = header->down;
4384 } while (header != NULL);
4386 other_data = ISC_TRUE;
4391 if (cname && other_data)
4398 add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
4399 rdatasetheader_t *newheader, unsigned int options, isc_boolean_t loading,
4400 dns_rdataset_t *addedrdataset, isc_stdtime_t now)
4402 rbtdb_changed_t *changed = NULL;
4403 rdatasetheader_t *topheader, *topheader_prev, *header;
4404 unsigned char *merged;
4405 isc_result_t result;
4406 isc_boolean_t header_nx;
4407 isc_boolean_t newheader_nx;
4408 isc_boolean_t merge;
4409 dns_rdatatype_t rdtype, covers;
4410 rbtdb_rdatatype_t negtype;
4414 * Add an rdatasetheader_t to a node.
4418 * Caller must be holding the node lock.
4421 if ((options & DNS_DBADD_MERGE) != 0) {
4422 REQUIRE(rbtversion != NULL);
4427 if ((options & DNS_DBADD_FORCE) != 0)
4428 trust = dns_trust_ultimate;
4430 trust = newheader->trust;
4432 if (rbtversion != NULL && !loading) {
4434 * We always add a changed record, even if no changes end up
4435 * being made to this node, because it's harmless and
4436 * simplifies the code.
4438 changed = add_changed(rbtdb, rbtversion, rbtnode);
4439 if (changed == NULL) {
4440 free_rdataset(rbtdb->common.mctx, newheader);
4441 return (ISC_R_NOMEMORY);
4445 newheader_nx = NONEXISTENT(newheader) ? ISC_TRUE : ISC_FALSE;
4446 topheader_prev = NULL;
4449 if (rbtversion == NULL && !newheader_nx) {
4450 rdtype = RBTDB_RDATATYPE_BASE(newheader->type);
4453 * We're adding a negative cache entry.
4455 covers = RBTDB_RDATATYPE_EXT(newheader->type);
4456 if (covers == dns_rdatatype_any) {
4458 * We're adding an negative cache entry
4459 * which covers all types (NXDOMAIN,
4460 * NODATA(QTYPE=ANY)).
4462 * We make all other data stale so that the
4463 * only rdataset that can be found at this
4464 * node is the negative cache entry.
4466 for (topheader = rbtnode->data;
4468 topheader = topheader->next) {
4470 topheader->attributes |=
4471 RDATASET_ATTR_STALE;
4476 negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
4479 * We're adding something that isn't a
4480 * negative cache entry. Look for an extant
4481 * non-stale NXDOMAIN/NODATA(QTYPE=ANY) negative
4484 for (topheader = rbtnode->data;
4486 topheader = topheader->next) {
4487 if (topheader->type ==
4488 RBTDB_RDATATYPE_NCACHEANY)
4491 if (topheader != NULL && EXISTS(topheader) &&
4492 topheader->ttl > now) {
4496 if (trust < topheader->trust) {
4498 * The NXDOMAIN/NODATA(QTYPE=ANY)
4502 free_rdataset(rbtdb->common.mctx,
4504 if (addedrdataset != NULL)
4505 bind_rdataset(rbtdb, rbtnode,
4508 return (DNS_R_UNCHANGED);
4511 * The new rdataset is better. Expire the
4512 * NXDOMAIN/NODATA(QTYPE=ANY).
4515 topheader->attributes |= RDATASET_ATTR_STALE;
4520 negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
4524 for (topheader = rbtnode->data;
4526 topheader = topheader->next) {
4527 if (topheader->type == newheader->type ||
4528 topheader->type == negtype)
4530 topheader_prev = topheader;
4535 * If header isn't NULL, we've found the right type. There may be
4536 * IGNORE rdatasets between the top of the chain and the first real
4537 * data. We skip over them.
4540 while (header != NULL && IGNORE(header))
4541 header = header->down;
4542 if (header != NULL) {
4543 header_nx = NONEXISTENT(header) ? ISC_TRUE : ISC_FALSE;
4546 * Deleting an already non-existent rdataset has no effect.
4548 if (header_nx && newheader_nx) {
4549 free_rdataset(rbtdb->common.mctx, newheader);
4550 return (DNS_R_UNCHANGED);
4554 * Trying to add an rdataset with lower trust to a cache DB
4555 * has no effect, provided that the cache data isn't stale.
4557 if (rbtversion == NULL && trust < header->trust &&
4558 (header->ttl > now || header_nx)) {
4559 free_rdataset(rbtdb->common.mctx, newheader);
4560 if (addedrdataset != NULL)
4561 bind_rdataset(rbtdb, rbtnode, header, now,
4563 return (DNS_R_UNCHANGED);
4567 * Don't merge if a nonexistent rdataset is involved.
4569 if (merge && (header_nx || newheader_nx))
4573 * If 'merge' is ISC_TRUE, we'll try to create a new rdataset
4574 * that is the union of 'newheader' and 'header'.
4577 unsigned int flags = 0;
4578 INSIST(rbtversion->serial >= header->serial);
4580 result = ISC_R_SUCCESS;
4582 if ((options & DNS_DBADD_EXACT) != 0)
4583 flags |= DNS_RDATASLAB_EXACT;
4584 if ((options & DNS_DBADD_EXACTTTL) != 0 &&
4585 newheader->ttl != header->ttl)
4586 result = DNS_R_NOTEXACT;
4587 else if (newheader->ttl != header->ttl)
4588 flags |= DNS_RDATASLAB_FORCE;
4589 if (result == ISC_R_SUCCESS)
4590 result = dns_rdataslab_merge(
4591 (unsigned char *)header,
4592 (unsigned char *)newheader,
4593 (unsigned int)(sizeof(*newheader)),
4595 rbtdb->common.rdclass,
4596 (dns_rdatatype_t)header->type,
4598 if (result == ISC_R_SUCCESS) {
4600 * If 'header' has the same serial number as
4601 * we do, we could clean it up now if we knew
4602 * that our caller had no references to it.
4603 * We don't know this, however, so we leave it
4604 * alone. It will get cleaned up when
4605 * clean_zone_node() runs.
4607 free_rdataset(rbtdb->common.mctx, newheader);
4608 newheader = (rdatasetheader_t *)merged;
4610 free_rdataset(rbtdb->common.mctx, newheader);
4615 * Don't replace existing NS, A and AAAA RRsets
4616 * in the cache if they are already exist. This
4617 * prevents named being locked to old servers.
4618 * Don't lower trust of existing record if the
4621 if (IS_CACHE(rbtdb) && header->ttl > now &&
4622 header->type == dns_rdatatype_ns &&
4623 !header_nx && !newheader_nx &&
4624 header->trust >= newheader->trust &&
4625 dns_rdataslab_equalx((unsigned char *)header,
4626 (unsigned char *)newheader,
4627 (unsigned int)(sizeof(*newheader)),
4628 rbtdb->common.rdclass,
4629 (dns_rdatatype_t)header->type)) {
4631 * Honour the new ttl if it is less than the
4634 if (header->ttl > newheader->ttl)
4635 header->ttl = newheader->ttl;
4636 if (header->noqname == NULL &&
4637 newheader->noqname != NULL) {
4638 header->noqname = newheader->noqname;
4639 newheader->noqname = NULL;
4641 free_rdataset(rbtdb->common.mctx, newheader);
4642 if (addedrdataset != NULL)
4643 bind_rdataset(rbtdb, rbtnode, header, now,
4645 return (ISC_R_SUCCESS);
4647 if (IS_CACHE(rbtdb) && header->ttl > now &&
4648 (header->type == dns_rdatatype_a ||
4649 header->type == dns_rdatatype_aaaa) &&
4650 !header_nx && !newheader_nx &&
4651 header->trust >= newheader->trust &&
4652 dns_rdataslab_equal((unsigned char *)header,
4653 (unsigned char *)newheader,
4654 (unsigned int)(sizeof(*newheader)))) {
4656 * Honour the new ttl if it is less than the
4659 if (header->ttl > newheader->ttl)
4660 header->ttl = newheader->ttl;
4661 if (header->noqname == NULL &&
4662 newheader->noqname != NULL) {
4663 header->noqname = newheader->noqname;
4664 newheader->noqname = NULL;
4666 free_rdataset(rbtdb->common.mctx, newheader);
4667 if (addedrdataset != NULL)
4668 bind_rdataset(rbtdb, rbtnode, header, now,
4670 return (ISC_R_SUCCESS);
4672 INSIST(rbtversion == NULL ||
4673 rbtversion->serial >= topheader->serial);
4674 if (topheader_prev != NULL)
4675 topheader_prev->next = newheader;
4677 rbtnode->data = newheader;
4678 newheader->next = topheader->next;
4681 * There are no other references to 'header' when
4682 * loading, so we MAY clean up 'header' now.
4683 * Since we don't generate changed records when
4684 * loading, we MUST clean up 'header' now.
4686 newheader->down = NULL;
4687 free_rdataset(rbtdb->common.mctx, header);
4689 newheader->down = topheader;
4690 topheader->next = newheader;
4692 if (changed != NULL)
4693 changed->dirty = ISC_TRUE;
4694 if (rbtversion == NULL) {
4696 header->attributes |= RDATASET_ATTR_STALE;
4701 * No non-IGNORED rdatasets of the given type exist at
4706 * If we're trying to delete the type, don't bother.
4709 free_rdataset(rbtdb->common.mctx, newheader);
4710 return (DNS_R_UNCHANGED);
4713 if (topheader != NULL) {
4715 * We have an list of rdatasets of the given type,
4716 * but they're all marked IGNORE. We simply insert
4717 * the new rdataset at the head of the list.
4719 * Ignored rdatasets cannot occur during loading, so
4723 INSIST(rbtversion == NULL ||
4724 rbtversion->serial >= topheader->serial);
4725 if (topheader_prev != NULL)
4726 topheader_prev->next = newheader;
4728 rbtnode->data = newheader;
4729 newheader->next = topheader->next;
4730 newheader->down = topheader;
4731 topheader->next = newheader;
4733 if (changed != NULL)
4734 changed->dirty = ISC_TRUE;
4737 * No rdatasets of the given type exist at the node.
4739 newheader->next = rbtnode->data;
4740 newheader->down = NULL;
4741 rbtnode->data = newheader;
4746 * Check if the node now contains CNAME and other data.
4748 if (rbtversion != NULL &&
4749 cname_and_other_data(rbtnode, rbtversion->serial))
4750 return (DNS_R_CNAMEANDOTHER);
4752 if (addedrdataset != NULL)
4753 bind_rdataset(rbtdb, rbtnode, newheader, now, addedrdataset);
4755 return (ISC_R_SUCCESS);
4758 static inline isc_boolean_t
4759 delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
4760 rbtdb_rdatatype_t type)
4762 if (IS_CACHE(rbtdb)) {
4763 if (type == dns_rdatatype_dname)
4767 } else if (type == dns_rdatatype_dname ||
4768 (type == dns_rdatatype_ns &&
4769 (node != rbtdb->origin_node || IS_STUB(rbtdb))))
4774 static inline isc_result_t
4775 addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
4776 dns_rdataset_t *rdataset)
4778 struct noqname *noqname;
4779 isc_mem_t *mctx = rbtdb->common.mctx;
4781 dns_rdataset_t nsec, nsecsig;
4782 isc_result_t result;
4785 dns_name_init(&name, NULL);
4786 dns_rdataset_init(&nsec);
4787 dns_rdataset_init(&nsecsig);
4789 result = dns_rdataset_getnoqname(rdataset, &name, &nsec, &nsecsig);
4790 RUNTIME_CHECK(result == ISC_R_SUCCESS);
4792 noqname = isc_mem_get(mctx, sizeof(*noqname));
4793 if (noqname == NULL) {
4794 result = ISC_R_NOMEMORY;
4797 dns_name_init(&noqname->name, NULL);
4798 noqname->nsec = NULL;
4799 noqname->nsecsig = NULL;
4800 result = dns_name_dup(&name, mctx, &noqname->name);
4801 if (result != ISC_R_SUCCESS)
4803 result = dns_rdataslab_fromrdataset(&nsec, mctx, &r, 0);
4804 if (result != ISC_R_SUCCESS)
4806 noqname->nsec = r.base;
4807 result = dns_rdataslab_fromrdataset(&nsecsig, mctx, &r, 0);
4808 if (result != ISC_R_SUCCESS)
4810 noqname->nsecsig = r.base;
4811 dns_rdataset_disassociate(&nsec);
4812 dns_rdataset_disassociate(&nsecsig);
4813 newheader->noqname = noqname;
4814 return (ISC_R_SUCCESS);
4817 dns_rdataset_disassociate(&nsec);
4818 dns_rdataset_disassociate(&nsecsig);
4819 free_noqname(mctx, &noqname);
4824 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
4825 isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
4826 dns_rdataset_t *addedrdataset)
4828 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
4829 dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
4830 rbtdb_version_t *rbtversion = version;
4831 isc_region_t region;
4832 rdatasetheader_t *newheader;
4833 isc_result_t result;
4834 isc_boolean_t delegating;
4836 REQUIRE(VALID_RBTDB(rbtdb));
4838 if (rbtversion == NULL) {
4840 isc_stdtime_get(&now);
4844 result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
4846 sizeof(rdatasetheader_t));
4847 if (result != ISC_R_SUCCESS)
4850 newheader = (rdatasetheader_t *)region.base;
4851 newheader->ttl = rdataset->ttl + now;
4852 newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
4854 newheader->attributes = 0;
4855 newheader->noqname = NULL;
4856 newheader->count = init_count++;
4857 newheader->trust = rdataset->trust;
4858 newheader->additional_auth = NULL;
4859 newheader->additional_glue = NULL;
4860 if (rbtversion != NULL) {
4861 newheader->serial = rbtversion->serial;
4864 newheader->serial = 1;
4865 if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
4866 newheader->attributes |= RDATASET_ATTR_NXDOMAIN;
4867 if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
4868 result = addnoqname(rbtdb, newheader, rdataset);
4869 if (result != ISC_R_SUCCESS) {
4870 free_rdataset(rbtdb->common.mctx, newheader);
4877 * If we're adding a delegation type (e.g. NS or DNAME for a zone,
4878 * just DNAME for the cache), then we need to set the callback bit
4879 * on the node, and to do that we must be holding an exclusive lock
4882 if (delegating_type(rbtdb, rbtnode, rdataset->type)) {
4883 delegating = ISC_TRUE;
4884 RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
4886 delegating = ISC_FALSE;
4888 NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
4889 isc_rwlocktype_write);
4891 result = add(rbtdb, rbtnode, rbtversion, newheader, options, ISC_FALSE,
4892 addedrdataset, now);
4893 if (result == ISC_R_SUCCESS && delegating)
4894 rbtnode->find_callback = 1;
4896 NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
4897 isc_rwlocktype_write);
4900 RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
4903 * Update the zone's secure status. If version is non-NULL
4904 * this is defered until closeversion() is called.
4906 if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
4907 rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
4913 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
4914 dns_rdataset_t *rdataset, unsigned int options,
4915 dns_rdataset_t *newrdataset)
4917 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
4918 dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
4919 rbtdb_version_t *rbtversion = version;
4920 rdatasetheader_t *topheader, *topheader_prev, *header, *newheader;
4921 unsigned char *subresult;
4922 isc_region_t region;
4923 isc_result_t result;
4924 rbtdb_changed_t *changed;
4926 REQUIRE(VALID_RBTDB(rbtdb));
4928 result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
4930 sizeof(rdatasetheader_t));
4931 if (result != ISC_R_SUCCESS)
4933 newheader = (rdatasetheader_t *)region.base;
4934 newheader->ttl = rdataset->ttl;
4935 newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
4937 newheader->attributes = 0;
4938 newheader->serial = rbtversion->serial;
4939 newheader->trust = 0;
4940 newheader->noqname = NULL;
4941 newheader->count = init_count++;
4942 newheader->additional_auth = NULL;
4943 newheader->additional_glue = NULL;
4945 NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
4946 isc_rwlocktype_write);
4948 changed = add_changed(rbtdb, rbtversion, rbtnode);
4949 if (changed == NULL) {
4950 free_rdataset(rbtdb->common.mctx, newheader);
4951 NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
4952 isc_rwlocktype_write);
4953 return (ISC_R_NOMEMORY);
4956 topheader_prev = NULL;
4957 for (topheader = rbtnode->data;
4959 topheader = topheader->next) {
4960 if (topheader->type == newheader->type)
4962 topheader_prev = topheader;
4965 * If header isn't NULL, we've found the right type. There may be
4966 * IGNORE rdatasets between the top of the chain and the first real
4967 * data. We skip over them.
4970 while (header != NULL && IGNORE(header))
4971 header = header->down;
4972 if (header != NULL && EXISTS(header)) {
4973 unsigned int flags = 0;
4975 result = ISC_R_SUCCESS;
4976 if ((options & DNS_DBSUB_EXACT) != 0) {
4977 flags |= DNS_RDATASLAB_EXACT;
4978 if (newheader->ttl != header->ttl)
4979 result = DNS_R_NOTEXACT;
4981 if (result == ISC_R_SUCCESS)
4982 result = dns_rdataslab_subtract(
4983 (unsigned char *)header,
4984 (unsigned char *)newheader,
4985 (unsigned int)(sizeof(*newheader)),
4987 rbtdb->common.rdclass,
4988 (dns_rdatatype_t)header->type,
4990 if (result == ISC_R_SUCCESS) {
4991 free_rdataset(rbtdb->common.mctx, newheader);
4992 newheader = (rdatasetheader_t *)subresult;
4994 * We have to set the serial since the rdataslab
4995 * subtraction routine copies the reserved portion of
4996 * header, not newheader.
4998 newheader->serial = rbtversion->serial;
5000 * XXXJT: dns_rdataslab_subtract() copied the pointers
5001 * to additional info. We need to clear these fields
5002 * to avoid having duplicated references.
5004 newheader->additional_auth = NULL;
5005 newheader->additional_glue = NULL;
5006 } else if (result == DNS_R_NXRRSET) {
5008 * This subtraction would remove all of the rdata;
5009 * add a nonexistent header instead.
5011 free_rdataset(rbtdb->common.mctx, newheader);
5012 newheader = isc_mem_get(rbtdb->common.mctx,
5013 sizeof(*newheader));
5014 if (newheader == NULL) {
5015 result = ISC_R_NOMEMORY;
5019 newheader->type = topheader->type;
5020 newheader->attributes = RDATASET_ATTR_NONEXISTENT;
5021 newheader->trust = 0;
5022 newheader->serial = rbtversion->serial;
5023 newheader->noqname = NULL;
5024 newheader->count = 0;
5025 newheader->additional_auth = NULL;
5026 newheader->additional_glue = NULL;
5028 free_rdataset(rbtdb->common.mctx, newheader);
5033 * If we're here, we want to link newheader in front of
5036 INSIST(rbtversion->serial >= topheader->serial);
5037 if (topheader_prev != NULL)
5038 topheader_prev->next = newheader;
5040 rbtnode->data = newheader;
5041 newheader->next = topheader->next;
5042 newheader->down = topheader;
5043 topheader->next = newheader;
5045 changed->dirty = ISC_TRUE;
5048 * The rdataset doesn't exist, so we don't need to do anything
5049 * to satisfy the deletion request.
5051 free_rdataset(rbtdb->common.mctx, newheader);
5052 if ((options & DNS_DBSUB_EXACT) != 0)
5053 result = DNS_R_NOTEXACT;
5055 result = DNS_R_UNCHANGED;
5058 if (result == ISC_R_SUCCESS && newrdataset != NULL)
5059 bind_rdataset(rbtdb, rbtnode, newheader, 0, newrdataset);
5062 NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
5063 isc_rwlocktype_write);
5066 * Update the zone's secure status. If version is non-NULL
5067 * this is defered until closeversion() is called.
5069 if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
5070 rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
5076 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
5077 dns_rdatatype_t type, dns_rdatatype_t covers)
5079 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
5080 dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
5081 rbtdb_version_t *rbtversion = version;
5082 isc_result_t result;
5083 rdatasetheader_t *newheader;
5085 REQUIRE(VALID_RBTDB(rbtdb));
5087 if (type == dns_rdatatype_any)
5088 return (ISC_R_NOTIMPLEMENTED);
5089 if (type == dns_rdatatype_rrsig && covers == 0)
5090 return (ISC_R_NOTIMPLEMENTED);
5092 newheader = isc_mem_get(rbtdb->common.mctx, sizeof(*newheader));
5093 if (newheader == NULL)
5094 return (ISC_R_NOMEMORY);
5096 newheader->type = RBTDB_RDATATYPE_VALUE(type, covers);
5097 newheader->attributes = RDATASET_ATTR_NONEXISTENT;
5098 newheader->trust = 0;
5099 newheader->noqname = NULL;
5100 newheader->additional_auth = NULL;
5101 newheader->additional_glue = NULL;
5102 if (rbtversion != NULL)
5103 newheader->serial = rbtversion->serial;
5105 newheader->serial = 0;
5106 newheader->count = 0;
5108 NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
5109 isc_rwlocktype_write);
5111 result = add(rbtdb, rbtnode, rbtversion, newheader, DNS_DBADD_FORCE,
5112 ISC_FALSE, NULL, 0);
5114 NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
5115 isc_rwlocktype_write);
5118 * Update the zone's secure status. If version is non-NULL
5119 * this is defered until closeversion() is called.
5121 if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
5122 rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
5128 loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) {
5129 rbtdb_load_t *loadctx = arg;
5130 dns_rbtdb_t *rbtdb = loadctx->rbtdb;
5131 dns_rbtnode_t *node;
5132 isc_result_t result;
5133 isc_region_t region;
5134 rdatasetheader_t *newheader;
5137 * This routine does no node locking. See comments in
5138 * 'load' below for more information on loading and
5144 * SOA records are only allowed at top of zone.
5146 if (rdataset->type == dns_rdatatype_soa &&
5147 !IS_CACHE(rbtdb) && !dns_name_equal(name, &rbtdb->common.origin))
5148 return (DNS_R_NOTZONETOP);
5150 add_empty_wildcards(rbtdb, name);
5152 if (dns_name_iswildcard(name)) {
5154 * NS record owners cannot legally be wild cards.
5156 if (rdataset->type == dns_rdatatype_ns)
5157 return (DNS_R_INVALIDNS);
5158 result = add_wildcard_magic(rbtdb, name);
5159 if (result != ISC_R_SUCCESS)
5164 result = dns_rbt_addnode(rbtdb->tree, name, &node);
5165 if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
5167 if (result != ISC_R_EXISTS) {
5168 dns_name_t foundname;
5169 dns_name_init(&foundname, NULL);
5170 dns_rbt_namefromnode(node, &foundname);
5171 #ifdef DNS_RBT_USEHASH
5172 node->locknum = node->hashval % rbtdb->node_lock_count;
5174 node->locknum = dns_name_hash(&foundname, ISC_TRUE) %
5175 rbtdb->node_lock_count;
5179 result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
5181 sizeof(rdatasetheader_t));
5182 if (result != ISC_R_SUCCESS)
5184 newheader = (rdatasetheader_t *)region.base;
5185 newheader->ttl = rdataset->ttl + loadctx->now; /* XXX overflow check */
5186 newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
5188 newheader->attributes = 0;
5189 newheader->trust = rdataset->trust;
5190 newheader->serial = 1;
5191 newheader->noqname = NULL;
5192 newheader->count = init_count++;
5193 newheader->additional_auth = NULL;
5194 newheader->additional_glue = NULL;
5196 result = add(rbtdb, node, rbtdb->current_version, newheader,
5197 DNS_DBADD_MERGE, ISC_TRUE, NULL, 0);
5198 if (result == ISC_R_SUCCESS &&
5199 delegating_type(rbtdb, node, rdataset->type))
5200 node->find_callback = 1;
5201 else if (result == DNS_R_UNCHANGED)
5202 result = ISC_R_SUCCESS;
5208 beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
5209 rbtdb_load_t *loadctx;
5212 rbtdb = (dns_rbtdb_t *)db;
5214 REQUIRE(VALID_RBTDB(rbtdb));
5216 loadctx = isc_mem_get(rbtdb->common.mctx, sizeof(*loadctx));
5217 if (loadctx == NULL)
5218 return (ISC_R_NOMEMORY);
5220 loadctx->rbtdb = rbtdb;
5221 if (IS_CACHE(rbtdb))
5222 isc_stdtime_get(&loadctx->now);
5226 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
5228 REQUIRE((rbtdb->attributes & (RBTDB_ATTR_LOADED|RBTDB_ATTR_LOADING))
5230 rbtdb->attributes |= RBTDB_ATTR_LOADING;
5232 RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
5234 *addp = loading_addrdataset;
5237 return (ISC_R_SUCCESS);
5241 endload(dns_db_t *db, dns_dbload_t **dbloadp) {
5242 rbtdb_load_t *loadctx;
5243 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
5245 REQUIRE(VALID_RBTDB(rbtdb));
5246 REQUIRE(dbloadp != NULL);
5248 REQUIRE(loadctx->rbtdb == rbtdb);
5250 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
5252 REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADING) != 0);
5253 REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADED) == 0);
5255 rbtdb->attributes &= ~RBTDB_ATTR_LOADING;
5256 rbtdb->attributes |= RBTDB_ATTR_LOADED;
5258 RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
5261 * If there's a KEY rdataset at the zone origin containing a
5262 * zone key, we consider the zone secure.
5264 if (! IS_CACHE(rbtdb))
5265 rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
5269 isc_mem_put(rbtdb->common.mctx, loadctx, sizeof(*loadctx));
5271 return (ISC_R_SUCCESS);
5275 dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
5276 dns_masterformat_t masterformat) {
5279 rbtdb = (dns_rbtdb_t *)db;
5281 REQUIRE(VALID_RBTDB(rbtdb));
5283 return (dns_master_dump2(rbtdb->common.mctx, db, version,
5284 &dns_master_style_default,
5285 filename, masterformat));
5289 delete_callback(void *data, void *arg) {
5290 dns_rbtdb_t *rbtdb = arg;
5291 rdatasetheader_t *current, *next;
5293 for (current = data; current != NULL; current = next) {
5294 next = current->next;
5295 free_rdataset(rbtdb->common.mctx, current);
5299 static isc_boolean_t
5300 issecure(dns_db_t *db) {
5302 isc_boolean_t secure;
5304 rbtdb = (dns_rbtdb_t *)db;
5306 REQUIRE(VALID_RBTDB(rbtdb));
5308 RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
5309 secure = rbtdb->secure;
5310 RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
5316 nodecount(dns_db_t *db) {
5320 rbtdb = (dns_rbtdb_t *)db;
5322 REQUIRE(VALID_RBTDB(rbtdb));
5324 RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
5325 count = dns_rbt_nodecount(rbtdb->tree);
5326 RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
5332 settask(dns_db_t *db, isc_task_t *task) {
5335 rbtdb = (dns_rbtdb_t *)db;
5337 REQUIRE(VALID_RBTDB(rbtdb));
5339 RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
5340 if (rbtdb->task != NULL)
5341 isc_task_detach(&rbtdb->task);
5343 isc_task_attach(task, &rbtdb->task);
5344 RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
5347 static isc_boolean_t
5348 ispersistent(dns_db_t *db) {
5354 getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
5355 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
5356 dns_rbtnode_t *onode;
5357 isc_result_t result = ISC_R_SUCCESS;
5359 REQUIRE(VALID_RBTDB(rbtdb));
5360 REQUIRE(nodep != NULL && *nodep == NULL);
5362 /* Note that the access to origin_node doesn't require a DB lock */
5363 onode = (dns_rbtnode_t *)rbtdb->origin_node;
5364 if (onode != NULL) {
5365 NODE_STRONGLOCK(&rbtdb->node_locks[onode->locknum].lock);
5366 new_reference(rbtdb, onode);
5367 NODE_STRONGUNLOCK(&rbtdb->node_locks[onode->locknum].lock);
5369 *nodep = rbtdb->origin_node;
5371 INSIST(!IS_CACHE(rbtdb));
5372 result = ISC_R_NOTFOUND;
5378 static dns_dbmethods_t zone_methods = {
5409 static dns_dbmethods_t cache_methods = {
5441 #ifdef DNS_RBTDB_VERSION64
5446 (isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
5447 dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
5448 void *driverarg, dns_db_t **dbp)
5451 isc_result_t result;
5455 /* Keep the compiler happy. */
5460 rbtdb = isc_mem_get(mctx, sizeof(*rbtdb));
5462 return (ISC_R_NOMEMORY);
5464 memset(rbtdb, '\0', sizeof(*rbtdb));
5465 dns_name_init(&rbtdb->common.origin, NULL);
5466 rbtdb->common.attributes = 0;
5467 if (type == dns_dbtype_cache) {
5468 rbtdb->common.methods = &cache_methods;
5469 rbtdb->common.attributes |= DNS_DBATTR_CACHE;
5470 } else if (type == dns_dbtype_stub) {
5471 rbtdb->common.methods = &zone_methods;
5472 rbtdb->common.attributes |= DNS_DBATTR_STUB;
5474 rbtdb->common.methods = &zone_methods;
5475 rbtdb->common.rdclass = rdclass;
5476 rbtdb->common.mctx = NULL;
5478 result = RBTDB_INITLOCK(&rbtdb->lock);
5479 if (result != ISC_R_SUCCESS)
5482 result = isc_rwlock_init(&rbtdb->tree_lock, 0, 0);
5483 if (result != ISC_R_SUCCESS)
5486 if (rbtdb->node_lock_count == 0) {
5487 if (IS_CACHE(rbtdb))
5488 rbtdb->node_lock_count = DEFAULT_CACHE_NODE_LOCK_COUNT;
5490 rbtdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT;
5492 INSIST(rbtdb->node_lock_count < (1 << DNS_RBT_LOCKLENGTH));
5493 rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count *
5494 sizeof(rbtdb_nodelock_t));
5495 if (rbtdb->node_locks == NULL) {
5496 result = ISC_R_NOMEMORY;
5497 goto cleanup_tree_lock;
5500 rbtdb->active = rbtdb->node_lock_count;
5502 for (i = 0; i < (int)(rbtdb->node_lock_count); i++) {
5503 result = NODE_INITLOCK(&rbtdb->node_locks[i].lock);
5504 if (result == ISC_R_SUCCESS) {
5505 result = isc_refcount_init(&rbtdb->node_locks[i].references, 0);
5506 if (result != ISC_R_SUCCESS)
5507 NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
5509 if (result != ISC_R_SUCCESS) {
5511 NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
5512 isc_refcount_decrement(&rbtdb->node_locks[i].references, NULL);
5513 isc_refcount_destroy(&rbtdb->node_locks[i].references);
5515 goto cleanup_node_locks;
5517 rbtdb->node_locks[i].exiting = ISC_FALSE;
5521 * Attach to the mctx. The database will persist so long as there
5522 * are references to it, and attaching to the mctx ensures that our
5523 * mctx won't disappear out from under us.
5525 isc_mem_attach(mctx, &rbtdb->common.mctx);
5528 * Must be initalized before free_rbtdb() is called.
5530 isc_ondestroy_init(&rbtdb->common.ondest);
5533 * Make a copy of the origin name.
5535 result = dns_name_dupwithoffsets(origin, mctx, &rbtdb->common.origin);
5536 if (result != ISC_R_SUCCESS) {
5537 free_rbtdb(rbtdb, ISC_FALSE, NULL);
5542 * Make the Red-Black Tree.
5544 result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree);
5545 if (result != ISC_R_SUCCESS) {
5546 free_rbtdb(rbtdb, ISC_FALSE, NULL);
5550 * In order to set the node callback bit correctly in zone databases,
5551 * we need to know if the node has the origin name of the zone.
5552 * In loading_addrdataset() we could simply compare the new name
5553 * to the origin name, but this is expensive. Also, we don't know the
5554 * node name in addrdataset(), so we need another way of knowing the
5557 * We now explicitly create a node for the zone's origin, and then
5558 * we simply remember the node's address. This is safe, because
5559 * the top-of-zone node can never be deleted, nor can its address
5562 if (!IS_CACHE(rbtdb)) {
5563 rbtdb->origin_node = NULL;
5564 result = dns_rbt_addnode(rbtdb->tree, &rbtdb->common.origin,
5565 &rbtdb->origin_node);
5566 if (result != ISC_R_SUCCESS) {
5567 INSIST(result != ISC_R_EXISTS);
5568 free_rbtdb(rbtdb, ISC_FALSE, NULL);
5572 * We need to give the origin node the right locknum.
5574 dns_name_init(&name, NULL);
5575 dns_rbt_namefromnode(rbtdb->origin_node, &name);
5576 #ifdef DNS_RBT_USEHASH
5577 rbtdb->origin_node->locknum =
5578 rbtdb->origin_node->hashval %
5579 rbtdb->node_lock_count;
5581 rbtdb->origin_node->locknum =
5582 dns_name_hash(&name, ISC_TRUE) %
5583 rbtdb->node_lock_count;
5588 * Misc. Initialization.
5590 result = isc_refcount_init(&rbtdb->references, 1);
5591 if (result != ISC_R_SUCCESS) {
5592 free_rbtdb(rbtdb, ISC_FALSE, NULL);
5595 rbtdb->attributes = 0;
5596 rbtdb->secure = ISC_FALSE;
5597 rbtdb->overmem = ISC_FALSE;
5601 * Version Initialization.
5603 rbtdb->current_serial = 1;
5604 rbtdb->least_serial = 1;
5605 rbtdb->next_serial = 2;
5606 rbtdb->current_version = allocate_version(mctx, 1, 1, ISC_FALSE);
5607 if (rbtdb->current_version == NULL) {
5608 isc_refcount_decrement(&rbtdb->references, NULL);
5609 isc_refcount_destroy(&rbtdb->references);
5610 free_rbtdb(rbtdb, ISC_FALSE, NULL);
5611 return (ISC_R_NOMEMORY);
5613 rbtdb->future_version = NULL;
5614 ISC_LIST_INIT(rbtdb->open_versions);
5616 * Keep the current version in the open list so that list operation
5617 * won't happen in normal lookup operations.
5619 PREPEND(rbtdb->open_versions, rbtdb->current_version, link);
5621 rbtdb->common.magic = DNS_DB_MAGIC;
5622 rbtdb->common.impmagic = RBTDB_MAGIC;
5624 *dbp = (dns_db_t *)rbtdb;
5626 return (ISC_R_SUCCESS);
5629 isc_mem_put(mctx, rbtdb->node_locks,
5630 rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));
5633 isc_rwlock_destroy(&rbtdb->tree_lock);
5636 RBTDB_DESTROYLOCK(&rbtdb->lock);
5639 isc_mem_put(mctx, rbtdb, sizeof(*rbtdb));
5645 * Slabbed Rdataset Methods
5649 rdataset_disassociate(dns_rdataset_t *rdataset) {
5650 dns_db_t *db = rdataset->private1;
5651 dns_dbnode_t *node = rdataset->private2;
5653 detachnode(db, &node);
5657 rdataset_first(dns_rdataset_t *rdataset) {
5658 unsigned char *raw = rdataset->private3; /* RDATASLAB */
5661 count = raw[0] * 256 + raw[1];
5663 rdataset->private5 = NULL;
5664 return (ISC_R_NOMORE);
5667 #if DNS_RDATASET_FIXED
5668 if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0)
5669 raw += 2 + (4 * count);
5675 * The privateuint4 field is the number of rdata beyond the
5676 * cursor position, so we decrement the total count by one
5677 * before storing it.
5679 * If DNS_RDATASETATTR_LOADORDER is not set 'raw' points to the
5680 * first record. If DNS_RDATASETATTR_LOADORDER is set 'raw' points
5681 * to the first entry in the offset table.
5684 rdataset->privateuint4 = count;
5685 rdataset->private5 = raw;
5687 return (ISC_R_SUCCESS);
5691 rdataset_next(dns_rdataset_t *rdataset) {
5693 unsigned int length;
5694 unsigned char *raw; /* RDATASLAB */
5696 count = rdataset->privateuint4;
5698 return (ISC_R_NOMORE);
5700 rdataset->privateuint4 = count;
5703 * Skip forward one record (length + 4) or one offset (4).
5705 raw = rdataset->private5;
5706 #if DNS_RDATASET_FIXED
5707 if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0) {
5709 length = raw[0] * 256 + raw[1];
5711 #if DNS_RDATASET_FIXED
5713 rdataset->private5 = raw + 4; /* length(2) + order(2) */
5715 rdataset->private5 = raw + 2; /* length(2) */
5718 return (ISC_R_SUCCESS);
5722 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
5723 unsigned char *raw = rdataset->private5; /* RDATASLAB */
5724 #if DNS_RDATASET_FIXED
5725 unsigned int offset;
5729 REQUIRE(raw != NULL);
5732 * Find the start of the record if not already in private5
5733 * then skip the length and order fields.
5735 #if DNS_RDATASET_FIXED
5736 if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) != 0) {
5737 offset = (raw[0] << 24) + (raw[1] << 16) +
5738 (raw[2] << 8) + raw[3];
5739 raw = rdataset->private3;
5743 r.length = raw[0] * 256 + raw[1];
5745 #if DNS_RDATASET_FIXED
5751 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
5755 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
5756 dns_db_t *db = source->private1;
5757 dns_dbnode_t *node = source->private2;
5758 dns_dbnode_t *cloned_node = NULL;
5760 attachnode(db, node, &cloned_node);
5764 * Reset iterator state.
5766 target->privateuint4 = 0;
5767 target->private5 = NULL;
5771 rdataset_count(dns_rdataset_t *rdataset) {
5772 unsigned char *raw = rdataset->private3; /* RDATASLAB */
5775 count = raw[0] * 256 + raw[1];
5781 rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
5782 dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
5784 dns_db_t *db = rdataset->private1;
5785 dns_dbnode_t *node = rdataset->private2;
5786 dns_dbnode_t *cloned_node;
5787 struct noqname *noqname = rdataset->private6;
5790 attachnode(db, node, &cloned_node);
5791 nsec->methods = &rdataset_methods;
5792 nsec->rdclass = db->rdclass;
5793 nsec->type = dns_rdatatype_nsec;
5795 nsec->ttl = rdataset->ttl;
5796 nsec->trust = rdataset->trust;
5797 nsec->private1 = rdataset->private1;
5798 nsec->private2 = rdataset->private2;
5799 nsec->private3 = noqname->nsec;
5800 nsec->privateuint4 = 0;
5801 nsec->private5 = NULL;
5802 nsec->private6 = NULL;
5805 attachnode(db, node, &cloned_node);
5806 nsecsig->methods = &rdataset_methods;
5807 nsecsig->rdclass = db->rdclass;
5808 nsecsig->type = dns_rdatatype_rrsig;
5809 nsecsig->covers = dns_rdatatype_nsec;
5810 nsecsig->ttl = rdataset->ttl;
5811 nsecsig->trust = rdataset->trust;
5812 nsecsig->private1 = rdataset->private1;
5813 nsecsig->private2 = rdataset->private2;
5814 nsecsig->private3 = noqname->nsecsig;
5815 nsecsig->privateuint4 = 0;
5816 nsecsig->private5 = NULL;
5817 nsec->private6 = NULL;
5819 dns_name_clone(&noqname->name, name);
5821 return (ISC_R_SUCCESS);
5825 * Rdataset Iterator Methods
5829 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
5830 rbtdb_rdatasetiter_t *rbtiterator;
5832 rbtiterator = (rbtdb_rdatasetiter_t *)(*iteratorp);
5834 if (rbtiterator->common.version != NULL)
5835 closeversion(rbtiterator->common.db,
5836 &rbtiterator->common.version, ISC_FALSE);
5837 detachnode(rbtiterator->common.db, &rbtiterator->common.node);
5838 isc_mem_put(rbtiterator->common.db->mctx, rbtiterator,
5839 sizeof(*rbtiterator));
5845 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
5846 rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
5847 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
5848 dns_rbtnode_t *rbtnode = rbtiterator->common.node;
5849 rbtdb_version_t *rbtversion = rbtiterator->common.version;
5850 rdatasetheader_t *header, *top_next;
5851 rbtdb_serial_t serial;
5854 if (IS_CACHE(rbtdb)) {
5856 now = rbtiterator->common.now;
5858 serial = rbtversion->serial;
5862 NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
5863 isc_rwlocktype_read);
5865 for (header = rbtnode->data; header != NULL; header = top_next) {
5866 top_next = header->next;
5868 if (header->serial <= serial && !IGNORE(header)) {
5870 * Is this a "this rdataset doesn't exist"
5871 * record? Or is it too old in the cache?
5873 * Note: unlike everywhere else, we
5874 * check for now > header->ttl instead
5875 * of now >= header->ttl. This allows
5876 * ANY and RRSIG queries for 0 TTL
5877 * rdatasets to work.
5879 if (NONEXISTENT(header) ||
5880 (now != 0 && now > header->ttl))
5884 header = header->down;
5885 } while (header != NULL);
5890 NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
5891 isc_rwlocktype_read);
5893 rbtiterator->current = header;
5896 return (ISC_R_NOMORE);
5898 return (ISC_R_SUCCESS);
5902 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
5903 rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
5904 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
5905 dns_rbtnode_t *rbtnode = rbtiterator->common.node;
5906 rbtdb_version_t *rbtversion = rbtiterator->common.version;
5907 rdatasetheader_t *header, *top_next;
5908 rbtdb_serial_t serial;
5910 rbtdb_rdatatype_t type, negtype;
5911 dns_rdatatype_t rdtype, covers;
5913 header = rbtiterator->current;
5915 return (ISC_R_NOMORE);
5917 if (IS_CACHE(rbtdb)) {
5919 now = rbtiterator->common.now;
5921 serial = rbtversion->serial;
5925 NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
5926 isc_rwlocktype_read);
5928 type = header->type;
5929 rdtype = RBTDB_RDATATYPE_BASE(header->type);
5931 covers = RBTDB_RDATATYPE_EXT(header->type);
5932 negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
5934 negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
5935 for (header = header->next; header != NULL; header = top_next) {
5936 top_next = header->next;
5938 * If not walking back up the down list.
5940 if (header->type != type && header->type != negtype) {
5942 if (header->serial <= serial &&
5945 * Is this a "this rdataset doesn't
5948 * Note: unlike everywhere else, we
5949 * check for now > header->ttl instead
5950 * of now >= header->ttl. This allows
5951 * ANY and RRSIG queries for 0 TTL
5952 * rdatasets to work.
5954 if ((header->attributes &
5955 RDATASET_ATTR_NONEXISTENT) != 0 ||
5956 (now != 0 && now > header->ttl))
5960 header = header->down;
5961 } while (header != NULL);
5967 NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
5968 isc_rwlocktype_read);
5970 rbtiterator->current = header;
5973 return (ISC_R_NOMORE);
5975 return (ISC_R_SUCCESS);
5979 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
5980 rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
5981 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
5982 dns_rbtnode_t *rbtnode = rbtiterator->common.node;
5983 rdatasetheader_t *header;
5985 header = rbtiterator->current;
5986 REQUIRE(header != NULL);
5988 NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
5989 isc_rwlocktype_read);
5991 bind_rdataset(rbtdb, rbtnode, header, rbtiterator->common.now,
5994 NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
5995 isc_rwlocktype_read);
6000 * Database Iterator Methods
6004 reference_iter_node(rbtdb_dbiterator_t *rbtdbiter) {
6005 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
6006 dns_rbtnode_t *node = rbtdbiter->node;
6011 INSIST(rbtdbiter->tree_locked != isc_rwlocktype_none);
6012 NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
6013 new_reference(rbtdb, node);
6014 NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
6018 dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter) {
6019 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
6020 dns_rbtnode_t *node = rbtdbiter->node;
6026 lock = &rbtdb->node_locks[node->locknum].lock;
6027 NODE_LOCK(lock, isc_rwlocktype_read);
6028 decrement_reference(rbtdb, node, 0, isc_rwlocktype_read,
6029 rbtdbiter->tree_locked);
6030 NODE_UNLOCK(lock, isc_rwlocktype_read);
6032 rbtdbiter->node = NULL;
6036 flush_deletions(rbtdb_dbiterator_t *rbtdbiter) {
6037 dns_rbtnode_t *node;
6038 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
6039 isc_boolean_t was_read_locked = ISC_FALSE;
6043 if (rbtdbiter->delete != 0) {
6045 * Note that "%d node of %d in tree" can report things like
6046 * "flush_deletions: 59 nodes of 41 in tree". This means
6047 * That some nodes appear on the deletions list more than
6048 * once. Only the last occurence will actually be deleted.
6050 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
6051 DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
6052 "flush_deletions: %d nodes of %d in tree",
6054 dns_rbt_nodecount(rbtdb->tree));
6056 if (rbtdbiter->tree_locked == isc_rwlocktype_read) {
6057 RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
6058 was_read_locked = ISC_TRUE;
6060 RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
6061 rbtdbiter->tree_locked = isc_rwlocktype_write;
6063 for (i = 0; i < rbtdbiter->delete; i++) {
6064 node = rbtdbiter->deletions[i];
6065 lock = &rbtdb->node_locks[node->locknum].lock;
6067 NODE_LOCK(lock, isc_rwlocktype_read);
6068 decrement_reference(rbtdb, node, 0,
6069 isc_rwlocktype_read,
6070 rbtdbiter->tree_locked);
6071 NODE_UNLOCK(lock, isc_rwlocktype_read);
6074 rbtdbiter->delete = 0;
6076 RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
6077 if (was_read_locked) {
6078 RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
6079 rbtdbiter->tree_locked = isc_rwlocktype_read;
6082 rbtdbiter->tree_locked = isc_rwlocktype_none;
6088 resume_iteration(rbtdb_dbiterator_t *rbtdbiter) {
6089 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
6091 REQUIRE(rbtdbiter->paused);
6092 REQUIRE(rbtdbiter->tree_locked == isc_rwlocktype_none);
6094 RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
6095 rbtdbiter->tree_locked = isc_rwlocktype_read;
6097 rbtdbiter->paused = ISC_FALSE;
6101 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
6102 rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)(*iteratorp);
6103 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
6104 dns_db_t *db = NULL;
6106 if (rbtdbiter->tree_locked == isc_rwlocktype_read) {
6107 RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
6108 rbtdbiter->tree_locked = isc_rwlocktype_none;
6110 INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none);
6112 dereference_iter_node(rbtdbiter);
6114 flush_deletions(rbtdbiter);
6116 dns_db_attach(rbtdbiter->common.db, &db);
6117 dns_db_detach(&rbtdbiter->common.db);
6119 dns_rbtnodechain_reset(&rbtdbiter->chain);
6120 isc_mem_put(db->mctx, rbtdbiter, sizeof(*rbtdbiter));
6127 dbiterator_first(dns_dbiterator_t *iterator) {
6128 isc_result_t result;
6129 rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
6130 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
6131 dns_name_t *name, *origin;
6133 if (rbtdbiter->result != ISC_R_SUCCESS &&
6134 rbtdbiter->result != ISC_R_NOMORE)
6135 return (rbtdbiter->result);
6137 if (rbtdbiter->paused)
6138 resume_iteration(rbtdbiter);
6140 dereference_iter_node(rbtdbiter);
6142 name = dns_fixedname_name(&rbtdbiter->name);
6143 origin = dns_fixedname_name(&rbtdbiter->origin);
6144 dns_rbtnodechain_reset(&rbtdbiter->chain);
6146 result = dns_rbtnodechain_first(&rbtdbiter->chain, rbtdb->tree, name,
6149 if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
6150 result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
6151 NULL, &rbtdbiter->node);
6152 if (result == ISC_R_SUCCESS) {
6153 rbtdbiter->new_origin = ISC_TRUE;
6154 reference_iter_node(rbtdbiter);
6157 INSIST(result == ISC_R_NOTFOUND);
6158 result = ISC_R_NOMORE; /* The tree is empty. */
6161 rbtdbiter->result = result;
6167 dbiterator_last(dns_dbiterator_t *iterator) {
6168 isc_result_t result;
6169 rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
6170 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
6171 dns_name_t *name, *origin;
6173 if (rbtdbiter->result != ISC_R_SUCCESS &&
6174 rbtdbiter->result != ISC_R_NOMORE)
6175 return (rbtdbiter->result);
6177 if (rbtdbiter->paused)
6178 resume_iteration(rbtdbiter);
6180 dereference_iter_node(rbtdbiter);
6182 name = dns_fixedname_name(&rbtdbiter->name);
6183 origin = dns_fixedname_name(&rbtdbiter->origin);
6184 dns_rbtnodechain_reset(&rbtdbiter->chain);
6186 result = dns_rbtnodechain_last(&rbtdbiter->chain, rbtdb->tree, name,
6188 if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
6189 result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
6190 NULL, &rbtdbiter->node);
6191 if (result == ISC_R_SUCCESS) {
6192 rbtdbiter->new_origin = ISC_TRUE;
6193 reference_iter_node(rbtdbiter);
6196 INSIST(result == ISC_R_NOTFOUND);
6197 result = ISC_R_NOMORE; /* The tree is empty. */
6200 rbtdbiter->result = result;
6206 dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
6207 isc_result_t result;
6208 rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
6209 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
6210 dns_name_t *iname, *origin;
6212 if (rbtdbiter->result != ISC_R_SUCCESS &&
6213 rbtdbiter->result != ISC_R_NOMORE)
6214 return (rbtdbiter->result);
6216 if (rbtdbiter->paused)
6217 resume_iteration(rbtdbiter);
6219 dereference_iter_node(rbtdbiter);
6221 iname = dns_fixedname_name(&rbtdbiter->name);
6222 origin = dns_fixedname_name(&rbtdbiter->origin);
6223 dns_rbtnodechain_reset(&rbtdbiter->chain);
6225 result = dns_rbt_findnode(rbtdb->tree, name, NULL, &rbtdbiter->node,
6226 &rbtdbiter->chain, DNS_RBTFIND_EMPTYDATA,
6228 if (result == ISC_R_SUCCESS) {
6229 result = dns_rbtnodechain_current(&rbtdbiter->chain, iname,
6231 if (result == ISC_R_SUCCESS) {
6232 rbtdbiter->new_origin = ISC_TRUE;
6233 reference_iter_node(rbtdbiter);
6236 } else if (result == DNS_R_PARTIALMATCH)
6237 result = ISC_R_NOTFOUND;
6239 rbtdbiter->result = result;
6245 dbiterator_prev(dns_dbiterator_t *iterator) {
6246 isc_result_t result;
6247 rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
6248 dns_name_t *name, *origin;
6250 REQUIRE(rbtdbiter->node != NULL);
6252 if (rbtdbiter->result != ISC_R_SUCCESS)
6253 return (rbtdbiter->result);
6255 if (rbtdbiter->paused)
6256 resume_iteration(rbtdbiter);
6258 name = dns_fixedname_name(&rbtdbiter->name);
6259 origin = dns_fixedname_name(&rbtdbiter->origin);
6260 result = dns_rbtnodechain_prev(&rbtdbiter->chain, name, origin);
6262 dereference_iter_node(rbtdbiter);
6264 if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
6265 rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN);
6266 result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
6267 NULL, &rbtdbiter->node);
6270 if (result == ISC_R_SUCCESS)
6271 reference_iter_node(rbtdbiter);
6273 rbtdbiter->result = result;
6279 dbiterator_next(dns_dbiterator_t *iterator) {
6280 isc_result_t result;
6281 rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
6282 dns_name_t *name, *origin;
6284 REQUIRE(rbtdbiter->node != NULL);
6286 if (rbtdbiter->result != ISC_R_SUCCESS)
6287 return (rbtdbiter->result);
6289 if (rbtdbiter->paused)
6290 resume_iteration(rbtdbiter);
6292 name = dns_fixedname_name(&rbtdbiter->name);
6293 origin = dns_fixedname_name(&rbtdbiter->origin);
6294 result = dns_rbtnodechain_next(&rbtdbiter->chain, name, origin);
6296 dereference_iter_node(rbtdbiter);
6298 if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
6299 rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN);
6300 result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
6301 NULL, &rbtdbiter->node);
6303 if (result == ISC_R_SUCCESS)
6304 reference_iter_node(rbtdbiter);
6306 rbtdbiter->result = result;
6312 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
6315 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
6316 rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
6317 dns_rbtnode_t *node = rbtdbiter->node;
6318 isc_result_t result;
6319 dns_name_t *nodename = dns_fixedname_name(&rbtdbiter->name);
6320 dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin);
6322 REQUIRE(rbtdbiter->result == ISC_R_SUCCESS);
6323 REQUIRE(rbtdbiter->node != NULL);
6325 if (rbtdbiter->paused)
6326 resume_iteration(rbtdbiter);
6329 if (rbtdbiter->common.relative_names)
6331 result = dns_name_concatenate(nodename, origin, name, NULL);
6332 if (result != ISC_R_SUCCESS)
6334 if (rbtdbiter->common.relative_names && rbtdbiter->new_origin)
6335 result = DNS_R_NEWORIGIN;
6337 result = ISC_R_SUCCESS;
6339 NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
6340 new_reference(rbtdb, node);
6341 NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
6343 *nodep = rbtdbiter->node;
6345 if (iterator->cleaning && result == ISC_R_SUCCESS) {
6346 isc_result_t expire_result;
6349 * If the deletion array is full, flush it before trying
6350 * to expire the current node. The current node can't
6351 * fully deleted while the iteration cursor is still on it.
6353 if (rbtdbiter->delete == DELETION_BATCH_MAX)
6354 flush_deletions(rbtdbiter);
6356 expire_result = expirenode(iterator->db, *nodep, 0);
6359 * expirenode() currently always returns success.
6361 if (expire_result == ISC_R_SUCCESS && node->down == NULL) {
6364 rbtdbiter->deletions[rbtdbiter->delete++] = node;
6365 NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
6366 dns_rbtnode_refincrement(node, &refs);
6368 NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
6376 dbiterator_pause(dns_dbiterator_t *iterator) {
6377 dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
6378 rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
6380 if (rbtdbiter->result != ISC_R_SUCCESS &&
6381 rbtdbiter->result != ISC_R_NOMORE)
6382 return (rbtdbiter->result);
6384 if (rbtdbiter->paused)
6385 return (ISC_R_SUCCESS);
6387 rbtdbiter->paused = ISC_TRUE;
6389 if (rbtdbiter->tree_locked != isc_rwlocktype_none) {
6390 INSIST(rbtdbiter->tree_locked == isc_rwlocktype_read);
6391 RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
6392 rbtdbiter->tree_locked = isc_rwlocktype_none;
6395 flush_deletions(rbtdbiter);
6397 return (ISC_R_SUCCESS);
6401 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
6402 rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
6403 dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin);
6405 if (rbtdbiter->result != ISC_R_SUCCESS)
6406 return (rbtdbiter->result);
6408 return (dns_name_copy(origin, name, NULL));
6412 * Additional cache routines.
6415 rdataset_getadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
6416 dns_rdatatype_t qtype, dns_acache_t *acache,
6417 dns_zone_t **zonep, dns_db_t **dbp,
6418 dns_dbversion_t **versionp, dns_dbnode_t **nodep,
6419 dns_name_t *fname, dns_message_t *msg,
6422 dns_rbtdb_t *rbtdb = rdataset->private1;
6423 dns_rbtnode_t *rbtnode = rdataset->private2;
6424 unsigned char *raw = rdataset->private3; /* RDATASLAB */
6425 unsigned int current_count = rdataset->privateuint4;
6427 rdatasetheader_t *header;
6428 nodelock_t *nodelock;
6429 unsigned int total_count;
6430 acachectl_t *acarray;
6431 dns_acacheentry_t *entry;
6432 isc_result_t result;
6434 UNUSED(qtype); /* we do not use this value at least for now */
6437 header = (struct rdatasetheader *)(raw - sizeof(*header));
6439 total_count = raw[0] * 256 + raw[1];
6440 INSIST(total_count > current_count);
6441 count = total_count - current_count - 1;
6445 nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
6446 NODE_LOCK(nodelock, isc_rwlocktype_read);
6449 case dns_rdatasetadditional_fromauth:
6450 acarray = header->additional_auth;
6452 case dns_rdatasetadditional_fromcache:
6455 case dns_rdatasetadditional_fromglue:
6456 acarray = header->additional_glue;
6462 if (acarray == NULL) {
6463 if (type != dns_rdatasetadditional_fromcache)
6464 dns_acache_countquerymiss(acache);
6465 NODE_UNLOCK(nodelock, isc_rwlocktype_read);
6466 return (ISC_R_NOTFOUND);
6469 if (acarray[count].entry == NULL) {
6470 dns_acache_countquerymiss(acache);
6471 NODE_UNLOCK(nodelock, isc_rwlocktype_read);
6472 return (ISC_R_NOTFOUND);
6476 dns_acache_attachentry(acarray[count].entry, &entry);
6478 NODE_UNLOCK(nodelock, isc_rwlocktype_read);
6480 result = dns_acache_getentry(entry, zonep, dbp, versionp,
6481 nodep, fname, msg, now);
6483 dns_acache_detachentry(&entry);
6489 acache_callback(dns_acacheentry_t *entry, void **arg) {
6491 dns_rbtnode_t *rbtnode;
6492 nodelock_t *nodelock;
6493 acachectl_t *acarray = NULL;
6494 acache_cbarg_t *cbarg;
6497 REQUIRE(arg != NULL);
6501 * The caller must hold the entry lock.
6504 rbtdb = (dns_rbtdb_t *)cbarg->db;
6505 rbtnode = (dns_rbtnode_t *)cbarg->node;
6507 nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
6508 NODE_LOCK(nodelock, isc_rwlocktype_write);
6510 switch (cbarg->type) {
6511 case dns_rdatasetadditional_fromauth:
6512 acarray = cbarg->header->additional_auth;
6514 case dns_rdatasetadditional_fromglue:
6515 acarray = cbarg->header->additional_glue;
6521 count = cbarg->count;
6522 if (acarray != NULL && acarray[count].entry == entry) {
6523 acarray[count].entry = NULL;
6524 INSIST(acarray[count].cbarg == cbarg);
6525 isc_mem_put(rbtdb->common.mctx, cbarg, sizeof(acache_cbarg_t));
6526 acarray[count].cbarg = NULL;
6528 isc_mem_put(rbtdb->common.mctx, cbarg, sizeof(acache_cbarg_t));
6530 dns_acache_detachentry(&entry);
6532 NODE_UNLOCK(nodelock, isc_rwlocktype_write);
6534 dns_db_detachnode((dns_db_t *)rbtdb, (dns_dbnode_t **)(void*)&rbtnode);
6535 dns_db_detach((dns_db_t **)(void*)&rbtdb);
6541 acache_cancelentry(isc_mem_t *mctx, dns_acacheentry_t *entry,
6542 acache_cbarg_t **cbargp)
6544 acache_cbarg_t *cbarg;
6546 REQUIRE(mctx != NULL);
6547 REQUIRE(entry != NULL);
6548 REQUIRE(cbargp != NULL && *cbargp != NULL);
6552 dns_acache_cancelentry(entry);
6553 dns_db_detachnode(cbarg->db, &cbarg->node);
6554 dns_db_detach(&cbarg->db);
6556 isc_mem_put(mctx, cbarg, sizeof(acache_cbarg_t));
6562 rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
6563 dns_rdatatype_t qtype, dns_acache_t *acache,
6564 dns_zone_t *zone, dns_db_t *db,
6565 dns_dbversion_t *version, dns_dbnode_t *node,
6568 dns_rbtdb_t *rbtdb = rdataset->private1;
6569 dns_rbtnode_t *rbtnode = rdataset->private2;
6570 unsigned char *raw = rdataset->private3; /* RDATASLAB */
6571 unsigned int current_count = rdataset->privateuint4;
6572 rdatasetheader_t *header;
6573 unsigned int total_count, count;
6574 nodelock_t *nodelock;
6575 isc_result_t result;
6576 acachectl_t *acarray;
6577 dns_acacheentry_t *newentry, *oldentry = NULL;
6578 acache_cbarg_t *newcbarg, *oldcbarg = NULL;
6582 if (type == dns_rdatasetadditional_fromcache)
6583 return (ISC_R_SUCCESS);
6585 header = (struct rdatasetheader *)(raw - sizeof(*header));
6587 total_count = raw[0] * 256 + raw[1];
6588 INSIST(total_count > current_count);
6589 count = total_count - current_count - 1; /* should be private data */
6591 newcbarg = isc_mem_get(rbtdb->common.mctx, sizeof(*newcbarg));
6592 if (newcbarg == NULL)
6593 return (ISC_R_NOMEMORY);
6594 newcbarg->type = type;
6595 newcbarg->count = count;
6596 newcbarg->header = header;
6597 newcbarg->db = NULL;
6598 dns_db_attach((dns_db_t *)rbtdb, &newcbarg->db);
6599 newcbarg->node = NULL;
6600 dns_db_attachnode((dns_db_t *)rbtdb, (dns_dbnode_t *)rbtnode,
6603 result = dns_acache_createentry(acache, (dns_db_t *)rbtdb,
6604 acache_callback, newcbarg, &newentry);
6605 if (result != ISC_R_SUCCESS)
6607 /* Set cache data in the new entry. */
6608 result = dns_acache_setentry(acache, newentry, zone, db,
6609 version, node, fname);
6610 if (result != ISC_R_SUCCESS)
6613 nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
6614 NODE_LOCK(nodelock, isc_rwlocktype_write);
6618 case dns_rdatasetadditional_fromauth:
6619 acarray = header->additional_auth;
6621 case dns_rdatasetadditional_fromglue:
6622 acarray = header->additional_glue;
6628 if (acarray == NULL) {
6631 acarray = isc_mem_get(rbtdb->common.mctx, total_count *
6632 sizeof(acachectl_t));
6634 if (acarray == NULL) {
6635 NODE_UNLOCK(nodelock, isc_rwlocktype_write);
6639 for (i = 0; i < total_count; i++) {
6640 acarray[i].entry = NULL;
6641 acarray[i].cbarg = NULL;
6645 case dns_rdatasetadditional_fromauth:
6646 header->additional_auth = acarray;
6648 case dns_rdatasetadditional_fromglue:
6649 header->additional_glue = acarray;
6655 if (acarray[count].entry != NULL) {
6657 * Swap the entry. Delay cleaning-up the old entry since
6658 * it would require a node lock.
6660 oldentry = acarray[count].entry;
6661 INSIST(acarray[count].cbarg != NULL);
6662 oldcbarg = acarray[count].cbarg;
6664 acarray[count].entry = newentry;
6665 acarray[count].cbarg = newcbarg;
6667 NODE_UNLOCK(nodelock, isc_rwlocktype_write);
6669 if (oldentry != NULL) {
6670 acache_cancelentry(rbtdb->common.mctx, oldentry, &oldcbarg);
6671 dns_acache_detachentry(&oldentry);
6674 return (ISC_R_SUCCESS);
6677 if (newcbarg != NULL) {
6678 if (newentry != NULL) {
6679 acache_cancelentry(rbtdb->common.mctx, newentry,
6681 dns_acache_detachentry(&newentry);
6683 dns_db_detachnode((dns_db_t *)rbtdb, &newcbarg->node);
6684 dns_db_detach(&newcbarg->db);
6685 isc_mem_put(rbtdb->common.mctx, newcbarg,
6694 rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset,
6695 dns_rdatasetadditional_t type, dns_rdatatype_t qtype)
6697 dns_rbtdb_t *rbtdb = rdataset->private1;
6698 dns_rbtnode_t *rbtnode = rdataset->private2;
6699 unsigned char *raw = rdataset->private3; /* RDATASLAB */
6700 unsigned int current_count = rdataset->privateuint4;
6701 rdatasetheader_t *header;
6702 nodelock_t *nodelock;
6703 unsigned int total_count, count;
6704 acachectl_t *acarray;
6705 dns_acacheentry_t *entry;
6706 acache_cbarg_t *cbarg;
6708 UNUSED(qtype); /* we do not use this value at least for now */
6711 if (type == dns_rdatasetadditional_fromcache)
6712 return (ISC_R_SUCCESS);
6714 header = (struct rdatasetheader *)(raw - sizeof(*header));
6716 total_count = raw[0] * 256 + raw[1];
6717 INSIST(total_count > current_count);
6718 count = total_count - current_count - 1;
6723 nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
6724 NODE_LOCK(nodelock, isc_rwlocktype_write);
6727 case dns_rdatasetadditional_fromauth:
6728 acarray = header->additional_auth;
6730 case dns_rdatasetadditional_fromglue:
6731 acarray = header->additional_glue;
6737 if (acarray == NULL) {
6738 NODE_UNLOCK(nodelock, isc_rwlocktype_write);
6739 return (ISC_R_NOTFOUND);
6742 entry = acarray[count].entry;
6743 if (entry == NULL) {
6744 NODE_UNLOCK(nodelock, isc_rwlocktype_write);
6745 return (ISC_R_NOTFOUND);
6748 acarray[count].entry = NULL;
6749 cbarg = acarray[count].cbarg;
6750 acarray[count].cbarg = NULL;
6752 NODE_UNLOCK(nodelock, isc_rwlocktype_write);
6754 if (entry != NULL) {
6755 acache_cancelentry(rbtdb->common.mctx, entry, &cbarg);
6756 dns_acache_detachentry(&entry);
6759 return (ISC_R_SUCCESS);