mirror of
https://github.com/isc-projects/bind9.git
synced 2026-04-23 07:07:00 -04:00
Also disable the semantic patch as the code needs tweaks here and there because some destroy functions might not destroy the object and return early if the object is still in use.
251 lines
5.8 KiB
C
251 lines
5.8 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <isc/mem.h>
|
|
#include <isc/rwlock.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/dbtable.h>
|
|
#include <dns/db.h>
|
|
#include <dns/rbt.h>
|
|
#include <dns/result.h>
|
|
|
|
struct dns_dbtable {
|
|
/* Unlocked. */
|
|
unsigned int magic;
|
|
isc_mem_t * mctx;
|
|
dns_rdataclass_t rdclass;
|
|
isc_rwlock_t tree_lock;
|
|
/* Protected by atomics */
|
|
isc_refcount_t references;
|
|
/* Locked by tree_lock. */
|
|
dns_rbt_t * rbt;
|
|
dns_db_t * default_db;
|
|
};
|
|
|
|
#define DBTABLE_MAGIC ISC_MAGIC('D', 'B', '-', '-')
|
|
#define VALID_DBTABLE(dbtable) ISC_MAGIC_VALID(dbtable, DBTABLE_MAGIC)
|
|
|
|
static void
|
|
dbdetach(void *data, void *arg) {
|
|
dns_db_t *db = data;
|
|
|
|
UNUSED(arg);
|
|
|
|
dns_db_detach(&db);
|
|
}
|
|
|
|
isc_result_t
|
|
dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
|
dns_dbtable_t **dbtablep)
|
|
{
|
|
dns_dbtable_t *dbtable;
|
|
isc_result_t result;
|
|
|
|
REQUIRE(mctx != NULL);
|
|
REQUIRE(dbtablep != NULL && *dbtablep == NULL);
|
|
|
|
dbtable = isc_mem_get(mctx, sizeof(*dbtable));
|
|
|
|
dbtable->rbt = NULL;
|
|
result = dns_rbt_create(mctx, dbdetach, NULL, &dbtable->rbt);
|
|
if (result != ISC_R_SUCCESS)
|
|
goto clean1;
|
|
|
|
result = isc_rwlock_init(&dbtable->tree_lock, 0, 0);
|
|
if (result != ISC_R_SUCCESS)
|
|
goto clean3;
|
|
|
|
dbtable->default_db = NULL;
|
|
dbtable->mctx = NULL;
|
|
isc_mem_attach(mctx, &dbtable->mctx);
|
|
dbtable->rdclass = rdclass;
|
|
dbtable->magic = DBTABLE_MAGIC;
|
|
isc_refcount_init(&dbtable->references, 1);
|
|
|
|
*dbtablep = dbtable;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
clean3:
|
|
dns_rbt_destroy(&dbtable->rbt);
|
|
|
|
clean1:
|
|
isc_mem_putanddetach(&mctx, dbtable, sizeof(*dbtable));
|
|
|
|
return (result);
|
|
}
|
|
|
|
static inline void
|
|
dbtable_free(dns_dbtable_t *dbtable) {
|
|
/*
|
|
* Caller must ensure that it is safe to call.
|
|
*/
|
|
|
|
RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
|
|
|
|
if (dbtable->default_db != NULL)
|
|
dns_db_detach(&dbtable->default_db);
|
|
|
|
dns_rbt_destroy(&dbtable->rbt);
|
|
|
|
RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
|
|
|
|
isc_rwlock_destroy(&dbtable->tree_lock);
|
|
|
|
dbtable->magic = 0;
|
|
|
|
isc_mem_putanddetach(&dbtable->mctx, dbtable, sizeof(*dbtable));
|
|
}
|
|
|
|
void
|
|
dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp) {
|
|
REQUIRE(VALID_DBTABLE(source));
|
|
REQUIRE(targetp != NULL && *targetp == NULL);
|
|
|
|
isc_refcount_increment(&source->references);
|
|
|
|
*targetp = source;
|
|
}
|
|
|
|
void
|
|
dns_dbtable_detach(dns_dbtable_t **dbtablep) {
|
|
dns_dbtable_t *dbtable;
|
|
|
|
REQUIRE(dbtablep != NULL);
|
|
dbtable = *dbtablep;
|
|
*dbtablep = NULL;
|
|
REQUIRE(VALID_DBTABLE(dbtable));
|
|
|
|
if (isc_refcount_decrement(&dbtable->references) == 1) {
|
|
dbtable_free(dbtable);
|
|
}
|
|
}
|
|
|
|
isc_result_t
|
|
dns_dbtable_add(dns_dbtable_t *dbtable, dns_db_t *db) {
|
|
isc_result_t result;
|
|
dns_db_t *dbclone;
|
|
|
|
REQUIRE(VALID_DBTABLE(dbtable));
|
|
REQUIRE(dns_db_class(db) == dbtable->rdclass);
|
|
|
|
dbclone = NULL;
|
|
dns_db_attach(db, &dbclone);
|
|
|
|
RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
|
|
result = dns_rbt_addname(dbtable->rbt, dns_db_origin(dbclone), dbclone);
|
|
RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
|
|
|
|
return (result);
|
|
}
|
|
|
|
void
|
|
dns_dbtable_remove(dns_dbtable_t *dbtable, dns_db_t *db) {
|
|
dns_db_t *stored_data = NULL;
|
|
isc_result_t result;
|
|
dns_name_t *name;
|
|
|
|
REQUIRE(VALID_DBTABLE(dbtable));
|
|
|
|
name = dns_db_origin(db);
|
|
|
|
/*
|
|
* There is a requirement that the association of name with db
|
|
* be verified. With the current rbt.c this is expensive to do,
|
|
* because effectively two find operations are being done, but
|
|
* deletion is relatively infrequent.
|
|
* XXXDCL ... this could be cheaper now with dns_rbt_deletenode.
|
|
*/
|
|
|
|
RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
|
|
|
|
result = dns_rbt_findname(dbtable->rbt, name, 0, NULL,
|
|
(void **) (void *)&stored_data);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
INSIST(stored_data == db);
|
|
|
|
(void)dns_rbt_deletename(dbtable->rbt, name, false);
|
|
}
|
|
|
|
RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
|
|
}
|
|
|
|
void
|
|
dns_dbtable_adddefault(dns_dbtable_t *dbtable, dns_db_t *db) {
|
|
REQUIRE(VALID_DBTABLE(dbtable));
|
|
REQUIRE(dbtable->default_db == NULL);
|
|
REQUIRE(dns_name_compare(dns_db_origin(db), dns_rootname) == 0);
|
|
|
|
RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
|
|
|
|
dbtable->default_db = NULL;
|
|
dns_db_attach(db, &dbtable->default_db);
|
|
|
|
RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
|
|
}
|
|
|
|
void
|
|
dns_dbtable_getdefault(dns_dbtable_t *dbtable, dns_db_t **dbp) {
|
|
REQUIRE(VALID_DBTABLE(dbtable));
|
|
REQUIRE(dbp != NULL && *dbp == NULL);
|
|
|
|
RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
|
|
|
|
dns_db_attach(dbtable->default_db, dbp);
|
|
|
|
RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
|
|
}
|
|
|
|
void
|
|
dns_dbtable_removedefault(dns_dbtable_t *dbtable) {
|
|
REQUIRE(VALID_DBTABLE(dbtable));
|
|
|
|
RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
|
|
|
|
dns_db_detach(&dbtable->default_db);
|
|
|
|
RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
|
|
}
|
|
|
|
isc_result_t
|
|
dns_dbtable_find(dns_dbtable_t *dbtable, const dns_name_t *name,
|
|
unsigned int options, dns_db_t **dbp)
|
|
{
|
|
dns_db_t *stored_data = NULL;
|
|
isc_result_t result;
|
|
unsigned int rbtoptions = 0;
|
|
|
|
REQUIRE(dbp != NULL && *dbp == NULL);
|
|
|
|
if ((options & DNS_DBTABLEFIND_NOEXACT) != 0)
|
|
rbtoptions |= DNS_RBTFIND_NOEXACT;
|
|
|
|
RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
|
|
|
|
result = dns_rbt_findname(dbtable->rbt, name, rbtoptions, NULL,
|
|
(void **) (void *)&stored_data);
|
|
|
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
|
|
dns_db_attach(stored_data, dbp);
|
|
else if (dbtable->default_db != NULL) {
|
|
dns_db_attach(dbtable->default_db, dbp);
|
|
result = DNS_R_PARTIALMATCH;
|
|
} else
|
|
result = ISC_R_NOTFOUND;
|
|
|
|
RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
|
|
|
|
return (result);
|
|
}
|