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