2 * Copyright (C) 2004-2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2002 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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.
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.
25 #include <isc/magic.h>
27 #include <isc/string.h>
34 #include <dns/rdataclass.h>
35 #include <dns/result.h>
44 dns_rdataclass_t rdclass;
46 dns_zt_allloaded_t loaddone;
50 isc_uint32_t references;
51 unsigned int loads_pending;
55 #define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l')
56 #define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC)
59 auto_detach(void *, void *);
62 load(dns_zone_t *zone, void *uap);
65 asyncload(dns_zone_t *zone, void *callback);
68 loadnew(dns_zone_t *zone, void *uap);
71 freezezones(dns_zone_t *zone, void *uap);
74 doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task);
77 dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp)
82 REQUIRE(ztp != NULL && *ztp == NULL);
84 zt = isc_mem_get(mctx, sizeof(*zt));
86 return (ISC_R_NOMEMORY);
89 result = dns_rbt_create(mctx, auto_detach, zt, &zt->table);
90 if (result != ISC_R_SUCCESS)
93 result = isc_rwlock_init(&zt->rwlock, 0, 0);
94 if (result != ISC_R_SUCCESS)
98 isc_mem_attach(mctx, &zt->mctx);
100 zt->flush = ISC_FALSE;
101 zt->rdclass = rdclass;
104 zt->loaddone_arg = NULL;
105 zt->loads_pending = 0;
108 return (ISC_R_SUCCESS);
111 dns_rbt_destroy(&zt->table);
114 isc_mem_put(mctx, zt, sizeof(*zt));
120 dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) {
122 dns_zone_t *dummy = NULL;
125 REQUIRE(VALID_ZT(zt));
127 name = dns_zone_getorigin(zone);
129 RWLOCK(&zt->rwlock, isc_rwlocktype_write);
131 result = dns_rbt_addname(zt->table, name, zone);
132 if (result == ISC_R_SUCCESS)
133 dns_zone_attach(zone, &dummy);
135 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
141 dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) {
145 REQUIRE(VALID_ZT(zt));
147 name = dns_zone_getorigin(zone);
149 RWLOCK(&zt->rwlock, isc_rwlocktype_write);
151 result = dns_rbt_deletename(zt->table, name, ISC_FALSE);
153 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
159 dns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options,
160 dns_name_t *foundname, dns_zone_t **zonep)
163 dns_zone_t *dummy = NULL;
164 unsigned int rbtoptions = 0;
166 REQUIRE(VALID_ZT(zt));
168 if ((options & DNS_ZTFIND_NOEXACT) != 0)
169 rbtoptions |= DNS_RBTFIND_NOEXACT;
171 RWLOCK(&zt->rwlock, isc_rwlocktype_read);
173 result = dns_rbt_findname(zt->table, name, rbtoptions, foundname,
174 (void **) (void*)&dummy);
175 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
176 dns_zone_attach(dummy, zonep);
178 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
184 dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) {
186 REQUIRE(VALID_ZT(zt));
187 REQUIRE(ztp != NULL && *ztp == NULL);
189 RWLOCK(&zt->rwlock, isc_rwlocktype_write);
191 INSIST(zt->references > 0);
193 INSIST(zt->references != 0);
195 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
201 flush(dns_zone_t *zone, void *uap) {
203 return (dns_zone_flush(zone));
207 zt_destroy(dns_zt_t *zt) {
209 (void)dns_zt_apply(zt, ISC_FALSE, flush, NULL);
210 dns_rbt_destroy(&zt->table);
211 isc_rwlock_destroy(&zt->rwlock);
213 isc_mem_putanddetach(&zt->mctx, zt, sizeof(*zt));
217 zt_flushanddetach(dns_zt_t **ztp, isc_boolean_t need_flush) {
218 isc_boolean_t destroy = ISC_FALSE;
221 REQUIRE(ztp != NULL && VALID_ZT(*ztp));
225 RWLOCK(&zt->rwlock, isc_rwlocktype_write);
227 INSIST(zt->references > 0);
229 if (zt->references == 0)
232 zt->flush = ISC_TRUE;
234 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
243 dns_zt_flushanddetach(dns_zt_t **ztp) {
244 zt_flushanddetach(ztp, ISC_TRUE);
248 dns_zt_detach(dns_zt_t **ztp) {
249 zt_flushanddetach(ztp, ISC_FALSE);
253 dns_zt_load(dns_zt_t *zt, isc_boolean_t stop) {
256 REQUIRE(VALID_ZT(zt));
258 RWLOCK(&zt->rwlock, isc_rwlocktype_read);
259 result = dns_zt_apply(zt, stop, load, NULL);
260 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
265 load(dns_zone_t *zone, void *uap) {
269 result = dns_zone_load(zone);
270 if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE)
271 result = ISC_R_SUCCESS;
277 dns_zt_asyncload(dns_zt_t *zt, dns_zt_allloaded_t alldone, void *arg) {
279 static dns_zt_zoneloaded_t dl = doneloading;
282 REQUIRE(VALID_ZT(zt));
284 RWLOCK(&zt->rwlock, isc_rwlocktype_write);
286 INSIST(zt->loads_pending == 0);
287 result = dns_zt_apply2(zt, ISC_FALSE, NULL, asyncload, &dl);
289 pending = zt->loads_pending;
291 zt->loaddone = alldone;
292 zt->loaddone_arg = arg;
295 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
304 * Initiates asynchronous loading of zone 'zone'. 'callback' is a
305 * pointer to a function which will be used to inform the caller when
306 * the zone loading is complete.
309 asyncload(dns_zone_t *zone, void *callback) {
311 dns_zt_zoneloaded_t *loaded = callback;
314 REQUIRE(zone != NULL);
315 zt = dns_zone_getview(zone)->zonetable;
316 INSIST(VALID_ZT(zt));
318 result = dns_zone_asyncload(zone, *loaded, zt);
319 if (result == ISC_R_SUCCESS) {
320 INSIST(zt->references > 0);
322 INSIST(zt->references != 0);
325 return (ISC_R_SUCCESS);
329 dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop) {
332 REQUIRE(VALID_ZT(zt));
334 RWLOCK(&zt->rwlock, isc_rwlocktype_read);
335 result = dns_zt_apply(zt, stop, loadnew, NULL);
336 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
341 loadnew(dns_zone_t *zone, void *uap) {
345 result = dns_zone_loadnew(zone);
346 if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE ||
347 result == DNS_R_DYNAMIC)
348 result = ISC_R_SUCCESS;
353 dns_zt_freezezones(dns_zt_t *zt, isc_boolean_t freeze) {
354 isc_result_t result, tresult;
356 REQUIRE(VALID_ZT(zt));
358 RWLOCK(&zt->rwlock, isc_rwlocktype_read);
359 result = dns_zt_apply2(zt, ISC_FALSE, &tresult, freezezones, &freeze);
360 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
361 if (tresult == ISC_R_NOTFOUND)
362 tresult = ISC_R_SUCCESS;
363 return ((result == ISC_R_SUCCESS) ? tresult : result);
367 freezezones(dns_zone_t *zone, void *uap) {
368 isc_boolean_t freeze = *(isc_boolean_t *)uap;
369 isc_boolean_t frozen;
370 isc_result_t result = ISC_R_SUCCESS;
371 char classstr[DNS_RDATACLASS_FORMATSIZE];
372 char zonename[DNS_NAME_FORMATSIZE];
373 dns_zone_t *raw = NULL;
379 dns_zone_getraw(zone, &raw);
382 if (dns_zone_gettype(zone) != dns_zone_master) {
384 dns_zone_detach(&raw);
385 return (ISC_R_SUCCESS);
387 if (!dns_zone_isdynamic(zone, ISC_TRUE)) {
389 dns_zone_detach(&raw);
390 return (ISC_R_SUCCESS);
393 frozen = dns_zone_getupdatedisabled(zone);
396 result = DNS_R_FROZEN;
397 if (result == ISC_R_SUCCESS)
398 result = dns_zone_flush(zone);
401 result = dns_zone_load(zone);
402 if (result == DNS_R_CONTINUE ||
403 result == DNS_R_UPTODATE)
404 result = ISC_R_SUCCESS;
407 if (result == ISC_R_SUCCESS)
408 dns_zone_setupdatedisabled(zone, freeze);
409 view = dns_zone_getview(zone);
410 if (strcmp(view->name, "_bind") == 0 ||
411 strcmp(view->name, "_default") == 0)
419 dns_rdataclass_format(dns_zone_getclass(zone), classstr,
421 dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
422 level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1);
423 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
424 level, "%s zone '%s/%s'%s%s: %s",
425 freeze ? "freezing" : "thawing",
426 zonename, classstr, sep, vname,
427 isc_result_totext(result));
429 dns_zone_detach(&raw);
434 dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop,
435 isc_result_t (*action)(dns_zone_t *, void *), void *uap)
437 return (dns_zt_apply2(zt, stop, NULL, action, uap));
441 dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub,
442 isc_result_t (*action)(dns_zone_t *, void *), void *uap)
445 dns_rbtnodechain_t chain;
446 isc_result_t result, tresult = ISC_R_SUCCESS;
449 REQUIRE(VALID_ZT(zt));
450 REQUIRE(action != NULL);
452 dns_rbtnodechain_init(&chain, zt->mctx);
453 result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
454 if (result == ISC_R_NOTFOUND) {
459 result = ISC_R_NOMORE;
461 while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
462 result = dns_rbtnodechain_current(&chain, NULL, NULL,
464 if (result == ISC_R_SUCCESS) {
467 result = (action)(zone, uap);
468 if (result != ISC_R_SUCCESS && stop) {
470 goto cleanup; /* don't break */
471 } else if (result != ISC_R_SUCCESS &&
472 tresult == ISC_R_SUCCESS)
475 result = dns_rbtnodechain_next(&chain, NULL, NULL);
477 if (result == ISC_R_NOMORE)
478 result = ISC_R_SUCCESS;
481 dns_rbtnodechain_invalidate(&chain);
489 * Decrement the loads_pending counter; when counter reaches
490 * zero, call the loaddone callback that was initially set by
491 * dns_zt_asyncload().
494 doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
495 isc_boolean_t destroy = ISC_FALSE;
496 dns_zt_allloaded_t alldone = NULL;
502 REQUIRE(VALID_ZT(zt));
504 RWLOCK(&zt->rwlock, isc_rwlocktype_write);
505 INSIST(zt->loads_pending != 0);
506 INSIST(zt->references != 0);
508 if (zt->references == 0)
511 if (zt->loads_pending == 0) {
512 alldone = zt->loaddone;
513 arg = zt->loaddone_arg;
515 zt->loaddone_arg = NULL;
517 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
525 return (ISC_R_SUCCESS);
533 auto_detach(void *data, void *arg) {
534 dns_zone_t *zone = data;
538 dns_zone_detach(&zone);