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