1/*
2 * Copyright (C) 2009-2012  Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* $Id$ */
18
19#include "config.h"
20
21#include <isc/result.h>
22#include <isc/util.h>
23#include <isc/mutex.h>
24#include <isc/mem.h>
25
26#include <dns/db.h>
27#include <dns/ecdb.h>
28#include <dns/rdata.h>
29#include <dns/rdataset.h>
30#include <dns/rdatasetiter.h>
31#include <dns/rdataslab.h>
32
33#define ECDB_MAGIC		ISC_MAGIC('E', 'C', 'D', 'B')
34#define VALID_ECDB(db)		((db) != NULL && \
35				 (db)->common.impmagic == ECDB_MAGIC)
36
37#define ECDBNODE_MAGIC		ISC_MAGIC('E', 'C', 'D', 'N')
38#define VALID_ECDBNODE(ecdbn)	ISC_MAGIC_VALID(ecdbn, ECDBNODE_MAGIC)
39
40/*%
41 * The 'ephemeral' cache DB (ecdb) implementation.  An ecdb just provides
42 * temporary storage for ongoing name resolution with the common DB interfaces.
43 * It actually doesn't cache anything.  The implementation expects any stored
44 * data is released within a short period, and does not care about the
45 * scalability in terms of the number of nodes.
46 */
47
48typedef struct dns_ecdb {
49	/* Unlocked */
50	dns_db_t			common;
51	isc_mutex_t			lock;
52
53	/* Locked */
54	unsigned int			references;
55	ISC_LIST(struct dns_ecdbnode)	nodes;
56} dns_ecdb_t;
57
58typedef struct dns_ecdbnode {
59	/* Unlocked */
60	unsigned int			magic;
61	isc_mutex_t			lock;
62	dns_ecdb_t			*ecdb;
63	dns_name_t			name;
64	ISC_LINK(struct dns_ecdbnode)	link;
65
66	/* Locked */
67	ISC_LIST(struct rdatasetheader)	rdatasets;
68	unsigned int			references;
69} dns_ecdbnode_t;
70
71typedef struct rdatasetheader {
72	dns_rdatatype_t			type;
73	dns_ttl_t			ttl;
74	dns_trust_t			trust;
75	dns_rdatatype_t			covers;
76	unsigned int			attributes;
77
78	ISC_LINK(struct rdatasetheader)	link;
79} rdatasetheader_t;
80
81/* Copied from rbtdb.c */
82#define RDATASET_ATTR_NXDOMAIN		0x0010
83#define NXDOMAIN(header) \
84	(((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
85
86static isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin,
87				    dns_dbtype_t type,
88				    dns_rdataclass_t rdclass,
89				    unsigned int argc, char *argv[],
90				    void *driverarg, dns_db_t **dbp);
91
92static void rdataset_disassociate(dns_rdataset_t *rdataset);
93static isc_result_t rdataset_first(dns_rdataset_t *rdataset);
94static isc_result_t rdataset_next(dns_rdataset_t *rdataset);
95static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
96static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
97static unsigned int rdataset_count(dns_rdataset_t *rdataset);
98static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
99
100static dns_rdatasetmethods_t rdataset_methods = {
101	rdataset_disassociate,
102	rdataset_first,
103	rdataset_next,
104	rdataset_current,
105	rdataset_clone,
106	rdataset_count,
107	NULL,			/* addnoqname */
108	NULL,			/* getnoqname */
109	NULL,			/* addclosest */
110	NULL,			/* getclosest */
111	NULL,			/* getadditional */
112	NULL,			/* setadditional */
113	NULL,			/* putadditional */
114	rdataset_settrust,	/* settrust */
115	NULL			/* expire */
116};
117
118typedef struct ecdb_rdatasetiter {
119	dns_rdatasetiter_t		common;
120	rdatasetheader_t	       *current;
121} ecdb_rdatasetiter_t;
122
123static void		rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
124static isc_result_t	rdatasetiter_first(dns_rdatasetiter_t *iterator);
125static isc_result_t	rdatasetiter_next(dns_rdatasetiter_t *iterator);
126static void		rdatasetiter_current(dns_rdatasetiter_t *iterator,
127					     dns_rdataset_t *rdataset);
128
129static dns_rdatasetitermethods_t rdatasetiter_methods = {
130	rdatasetiter_destroy,
131	rdatasetiter_first,
132	rdatasetiter_next,
133	rdatasetiter_current
134};
135
136isc_result_t
137dns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
138	REQUIRE(mctx != NULL);
139	REQUIRE(dbimp != NULL && *dbimp == NULL);
140
141	return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp));
142}
143
144void
145dns_ecdb_unregister(dns_dbimplementation_t **dbimp) {
146	REQUIRE(dbimp != NULL && *dbimp != NULL);
147
148	dns_db_unregister(dbimp);
149}
150
151/*%
152 * DB routines
153 */
154
155static void
156attach(dns_db_t *source, dns_db_t **targetp) {
157	dns_ecdb_t *ecdb = (dns_ecdb_t *)source;
158
159	REQUIRE(VALID_ECDB(ecdb));
160	REQUIRE(targetp != NULL && *targetp == NULL);
161
162	LOCK(&ecdb->lock);
163	ecdb->references++;
164	UNLOCK(&ecdb->lock);
165
166	*targetp = source;
167}
168
169static void
170destroy_ecdb(dns_ecdb_t **ecdbp) {
171	dns_ecdb_t *ecdb = *ecdbp;
172	isc_mem_t *mctx = ecdb->common.mctx;
173
174	if (dns_name_dynamic(&ecdb->common.origin))
175		dns_name_free(&ecdb->common.origin, mctx);
176
177	DESTROYLOCK(&ecdb->lock);
178
179	ecdb->common.impmagic = 0;
180	ecdb->common.magic = 0;
181
182	isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb));
183
184	*ecdbp = NULL;
185}
186
187static void
188detach(dns_db_t **dbp) {
189	dns_ecdb_t *ecdb;
190	isc_boolean_t need_destroy = ISC_FALSE;
191
192	REQUIRE(dbp != NULL);
193	ecdb = (dns_ecdb_t *)*dbp;
194	REQUIRE(VALID_ECDB(ecdb));
195
196	LOCK(&ecdb->lock);
197	ecdb->references--;
198	if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
199		need_destroy = ISC_TRUE;
200	UNLOCK(&ecdb->lock);
201
202	if (need_destroy)
203		destroy_ecdb(&ecdb);
204
205	*dbp = NULL;
206}
207
208static void
209attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
210	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
211	dns_ecdbnode_t *node = (dns_ecdbnode_t *)source;
212
213	REQUIRE(VALID_ECDB(ecdb));
214	REQUIRE(VALID_ECDBNODE(node));
215	REQUIRE(targetp != NULL && *targetp == NULL);
216
217	LOCK(&node->lock);
218	INSIST(node->references > 0);
219	node->references++;
220	INSIST(node->references != 0);		/* Catch overflow. */
221	UNLOCK(&node->lock);
222
223	*targetp = node;
224}
225
226static void
227destroynode(dns_ecdbnode_t *node) {
228	isc_mem_t *mctx;
229	dns_ecdb_t *ecdb = node->ecdb;
230	isc_boolean_t need_destroydb = ISC_FALSE;
231	rdatasetheader_t *header;
232
233	mctx = ecdb->common.mctx;
234
235	LOCK(&ecdb->lock);
236	ISC_LIST_UNLINK(ecdb->nodes, node, link);
237	if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
238		need_destroydb = ISC_TRUE;
239	UNLOCK(&ecdb->lock);
240
241	dns_name_free(&node->name, mctx);
242
243	while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) {
244		unsigned int headersize;
245
246		ISC_LIST_UNLINK(node->rdatasets, header, link);
247		headersize =
248			dns_rdataslab_size((unsigned char *)header,
249					   sizeof(*header));
250		isc_mem_put(mctx, header, headersize);
251	}
252
253	DESTROYLOCK(&node->lock);
254
255	node->magic = 0;
256	isc_mem_put(mctx, node, sizeof(*node));
257
258	if (need_destroydb)
259		destroy_ecdb(&ecdb);
260}
261
262static void
263detachnode(dns_db_t *db, dns_dbnode_t **nodep) {
264	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
265	dns_ecdbnode_t *node;
266	isc_boolean_t need_destroy = ISC_FALSE;
267
268	REQUIRE(VALID_ECDB(ecdb));
269	REQUIRE(nodep != NULL);
270	node = (dns_ecdbnode_t *)*nodep;
271	REQUIRE(VALID_ECDBNODE(node));
272
273	UNUSED(ecdb);		/* in case REQUIRE() is empty */
274
275	LOCK(&node->lock);
276	INSIST(node->references > 0);
277	node->references--;
278	if (node->references == 0)
279		need_destroy = ISC_TRUE;
280	UNLOCK(&node->lock);
281
282	if (need_destroy)
283		destroynode(node);
284
285	*nodep = NULL;
286}
287
288static isc_result_t
289find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
290    dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
291    dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
292    dns_rdataset_t *sigrdataset)
293{
294	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
295
296	REQUIRE(VALID_ECDB(ecdb));
297
298	UNUSED(name);
299	UNUSED(version);
300	UNUSED(type);
301	UNUSED(options);
302	UNUSED(now);
303	UNUSED(nodep);
304	UNUSED(foundname);
305	UNUSED(rdataset);
306	UNUSED(sigrdataset);
307
308	return (ISC_R_NOTFOUND);
309}
310
311static isc_result_t
312findzonecut(dns_db_t *db, dns_name_t *name,
313	    unsigned int options, isc_stdtime_t now,
314	    dns_dbnode_t **nodep, dns_name_t *foundname,
315	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
316{
317	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
318
319	REQUIRE(VALID_ECDB(ecdb));
320
321	UNUSED(name);
322	UNUSED(options);
323	UNUSED(now);
324	UNUSED(nodep);
325	UNUSED(foundname);
326	UNUSED(rdataset);
327	UNUSED(sigrdataset);
328
329	return (ISC_R_NOTFOUND);
330}
331
332static isc_result_t
333findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
334	 dns_dbnode_t **nodep)
335{
336	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
337	isc_mem_t *mctx;
338	dns_ecdbnode_t *node;
339	isc_result_t result;
340
341	REQUIRE(VALID_ECDB(ecdb));
342	REQUIRE(nodep != NULL && *nodep == NULL);
343
344	UNUSED(name);
345
346	if (create != ISC_TRUE)	{
347		/* an 'ephemeral' node is never reused. */
348		return (ISC_R_NOTFOUND);
349	}
350
351	mctx = ecdb->common.mctx;
352	node = isc_mem_get(mctx, sizeof(*node));
353	if (node == NULL)
354		return (ISC_R_NOMEMORY);
355
356	result = isc_mutex_init(&node->lock);
357	if (result != ISC_R_SUCCESS) {
358		UNEXPECTED_ERROR(__FILE__, __LINE__,
359				 "isc_mutex_init() failed: %s",
360				 isc_result_totext(result));
361		isc_mem_put(mctx, node, sizeof(*node));
362		return (ISC_R_UNEXPECTED);
363	}
364
365	dns_name_init(&node->name, NULL);
366	result = dns_name_dup(name, mctx, &node->name);
367	if (result != ISC_R_SUCCESS) {
368		DESTROYLOCK(&node->lock);
369		isc_mem_put(mctx, node, sizeof(*node));
370		return (result);
371	}
372	node->ecdb= ecdb;
373	node->references = 1;
374	ISC_LIST_INIT(node->rdatasets);
375
376	ISC_LINK_INIT(node, link);
377
378	LOCK(&ecdb->lock);
379	ISC_LIST_APPEND(ecdb->nodes, node, link);
380	UNLOCK(&ecdb->lock);
381
382	node->magic = ECDBNODE_MAGIC;
383
384	*nodep = node;
385
386	return (ISC_R_SUCCESS);
387}
388
389static void
390bind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node,
391	      rdatasetheader_t *header, dns_rdataset_t *rdataset)
392{
393	unsigned char *raw;
394
395	/*
396	 * Caller must be holding the node lock.
397	 */
398
399	REQUIRE(!dns_rdataset_isassociated(rdataset));
400
401	rdataset->methods = &rdataset_methods;
402	rdataset->rdclass = ecdb->common.rdclass;
403	rdataset->type = header->type;
404	rdataset->covers = header->covers;
405	rdataset->ttl = header->ttl;
406	rdataset->trust = header->trust;
407	if (NXDOMAIN(header))
408		rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
409
410	rdataset->private1 = ecdb;
411	rdataset->private2 = node;
412	raw = (unsigned char *)header + sizeof(*header);
413	rdataset->private3 = raw;
414	rdataset->count = 0;
415
416	/*
417	 * Reset iterator state.
418	 */
419	rdataset->privateuint4 = 0;
420	rdataset->private5 = NULL;
421
422	INSIST(node->references > 0);
423	node->references++;
424}
425
426static isc_result_t
427addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
428	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
429	    dns_rdataset_t *addedrdataset)
430{
431	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
432	isc_region_t r;
433	isc_result_t result = ISC_R_SUCCESS;
434	isc_mem_t *mctx;
435	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
436	rdatasetheader_t *header;
437
438	REQUIRE(VALID_ECDB(ecdb));
439	REQUIRE(VALID_ECDBNODE(ecdbnode));
440
441	UNUSED(version);
442	UNUSED(now);
443	UNUSED(options);
444
445	mctx = ecdb->common.mctx;
446
447	LOCK(&ecdbnode->lock);
448
449	/*
450	 * Sanity check: this implementation does not allow overriding an
451	 * existing rdataset of the same type.
452	 */
453	for (header = ISC_LIST_HEAD(ecdbnode->rdatasets); header != NULL;
454	     header = ISC_LIST_NEXT(header, link)) {
455		INSIST(header->type != rdataset->type ||
456		       header->covers != rdataset->covers);
457	}
458
459	result = dns_rdataslab_fromrdataset(rdataset, mctx,
460					    &r, sizeof(rdatasetheader_t));
461	if (result != ISC_R_SUCCESS)
462		goto unlock;
463
464	header = (rdatasetheader_t *)r.base;
465	header->type = rdataset->type;
466	header->ttl = rdataset->ttl;
467	header->trust = rdataset->trust;
468	header->covers = rdataset->covers;
469	header->attributes = 0;
470	if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
471		header->attributes |= RDATASET_ATTR_NXDOMAIN;
472	ISC_LINK_INIT(header, link);
473	ISC_LIST_APPEND(ecdbnode->rdatasets, header, link);
474
475	if (addedrdataset == NULL)
476		goto unlock;
477
478	bind_rdataset(ecdb, ecdbnode, header, addedrdataset);
479
480 unlock:
481	UNLOCK(&ecdbnode->lock);
482
483	return (result);
484}
485
486static isc_result_t
487deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
488	       dns_rdatatype_t type, dns_rdatatype_t covers)
489{
490	UNUSED(db);
491	UNUSED(node);
492	UNUSED(version);
493	UNUSED(type);
494	UNUSED(covers);
495
496	return (ISC_R_NOTIMPLEMENTED);
497}
498
499static isc_result_t
500createiterator(dns_db_t *db, unsigned int options,
501	       dns_dbiterator_t **iteratorp)
502{
503	UNUSED(db);
504	UNUSED(options);
505	UNUSED(iteratorp);
506
507	return (ISC_R_NOTIMPLEMENTED);
508}
509
510static isc_result_t
511allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
512	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
513{
514	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
515	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
516	isc_mem_t *mctx;
517	ecdb_rdatasetiter_t *iterator;
518
519	REQUIRE(VALID_ECDB(ecdb));
520	REQUIRE(VALID_ECDBNODE(ecdbnode));
521
522	mctx = ecdb->common.mctx;
523
524	iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t));
525	if (iterator == NULL)
526		return (ISC_R_NOMEMORY);
527
528	iterator->common.magic = DNS_RDATASETITER_MAGIC;
529	iterator->common.methods = &rdatasetiter_methods;
530	iterator->common.db = db;
531	iterator->common.node = NULL;
532	attachnode(db, node, &iterator->common.node);
533	iterator->common.version = version;
534	iterator->common.now = now;
535
536	*iteratorp = (dns_rdatasetiter_t *)iterator;
537
538	return (ISC_R_SUCCESS);
539}
540
541static dns_dbmethods_t ecdb_methods = {
542	attach,
543	detach,
544	NULL,			/* beginload */
545	NULL,			/* endload */
546	NULL,			/* dump */
547	NULL,			/* currentversion */
548	NULL,			/* newversion */
549	NULL,			/* attachversion */
550	NULL,			/* closeversion */
551	findnode,
552	find,
553	findzonecut,
554	attachnode,
555	detachnode,
556	NULL,			/* expirenode */
557	NULL,			/* printnode */
558	createiterator,		/* createiterator */
559	NULL,			/* findrdataset */
560	allrdatasets,
561	addrdataset,
562	NULL,			/* subtractrdataset */
563	deleterdataset,
564	NULL,			/* issecure */
565	NULL,			/* nodecount */
566	NULL,			/* ispersistent */
567	NULL,			/* overmem */
568	NULL,			/* settask */
569	NULL,			/* getoriginnode */
570	NULL,			/* transfernode */
571	NULL,			/* getnsec3parameters */
572	NULL,			/* findnsec3node */
573	NULL,			/* setsigningtime */
574	NULL,			/* getsigningtime */
575	NULL,			/* resigned */
576	NULL,			/* isdnssec */
577	NULL,			/* getrrsetstats */
578	NULL,			/* rpz_enabled */
579	NULL			/* rpz_findips */
580};
581
582static isc_result_t
583dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
584		dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
585		void *driverarg, dns_db_t **dbp)
586{
587	dns_ecdb_t *ecdb;
588	isc_result_t result;
589
590	REQUIRE(mctx != NULL);
591	REQUIRE(origin == dns_rootname);
592	REQUIRE(type == dns_dbtype_cache);
593	REQUIRE(dbp != NULL && *dbp == NULL);
594
595	UNUSED(argc);
596	UNUSED(argv);
597	UNUSED(driverarg);
598
599	ecdb = isc_mem_get(mctx, sizeof(*ecdb));
600	if (ecdb == NULL)
601		return (ISC_R_NOMEMORY);
602
603	ecdb->common.attributes = DNS_DBATTR_CACHE;
604	ecdb->common.rdclass = rdclass;
605	ecdb->common.methods = &ecdb_methods;
606	dns_name_init(&ecdb->common.origin, NULL);
607	result = dns_name_dupwithoffsets(origin, mctx, &ecdb->common.origin);
608	if (result != ISC_R_SUCCESS) {
609		isc_mem_put(mctx, ecdb, sizeof(*ecdb));
610		return (result);
611	}
612
613	result = isc_mutex_init(&ecdb->lock);
614	if (result != ISC_R_SUCCESS) {
615		UNEXPECTED_ERROR(__FILE__, __LINE__,
616				 "isc_mutex_init() failed: %s",
617				 isc_result_totext(result));
618		if (dns_name_dynamic(&ecdb->common.origin))
619			dns_name_free(&ecdb->common.origin, mctx);
620		isc_mem_put(mctx, ecdb, sizeof(*ecdb));
621		return (ISC_R_UNEXPECTED);
622	}
623
624	ecdb->references = 1;
625	ISC_LIST_INIT(ecdb->nodes);
626
627	ecdb->common.mctx = NULL;
628	isc_mem_attach(mctx, &ecdb->common.mctx);
629	ecdb->common.impmagic = ECDB_MAGIC;
630	ecdb->common.magic = DNS_DB_MAGIC;
631
632	*dbp = (dns_db_t *)ecdb;
633
634	return (ISC_R_SUCCESS);
635}
636
637/*%
638 * Rdataset Methods
639 */
640
641static void
642rdataset_disassociate(dns_rdataset_t *rdataset) {
643	dns_db_t *db = rdataset->private1;
644	dns_dbnode_t *node = rdataset->private2;
645
646	dns_db_detachnode(db, &node);
647}
648
649static isc_result_t
650rdataset_first(dns_rdataset_t *rdataset) {
651	unsigned char *raw = rdataset->private3;
652	unsigned int count;
653
654	count = raw[0] * 256 + raw[1];
655	if (count == 0) {
656		rdataset->private5 = NULL;
657		return (ISC_R_NOMORE);
658	}
659#if DNS_RDATASET_FIXED
660	raw += 2 + (4 * count);
661#else
662	raw += 2;
663#endif
664	/*
665	 * The privateuint4 field is the number of rdata beyond the cursor
666	 * position, so we decrement the total count by one before storing
667	 * it.
668	 */
669	count--;
670	rdataset->privateuint4 = count;
671	rdataset->private5 = raw;
672
673	return (ISC_R_SUCCESS);
674}
675
676static isc_result_t
677rdataset_next(dns_rdataset_t *rdataset) {
678	unsigned int count;
679	unsigned int length;
680	unsigned char *raw;
681
682	count = rdataset->privateuint4;
683	if (count == 0)
684		return (ISC_R_NOMORE);
685	count--;
686	rdataset->privateuint4 = count;
687	raw = rdataset->private5;
688	length = raw[0] * 256 + raw[1];
689#if DNS_RDATASET_FIXED
690	raw += length + 4;
691#else
692	raw += length + 2;
693#endif
694	rdataset->private5 = raw;
695
696	return (ISC_R_SUCCESS);
697}
698
699static void
700rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
701	unsigned char *raw = rdataset->private5;
702	isc_region_t r;
703	unsigned int length;
704	unsigned int flags = 0;
705
706	REQUIRE(raw != NULL);
707
708	length = raw[0] * 256 + raw[1];
709#if DNS_RDATASET_FIXED
710	raw += 4;
711#else
712	raw += 2;
713#endif
714	if (rdataset->type == dns_rdatatype_rrsig) {
715		if (*raw & DNS_RDATASLAB_OFFLINE)
716			flags |= DNS_RDATA_OFFLINE;
717		length--;
718		raw++;
719	}
720	r.length = length;
721	r.base = raw;
722	dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
723	rdata->flags |= flags;
724}
725
726static void
727rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
728	dns_db_t *db = source->private1;
729	dns_dbnode_t *node = source->private2;
730	dns_dbnode_t *cloned_node = NULL;
731
732	attachnode(db, node, &cloned_node);
733	*target = *source;
734
735	/*
736	 * Reset iterator state.
737	 */
738	target->privateuint4 = 0;
739	target->private5 = NULL;
740}
741
742static unsigned int
743rdataset_count(dns_rdataset_t *rdataset) {
744	unsigned char *raw = rdataset->private3;
745	unsigned int count;
746
747	count = raw[0] * 256 + raw[1];
748
749	return (count);
750}
751
752static void
753rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
754	rdatasetheader_t *header = rdataset->private3;
755
756	header--;
757	header->trust = rdataset->trust = trust;
758}
759
760/*
761 * Rdataset Iterator Methods
762 */
763
764static void
765rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
766	ecdb_rdatasetiter_t *ecdbiterator;
767	isc_mem_t *mctx;
768
769	REQUIRE(iteratorp != NULL);
770	ecdbiterator = (ecdb_rdatasetiter_t *)*iteratorp;
771	REQUIRE(DNS_RDATASETITER_VALID(&ecdbiterator->common));
772
773	mctx = ecdbiterator->common.db->mctx;
774
775	ecdbiterator->common.magic = 0;
776
777	dns_db_detachnode(ecdbiterator->common.db, &ecdbiterator->common.node);
778	isc_mem_put(mctx, ecdbiterator, sizeof(ecdb_rdatasetiter_t));
779
780	*iteratorp = NULL;
781}
782
783static isc_result_t
784rdatasetiter_first(dns_rdatasetiter_t *iterator) {
785	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
786	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)iterator->node;
787
788	REQUIRE(DNS_RDATASETITER_VALID(iterator));
789
790	if (ISC_LIST_EMPTY(ecdbnode->rdatasets))
791		return (ISC_R_NOMORE);
792	ecdbiterator->current = ISC_LIST_HEAD(ecdbnode->rdatasets);
793	return (ISC_R_SUCCESS);
794}
795
796static isc_result_t
797rdatasetiter_next(dns_rdatasetiter_t *iterator) {
798	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
799
800	REQUIRE(DNS_RDATASETITER_VALID(iterator));
801
802	ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link);
803	if (ecdbiterator->current == NULL)
804		return (ISC_R_NOMORE);
805	else
806		return (ISC_R_SUCCESS);
807}
808
809static void
810rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
811	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
812	dns_ecdb_t *ecdb;
813
814	ecdb = (dns_ecdb_t *)iterator->db;
815	REQUIRE(VALID_ECDB(ecdb));
816
817	bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset);
818}
819