2015-09-28 23:12:35 -07:00
|
|
|
/*
|
2018-02-23 09:53:12 +01:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2015-09-28 23:12:35 -07:00
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* 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/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
2015-09-28 23:12:35 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2016-01-04 17:27:31 +01:00
|
|
|
#if HAVE_DLFCN_H
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#elif _WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
|
2015-09-28 23:12:35 -07:00
|
|
|
#include <isc/buffer.h>
|
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/mutex.h>
|
|
|
|
#include <isc/once.h>
|
|
|
|
#include <isc/result.h>
|
|
|
|
#include <isc/region.h>
|
|
|
|
#include <isc/task.h>
|
|
|
|
#include <isc/types.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/dyndb.h>
|
|
|
|
#include <dns/log.h>
|
|
|
|
#include <dns/types.h>
|
|
|
|
#include <dns/view.h>
|
|
|
|
#include <dns/zone.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#define CHECK(op) \
|
|
|
|
do { result = (op); \
|
|
|
|
if (result != ISC_R_SUCCESS) goto cleanup; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct dyndb_implementation dyndb_implementation_t;
|
|
|
|
struct dyndb_implementation {
|
|
|
|
isc_mem_t *mctx;
|
|
|
|
void *handle;
|
|
|
|
dns_dyndb_register_t *register_func;
|
|
|
|
dns_dyndb_destroy_t *destroy_func;
|
|
|
|
char *name;
|
|
|
|
void *inst;
|
|
|
|
LINK(dyndb_implementation_t) link;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* List of dyndb implementations. Locked by dyndb_lock.
|
|
|
|
*
|
|
|
|
* These are stored here so they can be cleaned up on shutdown.
|
|
|
|
* (The order in which they are stored is not important.)
|
|
|
|
*/
|
|
|
|
static LIST(dyndb_implementation_t) dyndb_implementations;
|
|
|
|
|
|
|
|
/* Locks dyndb_implementations. */
|
|
|
|
static isc_mutex_t dyndb_lock;
|
|
|
|
static isc_once_t once = ISC_ONCE_INIT;
|
|
|
|
|
|
|
|
static void
|
|
|
|
dyndb_initialize(void) {
|
2018-11-16 15:33:22 +01:00
|
|
|
isc_mutex_init(&dyndb_lock);
|
2015-09-28 23:12:35 -07:00
|
|
|
INIT_LIST(dyndb_implementations);
|
|
|
|
}
|
|
|
|
|
|
|
|
static dyndb_implementation_t *
|
|
|
|
impfind(const char *name) {
|
|
|
|
dyndb_implementation_t *imp;
|
|
|
|
|
|
|
|
for (imp = ISC_LIST_HEAD(dyndb_implementations);
|
|
|
|
imp != NULL;
|
|
|
|
imp = ISC_LIST_NEXT(imp, link))
|
|
|
|
if (strcasecmp(name, imp->name) == 0)
|
|
|
|
return (imp);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2017-05-30 11:31:34 +10:00
|
|
|
#if HAVE_DLFCN_H && HAVE_DLOPEN
|
2015-09-28 23:12:35 -07:00
|
|
|
static isc_result_t
|
|
|
|
load_symbol(void *handle, const char *filename,
|
|
|
|
const char *symbol_name, void **symbolp)
|
|
|
|
{
|
|
|
|
const char *errmsg;
|
|
|
|
void *symbol;
|
|
|
|
|
|
|
|
REQUIRE(handle != NULL);
|
|
|
|
REQUIRE(symbolp != NULL && *symbolp == NULL);
|
|
|
|
|
|
|
|
symbol = dlsym(handle, symbol_name);
|
|
|
|
if (symbol == NULL) {
|
|
|
|
errmsg = dlerror();
|
|
|
|
if (errmsg == NULL)
|
|
|
|
errmsg = "returned function pointer is NULL";
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
|
|
DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
|
|
|
|
"failed to lookup symbol %s in "
|
|
|
|
"dyndb module '%s': %s",
|
|
|
|
symbol_name, filename, errmsg);
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
dlerror();
|
|
|
|
|
|
|
|
*symbolp = symbol;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
load_library(isc_mem_t *mctx, const char *filename, const char *instname,
|
|
|
|
dyndb_implementation_t **impp)
|
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
void *handle = NULL;
|
|
|
|
dyndb_implementation_t *imp = NULL;
|
|
|
|
dns_dyndb_register_t *register_func = NULL;
|
|
|
|
dns_dyndb_destroy_t *destroy_func = NULL;
|
|
|
|
dns_dyndb_version_t *version_func = NULL;
|
|
|
|
int version, flags;
|
|
|
|
|
|
|
|
REQUIRE(impp != NULL && *impp == NULL);
|
|
|
|
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
|
|
DNS_LOGMODULE_DYNDB, ISC_LOG_INFO,
|
|
|
|
"loading DynDB instance '%s' driver '%s'",
|
|
|
|
instname, filename);
|
|
|
|
|
|
|
|
flags = RTLD_NOW|RTLD_LOCAL;
|
2018-12-19 09:59:40 +01:00
|
|
|
#if defined(RTLD_DEEPBIND) && !__ADDRESS_SANITIZER__
|
2015-09-28 23:12:35 -07:00
|
|
|
flags |= RTLD_DEEPBIND;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
handle = dlopen(filename, flags);
|
|
|
|
if (handle == NULL)
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
|
|
|
|
/* Clear dlerror */
|
|
|
|
dlerror();
|
|
|
|
|
|
|
|
CHECK(load_symbol(handle, filename, "dyndb_version",
|
|
|
|
(void **)&version_func));
|
|
|
|
|
|
|
|
version = version_func(NULL);
|
|
|
|
if (version < (DNS_DYNDB_VERSION - DNS_DYNDB_AGE) ||
|
|
|
|
version > DNS_DYNDB_VERSION)
|
|
|
|
{
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
|
|
DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
|
|
|
|
"driver API version mismatch: %d/%d",
|
|
|
|
version, DNS_DYNDB_VERSION);
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(load_symbol(handle, filename, "dyndb_init",
|
|
|
|
(void **)®ister_func));
|
|
|
|
CHECK(load_symbol(handle, filename, "dyndb_destroy",
|
|
|
|
(void **)&destroy_func));
|
|
|
|
|
|
|
|
imp = isc_mem_get(mctx, sizeof(dyndb_implementation_t));
|
|
|
|
if (imp == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
imp->mctx = NULL;
|
|
|
|
isc_mem_attach(mctx, &imp->mctx);
|
|
|
|
imp->handle = handle;
|
|
|
|
imp->register_func = register_func;
|
|
|
|
imp->destroy_func = destroy_func;
|
|
|
|
imp->name = isc_mem_strdup(mctx, instname);
|
|
|
|
if (imp->name == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
imp->inst = NULL;
|
|
|
|
INIT_LINK(imp, link);
|
|
|
|
|
|
|
|
*impp = imp;
|
|
|
|
imp = NULL;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
|
|
DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
|
|
|
|
"failed to dynamically load instance '%s' "
|
|
|
|
"driver '%s': %s (%s)", instname, filename,
|
|
|
|
dlerror(), isc_result_totext(result));
|
|
|
|
if (imp != NULL)
|
2018-08-03 14:16:41 -07:00
|
|
|
isc_mem_putanddetach(&imp->mctx, imp,
|
|
|
|
sizeof(dyndb_implementation_t));
|
2015-09-28 23:12:35 -07:00
|
|
|
if (result != ISC_R_SUCCESS && handle != NULL)
|
|
|
|
dlclose(handle);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
unload_library(dyndb_implementation_t **impp) {
|
|
|
|
dyndb_implementation_t *imp;
|
|
|
|
|
|
|
|
REQUIRE(impp != NULL && *impp != NULL);
|
|
|
|
|
|
|
|
imp = *impp;
|
|
|
|
|
|
|
|
isc_mem_free(imp->mctx, imp->name);
|
|
|
|
isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t));
|
|
|
|
|
|
|
|
*impp = NULL;
|
|
|
|
}
|
2016-01-04 17:27:31 +01:00
|
|
|
#elif _WIN32
|
|
|
|
static isc_result_t
|
|
|
|
load_symbol(HMODULE handle, const char *filename,
|
|
|
|
const char *symbol_name, void **symbolp)
|
|
|
|
{
|
|
|
|
void *symbol;
|
|
|
|
|
|
|
|
REQUIRE(handle != NULL);
|
|
|
|
REQUIRE(symbolp != NULL && *symbolp == NULL);
|
|
|
|
|
|
|
|
symbol = GetProcAddress(handle, symbol_name);
|
|
|
|
if (symbol == NULL) {
|
|
|
|
int errstatus = GetLastError();
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
|
|
DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
|
|
|
|
"failed to lookup symbol %s in "
|
|
|
|
"dyndb module '%s': %d",
|
|
|
|
symbol_name, filename, errstatus);
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
*symbolp = symbol;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
load_library(isc_mem_t *mctx, const char *filename, const char *instname,
|
|
|
|
dyndb_implementation_t **impp)
|
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
HMODULE handle;
|
|
|
|
dyndb_implementation_t *imp = NULL;
|
|
|
|
dns_dyndb_register_t *register_func = NULL;
|
|
|
|
dns_dyndb_destroy_t *destroy_func = NULL;
|
|
|
|
dns_dyndb_version_t *version_func = NULL;
|
|
|
|
int version;
|
|
|
|
|
|
|
|
REQUIRE(impp != NULL && *impp == NULL);
|
|
|
|
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
|
|
DNS_LOGMODULE_DYNDB, ISC_LOG_INFO,
|
|
|
|
"loading DynDB instance '%s' driver '%s'",
|
|
|
|
instname, filename);
|
|
|
|
|
|
|
|
handle = LoadLibraryA(filename);
|
|
|
|
if (handle == NULL)
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
|
|
|
|
CHECK(load_symbol(handle, filename, "dyndb_version",
|
|
|
|
(void **)&version_func));
|
|
|
|
|
|
|
|
version = version_func(NULL);
|
|
|
|
if (version < (DNS_DYNDB_VERSION - DNS_DYNDB_AGE) ||
|
|
|
|
version > DNS_DYNDB_VERSION)
|
|
|
|
{
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
|
|
DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
|
|
|
|
"driver API version mismatch: %d/%d",
|
|
|
|
version, DNS_DYNDB_VERSION);
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(load_symbol(handle, filename, "dyndb_init",
|
|
|
|
(void **)®ister_func));
|
|
|
|
CHECK(load_symbol(handle, filename, "dyndb_destroy",
|
|
|
|
(void **)&destroy_func));
|
|
|
|
|
|
|
|
imp = isc_mem_get(mctx, sizeof(dyndb_implementation_t));
|
|
|
|
if (imp == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
imp->mctx = NULL;
|
|
|
|
isc_mem_attach(mctx, &imp->mctx);
|
|
|
|
imp->handle = handle;
|
|
|
|
imp->register_func = register_func;
|
|
|
|
imp->destroy_func = destroy_func;
|
|
|
|
imp->name = isc_mem_strdup(mctx, instname);
|
|
|
|
if (imp->name == NULL)
|
|
|
|
CHECK(ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
imp->inst = NULL;
|
|
|
|
INIT_LINK(imp, link);
|
|
|
|
|
|
|
|
*impp = imp;
|
|
|
|
imp = NULL;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
|
|
DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
|
|
|
|
"failed to dynamically load instance '%s' "
|
|
|
|
"driver '%s': %d (%s)", instname, filename,
|
|
|
|
GetLastError(), isc_result_totext(result));
|
|
|
|
if (imp != NULL)
|
2018-08-03 14:16:41 -07:00
|
|
|
isc_mem_putanddetach(&imp->mctx, imp,
|
|
|
|
sizeof(dyndb_implementation_t));
|
2016-01-04 17:27:31 +01:00
|
|
|
if (result != ISC_R_SUCCESS && handle != NULL)
|
|
|
|
FreeLibrary(handle);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
unload_library(dyndb_implementation_t **impp) {
|
|
|
|
dyndb_implementation_t *imp;
|
|
|
|
|
|
|
|
REQUIRE(impp != NULL && *impp != NULL);
|
|
|
|
|
|
|
|
imp = *impp;
|
|
|
|
|
|
|
|
isc_mem_free(imp->mctx, imp->name);
|
|
|
|
isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t));
|
|
|
|
|
|
|
|
*impp = NULL;
|
|
|
|
}
|
|
|
|
#else /* HAVE_DLFCN_H || _WIN32 */
|
2015-09-28 23:12:35 -07:00
|
|
|
static isc_result_t
|
|
|
|
load_library(isc_mem_t *mctx, const char *filename, const char *instname,
|
|
|
|
dyndb_implementation_t **impp)
|
|
|
|
{
|
|
|
|
UNUSED(mctx);
|
|
|
|
UNUSED(filename);
|
|
|
|
UNUSED(instname);
|
|
|
|
UNUSED(impp);
|
|
|
|
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DYNDB,
|
|
|
|
ISC_LOG_ERROR,
|
2015-11-16 17:47:10 +01:00
|
|
|
"dynamic database support is not implemented");
|
2015-09-28 23:12:35 -07:00
|
|
|
|
|
|
|
return (ISC_R_NOTIMPLEMENTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
unload_library(dyndb_implementation_t **impp)
|
|
|
|
{
|
2015-11-16 17:47:10 +01:00
|
|
|
UNUSED(impp);
|
2015-09-28 23:12:35 -07:00
|
|
|
}
|
|
|
|
#endif /* HAVE_DLFCN_H */
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_dyndb_load(const char *libname, const char *name, const char *parameters,
|
2016-08-25 18:08:26 -07:00
|
|
|
const char *file, unsigned long line, isc_mem_t *mctx,
|
|
|
|
const dns_dyndbctx_t *dctx)
|
2015-09-28 23:12:35 -07:00
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
dyndb_implementation_t *implementation = NULL;
|
|
|
|
|
|
|
|
REQUIRE(DNS_DYNDBCTX_VALID(dctx));
|
|
|
|
REQUIRE(name != NULL);
|
|
|
|
|
|
|
|
RUNTIME_CHECK(isc_once_do(&once, dyndb_initialize) == ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
LOCK(&dyndb_lock);
|
|
|
|
|
|
|
|
/* duplicate instance names are not allowed */
|
|
|
|
if (impfind(name) != NULL)
|
|
|
|
CHECK(ISC_R_EXISTS);
|
|
|
|
|
|
|
|
CHECK(load_library(mctx, libname, name, &implementation));
|
2016-08-25 18:08:26 -07:00
|
|
|
CHECK(implementation->register_func(mctx, name, parameters, file, line,
|
|
|
|
dctx, &implementation->inst));
|
2015-09-28 23:12:35 -07:00
|
|
|
|
|
|
|
APPEND(dyndb_implementations, implementation, link);
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
if (implementation != NULL)
|
|
|
|
unload_library(&implementation);
|
|
|
|
|
|
|
|
UNLOCK(&dyndb_lock);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-04-17 08:29:14 -07:00
|
|
|
dns_dyndb_cleanup(bool exiting) {
|
2015-09-28 23:12:35 -07:00
|
|
|
dyndb_implementation_t *elem;
|
|
|
|
dyndb_implementation_t *prev;
|
|
|
|
|
|
|
|
RUNTIME_CHECK(isc_once_do(&once, dyndb_initialize) == ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
LOCK(&dyndb_lock);
|
|
|
|
elem = TAIL(dyndb_implementations);
|
|
|
|
while (elem != NULL) {
|
|
|
|
prev = PREV(elem, link);
|
|
|
|
UNLINK(dyndb_implementations, elem, link);
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
|
|
DNS_LOGMODULE_DYNDB, ISC_LOG_INFO,
|
|
|
|
"unloading DynDB instance '%s'", elem->name);
|
|
|
|
elem->destroy_func(&elem->inst);
|
|
|
|
ENSURE(elem->inst == NULL);
|
|
|
|
unload_library(&elem);
|
|
|
|
elem = prev;
|
|
|
|
}
|
|
|
|
UNLOCK(&dyndb_lock);
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
if (exiting == true)
|
2015-09-28 23:12:35 -07:00
|
|
|
isc_mutex_destroy(&dyndb_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2016-02-12 00:22:45 -08:00
|
|
|
dns_dyndb_createctx(isc_mem_t *mctx, const void *hashinit, isc_log_t *lctx,
|
|
|
|
dns_view_t *view, dns_zonemgr_t *zmgr, isc_task_t *task,
|
|
|
|
isc_timermgr_t *tmgr, dns_dyndbctx_t **dctxp)
|
|
|
|
{
|
2015-09-28 23:12:35 -07:00
|
|
|
dns_dyndbctx_t *dctx;
|
|
|
|
|
|
|
|
REQUIRE(dctxp != NULL && *dctxp == NULL);
|
|
|
|
|
|
|
|
dctx = isc_mem_get(mctx, sizeof(*dctx));
|
|
|
|
if (dctx == NULL)
|
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
memset(dctx, 0, sizeof(*dctx));
|
|
|
|
if (view != NULL)
|
|
|
|
dns_view_attach(view, &dctx->view);
|
|
|
|
if (zmgr != NULL)
|
|
|
|
dns_zonemgr_attach(zmgr, &dctx->zmgr);
|
|
|
|
if (task != NULL)
|
|
|
|
isc_task_attach(task, &dctx->task);
|
|
|
|
dctx->timermgr = tmgr;
|
2016-02-12 00:22:45 -08:00
|
|
|
dctx->hashinit = hashinit;
|
2015-09-28 23:12:35 -07:00
|
|
|
dctx->lctx = lctx;
|
|
|
|
dctx->refvar = &isc_bind9;
|
|
|
|
|
|
|
|
isc_mem_attach(mctx, &dctx->mctx);
|
|
|
|
dctx->magic = DNS_DYNDBCTX_MAGIC;
|
|
|
|
|
|
|
|
*dctxp = dctx;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_dyndb_destroyctx(dns_dyndbctx_t **dctxp) {
|
|
|
|
dns_dyndbctx_t *dctx;
|
|
|
|
|
|
|
|
REQUIRE(dctxp != NULL && DNS_DYNDBCTX_VALID(*dctxp));
|
|
|
|
|
|
|
|
dctx = *dctxp;
|
2015-10-01 22:12:02 +10:00
|
|
|
*dctxp = NULL;
|
2015-09-28 23:12:35 -07:00
|
|
|
|
|
|
|
dctx->magic = 0;
|
|
|
|
|
|
|
|
if (dctx->view != NULL)
|
|
|
|
dns_view_detach(&dctx->view);
|
|
|
|
if (dctx->zmgr != NULL)
|
|
|
|
dns_zonemgr_detach(&dctx->zmgr);
|
|
|
|
if (dctx->task != NULL)
|
|
|
|
isc_task_detach(&dctx->task);
|
|
|
|
dctx->timermgr = NULL;
|
|
|
|
dctx->lctx = NULL;
|
|
|
|
|
|
|
|
isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx));
|
|
|
|
}
|