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