00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <config.h>
00028
00029 #include <isc/mem.h>
00030 #include <isc/rwlock.h>
00031 #include <isc/util.h>
00032
00033 #include <dns/dbtable.h>
00034 #include <dns/db.h>
00035 #include <dns/rbt.h>
00036 #include <dns/result.h>
00037
00038 struct dns_dbtable {
00039
00040 unsigned int magic;
00041 isc_mem_t * mctx;
00042 dns_rdataclass_t rdclass;
00043 isc_mutex_t lock;
00044 isc_rwlock_t tree_lock;
00045
00046 unsigned int references;
00047
00048 dns_rbt_t * rbt;
00049 dns_db_t * default_db;
00050 };
00051
00052 #define DBTABLE_MAGIC ISC_MAGIC('D', 'B', '-', '-')
00053 #define VALID_DBTABLE(dbtable) ISC_MAGIC_VALID(dbtable, DBTABLE_MAGIC)
00054
00055 static void
00056 dbdetach(void *data, void *arg) {
00057 dns_db_t *db = data;
00058
00059 UNUSED(arg);
00060
00061 dns_db_detach(&db);
00062 }
00063
00064 isc_result_t
00065 dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
00066 dns_dbtable_t **dbtablep)
00067 {
00068 dns_dbtable_t *dbtable;
00069 isc_result_t result;
00070
00071 REQUIRE(mctx != NULL);
00072 REQUIRE(dbtablep != NULL && *dbtablep == NULL);
00073
00074 dbtable = (dns_dbtable_t *)isc_mem_get(mctx, sizeof(*dbtable));
00075 if (dbtable == NULL)
00076 return (ISC_R_NOMEMORY);
00077
00078 dbtable->rbt = NULL;
00079 result = dns_rbt_create(mctx, dbdetach, NULL, &dbtable->rbt);
00080 if (result != ISC_R_SUCCESS)
00081 goto clean1;
00082
00083 result = isc_mutex_init(&dbtable->lock);
00084 if (result != ISC_R_SUCCESS)
00085 goto clean2;
00086
00087 result = isc_rwlock_init(&dbtable->tree_lock, 0, 0);
00088 if (result != ISC_R_SUCCESS)
00089 goto clean3;
00090
00091 dbtable->default_db = NULL;
00092 dbtable->mctx = NULL;
00093 isc_mem_attach(mctx, &dbtable->mctx);
00094 dbtable->rdclass = rdclass;
00095 dbtable->magic = DBTABLE_MAGIC;
00096 dbtable->references = 1;
00097
00098 *dbtablep = dbtable;
00099
00100 return (ISC_R_SUCCESS);
00101
00102 clean3:
00103 DESTROYLOCK(&dbtable->lock);
00104
00105 clean2:
00106 dns_rbt_destroy(&dbtable->rbt);
00107
00108 clean1:
00109 isc_mem_putanddetach(&mctx, dbtable, sizeof(*dbtable));
00110
00111 return (result);
00112 }
00113
00114 static inline void
00115 dbtable_free(dns_dbtable_t *dbtable) {
00116
00117
00118
00119
00120 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00121
00122 if (dbtable->default_db != NULL)
00123 dns_db_detach(&dbtable->default_db);
00124
00125 dns_rbt_destroy(&dbtable->rbt);
00126
00127 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00128
00129 isc_rwlock_destroy(&dbtable->tree_lock);
00130
00131 dbtable->magic = 0;
00132
00133 isc_mem_putanddetach(&dbtable->mctx, dbtable, sizeof(*dbtable));
00134 }
00135
00136 void
00137 dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp) {
00138 REQUIRE(VALID_DBTABLE(source));
00139 REQUIRE(targetp != NULL && *targetp == NULL);
00140
00141 LOCK(&source->lock);
00142
00143 INSIST(source->references > 0);
00144 source->references++;
00145 INSIST(source->references != 0);
00146
00147 UNLOCK(&source->lock);
00148
00149 *targetp = source;
00150 }
00151
00152 void
00153 dns_dbtable_detach(dns_dbtable_t **dbtablep) {
00154 dns_dbtable_t *dbtable;
00155 isc_boolean_t free_dbtable = ISC_FALSE;
00156
00157 REQUIRE(dbtablep != NULL);
00158 dbtable = *dbtablep;
00159 REQUIRE(VALID_DBTABLE(dbtable));
00160
00161 LOCK(&dbtable->lock);
00162
00163 INSIST(dbtable->references > 0);
00164 dbtable->references--;
00165 if (dbtable->references == 0)
00166 free_dbtable = ISC_TRUE;
00167
00168 UNLOCK(&dbtable->lock);
00169
00170 if (free_dbtable)
00171 dbtable_free(dbtable);
00172
00173 *dbtablep = NULL;
00174 }
00175
00176 isc_result_t
00177 dns_dbtable_add(dns_dbtable_t *dbtable, dns_db_t *db) {
00178 isc_result_t result;
00179 dns_db_t *clone;
00180
00181 REQUIRE(VALID_DBTABLE(dbtable));
00182 REQUIRE(dns_db_class(db) == dbtable->rdclass);
00183
00184 clone = NULL;
00185 dns_db_attach(db, &clone);
00186
00187 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00188 result = dns_rbt_addname(dbtable->rbt, dns_db_origin(clone), clone);
00189 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00190
00191 return (result);
00192 }
00193
00194 void
00195 dns_dbtable_remove(dns_dbtable_t *dbtable, dns_db_t *db) {
00196 dns_db_t *stored_data = NULL;
00197 isc_result_t result;
00198 dns_name_t *name;
00199
00200 REQUIRE(VALID_DBTABLE(dbtable));
00201
00202 name = dns_db_origin(db);
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00213
00214 result = dns_rbt_findname(dbtable->rbt, name, 0, NULL,
00215 (void **) (void *)&stored_data);
00216
00217 if (result == ISC_R_SUCCESS) {
00218 INSIST(stored_data == db);
00219
00220 (void)dns_rbt_deletename(dbtable->rbt, name, ISC_FALSE);
00221 }
00222
00223 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00224 }
00225
00226 void
00227 dns_dbtable_adddefault(dns_dbtable_t *dbtable, dns_db_t *db) {
00228 REQUIRE(VALID_DBTABLE(dbtable));
00229 REQUIRE(dbtable->default_db == NULL);
00230 REQUIRE(dns_name_compare(dns_db_origin(db), dns_rootname) == 0);
00231
00232 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00233
00234 dbtable->default_db = NULL;
00235 dns_db_attach(db, &dbtable->default_db);
00236
00237 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00238 }
00239
00240 void
00241 dns_dbtable_getdefault(dns_dbtable_t *dbtable, dns_db_t **dbp) {
00242 REQUIRE(VALID_DBTABLE(dbtable));
00243 REQUIRE(dbp != NULL && *dbp == NULL);
00244
00245 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
00246
00247 dns_db_attach(dbtable->default_db, dbp);
00248
00249 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
00250 }
00251
00252 void
00253 dns_dbtable_removedefault(dns_dbtable_t *dbtable) {
00254 REQUIRE(VALID_DBTABLE(dbtable));
00255
00256 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00257
00258 dns_db_detach(&dbtable->default_db);
00259
00260 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00261 }
00262
00263 isc_result_t
00264 dns_dbtable_find(dns_dbtable_t *dbtable, dns_name_t *name,
00265 unsigned int options, dns_db_t **dbp)
00266 {
00267 dns_db_t *stored_data = NULL;
00268 isc_result_t result;
00269 unsigned int rbtoptions = 0;
00270
00271 REQUIRE(dbp != NULL && *dbp == NULL);
00272
00273 if ((options & DNS_DBTABLEFIND_NOEXACT) != 0)
00274 rbtoptions |= DNS_RBTFIND_NOEXACT;
00275
00276 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
00277
00278 result = dns_rbt_findname(dbtable->rbt, name, rbtoptions, NULL,
00279 (void **) (void *)&stored_data);
00280
00281 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
00282 dns_db_attach(stored_data, dbp);
00283 else if (dbtable->default_db != NULL) {
00284 dns_db_attach(dbtable->default_db, dbp);
00285 result = DNS_R_PARTIALMATCH;
00286 } else
00287 result = ISC_R_NOTFOUND;
00288
00289 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
00290
00291 return (result);
00292 }