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