sdb.c revision 234010
1/*
2 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
4 *
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.
8 *
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.
16 */
17
18/* $Id$ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <string.h>
25
26#include <isc/buffer.h>
27#include <isc/lex.h>
28#include <isc/log.h>
29#include <isc/magic.h>
30#include <isc/mem.h>
31#include <isc/once.h>
32#include <isc/print.h>
33#include <isc/region.h>
34#include <isc/util.h>
35
36#include <dns/callbacks.h>
37#include <dns/db.h>
38#include <dns/dbiterator.h>
39#include <dns/fixedname.h>
40#include <dns/log.h>
41#include <dns/rdata.h>
42#include <dns/rdatalist.h>
43#include <dns/rdataset.h>
44#include <dns/rdatasetiter.h>
45#include <dns/rdatatype.h>
46#include <dns/result.h>
47#include <dns/sdb.h>
48#include <dns/types.h>
49
50#include "rdatalist_p.h"
51
52struct dns_sdbimplementation {
53	const dns_sdbmethods_t		*methods;
54	void				*driverdata;
55	unsigned int			flags;
56	isc_mem_t			*mctx;
57	isc_mutex_t			driverlock;
58	dns_dbimplementation_t		*dbimp;
59};
60
61struct dns_sdb {
62	/* Unlocked */
63	dns_db_t			common;
64	char				*zone;
65	dns_sdbimplementation_t		*implementation;
66	void				*dbdata;
67	isc_mutex_t			lock;
68	/* Locked */
69	unsigned int			references;
70};
71
72struct dns_sdblookup {
73	/* Unlocked */
74	unsigned int			magic;
75	dns_sdb_t			*sdb;
76	ISC_LIST(dns_rdatalist_t)	lists;
77	ISC_LIST(isc_buffer_t)		buffers;
78	dns_name_t			*name;
79	ISC_LINK(dns_sdblookup_t)	link;
80	isc_mutex_t			lock;
81	dns_rdatacallbacks_t		callbacks;
82	/* Locked */
83	unsigned int			references;
84};
85
86typedef struct dns_sdblookup dns_sdbnode_t;
87
88struct dns_sdballnodes {
89	dns_dbiterator_t		common;
90	ISC_LIST(dns_sdbnode_t)		nodelist;
91	dns_sdbnode_t			*current;
92	dns_sdbnode_t			*origin;
93};
94
95typedef dns_sdballnodes_t sdb_dbiterator_t;
96
97typedef struct sdb_rdatasetiter {
98	dns_rdatasetiter_t		common;
99	dns_rdatalist_t			*current;
100} sdb_rdatasetiter_t;
101
102#define SDB_MAGIC		ISC_MAGIC('S', 'D', 'B', '-')
103
104/*%
105 * Note that "impmagic" is not the first four bytes of the struct, so
106 * ISC_MAGIC_VALID cannot be used.
107 */
108#define VALID_SDB(sdb)		((sdb) != NULL && \
109				 (sdb)->common.impmagic == SDB_MAGIC)
110
111#define SDBLOOKUP_MAGIC		ISC_MAGIC('S','D','B','L')
112#define VALID_SDBLOOKUP(sdbl)	ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)
113#define VALID_SDBNODE(sdbn)	VALID_SDBLOOKUP(sdbn)
114
115/* These values are taken from RFC1537 */
116#define SDB_DEFAULT_REFRESH	(60 * 60 * 8)
117#define SDB_DEFAULT_RETRY	(60 * 60 * 2)
118#define SDB_DEFAULT_EXPIRE	(60 * 60 * 24 * 7)
119#define SDB_DEFAULT_MINIMUM	(60 * 60 * 24)
120
121/* This is a reasonable value */
122#define SDB_DEFAULT_TTL		(60 * 60 * 24)
123
124#ifdef __COVERITY__
125#define MAYBE_LOCK(sdb) LOCK(&sdb->implementation->driverlock)
126#define MAYBE_UNLOCK(sdb) UNLOCK(&sdb->implementation->driverlock)
127#else
128#define MAYBE_LOCK(sdb)							\
129	do {								\
130		unsigned int flags = sdb->implementation->flags;	\
131		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)		\
132			LOCK(&sdb->implementation->driverlock);		\
133	} while (0)
134
135#define MAYBE_UNLOCK(sdb)						\
136	do {								\
137		unsigned int flags = sdb->implementation->flags;	\
138		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)		\
139			UNLOCK(&sdb->implementation->driverlock);	\
140	} while (0)
141#endif
142
143static int dummy;
144
145static isc_result_t dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin,
146				   dns_dbtype_t type, dns_rdataclass_t rdclass,
147				   unsigned int argc, char *argv[],
148				   void *driverarg, dns_db_t **dbp);
149
150static isc_result_t findrdataset(dns_db_t *db, dns_dbnode_t *node,
151				 dns_dbversion_t *version,
152				 dns_rdatatype_t type, dns_rdatatype_t covers,
153				 isc_stdtime_t now, dns_rdataset_t *rdataset,
154				 dns_rdataset_t *sigrdataset);
155
156static isc_result_t createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);
157
158static void destroynode(dns_sdbnode_t *node);
159
160static void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
161
162
163static void list_tordataset(dns_rdatalist_t *rdatalist,
164			    dns_db_t *db, dns_dbnode_t *node,
165			    dns_rdataset_t *rdataset);
166
167static void		dbiterator_destroy(dns_dbiterator_t **iteratorp);
168static isc_result_t	dbiterator_first(dns_dbiterator_t *iterator);
169static isc_result_t	dbiterator_last(dns_dbiterator_t *iterator);
170static isc_result_t	dbiterator_seek(dns_dbiterator_t *iterator,
171					dns_name_t *name);
172static isc_result_t	dbiterator_prev(dns_dbiterator_t *iterator);
173static isc_result_t	dbiterator_next(dns_dbiterator_t *iterator);
174static isc_result_t	dbiterator_current(dns_dbiterator_t *iterator,
175					   dns_dbnode_t **nodep,
176					   dns_name_t *name);
177static isc_result_t	dbiterator_pause(dns_dbiterator_t *iterator);
178static isc_result_t	dbiterator_origin(dns_dbiterator_t *iterator,
179					  dns_name_t *name);
180
181static dns_dbiteratormethods_t dbiterator_methods = {
182	dbiterator_destroy,
183	dbiterator_first,
184	dbiterator_last,
185	dbiterator_seek,
186	dbiterator_prev,
187	dbiterator_next,
188	dbiterator_current,
189	dbiterator_pause,
190	dbiterator_origin
191};
192
193static void		rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
194static isc_result_t	rdatasetiter_first(dns_rdatasetiter_t *iterator);
195static isc_result_t	rdatasetiter_next(dns_rdatasetiter_t *iterator);
196static void		rdatasetiter_current(dns_rdatasetiter_t *iterator,
197					     dns_rdataset_t *rdataset);
198
199static dns_rdatasetitermethods_t rdatasetiter_methods = {
200	rdatasetiter_destroy,
201	rdatasetiter_first,
202	rdatasetiter_next,
203	rdatasetiter_current
204};
205
206/*
207 * Functions used by implementors of simple databases
208 */
209isc_result_t
210dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
211		 void *driverdata, unsigned int flags, isc_mem_t *mctx,
212		 dns_sdbimplementation_t **sdbimp)
213{
214	dns_sdbimplementation_t *imp;
215	isc_result_t result;
216
217	REQUIRE(drivername != NULL);
218	REQUIRE(methods != NULL);
219	REQUIRE(methods->lookup != NULL);
220	REQUIRE(mctx != NULL);
221	REQUIRE(sdbimp != NULL && *sdbimp == NULL);
222	REQUIRE((flags & ~(DNS_SDBFLAG_RELATIVEOWNER |
223			   DNS_SDBFLAG_RELATIVERDATA |
224			   DNS_SDBFLAG_THREADSAFE)) == 0);
225
226	imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
227	if (imp == NULL)
228		return (ISC_R_NOMEMORY);
229	imp->methods = methods;
230	imp->driverdata = driverdata;
231	imp->flags = flags;
232	imp->mctx = NULL;
233	isc_mem_attach(mctx, &imp->mctx);
234	result = isc_mutex_init(&imp->driverlock);
235	if (result != ISC_R_SUCCESS)
236		goto cleanup_mctx;
237
238	imp->dbimp = NULL;
239	result = dns_db_register(drivername, dns_sdb_create, imp, mctx,
240				 &imp->dbimp);
241	if (result != ISC_R_SUCCESS)
242		goto cleanup_mutex;
243	*sdbimp = imp;
244
245	return (ISC_R_SUCCESS);
246
247 cleanup_mutex:
248	DESTROYLOCK(&imp->driverlock);
249 cleanup_mctx:
250	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
251	return (result);
252}
253
254void
255dns_sdb_unregister(dns_sdbimplementation_t **sdbimp) {
256	dns_sdbimplementation_t *imp;
257	isc_mem_t *mctx;
258
259	REQUIRE(sdbimp != NULL && *sdbimp != NULL);
260
261	imp = *sdbimp;
262	dns_db_unregister(&imp->dbimp);
263	DESTROYLOCK(&imp->driverlock);
264
265	mctx = imp->mctx;
266	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
267	isc_mem_detach(&mctx);
268
269	*sdbimp = NULL;
270}
271
272static inline unsigned int
273initial_size(unsigned int len) {
274	unsigned int size;
275
276	for (size = 1024; size < (64 * 1024); size *= 2)
277		if (len < size)
278			return (size);
279	return (65535);
280}
281
282isc_result_t
283dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval, dns_ttl_t ttl,
284		 const unsigned char *rdatap, unsigned int rdlen)
285{
286	dns_rdatalist_t *rdatalist;
287	dns_rdata_t *rdata;
288	isc_buffer_t *rdatabuf = NULL;
289	isc_result_t result;
290	isc_mem_t *mctx;
291	isc_region_t region;
292
293	mctx = lookup->sdb->common.mctx;
294
295	rdatalist = ISC_LIST_HEAD(lookup->lists);
296	while (rdatalist != NULL) {
297		if (rdatalist->type == typeval)
298			break;
299		rdatalist = ISC_LIST_NEXT(rdatalist, link);
300	}
301
302	if (rdatalist == NULL) {
303		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
304		if (rdatalist == NULL)
305			return (ISC_R_NOMEMORY);
306		rdatalist->rdclass = lookup->sdb->common.rdclass;
307		rdatalist->type = typeval;
308		rdatalist->covers = 0;
309		rdatalist->ttl = ttl;
310		ISC_LIST_INIT(rdatalist->rdata);
311		ISC_LINK_INIT(rdatalist, link);
312		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
313	} else
314		if (rdatalist->ttl != ttl)
315			return (DNS_R_BADTTL);
316
317	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
318	if (rdata == NULL)
319		return (ISC_R_NOMEMORY);
320
321	result = isc_buffer_allocate(mctx, &rdatabuf, rdlen);
322	if (result != ISC_R_SUCCESS)
323		goto failure;
324	DE_CONST(rdatap, region.base);
325	region.length = rdlen;
326	isc_buffer_copyregion(rdatabuf, &region);
327	isc_buffer_usedregion(rdatabuf, &region);
328	dns_rdata_init(rdata);
329	dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
330			     &region);
331	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
332	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
333	rdata = NULL;
334
335 failure:
336	if (rdata != NULL)
337		isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
338	return (result);
339}
340
341
342isc_result_t
343dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
344	      const char *data)
345{
346	unsigned int datalen;
347	dns_rdatatype_t typeval;
348	isc_textregion_t r;
349	isc_lex_t *lex = NULL;
350	isc_result_t result;
351	unsigned char *p = NULL;
352	unsigned int size = 0; /* Init to suppress compiler warning */
353	isc_mem_t *mctx;
354	dns_sdbimplementation_t *imp;
355	dns_name_t *origin;
356	isc_buffer_t b;
357	isc_buffer_t rb;
358
359	REQUIRE(VALID_SDBLOOKUP(lookup));
360	REQUIRE(type != NULL);
361	REQUIRE(data != NULL);
362
363	mctx = lookup->sdb->common.mctx;
364
365	DE_CONST(type, r.base);
366	r.length = strlen(type);
367	result = dns_rdatatype_fromtext(&typeval, &r);
368	if (result != ISC_R_SUCCESS)
369		return (result);
370
371	imp = lookup->sdb->implementation;
372	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
373		origin = &lookup->sdb->common.origin;
374	else
375		origin = dns_rootname;
376
377	result = isc_lex_create(mctx, 64, &lex);
378	if (result != ISC_R_SUCCESS)
379		goto failure;
380
381	datalen = strlen(data);
382	size = initial_size(datalen);
383	do {
384		isc_buffer_init(&b, data, datalen);
385		isc_buffer_add(&b, datalen);
386		result = isc_lex_openbuffer(lex, &b);
387		if (result != ISC_R_SUCCESS)
388			goto failure;
389
390		if (size >= 65535)
391			size = 65535;
392		p = isc_mem_get(mctx, size);
393		if (p == NULL) {
394			result = ISC_R_NOMEMORY;
395			goto failure;
396		}
397		isc_buffer_init(&rb, p, size);
398		result = dns_rdata_fromtext(NULL,
399					    lookup->sdb->common.rdclass,
400					    typeval, lex,
401					    origin, 0,
402					    mctx, &rb,
403					    &lookup->callbacks);
404		if (result != ISC_R_NOSPACE)
405			break;
406
407		/*
408		 * Is the RR too big?
409		 */
410		if (size >= 65535)
411			break;
412		isc_mem_put(mctx, p, size);
413		p = NULL;
414		size *= 2;
415	} while (result == ISC_R_NOSPACE);
416
417	if (result != ISC_R_SUCCESS)
418		goto failure;
419
420	result = dns_sdb_putrdata(lookup, typeval, ttl,
421				  isc_buffer_base(&rb),
422				  isc_buffer_usedlength(&rb));
423 failure:
424	if (p != NULL)
425		isc_mem_put(mctx, p, size);
426	if (lex != NULL)
427		isc_lex_destroy(&lex);
428
429	return (result);
430}
431
432static isc_result_t
433getnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
434	dns_name_t *newname, *origin;
435	dns_fixedname_t fnewname;
436	dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
437	dns_sdbimplementation_t *imp = sdb->implementation;
438	dns_sdbnode_t *sdbnode;
439	isc_mem_t *mctx = sdb->common.mctx;
440	isc_buffer_t b;
441	isc_result_t result;
442
443	dns_fixedname_init(&fnewname);
444	newname = dns_fixedname_name(&fnewname);
445
446	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
447		origin = &sdb->common.origin;
448	else
449		origin = dns_rootname;
450	isc_buffer_init(&b, name, strlen(name));
451	isc_buffer_add(&b, strlen(name));
452
453	result = dns_name_fromtext(newname, &b, origin, 0, NULL);
454	if (result != ISC_R_SUCCESS)
455		return (result);
456
457	if (allnodes->common.relative_names) {
458		/* All names are relative to the root */
459		unsigned int nlabels = dns_name_countlabels(newname);
460		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
461	}
462
463	sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
464	if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
465		sdbnode = NULL;
466		result = createnode(sdb, &sdbnode);
467		if (result != ISC_R_SUCCESS)
468			return (result);
469		sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
470		if (sdbnode->name == NULL) {
471			destroynode(sdbnode);
472			return (ISC_R_NOMEMORY);
473		}
474		dns_name_init(sdbnode->name, NULL);
475		result = dns_name_dup(newname, mctx, sdbnode->name);
476		if (result != ISC_R_SUCCESS) {
477			isc_mem_put(mctx, sdbnode->name, sizeof(dns_name_t));
478			destroynode(sdbnode);
479			return (result);
480		}
481		ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
482		if (allnodes->origin == NULL &&
483		    dns_name_equal(newname, &sdb->common.origin))
484			allnodes->origin = sdbnode;
485	}
486	*nodep = sdbnode;
487	return (ISC_R_SUCCESS);
488}
489
490isc_result_t
491dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
492		   const char *type, dns_ttl_t ttl, const char *data)
493{
494	isc_result_t result;
495	dns_sdbnode_t *sdbnode = NULL;
496	result = getnode(allnodes, name, &sdbnode);
497	if (result != ISC_R_SUCCESS)
498		return (result);
499	return (dns_sdb_putrr(sdbnode, type, ttl, data));
500}
501
502isc_result_t
503dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
504		      dns_rdatatype_t type, dns_ttl_t ttl,
505		      const void *rdata, unsigned int rdlen)
506{
507	isc_result_t result;
508	dns_sdbnode_t *sdbnode = NULL;
509	result = getnode(allnodes, name, &sdbnode);
510	if (result != ISC_R_SUCCESS)
511		return (result);
512	return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
513}
514
515isc_result_t
516dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
517	       isc_uint32_t serial)
518{
519	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
520	int n;
521
522	REQUIRE(mname != NULL);
523	REQUIRE(rname != NULL);
524
525	n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u",
526		     mname, rname, serial,
527		     SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
528		     SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
529	if (n >= (int)sizeof(str) || n < 0)
530		return (ISC_R_NOSPACE);
531	return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
532}
533
534/*
535 * DB routines
536 */
537
538static void
539attach(dns_db_t *source, dns_db_t **targetp) {
540	dns_sdb_t *sdb = (dns_sdb_t *) source;
541
542	REQUIRE(VALID_SDB(sdb));
543
544	LOCK(&sdb->lock);
545	REQUIRE(sdb->references > 0);
546	sdb->references++;
547	UNLOCK(&sdb->lock);
548
549	*targetp = source;
550}
551
552static void
553destroy(dns_sdb_t *sdb) {
554	isc_mem_t *mctx;
555	dns_sdbimplementation_t *imp = sdb->implementation;
556
557	mctx = sdb->common.mctx;
558
559	if (imp->methods->destroy != NULL) {
560		MAYBE_LOCK(sdb);
561		imp->methods->destroy(sdb->zone, imp->driverdata,
562				      &sdb->dbdata);
563		MAYBE_UNLOCK(sdb);
564	}
565
566	isc_mem_free(mctx, sdb->zone);
567	DESTROYLOCK(&sdb->lock);
568
569	sdb->common.magic = 0;
570	sdb->common.impmagic = 0;
571
572	dns_name_free(&sdb->common.origin, mctx);
573
574	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
575	isc_mem_detach(&mctx);
576}
577
578static void
579detach(dns_db_t **dbp) {
580	dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);
581	isc_boolean_t need_destroy = ISC_FALSE;
582
583	REQUIRE(VALID_SDB(sdb));
584	LOCK(&sdb->lock);
585	REQUIRE(sdb->references > 0);
586	sdb->references--;
587	if (sdb->references == 0)
588		need_destroy = ISC_TRUE;
589	UNLOCK(&sdb->lock);
590
591	if (need_destroy)
592		destroy(sdb);
593
594	*dbp = NULL;
595}
596
597static isc_result_t
598beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
599	UNUSED(db);
600	UNUSED(addp);
601	UNUSED(dbloadp);
602	return (ISC_R_NOTIMPLEMENTED);
603}
604
605static isc_result_t
606endload(dns_db_t *db, dns_dbload_t **dbloadp) {
607	UNUSED(db);
608	UNUSED(dbloadp);
609	return (ISC_R_NOTIMPLEMENTED);
610}
611
612static isc_result_t
613dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
614     dns_masterformat_t masterformat) {
615	UNUSED(db);
616	UNUSED(version);
617	UNUSED(filename);
618	UNUSED(masterformat);
619	return (ISC_R_NOTIMPLEMENTED);
620}
621
622static void
623currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
624	REQUIRE(versionp != NULL && *versionp == NULL);
625
626	UNUSED(db);
627
628	*versionp = (void *) &dummy;
629	return;
630}
631
632static isc_result_t
633newversion(dns_db_t *db, dns_dbversion_t **versionp) {
634	UNUSED(db);
635	UNUSED(versionp);
636
637	return (ISC_R_NOTIMPLEMENTED);
638}
639
640static void
641attachversion(dns_db_t *db, dns_dbversion_t *source,
642	      dns_dbversion_t **targetp)
643{
644	REQUIRE(source != NULL && source == (void *) &dummy);
645	REQUIRE(targetp != NULL && *targetp == NULL);
646
647	UNUSED(db);
648	*targetp = source;
649	return;
650}
651
652static void
653closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
654	REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
655	REQUIRE(commit == ISC_FALSE);
656
657	UNUSED(db);
658	UNUSED(commit);
659
660	*versionp = NULL;
661}
662
663static isc_result_t
664createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
665	dns_sdbnode_t *node;
666	isc_result_t result;
667
668	node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));
669	if (node == NULL)
670		return (ISC_R_NOMEMORY);
671
672	node->sdb = NULL;
673	attach((dns_db_t *)sdb, (dns_db_t **)&node->sdb);
674	ISC_LIST_INIT(node->lists);
675	ISC_LIST_INIT(node->buffers);
676	ISC_LINK_INIT(node, link);
677	node->name = NULL;
678	result = isc_mutex_init(&node->lock);
679	if (result != ISC_R_SUCCESS) {
680		isc_mem_put(sdb->common.mctx, node, sizeof(dns_sdbnode_t));
681		return (result);
682	}
683	dns_rdatacallbacks_init(&node->callbacks);
684	node->references = 1;
685	node->magic = SDBLOOKUP_MAGIC;
686
687	*nodep = node;
688	return (ISC_R_SUCCESS);
689}
690
691static void
692destroynode(dns_sdbnode_t *node) {
693	dns_rdatalist_t *list;
694	dns_rdata_t *rdata;
695	isc_buffer_t *b;
696	dns_sdb_t *sdb;
697	isc_mem_t *mctx;
698
699	sdb = node->sdb;
700	mctx = sdb->common.mctx;
701
702	while (!ISC_LIST_EMPTY(node->lists)) {
703		list = ISC_LIST_HEAD(node->lists);
704		while (!ISC_LIST_EMPTY(list->rdata)) {
705			rdata = ISC_LIST_HEAD(list->rdata);
706			ISC_LIST_UNLINK(list->rdata, rdata, link);
707			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
708		}
709		ISC_LIST_UNLINK(node->lists, list, link);
710		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
711	}
712
713	while (!ISC_LIST_EMPTY(node->buffers)) {
714		b = ISC_LIST_HEAD(node->buffers);
715		ISC_LIST_UNLINK(node->buffers, b, link);
716		isc_buffer_free(&b);
717	}
718
719	if (node->name != NULL) {
720		dns_name_free(node->name, mctx);
721		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
722	}
723	DESTROYLOCK(&node->lock);
724	node->magic = 0;
725	isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
726	detach((dns_db_t **) (void *)&sdb);
727}
728
729static isc_result_t
730findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
731	 dns_dbnode_t **nodep)
732{
733	dns_sdb_t *sdb = (dns_sdb_t *)db;
734	dns_sdbnode_t *node = NULL;
735	isc_result_t result;
736	isc_buffer_t b;
737	char namestr[DNS_NAME_MAXTEXT + 1];
738	isc_boolean_t isorigin;
739	dns_sdbimplementation_t *imp;
740
741	REQUIRE(VALID_SDB(sdb));
742	REQUIRE(create == ISC_FALSE);
743	REQUIRE(nodep != NULL && *nodep == NULL);
744
745	UNUSED(name);
746	UNUSED(create);
747
748	imp = sdb->implementation;
749
750	isc_buffer_init(&b, namestr, sizeof(namestr));
751	if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
752		dns_name_t relname;
753		unsigned int labels;
754
755		labels = dns_name_countlabels(name) -
756			 dns_name_countlabels(&db->origin);
757		dns_name_init(&relname, NULL);
758		dns_name_getlabelsequence(name, 0, labels, &relname);
759		result = dns_name_totext(&relname, ISC_TRUE, &b);
760		if (result != ISC_R_SUCCESS)
761			return (result);
762	} else {
763		result = dns_name_totext(name, ISC_TRUE, &b);
764		if (result != ISC_R_SUCCESS)
765			return (result);
766	}
767	isc_buffer_putuint8(&b, 0);
768
769	result = createnode(sdb, &node);
770	if (result != ISC_R_SUCCESS)
771		return (result);
772
773	isorigin = dns_name_equal(name, &sdb->common.origin);
774
775	MAYBE_LOCK(sdb);
776	result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata, node);
777	MAYBE_UNLOCK(sdb);
778	if (result != ISC_R_SUCCESS &&
779	    !(result == ISC_R_NOTFOUND &&
780	      isorigin && imp->methods->authority != NULL))
781	{
782		destroynode(node);
783		return (result);
784	}
785
786	if (isorigin && imp->methods->authority != NULL) {
787		MAYBE_LOCK(sdb);
788		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
789		MAYBE_UNLOCK(sdb);
790		if (result != ISC_R_SUCCESS) {
791			destroynode(node);
792			return (result);
793		}
794	}
795
796	*nodep = node;
797	return (ISC_R_SUCCESS);
798}
799
800static isc_result_t
801find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
802     dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
803     dns_dbnode_t **nodep, dns_name_t *foundname,
804     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
805{
806	dns_sdb_t *sdb = (dns_sdb_t *)db;
807	dns_dbnode_t *node = NULL;
808	dns_fixedname_t fname;
809	dns_rdataset_t xrdataset;
810	dns_name_t *xname;
811	unsigned int nlabels, olabels;
812	isc_result_t result;
813	unsigned int i;
814
815	REQUIRE(VALID_SDB(sdb));
816	REQUIRE(nodep == NULL || *nodep == NULL);
817	REQUIRE(version == NULL || version == (void *) &dummy);
818
819	UNUSED(options);
820	UNUSED(sdb);
821
822	if (!dns_name_issubdomain(name, &db->origin))
823		return (DNS_R_NXDOMAIN);
824
825	olabels = dns_name_countlabels(&db->origin);
826	nlabels = dns_name_countlabels(name);
827
828	dns_fixedname_init(&fname);
829	xname = dns_fixedname_name(&fname);
830
831	if (rdataset == NULL) {
832		dns_rdataset_init(&xrdataset);
833		rdataset = &xrdataset;
834	}
835
836	result = DNS_R_NXDOMAIN;
837
838	for (i = olabels; i <= nlabels; i++) {
839		/*
840		 * Look up the next label.
841		 */
842		dns_name_getlabelsequence(name, nlabels - i, i, xname);
843		result = findnode(db, xname, ISC_FALSE, &node);
844		if (result != ISC_R_SUCCESS) {
845			result = DNS_R_NXDOMAIN;
846			continue;
847		}
848
849		/*
850		 * Look for a DNAME at the current label, unless this is
851		 * the qname.
852		 */
853		if (i < nlabels) {
854			result = findrdataset(db, node, version,
855					      dns_rdatatype_dname,
856					      0, now, rdataset, sigrdataset);
857			if (result == ISC_R_SUCCESS) {
858				result = DNS_R_DNAME;
859				break;
860			}
861		}
862
863		/*
864		 * Look for an NS at the current label, unless this is the
865		 * origin or glue is ok.
866		 */
867		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
868			result = findrdataset(db, node, version,
869					      dns_rdatatype_ns,
870					      0, now, rdataset, sigrdataset);
871			if (result == ISC_R_SUCCESS) {
872				if (i == nlabels && type == dns_rdatatype_any)
873				{
874					result = DNS_R_ZONECUT;
875					dns_rdataset_disassociate(rdataset);
876					if (sigrdataset != NULL &&
877					    dns_rdataset_isassociated
878							(sigrdataset)) {
879						dns_rdataset_disassociate
880								(sigrdataset);
881					}
882				} else
883					result = DNS_R_DELEGATION;
884				break;
885			}
886		}
887
888		/*
889		 * If the current name is not the qname, add another label
890		 * and try again.
891		 */
892		if (i < nlabels) {
893			destroynode(node);
894			node = NULL;
895			continue;
896		}
897
898		/*
899		 * If we're looking for ANY, we're done.
900		 */
901		if (type == dns_rdatatype_any) {
902			result = ISC_R_SUCCESS;
903			break;
904		}
905
906		/*
907		 * Look for the qtype.
908		 */
909		result = findrdataset(db, node, version, type,
910				      0, now, rdataset, sigrdataset);
911		if (result == ISC_R_SUCCESS)
912			break;
913
914		/*
915		 * Look for a CNAME
916		 */
917		if (type != dns_rdatatype_cname) {
918			result = findrdataset(db, node, version,
919					      dns_rdatatype_cname,
920					      0, now, rdataset, sigrdataset);
921			if (result == ISC_R_SUCCESS) {
922				result = DNS_R_CNAME;
923				break;
924			}
925		}
926
927		result = DNS_R_NXRRSET;
928		break;
929	}
930
931	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
932		dns_rdataset_disassociate(rdataset);
933
934	if (foundname != NULL) {
935		isc_result_t xresult;
936
937		xresult = dns_name_copy(xname, foundname, NULL);
938		if (xresult != ISC_R_SUCCESS) {
939			if (node != NULL)
940				destroynode(node);
941			if (dns_rdataset_isassociated(rdataset))
942				dns_rdataset_disassociate(rdataset);
943			return (DNS_R_BADDB);
944		}
945	}
946
947	if (nodep != NULL)
948		*nodep = node;
949	else if (node != NULL)
950		detachnode(db, &node);
951
952	return (result);
953}
954
955static isc_result_t
956findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
957	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
958	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
959{
960	UNUSED(db);
961	UNUSED(name);
962	UNUSED(options);
963	UNUSED(now);
964	UNUSED(nodep);
965	UNUSED(foundname);
966	UNUSED(rdataset);
967	UNUSED(sigrdataset);
968
969	return (ISC_R_NOTIMPLEMENTED);
970}
971
972static void
973attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
974	dns_sdb_t *sdb = (dns_sdb_t *)db;
975	dns_sdbnode_t *node = (dns_sdbnode_t *)source;
976
977	REQUIRE(VALID_SDB(sdb));
978
979	UNUSED(sdb);
980
981	LOCK(&node->lock);
982	INSIST(node->references > 0);
983	node->references++;
984	INSIST(node->references != 0);		/* Catch overflow. */
985	UNLOCK(&node->lock);
986
987	*targetp = source;
988}
989
990static void
991detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
992	dns_sdb_t *sdb = (dns_sdb_t *)db;
993	dns_sdbnode_t *node;
994	isc_boolean_t need_destroy = ISC_FALSE;
995
996	REQUIRE(VALID_SDB(sdb));
997	REQUIRE(targetp != NULL && *targetp != NULL);
998
999	UNUSED(sdb);
1000
1001	node = (dns_sdbnode_t *)(*targetp);
1002
1003	LOCK(&node->lock);
1004	INSIST(node->references > 0);
1005	node->references--;
1006	if (node->references == 0)
1007		need_destroy = ISC_TRUE;
1008	UNLOCK(&node->lock);
1009
1010	if (need_destroy)
1011		destroynode(node);
1012
1013	*targetp = NULL;
1014}
1015
1016static isc_result_t
1017expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1018	UNUSED(db);
1019	UNUSED(node);
1020	UNUSED(now);
1021	INSIST(0);
1022	return (ISC_R_UNEXPECTED);
1023}
1024
1025static void
1026printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1027	UNUSED(db);
1028	UNUSED(node);
1029	UNUSED(out);
1030	return;
1031}
1032
1033static isc_result_t
1034createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
1035{
1036	dns_sdb_t *sdb = (dns_sdb_t *)db;
1037	sdb_dbiterator_t *sdbiter;
1038	dns_sdbimplementation_t *imp = sdb->implementation;
1039	isc_result_t result;
1040
1041	REQUIRE(VALID_SDB(sdb));
1042
1043	if (imp->methods->allnodes == NULL)
1044		return (ISC_R_NOTIMPLEMENTED);
1045
1046	if ((options & DNS_DB_NSEC3ONLY) != 0 ||
1047	    (options & DNS_DB_NONSEC3) != 0)
1048		return (ISC_R_NOTIMPLEMENTED);
1049
1050	sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1051	if (sdbiter == NULL)
1052		return (ISC_R_NOMEMORY);
1053
1054	sdbiter->common.methods = &dbiterator_methods;
1055	sdbiter->common.db = NULL;
1056	dns_db_attach(db, &sdbiter->common.db);
1057	sdbiter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
1058	sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1059	ISC_LIST_INIT(sdbiter->nodelist);
1060	sdbiter->current = NULL;
1061	sdbiter->origin = NULL;
1062
1063	MAYBE_LOCK(sdb);
1064	result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1065	MAYBE_UNLOCK(sdb);
1066	if (result != ISC_R_SUCCESS) {
1067		dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
1068		return (result);
1069	}
1070
1071	if (sdbiter->origin != NULL) {
1072		ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1073		ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1074	}
1075
1076	*iteratorp = (dns_dbiterator_t *)sdbiter;
1077
1078	return (ISC_R_SUCCESS);
1079}
1080
1081static isc_result_t
1082findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1083	     dns_rdatatype_t type, dns_rdatatype_t covers,
1084	     isc_stdtime_t now, dns_rdataset_t *rdataset,
1085	     dns_rdataset_t *sigrdataset)
1086{
1087	dns_rdatalist_t *list;
1088	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1089
1090	REQUIRE(VALID_SDBNODE(node));
1091
1092	UNUSED(db);
1093	UNUSED(version);
1094	UNUSED(covers);
1095	UNUSED(now);
1096	UNUSED(sigrdataset);
1097
1098	if (type == dns_rdatatype_rrsig)
1099		return (ISC_R_NOTIMPLEMENTED);
1100
1101	list = ISC_LIST_HEAD(sdbnode->lists);
1102	while (list != NULL) {
1103		if (list->type == type)
1104			break;
1105		list = ISC_LIST_NEXT(list, link);
1106	}
1107	if (list == NULL)
1108		return (ISC_R_NOTFOUND);
1109
1110	list_tordataset(list, db, node, rdataset);
1111
1112	return (ISC_R_SUCCESS);
1113}
1114
1115static isc_result_t
1116allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1117	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1118{
1119	sdb_rdatasetiter_t *iterator;
1120
1121	REQUIRE(version == NULL || version == &dummy);
1122
1123	UNUSED(version);
1124	UNUSED(now);
1125
1126	iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1127	if (iterator == NULL)
1128		return (ISC_R_NOMEMORY);
1129
1130	iterator->common.magic = DNS_RDATASETITER_MAGIC;
1131	iterator->common.methods = &rdatasetiter_methods;
1132	iterator->common.db = db;
1133	iterator->common.node = NULL;
1134	attachnode(db, node, &iterator->common.node);
1135	iterator->common.version = version;
1136	iterator->common.now = now;
1137
1138	*iteratorp = (dns_rdatasetiter_t *)iterator;
1139
1140	return (ISC_R_SUCCESS);
1141}
1142
1143static isc_result_t
1144addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1145	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1146	    dns_rdataset_t *addedrdataset)
1147{
1148	UNUSED(db);
1149	UNUSED(node);
1150	UNUSED(version);
1151	UNUSED(now);
1152	UNUSED(rdataset);
1153	UNUSED(options);
1154	UNUSED(addedrdataset);
1155
1156	return (ISC_R_NOTIMPLEMENTED);
1157}
1158
1159static isc_result_t
1160subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1161		 dns_rdataset_t *rdataset, unsigned int options,
1162		 dns_rdataset_t *newrdataset)
1163{
1164	UNUSED(db);
1165	UNUSED(node);
1166	UNUSED(version);
1167	UNUSED(rdataset);
1168	UNUSED(options);
1169	UNUSED(newrdataset);
1170
1171	return (ISC_R_NOTIMPLEMENTED);
1172}
1173
1174static isc_result_t
1175deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1176	       dns_rdatatype_t type, dns_rdatatype_t covers)
1177{
1178	UNUSED(db);
1179	UNUSED(node);
1180	UNUSED(version);
1181	UNUSED(type);
1182	UNUSED(covers);
1183
1184	return (ISC_R_NOTIMPLEMENTED);
1185}
1186
1187static isc_boolean_t
1188issecure(dns_db_t *db) {
1189	UNUSED(db);
1190
1191	return (ISC_FALSE);
1192}
1193
1194static unsigned int
1195nodecount(dns_db_t *db) {
1196	UNUSED(db);
1197
1198	return (0);
1199}
1200
1201static isc_boolean_t
1202ispersistent(dns_db_t *db) {
1203	UNUSED(db);
1204	return (ISC_TRUE);
1205}
1206
1207static void
1208overmem(dns_db_t *db, isc_boolean_t overmem) {
1209	UNUSED(db);
1210	UNUSED(overmem);
1211}
1212
1213static void
1214settask(dns_db_t *db, isc_task_t *task) {
1215	UNUSED(db);
1216	UNUSED(task);
1217}
1218
1219
1220static dns_dbmethods_t sdb_methods = {
1221	attach,
1222	detach,
1223	beginload,
1224	endload,
1225	dump,
1226	currentversion,
1227	newversion,
1228	attachversion,
1229	closeversion,
1230	findnode,
1231	find,
1232	findzonecut,
1233	attachnode,
1234	detachnode,
1235	expirenode,
1236	printnode,
1237	createiterator,
1238	findrdataset,
1239	allrdatasets,
1240	addrdataset,
1241	subtractrdataset,
1242	deleterdataset,
1243	issecure,
1244	nodecount,
1245	ispersistent,
1246	overmem,
1247	settask,
1248	NULL,
1249	NULL,
1250	NULL,
1251	NULL,
1252	NULL,
1253	NULL,
1254	NULL,
1255	NULL,
1256	NULL,
1257	NULL,
1258	NULL
1259};
1260
1261static isc_result_t
1262dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
1263	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1264	       void *driverarg, dns_db_t **dbp)
1265{
1266	dns_sdb_t *sdb;
1267	isc_result_t result;
1268	char zonestr[DNS_NAME_MAXTEXT + 1];
1269	isc_buffer_t b;
1270	dns_sdbimplementation_t *imp;
1271
1272	REQUIRE(driverarg != NULL);
1273
1274	imp = driverarg;
1275
1276	if (type != dns_dbtype_zone)
1277		return (ISC_R_NOTIMPLEMENTED);
1278
1279	sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1280	if (sdb == NULL)
1281		return (ISC_R_NOMEMORY);
1282	memset(sdb, 0, sizeof(dns_sdb_t));
1283
1284	dns_name_init(&sdb->common.origin, NULL);
1285	sdb->common.attributes = 0;
1286	sdb->common.methods = &sdb_methods;
1287	sdb->common.rdclass = rdclass;
1288	sdb->common.mctx = NULL;
1289	sdb->implementation = imp;
1290
1291	isc_mem_attach(mctx, &sdb->common.mctx);
1292
1293	result = isc_mutex_init(&sdb->lock);
1294	if (result != ISC_R_SUCCESS)
1295		goto cleanup_mctx;
1296
1297	result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1298	if (result != ISC_R_SUCCESS)
1299		goto cleanup_lock;
1300
1301	isc_buffer_init(&b, zonestr, sizeof(zonestr));
1302	result = dns_name_totext(origin, ISC_TRUE, &b);
1303	if (result != ISC_R_SUCCESS)
1304		goto cleanup_origin;
1305	isc_buffer_putuint8(&b, 0);
1306
1307	sdb->zone = isc_mem_strdup(mctx, zonestr);
1308	if (sdb->zone == NULL) {
1309		result = ISC_R_NOMEMORY;
1310		goto cleanup_origin;
1311	}
1312
1313	sdb->dbdata = NULL;
1314	if (imp->methods->create != NULL) {
1315		MAYBE_LOCK(sdb);
1316		result = imp->methods->create(sdb->zone, argc, argv,
1317					      imp->driverdata, &sdb->dbdata);
1318		MAYBE_UNLOCK(sdb);
1319		if (result != ISC_R_SUCCESS)
1320			goto cleanup_zonestr;
1321	}
1322
1323	sdb->references = 1;
1324
1325	sdb->common.magic = DNS_DB_MAGIC;
1326	sdb->common.impmagic = SDB_MAGIC;
1327
1328	*dbp = (dns_db_t *)sdb;
1329
1330	return (ISC_R_SUCCESS);
1331
1332 cleanup_zonestr:
1333	isc_mem_free(mctx, sdb->zone);
1334 cleanup_origin:
1335	dns_name_free(&sdb->common.origin, mctx);
1336 cleanup_lock:
1337	(void)isc_mutex_destroy(&sdb->lock);
1338 cleanup_mctx:
1339	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
1340	isc_mem_detach(&mctx);
1341
1342	return (result);
1343}
1344
1345
1346/*
1347 * Rdataset Methods
1348 */
1349
1350static void
1351disassociate(dns_rdataset_t *rdataset) {
1352	dns_dbnode_t *node = rdataset->private5;
1353	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1354	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1355
1356	detachnode(db, &node);
1357	isc__rdatalist_disassociate(rdataset);
1358}
1359
1360static void
1361rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1362	dns_dbnode_t *node = source->private5;
1363	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1364	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1365	dns_dbnode_t *tempdb = NULL;
1366
1367	isc__rdatalist_clone(source, target);
1368	attachnode(db, node, &tempdb);
1369	source->private5 = tempdb;
1370}
1371
1372static dns_rdatasetmethods_t methods = {
1373	disassociate,
1374	isc__rdatalist_first,
1375	isc__rdatalist_next,
1376	isc__rdatalist_current,
1377	rdataset_clone,
1378	isc__rdatalist_count,
1379	isc__rdatalist_addnoqname,
1380	isc__rdatalist_getnoqname,
1381	NULL,
1382	NULL,
1383	NULL,
1384	NULL,
1385	NULL,
1386	NULL,
1387	NULL
1388};
1389
1390static void
1391list_tordataset(dns_rdatalist_t *rdatalist,
1392		dns_db_t *db, dns_dbnode_t *node,
1393		dns_rdataset_t *rdataset)
1394{
1395	/*
1396	 * The sdb rdataset is an rdatalist with some additions.
1397	 *	- private1 & private2 are used by the rdatalist.
1398	 *	- private3 & private 4 are unused.
1399	 *	- private5 is the node.
1400	 */
1401
1402	/* This should never fail. */
1403	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1404		      ISC_R_SUCCESS);
1405
1406	rdataset->methods = &methods;
1407	dns_db_attachnode(db, node, &rdataset->private5);
1408}
1409
1410/*
1411 * Database Iterator Methods
1412 */
1413static void
1414dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1415	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1416	dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1417
1418	while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1419		dns_sdbnode_t *node;
1420		node = ISC_LIST_HEAD(sdbiter->nodelist);
1421		ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1422		destroynode(node);
1423	}
1424
1425	dns_db_detach(&sdbiter->common.db);
1426	isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1427
1428	*iteratorp = NULL;
1429}
1430
1431static isc_result_t
1432dbiterator_first(dns_dbiterator_t *iterator) {
1433	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1434
1435	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1436	if (sdbiter->current == NULL)
1437		return (ISC_R_NOMORE);
1438	else
1439		return (ISC_R_SUCCESS);
1440}
1441
1442static isc_result_t
1443dbiterator_last(dns_dbiterator_t *iterator) {
1444	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1445
1446	sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1447	if (sdbiter->current == NULL)
1448		return (ISC_R_NOMORE);
1449	else
1450		return (ISC_R_SUCCESS);
1451}
1452
1453static isc_result_t
1454dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1455	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1456
1457	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1458	while (sdbiter->current != NULL) {
1459		if (dns_name_equal(sdbiter->current->name, name))
1460			return (ISC_R_SUCCESS);
1461		sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1462	}
1463	return (ISC_R_NOTFOUND);
1464}
1465
1466static isc_result_t
1467dbiterator_prev(dns_dbiterator_t *iterator) {
1468	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1469
1470	sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1471	if (sdbiter->current == NULL)
1472		return (ISC_R_NOMORE);
1473	else
1474		return (ISC_R_SUCCESS);
1475}
1476
1477static isc_result_t
1478dbiterator_next(dns_dbiterator_t *iterator) {
1479	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1480
1481	sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1482	if (sdbiter->current == NULL)
1483		return (ISC_R_NOMORE);
1484	else
1485		return (ISC_R_SUCCESS);
1486}
1487
1488static isc_result_t
1489dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1490		   dns_name_t *name)
1491{
1492	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1493
1494	attachnode(iterator->db, sdbiter->current, nodep);
1495	if (name != NULL)
1496		return (dns_name_copy(sdbiter->current->name, name, NULL));
1497	return (ISC_R_SUCCESS);
1498}
1499
1500static isc_result_t
1501dbiterator_pause(dns_dbiterator_t *iterator) {
1502	UNUSED(iterator);
1503	return (ISC_R_SUCCESS);
1504}
1505
1506static isc_result_t
1507dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1508	UNUSED(iterator);
1509	return (dns_name_copy(dns_rootname, name, NULL));
1510}
1511
1512/*
1513 * Rdataset Iterator Methods
1514 */
1515
1516static void
1517rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1518	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1519	detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1520	isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1521		    sizeof(sdb_rdatasetiter_t));
1522	*iteratorp = NULL;
1523}
1524
1525static isc_result_t
1526rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1527	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1528	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1529
1530	if (ISC_LIST_EMPTY(sdbnode->lists))
1531		return (ISC_R_NOMORE);
1532	sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1533	return (ISC_R_SUCCESS);
1534}
1535
1536static isc_result_t
1537rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1538	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1539
1540	sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1541	if (sdbiterator->current == NULL)
1542		return (ISC_R_NOMORE);
1543	else
1544		return (ISC_R_SUCCESS);
1545}
1546
1547static void
1548rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1549	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1550
1551	list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1552			rdataset);
1553}
1554