zt.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2007, 2011-2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2002  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <isc/file.h>
00025 #include <isc/magic.h>
00026 #include <isc/mem.h>
00027 #include <isc/string.h>
00028 #include <isc/task.h>
00029 #include <isc/util.h>
00030 
00031 #include <dns/log.h>
00032 #include <dns/name.h>
00033 #include <dns/rbt.h>
00034 #include <dns/rdataclass.h>
00035 #include <dns/result.h>
00036 #include <dns/view.h>
00037 #include <dns/zone.h>
00038 #include <dns/zt.h>
00039 
00040 struct dns_zt {
00041         /* Unlocked. */
00042         unsigned int            magic;
00043         isc_mem_t               *mctx;
00044         dns_rdataclass_t        rdclass;
00045         isc_rwlock_t            rwlock;
00046         dns_zt_allloaded_t      loaddone;
00047         void *                  loaddone_arg;
00048         /* Locked by lock. */
00049         isc_boolean_t           flush;
00050         isc_uint32_t            references;
00051         unsigned int            loads_pending;
00052         dns_rbt_t               *table;
00053 };
00054 
00055 #define ZTMAGIC                 ISC_MAGIC('Z', 'T', 'b', 'l')
00056 #define VALID_ZT(zt)            ISC_MAGIC_VALID(zt, ZTMAGIC)
00057 
00058 static void
00059 auto_detach(void *, void *);
00060 
00061 static isc_result_t
00062 load(dns_zone_t *zone, void *uap);
00063 
00064 static isc_result_t
00065 asyncload(dns_zone_t *zone, void *callback);
00066 
00067 static isc_result_t
00068 loadnew(dns_zone_t *zone, void *uap);
00069 
00070 static isc_result_t
00071 freezezones(dns_zone_t *zone, void *uap);
00072 
00073 static isc_result_t
00074 doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task);
00075 
00076 isc_result_t
00077 dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) {
00078         dns_zt_t *zt;
00079         isc_result_t result;
00080 
00081         REQUIRE(ztp != NULL && *ztp == NULL);
00082 
00083         zt = isc_mem_get(mctx, sizeof(*zt));
00084         if (zt == NULL)
00085                 return (ISC_R_NOMEMORY);
00086 
00087         zt->table = NULL;
00088         result = dns_rbt_create(mctx, auto_detach, zt, &zt->table);
00089         if (result != ISC_R_SUCCESS)
00090                 goto cleanup_zt;
00091 
00092         result = isc_rwlock_init(&zt->rwlock, 0, 0);
00093         if (result != ISC_R_SUCCESS)
00094                 goto cleanup_rbt;
00095 
00096         zt->mctx = NULL;
00097         isc_mem_attach(mctx, &zt->mctx);
00098         zt->references = 1;
00099         zt->flush = ISC_FALSE;
00100         zt->rdclass = rdclass;
00101         zt->magic = ZTMAGIC;
00102         zt->loaddone = NULL;
00103         zt->loaddone_arg = NULL;
00104         zt->loads_pending = 0;
00105         *ztp = zt;
00106 
00107         return (ISC_R_SUCCESS);
00108 
00109    cleanup_rbt:
00110         dns_rbt_destroy(&zt->table);
00111 
00112    cleanup_zt:
00113         isc_mem_put(mctx, zt, sizeof(*zt));
00114 
00115         return (result);
00116 }
00117 
00118 isc_result_t
00119 dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) {
00120         isc_result_t result;
00121         dns_zone_t *dummy = NULL;
00122         dns_name_t *name;
00123 
00124         REQUIRE(VALID_ZT(zt));
00125 
00126         name = dns_zone_getorigin(zone);
00127 
00128         RWLOCK(&zt->rwlock, isc_rwlocktype_write);
00129 
00130         result = dns_rbt_addname(zt->table, name, zone);
00131         if (result == ISC_R_SUCCESS)
00132                 dns_zone_attach(zone, &dummy);
00133 
00134         RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
00135 
00136         return (result);
00137 }
00138 
00139 isc_result_t
00140 dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) {
00141         isc_result_t result;
00142         dns_name_t *name;
00143 
00144         REQUIRE(VALID_ZT(zt));
00145 
00146         name = dns_zone_getorigin(zone);
00147 
00148         RWLOCK(&zt->rwlock, isc_rwlocktype_write);
00149 
00150         result = dns_rbt_deletename(zt->table, name, ISC_FALSE);
00151 
00152         RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
00153 
00154         return (result);
00155 }
00156 
00157 isc_result_t
00158 dns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options,
00159             dns_name_t *foundname, dns_zone_t **zonep)
00160 {
00161         isc_result_t result;
00162         dns_zone_t *dummy = NULL;
00163         unsigned int rbtoptions = 0;
00164 
00165         REQUIRE(VALID_ZT(zt));
00166 
00167         if ((options & DNS_ZTFIND_NOEXACT) != 0)
00168                 rbtoptions |= DNS_RBTFIND_NOEXACT;
00169 
00170         RWLOCK(&zt->rwlock, isc_rwlocktype_read);
00171 
00172         result = dns_rbt_findname(zt->table, name, rbtoptions, foundname,
00173                                   (void **) (void*)&dummy);
00174         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
00175                 dns_zone_attach(dummy, zonep);
00176 
00177         RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
00178 
00179         return (result);
00180 }
00181 
00182 void
00183 dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) {
00184 
00185         REQUIRE(VALID_ZT(zt));
00186         REQUIRE(ztp != NULL && *ztp == NULL);
00187 
00188         RWLOCK(&zt->rwlock, isc_rwlocktype_write);
00189 
00190         INSIST(zt->references > 0);
00191         zt->references++;
00192         INSIST(zt->references != 0);
00193 
00194         RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
00195 
00196         *ztp = zt;
00197 }
00198 
00199 static isc_result_t
00200 flush(dns_zone_t *zone, void *uap) {
00201         UNUSED(uap);
00202         return (dns_zone_flush(zone));
00203 }
00204 
00205 static void
00206 zt_destroy(dns_zt_t *zt) {
00207         if (zt->flush)
00208                 (void)dns_zt_apply(zt, ISC_FALSE, flush, NULL);
00209         dns_rbt_destroy(&zt->table);
00210         isc_rwlock_destroy(&zt->rwlock);
00211         zt->magic = 0;
00212         isc_mem_putanddetach(&zt->mctx, zt, sizeof(*zt));
00213 }
00214 
00215 static void
00216 zt_flushanddetach(dns_zt_t **ztp, isc_boolean_t need_flush) {
00217         isc_boolean_t destroy = ISC_FALSE;
00218         dns_zt_t *zt;
00219 
00220         REQUIRE(ztp != NULL && VALID_ZT(*ztp));
00221 
00222         zt = *ztp;
00223 
00224         RWLOCK(&zt->rwlock, isc_rwlocktype_write);
00225 
00226         INSIST(zt->references > 0);
00227         zt->references--;
00228         if (zt->references == 0)
00229                 destroy = ISC_TRUE;
00230         if (need_flush)
00231                 zt->flush = ISC_TRUE;
00232 
00233         RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
00234 
00235         if (destroy)
00236                 zt_destroy(zt);
00237 
00238         *ztp = NULL;
00239 }
00240 
00241 void
00242 dns_zt_flushanddetach(dns_zt_t **ztp) {
00243         zt_flushanddetach(ztp, ISC_TRUE);
00244 }
00245 
00246 void
00247 dns_zt_detach(dns_zt_t **ztp) {
00248         zt_flushanddetach(ztp, ISC_FALSE);
00249 }
00250 
00251 isc_result_t
00252 dns_zt_load(dns_zt_t *zt, isc_boolean_t stop) {
00253         isc_result_t result;
00254 
00255         REQUIRE(VALID_ZT(zt));
00256 
00257         RWLOCK(&zt->rwlock, isc_rwlocktype_read);
00258         result = dns_zt_apply(zt, stop, load, NULL);
00259         RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
00260         return (result);
00261 }
00262 
00263 static isc_result_t
00264 load(dns_zone_t *zone, void *uap) {
00265         isc_result_t result;
00266         UNUSED(uap);
00267 
00268         result = dns_zone_load(zone);
00269         if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE)
00270                 result = ISC_R_SUCCESS;
00271 
00272         return (result);
00273 }
00274 
00275 isc_result_t
00276 dns_zt_asyncload(dns_zt_t *zt, dns_zt_allloaded_t alldone, void *arg) {
00277         isc_result_t result;
00278         static dns_zt_zoneloaded_t dl = doneloading;
00279         int pending;
00280 
00281         REQUIRE(VALID_ZT(zt));
00282 
00283         RWLOCK(&zt->rwlock, isc_rwlocktype_write);
00284 
00285         INSIST(zt->loads_pending == 0);
00286         result = dns_zt_apply2(zt, ISC_FALSE, NULL, asyncload, &dl);
00287 
00288         pending = zt->loads_pending;
00289         if (pending != 0) {
00290                 zt->loaddone = alldone;
00291                 zt->loaddone_arg = arg;
00292         }
00293 
00294         RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
00295 
00296         if (pending == 0)
00297                 alldone(arg);
00298 
00299         return (result);
00300 }
00301 
00302 /*
00303  * Initiates asynchronous loading of zone 'zone'.  'callback' is a
00304  * pointer to a function which will be used to inform the caller when
00305  * the zone loading is complete.
00306  */
00307 static isc_result_t
00308 asyncload(dns_zone_t *zone, void *callback) {
00309         isc_result_t result;
00310         dns_zt_zoneloaded_t *loaded = callback;
00311         dns_zt_t *zt;
00312 
00313         REQUIRE(zone != NULL);
00314         zt = dns_zone_getview(zone)->zonetable;
00315         INSIST(VALID_ZT(zt));
00316 
00317         result = dns_zone_asyncload(zone, *loaded, zt);
00318         if (result == ISC_R_SUCCESS) {
00319                 INSIST(zt->references > 0);
00320                 zt->references++;
00321                 INSIST(zt->references != 0);
00322                 zt->loads_pending++;
00323         }
00324         return (ISC_R_SUCCESS);
00325 }
00326 
00327 isc_result_t
00328 dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop) {
00329         isc_result_t result;
00330 
00331         REQUIRE(VALID_ZT(zt));
00332 
00333         RWLOCK(&zt->rwlock, isc_rwlocktype_read);
00334         result = dns_zt_apply(zt, stop, loadnew, NULL);
00335         RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
00336         return (result);
00337 }
00338 
00339 static isc_result_t
00340 loadnew(dns_zone_t *zone, void *uap) {
00341         isc_result_t result;
00342         UNUSED(uap);
00343 
00344         result = dns_zone_loadnew(zone);
00345         if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE ||
00346             result == DNS_R_DYNAMIC)
00347                 result = ISC_R_SUCCESS;
00348         return (result);
00349 }
00350 
00351 isc_result_t
00352 dns_zt_freezezones(dns_zt_t *zt, isc_boolean_t freeze) {
00353         isc_result_t result, tresult;
00354 
00355         REQUIRE(VALID_ZT(zt));
00356 
00357         RWLOCK(&zt->rwlock, isc_rwlocktype_read);
00358         result = dns_zt_apply2(zt, ISC_FALSE, &tresult, freezezones, &freeze);
00359         RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
00360         if (tresult == ISC_R_NOTFOUND)
00361                 tresult = ISC_R_SUCCESS;
00362         return ((result == ISC_R_SUCCESS) ? tresult : result);
00363 }
00364 
00365 static isc_result_t
00366 freezezones(dns_zone_t *zone, void *uap) {
00367         isc_boolean_t freeze = *(isc_boolean_t *)uap;
00368         isc_boolean_t frozen;
00369         isc_result_t result = ISC_R_SUCCESS;
00370         char classstr[DNS_RDATACLASS_FORMATSIZE];
00371         char zonename[DNS_NAME_FORMATSIZE];
00372         dns_zone_t *raw = NULL;
00373         dns_view_t *view;
00374         const char *vname;
00375         const char *sep;
00376         int level;
00377 
00378         dns_zone_getraw(zone, &raw);
00379         if (raw != NULL)
00380                 zone = raw;
00381         if (dns_zone_gettype(zone) != dns_zone_master) {
00382                 if (raw != NULL)
00383                         dns_zone_detach(&raw);
00384                 return (ISC_R_SUCCESS);
00385         }
00386         if (!dns_zone_isdynamic(zone, ISC_TRUE)) {
00387                 if (raw != NULL)
00388                         dns_zone_detach(&raw);
00389                 return (ISC_R_SUCCESS);
00390         }
00391 
00392         frozen = dns_zone_getupdatedisabled(zone);
00393         if (freeze) {
00394                 if (frozen)
00395                         result = DNS_R_FROZEN;
00396                 if (result == ISC_R_SUCCESS)
00397                         result = dns_zone_flush(zone);
00398                 if (result == ISC_R_SUCCESS)
00399                         dns_zone_setupdatedisabled(zone, freeze);
00400         } else {
00401                 if (frozen) {
00402                         result = dns_zone_loadandthaw(zone);
00403                         if (result == DNS_R_CONTINUE ||
00404                             result == DNS_R_UPTODATE)
00405                                 result = ISC_R_SUCCESS;
00406                 }
00407         }
00408         view = dns_zone_getview(zone);
00409         if (strcmp(view->name, "_bind") == 0 ||
00410             strcmp(view->name, "_default") == 0)
00411         {
00412                 vname = "";
00413                 sep = "";
00414         } else {
00415                 vname = view->name;
00416                 sep = " ";
00417         }
00418         dns_rdataclass_format(dns_zone_getclass(zone), classstr,
00419                               sizeof(classstr));
00420         dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
00421         level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1);
00422         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
00423                       level, "%s zone '%s/%s'%s%s: %s",
00424                       freeze ? "freezing" : "thawing",
00425                       zonename, classstr, sep, vname,
00426                       isc_result_totext(result));
00427         if (raw != NULL)
00428                 dns_zone_detach(&raw);
00429         return (result);
00430 }
00431 
00432 isc_result_t
00433 dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop,
00434              isc_result_t (*action)(dns_zone_t *, void *), void *uap)
00435 {
00436         return (dns_zt_apply2(zt, stop, NULL, action, uap));
00437 }
00438 
00439 isc_result_t
00440 dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub,
00441               isc_result_t (*action)(dns_zone_t *, void *), void *uap)
00442 {
00443         dns_rbtnode_t *node;
00444         dns_rbtnodechain_t chain;
00445         isc_result_t result, tresult = ISC_R_SUCCESS;
00446         dns_zone_t *zone;
00447 
00448         REQUIRE(VALID_ZT(zt));
00449         REQUIRE(action != NULL);
00450 
00451         dns_rbtnodechain_init(&chain, zt->mctx);
00452         result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
00453         if (result == ISC_R_NOTFOUND) {
00454                 /*
00455                  * The tree is empty.
00456                  */
00457                 tresult = result;
00458                 result = ISC_R_NOMORE;
00459         }
00460         while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
00461                 result = dns_rbtnodechain_current(&chain, NULL, NULL,
00462                                                   &node);
00463                 if (result == ISC_R_SUCCESS) {
00464                         zone = node->data;
00465                         if (zone != NULL)
00466                                 result = (action)(zone, uap);
00467                         if (result != ISC_R_SUCCESS && stop) {
00468                                 tresult = result;
00469                                 goto cleanup;   /* don't break */
00470                         } else if (result != ISC_R_SUCCESS &&
00471                                    tresult == ISC_R_SUCCESS)
00472                                 tresult = result;
00473                 }
00474                 result = dns_rbtnodechain_next(&chain, NULL, NULL);
00475         }
00476         if (result == ISC_R_NOMORE)
00477                 result = ISC_R_SUCCESS;
00478 
00479  cleanup:
00480         dns_rbtnodechain_invalidate(&chain);
00481         if (sub != NULL)
00482                 *sub = tresult;
00483 
00484         return (result);
00485 }
00486 
00487 /*
00488  * Decrement the loads_pending counter; when counter reaches
00489  * zero, call the loaddone callback that was initially set by
00490  * dns_zt_asyncload().
00491  */
00492 static isc_result_t
00493 doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
00494         isc_boolean_t destroy = ISC_FALSE;
00495         dns_zt_allloaded_t alldone = NULL;
00496         void *arg = NULL;
00497 
00498         UNUSED(zone);
00499         UNUSED(task);
00500 
00501         REQUIRE(VALID_ZT(zt));
00502 
00503         RWLOCK(&zt->rwlock, isc_rwlocktype_write);
00504         INSIST(zt->loads_pending != 0);
00505         INSIST(zt->references != 0);
00506         zt->references--;
00507         if (zt->references == 0)
00508                 destroy = ISC_TRUE;
00509         zt->loads_pending--;
00510         if (zt->loads_pending == 0) {
00511                 alldone = zt->loaddone;
00512                 arg = zt->loaddone_arg;
00513                 zt->loaddone = NULL;
00514                 zt->loaddone_arg = NULL;
00515         }
00516         RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
00517 
00518         if (alldone != NULL)
00519                 alldone(arg);
00520 
00521         if (destroy)
00522                 zt_destroy(zt);
00523 
00524         return (ISC_R_SUCCESS);
00525 }
00526 
00527 /***
00528  *** Private
00529  ***/
00530 
00531 static void
00532 auto_detach(void *data, void *arg) {
00533         dns_zone_t *zone = data;
00534 
00535         UNUSED(arg);
00536         dns_zone_detach(&zone);
00537 }

Generated on Tue Apr 28 17:41:03 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha