Commit ca973980 authored by Michael Graff's avatar Michael Graff
Browse files

implement dns_dispatchmgr_t, replacing dns_dispatchlist_t. Use it throughout the library/server.

parent f019e004
......@@ -26,6 +26,7 @@
#include <dns/cache.h>
#include <dns/db.h>
#include <dns/dispatch.h>
#include <dns/log.h>
#include <dns/resolver.h>
#include <dns/result.h>
......@@ -53,6 +54,7 @@ dns_view_t *view;
isc_taskmgr_t *taskmgr;
isc_socketmgr_t *sockmgr;
isc_timermgr_t *timermgr;
dns_dispatchmgr_t *dispatchmgr;
isc_sockaddrlist_t forwarders;
......@@ -88,7 +90,7 @@ create_view(isc_mem_t *mctx) {
* XXXMLG hardwired number of tasks.
*/
result = dns_view_createresolver(view, taskmgr, 16, sockmgr,
timermgr, 0, NULL, NULL);
timermgr, dispatchmgr, 0, NULL, NULL);
if (result != ISC_R_SUCCESS)
goto out;
......@@ -271,6 +273,13 @@ main(int argc, char **argv) {
result = isc_timermgr_create(mem, &timermgr);
INSIST(result == ISC_R_SUCCESS);
/*
* Create a dispatch manager.
*/
dispatchmgr = NULL;
result = dns_dispatchmgr_create(mem, &dispatchmgr);
INSIST(result == ISC_R_SUCCESS);
/*
* Read resolv.conf to get our forwarders.
*/
......
......@@ -39,6 +39,7 @@
EXTERN isc_mem_t * ns_g_mctx INIT(NULL);
EXTERN unsigned int ns_g_cpus INIT(1);
EXTERN isc_taskmgr_t * ns_g_taskmgr INIT(NULL);
EXTERN dns_dispatchmgr_t * ns_g_dispatchmgr INIT(NULL);
/*
* XXXRTH We're going to want multiple timer managers eventually. One
* for really short timers, another for client timers, and one
......
......@@ -87,8 +87,9 @@ struct ns_interface {
isc_result_t
ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_socketmgr_t *socketmgr, ns_clientmgr_t *clientmgr,
ns_interfacemgr_t **mgrp);
isc_socketmgr_t *socketmgr,
dns_dispatchmgr_t *dispatchmgr,
ns_clientmgr_t *clientmgr, ns_interfacemgr_t **mgrp);
void
ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target);
......
......@@ -42,6 +42,7 @@ struct ns_interfacemgr {
isc_mem_t * mctx; /* Memory context. */
isc_taskmgr_t * taskmgr; /* Task manager. */
isc_socketmgr_t * socketmgr; /* Socket manager. */
dns_dispatchmgr_t * dispatchmgr;
ns_clientmgr_t * clientmgr; /* Client manager. */
unsigned int generation; /* Current generation no. */
ns_listenlist_t * listenon;
......@@ -71,8 +72,9 @@ sockaddr_format(isc_sockaddr_t *sa, char *array, unsigned int size) {
isc_result_t
ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_socketmgr_t *socketmgr, ns_clientmgr_t *clientmgr,
ns_interfacemgr_t **mgrp)
isc_socketmgr_t *socketmgr,
dns_dispatchmgr_t *dispatchmgr,
ns_clientmgr_t *clientmgr, ns_interfacemgr_t **mgrp)
{
isc_result_t result;
ns_interfacemgr_t *mgr;
......@@ -92,6 +94,7 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
mgr->mctx = mctx;
mgr->taskmgr = taskmgr;
mgr->socketmgr = socketmgr;
mgr->dispatchmgr = dispatchmgr;
mgr->clientmgr = clientmgr;
mgr->generation = 1;
mgr->listenon = NULL;
......@@ -245,6 +248,7 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
static isc_result_t
ns_interface_listenudp(ns_interface_t *ifp) {
isc_result_t result;
unsigned int attrs;
/*
* Open a UDP socket.
......@@ -266,9 +270,17 @@ ns_interface_listenudp(ns_interface_t *ifp) {
isc_result_totext(result));
goto udp_bind_failure;
}
result = dns_dispatch_create(ifp->mgr->mctx, ifp->udpsocket, ifp->task,
4096, 1000, 32768, 8219, 8237, NULL,
&ifp->udpdispatch);
attrs = 0;
attrs |= DNS_DISPATCHATTR_UDP;
if (isc_sockaddr_pf(&ifp->addr) == AF_INET)
attrs |= DNS_DISPATCHATTR_IPV4;
else
attrs |= DNS_DISPATCHATTR_IPV6;
attrs |= DNS_DISPATCHATTR_MAKEQUERY;
attrs |= DNS_DISPATCHATTR_ACCEPTREQUEST;
result = dns_dispatch_create(ifp->mgr->dispatchmgr, ifp->udpsocket,
ifp->task, 4096, 1000, 32768, 8219,
8237, NULL, attrs, &ifp->udpdispatch);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"UDP dns_dispatch_create(): %s",
......
......@@ -25,6 +25,8 @@
#include <isc/timer.h>
#include <isc/util.h>
#include <dns/dispatch.h>
#include <dst/result.h>
/*
......@@ -258,6 +260,14 @@ create_managers() {
return (ISC_R_UNEXPECTED);
}
result = dns_dispatchmgr_create(ns_g_mctx, &ns_g_dispatchmgr);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"dns_dispatchmgr_create() failed: %s",
isc_result_totext(result));
return (ISC_R_UNEXPECTED);
}
return (ISC_R_SUCCESS);
}
......@@ -274,6 +284,7 @@ destroy_managers(void) {
isc_taskmgr_destroy(&ns_g_taskmgr);
isc_timermgr_destroy(&ns_g_timermgr);
isc_socketmgr_destroy(&ns_g_socketmgr);
dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
}
static void
......
......@@ -356,7 +356,8 @@ configure_view(dns_view_t *view, dns_c_ctx_t *cctx, dns_c_view_t *cview,
*/
CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31,
ns_g_socketmgr, ns_g_timermgr,
0, dispatchv4, dispatchv6));
0, ns_g_dispatchmgr,
dispatchv4, dispatchv6));
/*
* Set resolver forwarding policy.
......@@ -866,6 +867,7 @@ static isc_result_t
configure_server_querysource(dns_c_ctx_t *cctx, ns_server_t *server, int af,
dns_dispatch_t **dispatchp) {
isc_result_t result;
unsigned int attrs;
struct in_addr ina;
isc_sockaddr_t sa, any4, any6, *any;
isc_socket_t *socket;
......@@ -982,10 +984,18 @@ configure_server_querysource(dns_c_ctx_t *cctx, ns_server_t *server, int af,
isc_socket_detach(&socket);
return (result);
}
result = dns_dispatch_create(ns_g_mctx, socket,
attrs = 0;
attrs = DNS_DISPATCHATTR_UDP;
attrs |= DNS_DISPATCHATTR_PRIVATE;
if (af == AF_INET)
attrs |= DNS_DISPATCHATTR_IPV4;
else
attrs |= DNS_DISPATCHATTR_IPV6;
attrs |= DNS_DISPATCHATTR_MAKEQUERY;
result = dns_dispatch_create(ns_g_dispatchmgr, socket,
server->task, 4096,
1000, 32768, 16411, 16433, NULL,
server_dispatchp);
attrs, server_dispatchp);
/*
* Regardless of whether dns_dispatch_create() succeeded or
* failed, we don't need to keep the reference to the socket.
......@@ -1390,7 +1400,8 @@ run_server(isc_task_t *task, isc_event_t *event) {
"creating client manager");
CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
ns_g_socketmgr, server->clientmgr,
ns_g_socketmgr, ns_g_dispatchmgr,
server->clientmgr,
&server->interfacemgr),
"creating interface manager");
......
......@@ -119,7 +119,6 @@ DNSSAFEOBJS = sec/dnssafe/ahchdig.@O@ sec/dnssafe/ahchencr.@O@ \
OBJS = a6.@O@ acl.@O@ aclconf.@O@ adb.@O@ byaddr.@O@ \
cache.@O@ callbacks.@O@ compress.@O@ \
db.@O@ dbiterator.@O@ dbtable.@O@ dispatch.@O@ dnssec.@O@ \
dispatchlist.@O@ \
journal.@O@ keytable.@O@ lib.@O@ log.@O@ \
master.@O@ masterdump.@O@ message.@O@ \
name.@O@ ncache.@O@ nxt.@O@ peer.@O@ \
......@@ -135,7 +134,6 @@ OBJS = a6.@O@ acl.@O@ aclconf.@O@ adb.@O@ byaddr.@O@ \
SRCS = a6.c acl.c aclconf.c adb.c byaddr.c \
cache.c callbacks.c compress.c \
db.c dbiterator.c dbtable.c dispatch.c dnssec.c \
dispatchlist.c \
journal.c keytable.c lib.c log.c \
master.c masterdump.c message.c \
name.c ncache.c nxt.c peer.c \
......
......@@ -20,7 +20,9 @@
#include <stdlib.h>
#include <isc/lfsr.h>
#include <isc/list.h>
#include <isc/mem.h>
#include <isc/mutex.h>
#include <isc/print.h>
#include <isc/task.h>
#include <isc/util.h>
......@@ -30,6 +32,23 @@
#include <dns/log.h>
#include <dns/message.h>
#include <dns/tcpmsg.h>
#include <dns/types.h>
struct dns_dispatchmgr {
/* Unlocked. */
unsigned int magic;
isc_mem_t *mctx;
/* Locked by "lock". */
isc_mutex_t lock;
unsigned int state;
ISC_LIST(dns_dispatch_t) list;
};
#define MGR_SHUTTINGDOWN 0x00000001U
#define MGR_IS_SHUTTINGDOWN(l) (((l)->state & MGR_SHUTTINGDOWN) != 0)
#define IS_PRIVATE(d) (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0)
struct dns_dispentry {
unsigned int magic;
......@@ -51,14 +70,18 @@ typedef ISC_LIST(dns_dispentry_t) dns_displist_t;
struct dns_dispatch {
/* Unlocked. */
unsigned int magic; /* magic */
isc_mem_t *mctx; /* memory context */
dns_dispatchmgr_t *mgr; /* dispatch manager */
isc_task_t *task; /* internal task */
isc_socket_t *socket; /* isc socket attached to */
unsigned int buffersize; /* size of each buffer */
unsigned int maxrequests; /* max requests */
unsigned int maxbuffers; /* max buffers */
/* Locked. */
/* Locked by mgr->lock. */
unsigned int attributes;
ISC_LINK(dns_dispatch_t) link;
/* Locked by "lock". */
isc_mutex_t lock; /* locks all below */
unsigned int refcount; /* number of users */
isc_mempool_t *epool; /* memory pool for events */
......@@ -83,21 +106,24 @@ struct dns_dispatch {
dns_displist_t *qid_table; /* the table itself */
};
#define REQUEST_MAGIC 0x53912051 /* "random" value */
#define VALID_REQUEST(e) ((e) != NULL && (e)->magic == REQUEST_MAGIC)
#define REQUEST_MAGIC ISC_MAGIC('D', 'r', 'q', 's')
#define VALID_REQUEST(e) ISC_MAGIC_VALID((e), REQUEST_MAGIC)
#define RESPONSE_MAGIC ISC_MAGIC('D', 'r', 's', 'p')
#define VALID_RESPONSE(e) ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
#define RESPONSE_MAGIC 0x15021935 /* "random" value */
#define VALID_RESPONSE(e) ((e) != NULL && (e)->magic == RESPONSE_MAGIC)
#define DISPATCH_MAGIC ISC_MAGIC('D', 'i', 's', 'p')
#define VALID_DISPATCH(e) ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
#define DISPATCH_MAGIC 0x69385829 /* "random" value */
#define VALID_DISPATCH(e) ((e) != NULL && (e)->magic == DISPATCH_MAGIC)
#define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r')
#define VALID_DISPATCHMGR(e) ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC)
/*
* statics.
*/
static dns_dispentry_t *bucket_search(dns_dispatch_t *, isc_sockaddr_t *,
dns_messageid_t, unsigned int);
static void destroy(dns_dispatch_t *);
static void destroy_disp(dns_dispatch_t *);
static void udp_recv(isc_task_t *, isc_event_t *);
static void tcp_recv(isc_task_t *, isc_event_t *);
static inline void startrecv(dns_dispatch_t *);
......@@ -124,7 +150,8 @@ static dns_dispentry_t *linear_next(dns_dispatch_t *disp,
* The resulting string is guaranteed to be null-terminated.
*/
static void
sockaddr_format(isc_sockaddr_t *sa, char *array, unsigned int size) {
sockaddr_format(isc_sockaddr_t *sa, char *array, unsigned int size)
{
isc_result_t result;
isc_buffer_t buf;
......@@ -182,7 +209,8 @@ request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
}
static void
reseed_lfsr(isc_lfsr_t *lfsr, void *arg) {
reseed_lfsr(isc_lfsr_t *lfsr, void *arg)
{
UNUSED(arg);
lfsr->count = (random() & 0x1f) + 32; /* From 32 to 63 states */
......@@ -194,7 +222,8 @@ reseed_lfsr(isc_lfsr_t *lfsr, void *arg) {
* Return an unpredictable message ID.
*/
static isc_uint32_t
dns_randomid(dns_dispatch_t *disp) {
dns_randomid(dns_dispatch_t *disp)
{
isc_uint32_t id;
id = isc_lfsr_generate32(&disp->qid_lfsr1, &disp->qid_lfsr2);
......@@ -206,7 +235,8 @@ dns_randomid(dns_dispatch_t *disp) {
* Return a hash of the destination and message id.
*/
static isc_uint32_t
dns_hash(dns_dispatch_t *disp, isc_sockaddr_t *dest, isc_uint32_t id) {
dns_hash(dns_dispatch_t *disp, isc_sockaddr_t *dest, isc_uint32_t id)
{
unsigned int ret;
ret = isc_sockaddr_hash(dest, ISC_TRUE);
......@@ -224,7 +254,8 @@ static dns_dispatchmethods_t dns_wire_methods = {
};
static dns_dispentry_t *
linear_first(dns_dispatch_t *disp) {
linear_first(dns_dispatch_t *disp)
{
dns_dispentry_t *ret;
unsigned int bucket;
......@@ -241,7 +272,8 @@ linear_first(dns_dispatch_t *disp) {
}
static dns_dispentry_t *
linear_next(dns_dispatch_t *disp, dns_dispentry_t *resp) {
linear_next(dns_dispatch_t *disp, dns_dispentry_t *resp)
{
dns_dispentry_t *ret;
unsigned int bucket;
......@@ -261,11 +293,21 @@ linear_next(dns_dispatch_t *disp, dns_dispentry_t *resp) {
}
/*
* Called when refcount reaches 0 (and safe to destroy)
* Called when refcount reaches 0 (and safe to destroy).
*
* The dispatch lock must NOT be locked, and the manager lock MUST be
* locked.
*/
static void
destroy(dns_dispatch_t *disp) {
destroy_disp(dns_dispatch_t *disp)
{
dns_dispatchevent_t *ev;
dns_dispatchmgr_t *mgr;
mgr = disp->mgr;
disp->mgr = NULL;
ISC_LIST_UNLINK(mgr->list, disp, link);
disp->magic = 0;
......@@ -299,10 +341,10 @@ destroy(dns_dispatch_t *disp) {
isc_mempool_destroy(&disp->rpool);
isc_mempool_destroy(&disp->bpool);
isc_mempool_destroy(&disp->epool);
isc_mem_put(disp->mctx, disp->qid_table,
isc_mem_put(mgr->mctx, disp->qid_table,
disp->qid_nbuckets * sizeof(dns_displist_t));
isc_mem_put(disp->mctx, disp, sizeof(dns_dispatch_t));
isc_mem_put(mgr->mctx, disp, sizeof(dns_dispatch_t));
}
......@@ -326,7 +368,8 @@ bucket_search(dns_dispatch_t *disp, isc_sockaddr_t *dest, dns_messageid_t id,
}
static void
free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len)
{
isc_sockettype_t socktype;
INSIST(buf != NULL && len != 0);
......@@ -337,13 +380,13 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
switch (socktype) {
case isc_sockettype_tcp:
isc_mem_put(disp->mctx, buf, len);
isc_mem_put(disp->mgr->mctx, buf, len);
break;
case isc_sockettype_udp:
if (len == disp->buffersize)
isc_mempool_put(disp->bpool, buf);
else
isc_mem_put(disp->mctx, buf, len);
isc_mem_put(disp->mgr->mctx, buf, len);
break;
default:
INSIST(0);
......@@ -352,7 +395,8 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
}
static void *
allocate_buffer(dns_dispatch_t *disp, unsigned int len) {
allocate_buffer(dns_dispatch_t *disp, unsigned int len)
{
void *temp;
INSIST(len > 0);
......@@ -360,7 +404,7 @@ allocate_buffer(dns_dispatch_t *disp, unsigned int len) {
if (len == disp->buffersize)
temp = isc_mempool_get(disp->bpool);
else
temp = isc_mem_get(disp->mctx, len);
temp = isc_mem_get(disp->mgr->mctx, len);
if (temp != NULL)
disp->buffers++;
......@@ -369,7 +413,8 @@ allocate_buffer(dns_dispatch_t *disp, unsigned int len) {
}
static inline void
free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev)
{
if (disp->failsafe_ev == ev) {
INSIST(disp->shutdown_out == 1);
disp->shutdown_out = 0;
......@@ -381,7 +426,8 @@ free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
}
static inline dns_dispatchevent_t *
allocate_event(dns_dispatch_t *disp) {
allocate_event(dns_dispatch_t *disp)
{
dns_dispatchevent_t *ev;
ev = isc_mempool_get(disp->epool);
......@@ -413,7 +459,8 @@ allocate_event(dns_dispatch_t *disp) {
* restart.
*/
static void
udp_recv(isc_task_t *task, isc_event_t *ev_in) {
udp_recv(isc_task_t *task, isc_event_t *ev_in)
{
isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
dns_dispatch_t *disp = ev_in->ev_arg;
dns_messageid_t id;
......@@ -451,7 +498,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
UNLOCK(&disp->lock);
if (killit)
destroy(disp);
destroy_disp(disp);
isc_event_free(&ev_in);
return;
......@@ -596,7 +643,8 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
* restart.
*/
static void
tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
tcp_recv(isc_task_t *task, isc_event_t *ev_in)
{
dns_dispatch_t *disp = ev_in->ev_arg;
dns_tcpmsg_t *tcpmsg = &disp->tcpmsg;
dns_messageid_t id;
......@@ -652,13 +700,13 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
/*
* The event is statically allocated in the tcpmsg
* structure, and destroy() frees the tcpmsg, so we must
* free the event *before* calling destroy().
* structure, and destroy_disp() frees the tcpmsg, so we must
* free the event *before* calling destroy_disp().
*/
isc_event_free(&ev_in);
if (killit)
destroy(disp);
destroy_disp(disp);
return;
......@@ -767,7 +815,8 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
* disp must be locked.
*/
static void
startrecv(dns_dispatch_t *disp) {
startrecv(dns_dispatch_t *disp)
{
isc_sockettype_t socktype;
isc_result_t res;
isc_region_t region;
......@@ -825,16 +874,142 @@ startrecv(dns_dispatch_t *disp) {
}
}
/*
* Mgr must be locked when calling this function.
*/
static isc_boolean_t
destroy_mgr_ok(dns_dispatchmgr_t *mgr)
{
if (!MGR_IS_SHUTTINGDOWN(mgr))
return (ISC_FALSE);
if (!ISC_LIST_EMPTY(mgr->list))
return (ISC_FALSE);
return (ISC_TRUE);
}
/*
* Mgr must be unlocked when calling this function.
*/
static void
destroy_mgr(dns_dispatchmgr_t **mgrp)
{
isc_mem_t *mctx;
dns_dispatchmgr_t *mgr;
mgr = *mgrp;
*mgrp = NULL;
mctx = mgr->mctx;
mgr->magic = 0;
mgr->mctx = 0;
isc_mutex_destroy(&mgr->lock);
mgr->state = 0;
isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
isc_mem_detach(&mctx);
}
/*
* Publics.
*/
isc_result_t
dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
unsigned int maxbuffersize,
dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp)
{
dns_dispatchmgr_t *mgr;
isc_result_t result;
REQUIRE(mctx != NULL);
REQUIRE(mgrp != NULL && *mgrp == NULL);
mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
if (mgr == NULL)
return (ISC_R_NOMEMORY);
result = isc_mutex_init(&mgr->lock);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
return (result);
}
mgr->magic = DNS_DISPATCHMGR_MAGIC;
mgr->state = 0;
mgr->mctx = NULL;
isc_mem_attach(mctx, &mgr->mctx);
ISC_LIST_INIT(mgr->list);
*mgrp = mgr;
return (ISC_R_SUCCESS);
}
void
dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp)
{
dns_dispatchmgr_t *mgr;
isc_boolean_t killit;
REQUIRE(mgrp != NULL);
REQUIRE(VALID_DISPATCHMGR(*mgrp));
mgr = *mgrp;
*mgrp = NULL;
LOCK(&mgr->lock);
mgr->state |= MGR_SHUTTINGDOWN;
killit = destroy_mgr_ok(mgr);
UNLOCK(&mgr->lock);
if (killit)
destroy_mgr(&mgr);
}
#define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))
isc_result_t
dns_dispatchmgr_find(dns_dispatchmgr_t *mgr, unsigned int attributes,
unsigned int mask, dns_dispatch_t **dispp)
{
dns_dispatch_t *disp;
isc_result_t result;
REQUIRE(VALID_DISPATCHMGR(mgr));
REQUIRE(dispp != NULL && *dispp == NULL);
LOCK(&mgr->lock);
disp = ISC_LIST_HEAD(mgr->list);
while (disp != NULL) {
if (!IS_PRIVATE(disp)
&& ATTRMATCH(disp->attributes, attributes, mask))
break;
disp = ISC_LIST_NEXT(disp, link);
}
if (disp == NULL) {
result = ISC_R_NOTFOUND;
goto out;
}
dns_dispatch_attach(disp, dispp);
result = ISC_R_SUCCESS;
out: