ecdb.c revision 234010
1224090Sdougb/*
2234010Sdougb * Copyright (C) 2009-2012  Internet Systems Consortium, Inc. ("ISC")
3224090Sdougb *
4224090Sdougb * Permission to use, copy, modify, and/or distribute this software for any
5224090Sdougb * purpose with or without fee is hereby granted, provided that the above
6224090Sdougb * copyright notice and this permission notice appear in all copies.
7224090Sdougb *
8224090Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9224090Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10224090Sdougb * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11224090Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12224090Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13224090Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14224090Sdougb * PERFORMANCE OF THIS SOFTWARE.
15224090Sdougb */
16224090Sdougb
17234010Sdougb/* $Id$ */
18224090Sdougb
19224090Sdougb#include "config.h"
20224090Sdougb
21224090Sdougb#include <isc/result.h>
22224090Sdougb#include <isc/util.h>
23224090Sdougb#include <isc/mutex.h>
24224090Sdougb#include <isc/mem.h>
25224090Sdougb
26224090Sdougb#include <dns/db.h>
27224090Sdougb#include <dns/ecdb.h>
28224090Sdougb#include <dns/rdata.h>
29224090Sdougb#include <dns/rdataset.h>
30224090Sdougb#include <dns/rdatasetiter.h>
31224090Sdougb#include <dns/rdataslab.h>
32224090Sdougb
33224090Sdougb#define ECDB_MAGIC		ISC_MAGIC('E', 'C', 'D', 'B')
34224090Sdougb#define VALID_ECDB(db)		((db) != NULL && \
35224090Sdougb				 (db)->common.impmagic == ECDB_MAGIC)
36224090Sdougb
37224090Sdougb#define ECDBNODE_MAGIC		ISC_MAGIC('E', 'C', 'D', 'N')
38224090Sdougb#define VALID_ECDBNODE(ecdbn)	ISC_MAGIC_VALID(ecdbn, ECDBNODE_MAGIC)
39224090Sdougb
40224090Sdougb/*%
41224090Sdougb * The 'ephemeral' cache DB (ecdb) implementation.  An ecdb just provides
42224090Sdougb * temporary storage for ongoing name resolution with the common DB interfaces.
43224090Sdougb * It actually doesn't cache anything.  The implementation expects any stored
44224090Sdougb * data is released within a short period, and does not care about the
45224090Sdougb * scalability in terms of the number of nodes.
46224090Sdougb */
47224090Sdougb
48224090Sdougbtypedef struct dns_ecdb {
49224090Sdougb	/* Unlocked */
50224090Sdougb	dns_db_t			common;
51224090Sdougb	isc_mutex_t			lock;
52224090Sdougb
53224090Sdougb	/* Locked */
54224090Sdougb	unsigned int			references;
55224090Sdougb	ISC_LIST(struct dns_ecdbnode)	nodes;
56224090Sdougb} dns_ecdb_t;
57224090Sdougb
58224090Sdougbtypedef struct dns_ecdbnode {
59224090Sdougb	/* Unlocked */
60224090Sdougb	unsigned int			magic;
61224090Sdougb	isc_mutex_t			lock;
62224090Sdougb	dns_ecdb_t			*ecdb;
63224090Sdougb	dns_name_t			name;
64224090Sdougb	ISC_LINK(struct dns_ecdbnode)	link;
65224090Sdougb
66224090Sdougb	/* Locked */
67224090Sdougb	ISC_LIST(struct rdatasetheader)	rdatasets;
68224090Sdougb	unsigned int			references;
69224090Sdougb} dns_ecdbnode_t;
70224090Sdougb
71224090Sdougbtypedef struct rdatasetheader {
72224090Sdougb	dns_rdatatype_t			type;
73224090Sdougb	dns_ttl_t			ttl;
74224090Sdougb	dns_trust_t			trust;
75224090Sdougb	dns_rdatatype_t			covers;
76224090Sdougb	unsigned int			attributes;
77224090Sdougb
78224090Sdougb	ISC_LINK(struct rdatasetheader)	link;
79224090Sdougb} rdatasetheader_t;
80224090Sdougb
81224090Sdougb/* Copied from rbtdb.c */
82224090Sdougb#define RDATASET_ATTR_NXDOMAIN		0x0010
83224090Sdougb#define NXDOMAIN(header) \
84224090Sdougb	(((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
85224090Sdougb
86224090Sdougbstatic isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin,
87224090Sdougb				    dns_dbtype_t type,
88224090Sdougb				    dns_rdataclass_t rdclass,
89224090Sdougb				    unsigned int argc, char *argv[],
90224090Sdougb				    void *driverarg, dns_db_t **dbp);
91224090Sdougb
92224090Sdougbstatic void rdataset_disassociate(dns_rdataset_t *rdataset);
93224090Sdougbstatic isc_result_t rdataset_first(dns_rdataset_t *rdataset);
94224090Sdougbstatic isc_result_t rdataset_next(dns_rdataset_t *rdataset);
95224090Sdougbstatic void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
96224090Sdougbstatic void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
97224090Sdougbstatic unsigned int rdataset_count(dns_rdataset_t *rdataset);
98224090Sdougbstatic void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
99224090Sdougb
100224090Sdougbstatic dns_rdatasetmethods_t rdataset_methods = {
101224090Sdougb	rdataset_disassociate,
102224090Sdougb	rdataset_first,
103224090Sdougb	rdataset_next,
104224090Sdougb	rdataset_current,
105224090Sdougb	rdataset_clone,
106224090Sdougb	rdataset_count,
107224090Sdougb	NULL,			/* addnoqname */
108224090Sdougb	NULL,			/* getnoqname */
109224090Sdougb	NULL,			/* addclosest */
110224090Sdougb	NULL,			/* getclosest */
111224090Sdougb	NULL,			/* getadditional */
112224090Sdougb	NULL,			/* setadditional */
113224090Sdougb	NULL,			/* putadditional */
114224090Sdougb	rdataset_settrust,	/* settrust */
115224090Sdougb	NULL			/* expire */
116224090Sdougb};
117224090Sdougb
118224090Sdougbtypedef struct ecdb_rdatasetiter {
119224090Sdougb	dns_rdatasetiter_t		common;
120224090Sdougb	rdatasetheader_t	       *current;
121224090Sdougb} ecdb_rdatasetiter_t;
122224090Sdougb
123224090Sdougbstatic void		rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
124224090Sdougbstatic isc_result_t	rdatasetiter_first(dns_rdatasetiter_t *iterator);
125224090Sdougbstatic isc_result_t	rdatasetiter_next(dns_rdatasetiter_t *iterator);
126224090Sdougbstatic void		rdatasetiter_current(dns_rdatasetiter_t *iterator,
127224090Sdougb					     dns_rdataset_t *rdataset);
128224090Sdougb
129224090Sdougbstatic dns_rdatasetitermethods_t rdatasetiter_methods = {
130224090Sdougb	rdatasetiter_destroy,
131224090Sdougb	rdatasetiter_first,
132224090Sdougb	rdatasetiter_next,
133224090Sdougb	rdatasetiter_current
134224090Sdougb};
135224090Sdougb
136224090Sdougbisc_result_t
137224090Sdougbdns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
138224090Sdougb	REQUIRE(mctx != NULL);
139224090Sdougb	REQUIRE(dbimp != NULL && *dbimp == NULL);
140224090Sdougb
141224090Sdougb	return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp));
142224090Sdougb}
143224090Sdougb
144224090Sdougbvoid
145224090Sdougbdns_ecdb_unregister(dns_dbimplementation_t **dbimp) {
146224090Sdougb	REQUIRE(dbimp != NULL && *dbimp != NULL);
147224090Sdougb
148224090Sdougb	dns_db_unregister(dbimp);
149224090Sdougb}
150224090Sdougb
151224090Sdougb/*%
152224090Sdougb * DB routines
153224090Sdougb */
154224090Sdougb
155224090Sdougbstatic void
156224090Sdougbattach(dns_db_t *source, dns_db_t **targetp) {
157224090Sdougb	dns_ecdb_t *ecdb = (dns_ecdb_t *)source;
158224090Sdougb
159224090Sdougb	REQUIRE(VALID_ECDB(ecdb));
160224090Sdougb	REQUIRE(targetp != NULL && *targetp == NULL);
161224090Sdougb
162224090Sdougb	LOCK(&ecdb->lock);
163224090Sdougb	ecdb->references++;
164224090Sdougb	UNLOCK(&ecdb->lock);
165224090Sdougb
166224090Sdougb	*targetp = source;
167224090Sdougb}
168224090Sdougb
169224090Sdougbstatic void
170224090Sdougbdestroy_ecdb(dns_ecdb_t **ecdbp) {
171224090Sdougb	dns_ecdb_t *ecdb = *ecdbp;
172224090Sdougb	isc_mem_t *mctx = ecdb->common.mctx;
173224090Sdougb
174224090Sdougb	if (dns_name_dynamic(&ecdb->common.origin))
175224090Sdougb		dns_name_free(&ecdb->common.origin, mctx);
176224090Sdougb
177224090Sdougb	DESTROYLOCK(&ecdb->lock);
178224090Sdougb
179224090Sdougb	ecdb->common.impmagic = 0;
180224090Sdougb	ecdb->common.magic = 0;
181224090Sdougb
182224090Sdougb	isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb));
183224090Sdougb
184224090Sdougb	*ecdbp = NULL;
185224090Sdougb}
186224090Sdougb
187224090Sdougbstatic void
188224090Sdougbdetach(dns_db_t **dbp) {
189224090Sdougb	dns_ecdb_t *ecdb;
190224090Sdougb	isc_boolean_t need_destroy = ISC_FALSE;
191224090Sdougb
192224090Sdougb	REQUIRE(dbp != NULL);
193224090Sdougb	ecdb = (dns_ecdb_t *)*dbp;
194224090Sdougb	REQUIRE(VALID_ECDB(ecdb));
195224090Sdougb
196224090Sdougb	LOCK(&ecdb->lock);
197224090Sdougb	ecdb->references--;
198224090Sdougb	if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
199224090Sdougb		need_destroy = ISC_TRUE;
200224090Sdougb	UNLOCK(&ecdb->lock);
201224090Sdougb
202224090Sdougb	if (need_destroy)
203224090Sdougb		destroy_ecdb(&ecdb);
204224090Sdougb
205224090Sdougb	*dbp = NULL;
206224090Sdougb}
207224090Sdougb
208224090Sdougbstatic void
209224090Sdougbattachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
210224090Sdougb	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
211224090Sdougb	dns_ecdbnode_t *node = (dns_ecdbnode_t *)source;
212224090Sdougb
213224090Sdougb	REQUIRE(VALID_ECDB(ecdb));
214224090Sdougb	REQUIRE(VALID_ECDBNODE(node));
215224090Sdougb	REQUIRE(targetp != NULL && *targetp == NULL);
216224090Sdougb
217224090Sdougb	LOCK(&node->lock);
218224090Sdougb	INSIST(node->references > 0);
219224090Sdougb	node->references++;
220224090Sdougb	INSIST(node->references != 0);		/* Catch overflow. */
221224090Sdougb	UNLOCK(&node->lock);
222224090Sdougb
223224090Sdougb	*targetp = node;
224224090Sdougb}
225224090Sdougb
226224090Sdougbstatic void
227224090Sdougbdestroynode(dns_ecdbnode_t *node) {
228224090Sdougb	isc_mem_t *mctx;
229224090Sdougb	dns_ecdb_t *ecdb = node->ecdb;
230224090Sdougb	isc_boolean_t need_destroydb = ISC_FALSE;
231224090Sdougb	rdatasetheader_t *header;
232224090Sdougb
233224090Sdougb	mctx = ecdb->common.mctx;
234224090Sdougb
235224090Sdougb	LOCK(&ecdb->lock);
236224090Sdougb	ISC_LIST_UNLINK(ecdb->nodes, node, link);
237224090Sdougb	if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
238224090Sdougb		need_destroydb = ISC_TRUE;
239224090Sdougb	UNLOCK(&ecdb->lock);
240224090Sdougb
241224090Sdougb	dns_name_free(&node->name, mctx);
242224090Sdougb
243224090Sdougb	while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) {
244224090Sdougb		unsigned int headersize;
245224090Sdougb
246224090Sdougb		ISC_LIST_UNLINK(node->rdatasets, header, link);
247224090Sdougb		headersize =
248224090Sdougb			dns_rdataslab_size((unsigned char *)header,
249224090Sdougb					   sizeof(*header));
250224090Sdougb		isc_mem_put(mctx, header, headersize);
251224090Sdougb	}
252224090Sdougb
253224090Sdougb	DESTROYLOCK(&node->lock);
254224090Sdougb
255224090Sdougb	node->magic = 0;
256224090Sdougb	isc_mem_put(mctx, node, sizeof(*node));
257224090Sdougb
258224090Sdougb	if (need_destroydb)
259224090Sdougb		destroy_ecdb(&ecdb);
260224090Sdougb}
261224090Sdougb
262224090Sdougbstatic void
263224090Sdougbdetachnode(dns_db_t *db, dns_dbnode_t **nodep) {
264224090Sdougb	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
265224090Sdougb	dns_ecdbnode_t *node;
266224090Sdougb	isc_boolean_t need_destroy = ISC_FALSE;
267224090Sdougb
268224090Sdougb	REQUIRE(VALID_ECDB(ecdb));
269224090Sdougb	REQUIRE(nodep != NULL);
270224090Sdougb	node = (dns_ecdbnode_t *)*nodep;
271224090Sdougb	REQUIRE(VALID_ECDBNODE(node));
272224090Sdougb
273224090Sdougb	UNUSED(ecdb);		/* in case REQUIRE() is empty */
274224090Sdougb
275224090Sdougb	LOCK(&node->lock);
276224090Sdougb	INSIST(node->references > 0);
277224090Sdougb	node->references--;
278224090Sdougb	if (node->references == 0)
279224090Sdougb		need_destroy = ISC_TRUE;
280224090Sdougb	UNLOCK(&node->lock);
281224090Sdougb
282224090Sdougb	if (need_destroy)
283224090Sdougb		destroynode(node);
284224090Sdougb
285224090Sdougb	*nodep = NULL;
286224090Sdougb}
287224090Sdougb
288224090Sdougbstatic isc_result_t
289224090Sdougbfind(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
290224090Sdougb    dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
291224090Sdougb    dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
292224090Sdougb    dns_rdataset_t *sigrdataset)
293224090Sdougb{
294224090Sdougb	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
295224090Sdougb
296224090Sdougb	REQUIRE(VALID_ECDB(ecdb));
297224090Sdougb
298224090Sdougb	UNUSED(name);
299224090Sdougb	UNUSED(version);
300224090Sdougb	UNUSED(type);
301224090Sdougb	UNUSED(options);
302224090Sdougb	UNUSED(now);
303224090Sdougb	UNUSED(nodep);
304224090Sdougb	UNUSED(foundname);
305224090Sdougb	UNUSED(rdataset);
306224090Sdougb	UNUSED(sigrdataset);
307224090Sdougb
308224090Sdougb	return (ISC_R_NOTFOUND);
309224090Sdougb}
310224090Sdougb
311224090Sdougbstatic isc_result_t
312224090Sdougbfindzonecut(dns_db_t *db, dns_name_t *name,
313224090Sdougb	    unsigned int options, isc_stdtime_t now,
314224090Sdougb	    dns_dbnode_t **nodep, dns_name_t *foundname,
315224090Sdougb	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
316224090Sdougb{
317224090Sdougb	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
318224090Sdougb
319224090Sdougb	REQUIRE(VALID_ECDB(ecdb));
320224090Sdougb
321224090Sdougb	UNUSED(name);
322224090Sdougb	UNUSED(options);
323224090Sdougb	UNUSED(now);
324224090Sdougb	UNUSED(nodep);
325224090Sdougb	UNUSED(foundname);
326224090Sdougb	UNUSED(rdataset);
327224090Sdougb	UNUSED(sigrdataset);
328224090Sdougb
329224090Sdougb	return (ISC_R_NOTFOUND);
330224090Sdougb}
331224090Sdougb
332224090Sdougbstatic isc_result_t
333224090Sdougbfindnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
334224090Sdougb	 dns_dbnode_t **nodep)
335224090Sdougb{
336224090Sdougb	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
337224090Sdougb	isc_mem_t *mctx;
338224090Sdougb	dns_ecdbnode_t *node;
339224090Sdougb	isc_result_t result;
340224090Sdougb
341224090Sdougb	REQUIRE(VALID_ECDB(ecdb));
342224090Sdougb	REQUIRE(nodep != NULL && *nodep == NULL);
343224090Sdougb
344224090Sdougb	UNUSED(name);
345224090Sdougb
346224090Sdougb	if (create != ISC_TRUE)	{
347224090Sdougb		/* an 'ephemeral' node is never reused. */
348224090Sdougb		return (ISC_R_NOTFOUND);
349224090Sdougb	}
350224090Sdougb
351224090Sdougb	mctx = ecdb->common.mctx;
352224090Sdougb	node = isc_mem_get(mctx, sizeof(*node));
353224090Sdougb	if (node == NULL)
354224090Sdougb		return (ISC_R_NOMEMORY);
355224090Sdougb
356224090Sdougb	result = isc_mutex_init(&node->lock);
357224090Sdougb	if (result != ISC_R_SUCCESS) {
358224090Sdougb		UNEXPECTED_ERROR(__FILE__, __LINE__,
359224090Sdougb				 "isc_mutex_init() failed: %s",
360224090Sdougb				 isc_result_totext(result));
361224090Sdougb		isc_mem_put(mctx, node, sizeof(*node));
362224090Sdougb		return (ISC_R_UNEXPECTED);
363224090Sdougb	}
364224090Sdougb
365224090Sdougb	dns_name_init(&node->name, NULL);
366224090Sdougb	result = dns_name_dup(name, mctx, &node->name);
367224090Sdougb	if (result != ISC_R_SUCCESS) {
368224090Sdougb		DESTROYLOCK(&node->lock);
369224090Sdougb		isc_mem_put(mctx, node, sizeof(*node));
370224090Sdougb		return (result);
371224090Sdougb	}
372224090Sdougb	node->ecdb= ecdb;
373224090Sdougb	node->references = 1;
374224090Sdougb	ISC_LIST_INIT(node->rdatasets);
375224090Sdougb
376224090Sdougb	ISC_LINK_INIT(node, link);
377224090Sdougb
378224090Sdougb	LOCK(&ecdb->lock);
379224090Sdougb	ISC_LIST_APPEND(ecdb->nodes, node, link);
380224090Sdougb	UNLOCK(&ecdb->lock);
381224090Sdougb
382224090Sdougb	node->magic = ECDBNODE_MAGIC;
383224090Sdougb
384224090Sdougb	*nodep = node;
385224090Sdougb
386224090Sdougb	return (ISC_R_SUCCESS);
387224090Sdougb}
388224090Sdougb
389224090Sdougbstatic void
390224090Sdougbbind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node,
391224090Sdougb	      rdatasetheader_t *header, dns_rdataset_t *rdataset)
392224090Sdougb{
393224090Sdougb	unsigned char *raw;
394224090Sdougb
395224090Sdougb	/*
396224090Sdougb	 * Caller must be holding the node lock.
397224090Sdougb	 */
398224090Sdougb
399224090Sdougb	REQUIRE(!dns_rdataset_isassociated(rdataset));
400224090Sdougb
401224090Sdougb	rdataset->methods = &rdataset_methods;
402224090Sdougb	rdataset->rdclass = ecdb->common.rdclass;
403224090Sdougb	rdataset->type = header->type;
404224090Sdougb	rdataset->covers = header->covers;
405224090Sdougb	rdataset->ttl = header->ttl;
406224090Sdougb	rdataset->trust = header->trust;
407224090Sdougb	if (NXDOMAIN(header))
408224090Sdougb		rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
409224090Sdougb
410224090Sdougb	rdataset->private1 = ecdb;
411224090Sdougb	rdataset->private2 = node;
412224090Sdougb	raw = (unsigned char *)header + sizeof(*header);
413224090Sdougb	rdataset->private3 = raw;
414224090Sdougb	rdataset->count = 0;
415224090Sdougb
416224090Sdougb	/*
417224090Sdougb	 * Reset iterator state.
418224090Sdougb	 */
419224090Sdougb	rdataset->privateuint4 = 0;
420224090Sdougb	rdataset->private5 = NULL;
421224090Sdougb
422224090Sdougb	INSIST(node->references > 0);
423224090Sdougb	node->references++;
424224090Sdougb}
425224090Sdougb
426224090Sdougbstatic isc_result_t
427224090Sdougbaddrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
428224090Sdougb	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
429224090Sdougb	    dns_rdataset_t *addedrdataset)
430224090Sdougb{
431224090Sdougb	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
432224090Sdougb	isc_region_t r;
433224090Sdougb	isc_result_t result = ISC_R_SUCCESS;
434224090Sdougb	isc_mem_t *mctx;
435224090Sdougb	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
436224090Sdougb	rdatasetheader_t *header;
437224090Sdougb
438224090Sdougb	REQUIRE(VALID_ECDB(ecdb));
439224090Sdougb	REQUIRE(VALID_ECDBNODE(ecdbnode));
440224090Sdougb
441224090Sdougb	UNUSED(version);
442224090Sdougb	UNUSED(now);
443224090Sdougb	UNUSED(options);
444224090Sdougb
445224090Sdougb	mctx = ecdb->common.mctx;
446224090Sdougb
447224090Sdougb	LOCK(&ecdbnode->lock);
448224090Sdougb
449224090Sdougb	/*
450224090Sdougb	 * Sanity check: this implementation does not allow overriding an
451224090Sdougb	 * existing rdataset of the same type.
452224090Sdougb	 */
453224090Sdougb	for (header = ISC_LIST_HEAD(ecdbnode->rdatasets); header != NULL;
454224090Sdougb	     header = ISC_LIST_NEXT(header, link)) {
455224090Sdougb		INSIST(header->type != rdataset->type ||
456224090Sdougb		       header->covers != rdataset->covers);
457224090Sdougb	}
458224090Sdougb
459224090Sdougb	result = dns_rdataslab_fromrdataset(rdataset, mctx,
460224090Sdougb					    &r, sizeof(rdatasetheader_t));
461224090Sdougb	if (result != ISC_R_SUCCESS)
462224090Sdougb		goto unlock;
463224090Sdougb
464224090Sdougb	header = (rdatasetheader_t *)r.base;
465224090Sdougb	header->type = rdataset->type;
466224090Sdougb	header->ttl = rdataset->ttl;
467224090Sdougb	header->trust = rdataset->trust;
468224090Sdougb	header->covers = rdataset->covers;
469224090Sdougb	header->attributes = 0;
470224090Sdougb	if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
471224090Sdougb		header->attributes |= RDATASET_ATTR_NXDOMAIN;
472224090Sdougb	ISC_LINK_INIT(header, link);
473224090Sdougb	ISC_LIST_APPEND(ecdbnode->rdatasets, header, link);
474224090Sdougb
475224090Sdougb	if (addedrdataset == NULL)
476224090Sdougb		goto unlock;
477224090Sdougb
478224090Sdougb	bind_rdataset(ecdb, ecdbnode, header, addedrdataset);
479224090Sdougb
480224090Sdougb unlock:
481224090Sdougb	UNLOCK(&ecdbnode->lock);
482224090Sdougb
483224090Sdougb	return (result);
484224090Sdougb}
485224090Sdougb
486224090Sdougbstatic isc_result_t
487224090Sdougbdeleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
488224090Sdougb	       dns_rdatatype_t type, dns_rdatatype_t covers)
489224090Sdougb{
490224090Sdougb	UNUSED(db);
491224090Sdougb	UNUSED(node);
492224090Sdougb	UNUSED(version);
493224090Sdougb	UNUSED(type);
494224090Sdougb	UNUSED(covers);
495224090Sdougb
496224090Sdougb	return (ISC_R_NOTIMPLEMENTED);
497224090Sdougb}
498224090Sdougb
499224090Sdougbstatic isc_result_t
500224090Sdougbcreateiterator(dns_db_t *db, unsigned int options,
501224090Sdougb	       dns_dbiterator_t **iteratorp)
502224090Sdougb{
503224090Sdougb	UNUSED(db);
504224090Sdougb	UNUSED(options);
505224090Sdougb	UNUSED(iteratorp);
506224090Sdougb
507224090Sdougb	return (ISC_R_NOTIMPLEMENTED);
508224090Sdougb}
509224090Sdougb
510224090Sdougbstatic isc_result_t
511224090Sdougballrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
512224090Sdougb	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
513224090Sdougb{
514224090Sdougb	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
515224090Sdougb	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
516224090Sdougb	isc_mem_t *mctx;
517224090Sdougb	ecdb_rdatasetiter_t *iterator;
518224090Sdougb
519224090Sdougb	REQUIRE(VALID_ECDB(ecdb));
520224090Sdougb	REQUIRE(VALID_ECDBNODE(ecdbnode));
521224090Sdougb
522224090Sdougb	mctx = ecdb->common.mctx;
523224090Sdougb
524224090Sdougb	iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t));
525224090Sdougb	if (iterator == NULL)
526224090Sdougb		return (ISC_R_NOMEMORY);
527224090Sdougb
528224090Sdougb	iterator->common.magic = DNS_RDATASETITER_MAGIC;
529224090Sdougb	iterator->common.methods = &rdatasetiter_methods;
530224090Sdougb	iterator->common.db = db;
531224090Sdougb	iterator->common.node = NULL;
532224090Sdougb	attachnode(db, node, &iterator->common.node);
533224090Sdougb	iterator->common.version = version;
534224090Sdougb	iterator->common.now = now;
535224090Sdougb
536224090Sdougb	*iteratorp = (dns_rdatasetiter_t *)iterator;
537224090Sdougb
538224090Sdougb	return (ISC_R_SUCCESS);
539224090Sdougb}
540224090Sdougb
541224090Sdougbstatic dns_dbmethods_t ecdb_methods = {
542224090Sdougb	attach,
543224090Sdougb	detach,
544224090Sdougb	NULL,			/* beginload */
545224090Sdougb	NULL,			/* endload */
546224090Sdougb	NULL,			/* dump */
547224090Sdougb	NULL,			/* currentversion */
548224090Sdougb	NULL,			/* newversion */
549224090Sdougb	NULL,			/* attachversion */
550224090Sdougb	NULL,			/* closeversion */
551224090Sdougb	findnode,
552224090Sdougb	find,
553224090Sdougb	findzonecut,
554224090Sdougb	attachnode,
555224090Sdougb	detachnode,
556224090Sdougb	NULL,			/* expirenode */
557224090Sdougb	NULL,			/* printnode */
558224090Sdougb	createiterator,		/* createiterator */
559224090Sdougb	NULL,			/* findrdataset */
560224090Sdougb	allrdatasets,
561224090Sdougb	addrdataset,
562224090Sdougb	NULL,			/* subtractrdataset */
563224090Sdougb	deleterdataset,
564224090Sdougb	NULL,			/* issecure */
565224090Sdougb	NULL,			/* nodecount */
566224090Sdougb	NULL,			/* ispersistent */
567224090Sdougb	NULL,			/* overmem */
568224090Sdougb	NULL,			/* settask */
569224090Sdougb	NULL,			/* getoriginnode */
570224090Sdougb	NULL,			/* transfernode */
571224090Sdougb	NULL,			/* getnsec3parameters */
572224090Sdougb	NULL,			/* findnsec3node */
573224090Sdougb	NULL,			/* setsigningtime */
574224090Sdougb	NULL,			/* getsigningtime */
575224090Sdougb	NULL,			/* resigned */
576224090Sdougb	NULL,			/* isdnssec */
577224090Sdougb	NULL,			/* getrrsetstats */
578224090Sdougb	NULL,			/* rpz_enabled */
579224090Sdougb	NULL			/* rpz_findips */
580224090Sdougb};
581224090Sdougb
582224090Sdougbstatic isc_result_t
583224090Sdougbdns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
584224090Sdougb		dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
585224090Sdougb		void *driverarg, dns_db_t **dbp)
586224090Sdougb{
587224090Sdougb	dns_ecdb_t *ecdb;
588224090Sdougb	isc_result_t result;
589224090Sdougb
590224090Sdougb	REQUIRE(mctx != NULL);
591224090Sdougb	REQUIRE(origin == dns_rootname);
592224090Sdougb	REQUIRE(type == dns_dbtype_cache);
593224090Sdougb	REQUIRE(dbp != NULL && *dbp == NULL);
594224090Sdougb
595224090Sdougb	UNUSED(argc);
596224090Sdougb	UNUSED(argv);
597224090Sdougb	UNUSED(driverarg);
598224090Sdougb
599224090Sdougb	ecdb = isc_mem_get(mctx, sizeof(*ecdb));
600224090Sdougb	if (ecdb == NULL)
601224090Sdougb		return (ISC_R_NOMEMORY);
602224090Sdougb
603224090Sdougb	ecdb->common.attributes = DNS_DBATTR_CACHE;
604224090Sdougb	ecdb->common.rdclass = rdclass;
605224090Sdougb	ecdb->common.methods = &ecdb_methods;
606224090Sdougb	dns_name_init(&ecdb->common.origin, NULL);
607224090Sdougb	result = dns_name_dupwithoffsets(origin, mctx, &ecdb->common.origin);
608224090Sdougb	if (result != ISC_R_SUCCESS) {
609224090Sdougb		isc_mem_put(mctx, ecdb, sizeof(*ecdb));
610224090Sdougb		return (result);
611224090Sdougb	}
612224090Sdougb
613224090Sdougb	result = isc_mutex_init(&ecdb->lock);
614224090Sdougb	if (result != ISC_R_SUCCESS) {
615224090Sdougb		UNEXPECTED_ERROR(__FILE__, __LINE__,
616224090Sdougb				 "isc_mutex_init() failed: %s",
617224090Sdougb				 isc_result_totext(result));
618224090Sdougb		if (dns_name_dynamic(&ecdb->common.origin))
619224090Sdougb			dns_name_free(&ecdb->common.origin, mctx);
620224090Sdougb		isc_mem_put(mctx, ecdb, sizeof(*ecdb));
621224090Sdougb		return (ISC_R_UNEXPECTED);
622224090Sdougb	}
623224090Sdougb
624224090Sdougb	ecdb->references = 1;
625224090Sdougb	ISC_LIST_INIT(ecdb->nodes);
626224090Sdougb
627224090Sdougb	ecdb->common.mctx = NULL;
628224090Sdougb	isc_mem_attach(mctx, &ecdb->common.mctx);
629224090Sdougb	ecdb->common.impmagic = ECDB_MAGIC;
630224090Sdougb	ecdb->common.magic = DNS_DB_MAGIC;
631224090Sdougb
632224090Sdougb	*dbp = (dns_db_t *)ecdb;
633224090Sdougb
634224090Sdougb	return (ISC_R_SUCCESS);
635224090Sdougb}
636224090Sdougb
637224090Sdougb/*%
638224090Sdougb * Rdataset Methods
639224090Sdougb */
640224090Sdougb
641224090Sdougbstatic void
642224090Sdougbrdataset_disassociate(dns_rdataset_t *rdataset) {
643224090Sdougb	dns_db_t *db = rdataset->private1;
644224090Sdougb	dns_dbnode_t *node = rdataset->private2;
645224090Sdougb
646224090Sdougb	dns_db_detachnode(db, &node);
647224090Sdougb}
648224090Sdougb
649224090Sdougbstatic isc_result_t
650224090Sdougbrdataset_first(dns_rdataset_t *rdataset) {
651224090Sdougb	unsigned char *raw = rdataset->private3;
652224090Sdougb	unsigned int count;
653224090Sdougb
654224090Sdougb	count = raw[0] * 256 + raw[1];
655224090Sdougb	if (count == 0) {
656224090Sdougb		rdataset->private5 = NULL;
657224090Sdougb		return (ISC_R_NOMORE);
658224090Sdougb	}
659234010Sdougb#if DNS_RDATASET_FIXED
660234010Sdougb	raw += 2 + (4 * count);
661234010Sdougb#else
662224090Sdougb	raw += 2;
663234010Sdougb#endif
664224090Sdougb	/*
665224090Sdougb	 * The privateuint4 field is the number of rdata beyond the cursor
666224090Sdougb	 * position, so we decrement the total count by one before storing
667224090Sdougb	 * it.
668224090Sdougb	 */
669224090Sdougb	count--;
670224090Sdougb	rdataset->privateuint4 = count;
671224090Sdougb	rdataset->private5 = raw;
672224090Sdougb
673224090Sdougb	return (ISC_R_SUCCESS);
674224090Sdougb}
675224090Sdougb
676224090Sdougbstatic isc_result_t
677224090Sdougbrdataset_next(dns_rdataset_t *rdataset) {
678224090Sdougb	unsigned int count;
679224090Sdougb	unsigned int length;
680224090Sdougb	unsigned char *raw;
681224090Sdougb
682224090Sdougb	count = rdataset->privateuint4;
683224090Sdougb	if (count == 0)
684224090Sdougb		return (ISC_R_NOMORE);
685224090Sdougb	count--;
686224090Sdougb	rdataset->privateuint4 = count;
687224090Sdougb	raw = rdataset->private5;
688224090Sdougb	length = raw[0] * 256 + raw[1];
689234010Sdougb#if DNS_RDATASET_FIXED
690234010Sdougb	raw += length + 4;
691234010Sdougb#else
692224090Sdougb	raw += length + 2;
693234010Sdougb#endif
694224090Sdougb	rdataset->private5 = raw;
695224090Sdougb
696224090Sdougb	return (ISC_R_SUCCESS);
697224090Sdougb}
698224090Sdougb
699224090Sdougbstatic void
700224090Sdougbrdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
701224090Sdougb	unsigned char *raw = rdataset->private5;
702224090Sdougb	isc_region_t r;
703224090Sdougb	unsigned int length;
704224090Sdougb	unsigned int flags = 0;
705224090Sdougb
706224090Sdougb	REQUIRE(raw != NULL);
707224090Sdougb
708224090Sdougb	length = raw[0] * 256 + raw[1];
709234010Sdougb#if DNS_RDATASET_FIXED
710234010Sdougb	raw += 4;
711234010Sdougb#else
712224090Sdougb	raw += 2;
713234010Sdougb#endif
714224090Sdougb	if (rdataset->type == dns_rdatatype_rrsig) {
715224090Sdougb		if (*raw & DNS_RDATASLAB_OFFLINE)
716224090Sdougb			flags |= DNS_RDATA_OFFLINE;
717224090Sdougb		length--;
718224090Sdougb		raw++;
719224090Sdougb	}
720224090Sdougb	r.length = length;
721224090Sdougb	r.base = raw;
722224090Sdougb	dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
723224090Sdougb	rdata->flags |= flags;
724224090Sdougb}
725224090Sdougb
726224090Sdougbstatic void
727224090Sdougbrdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
728224090Sdougb	dns_db_t *db = source->private1;
729224090Sdougb	dns_dbnode_t *node = source->private2;
730224090Sdougb	dns_dbnode_t *cloned_node = NULL;
731224090Sdougb
732224090Sdougb	attachnode(db, node, &cloned_node);
733224090Sdougb	*target = *source;
734224090Sdougb
735224090Sdougb	/*
736224090Sdougb	 * Reset iterator state.
737224090Sdougb	 */
738224090Sdougb	target->privateuint4 = 0;
739224090Sdougb	target->private5 = NULL;
740224090Sdougb}
741224090Sdougb
742224090Sdougbstatic unsigned int
743224090Sdougbrdataset_count(dns_rdataset_t *rdataset) {
744224090Sdougb	unsigned char *raw = rdataset->private3;
745224090Sdougb	unsigned int count;
746224090Sdougb
747224090Sdougb	count = raw[0] * 256 + raw[1];
748224090Sdougb
749224090Sdougb	return (count);
750224090Sdougb}
751224090Sdougb
752224090Sdougbstatic void
753224090Sdougbrdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
754224090Sdougb	rdatasetheader_t *header = rdataset->private3;
755224090Sdougb
756224090Sdougb	header--;
757224090Sdougb	header->trust = rdataset->trust = trust;
758224090Sdougb}
759224090Sdougb
760224090Sdougb/*
761224090Sdougb * Rdataset Iterator Methods
762224090Sdougb */
763224090Sdougb
764224090Sdougbstatic void
765224090Sdougbrdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
766224090Sdougb	ecdb_rdatasetiter_t *ecdbiterator;
767224090Sdougb	isc_mem_t *mctx;
768224090Sdougb
769224090Sdougb	REQUIRE(iteratorp != NULL);
770224090Sdougb	ecdbiterator = (ecdb_rdatasetiter_t *)*iteratorp;
771224090Sdougb	REQUIRE(DNS_RDATASETITER_VALID(&ecdbiterator->common));
772224090Sdougb
773224090Sdougb	mctx = ecdbiterator->common.db->mctx;
774224090Sdougb
775224090Sdougb	ecdbiterator->common.magic = 0;
776224090Sdougb
777224090Sdougb	dns_db_detachnode(ecdbiterator->common.db, &ecdbiterator->common.node);
778224090Sdougb	isc_mem_put(mctx, ecdbiterator, sizeof(ecdb_rdatasetiter_t));
779224090Sdougb
780224090Sdougb	*iteratorp = NULL;
781224090Sdougb}
782224090Sdougb
783224090Sdougbstatic isc_result_t
784224090Sdougbrdatasetiter_first(dns_rdatasetiter_t *iterator) {
785224090Sdougb	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
786224090Sdougb	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)iterator->node;
787224090Sdougb
788224090Sdougb	REQUIRE(DNS_RDATASETITER_VALID(iterator));
789224090Sdougb
790224090Sdougb	if (ISC_LIST_EMPTY(ecdbnode->rdatasets))
791224090Sdougb		return (ISC_R_NOMORE);
792224090Sdougb	ecdbiterator->current = ISC_LIST_HEAD(ecdbnode->rdatasets);
793224090Sdougb	return (ISC_R_SUCCESS);
794224090Sdougb}
795224090Sdougb
796224090Sdougbstatic isc_result_t
797224090Sdougbrdatasetiter_next(dns_rdatasetiter_t *iterator) {
798224090Sdougb	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
799224090Sdougb
800224090Sdougb	REQUIRE(DNS_RDATASETITER_VALID(iterator));
801224090Sdougb
802224090Sdougb	ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link);
803224090Sdougb	if (ecdbiterator->current == NULL)
804224090Sdougb		return (ISC_R_NOMORE);
805224090Sdougb	else
806224090Sdougb		return (ISC_R_SUCCESS);
807224090Sdougb}
808224090Sdougb
809224090Sdougbstatic void
810224090Sdougbrdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
811224090Sdougb	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
812224090Sdougb	dns_ecdb_t *ecdb;
813224090Sdougb
814224090Sdougb	ecdb = (dns_ecdb_t *)iterator->db;
815224090Sdougb	REQUIRE(VALID_ECDB(ecdb));
816224090Sdougb
817224090Sdougb	bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset);
818224090Sdougb}
819