diff options
Diffstat (limited to 'contrib/bind9/lib/dns/dispatch.c')
-rw-r--r-- | contrib/bind9/lib/dns/dispatch.c | 534 |
1 files changed, 429 insertions, 105 deletions
diff --git a/contrib/bind9/lib/dns/dispatch.c b/contrib/bind9/lib/dns/dispatch.c index 9848ac2..5063914 100644 --- a/contrib/bind9/lib/dns/dispatch.c +++ b/contrib/bind9/lib/dns/dispatch.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id$ */ +/* $Id: dispatch.c,v 1.175 2011/11/29 01:03:47 marka Exp $ */ /*! \file */ @@ -32,6 +32,7 @@ #include <isc/portset.h> #include <isc/print.h> #include <isc/random.h> +#include <isc/socket.h> #include <isc/stats.h> #include <isc/string.h> #include <isc/task.h> @@ -101,12 +102,16 @@ struct dns_dispatchmgr { unsigned int maxbuffers; /*%< max buffers */ /* Locked internally. */ - isc_mutex_t pool_lock; - isc_mempool_t *epool; /*%< memory pool for events */ - isc_mempool_t *rpool; /*%< memory pool for replies */ + isc_mutex_t depool_lock; + isc_mempool_t *depool; /*%< pool for dispatch events */ + isc_mutex_t rpool_lock; + isc_mempool_t *rpool; /*%< pool for replies */ + isc_mutex_t dpool_lock; isc_mempool_t *dpool; /*%< dispatch allocations */ - isc_mempool_t *bpool; /*%< memory pool for buffers */ - isc_mempool_t *spool; /*%< memory pool for dispsocs */ + isc_mutex_t bpool_lock; + isc_mempool_t *bpool; /*%< pool for buffers */ + isc_mutex_t spool_lock; + isc_mempool_t *spool; /*%< pool for dispsocks */ /*% * Locked by qid->lock if qid exists; otherwise, can be used without @@ -226,6 +231,9 @@ struct dns_dispatch { unsigned int maxrequests; /*%< max requests */ isc_event_t *ctlevent; + isc_mutex_t sepool_lock; + isc_mempool_t *sepool; /*%< pool for socket events */ + /*% Locked by mgr->lock. */ ISC_LINK(dns_dispatch_t) link; @@ -301,8 +309,8 @@ static isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t, in_port_t); static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len); static void *allocate_udp_buffer(dns_dispatch_t *disp); -static inline void free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev); -static inline dns_dispatchevent_t *allocate_event(dns_dispatch_t *disp); +static inline void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev); +static inline dns_dispatchevent_t *allocate_devent(dns_dispatch_t *disp); static void do_cancel(dns_dispatch_t *disp); static dns_dispentry_t *linear_first(dns_qid_t *disp); static dns_dispentry_t *linear_next(dns_qid_t *disp, @@ -312,14 +320,16 @@ static isc_result_t get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, isc_socketmgr_t *sockmgr, isc_sockaddr_t *localaddr, - isc_socket_t **sockp); + isc_socket_t **sockp, + isc_socket_t *dup_socket); static isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr, unsigned int maxrequests, unsigned int attributes, - dns_dispatch_t **dispp); + dns_dispatch_t **dispp, + isc_socket_t *dup_socket); static isc_boolean_t destroy_mgr_ok(dns_dispatchmgr_t *mgr); static void destroy_mgr(dns_dispatchmgr_t **mgrp); static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, @@ -327,7 +337,8 @@ static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, isc_boolean_t needaddrtable); static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp); static isc_result_t open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local, - unsigned int options, isc_socket_t **sockp); + unsigned int options, isc_socket_t **sockp, + isc_socket_t *dup_socket); static isc_boolean_t portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock, isc_sockaddr_t *sockaddrp); @@ -720,6 +731,11 @@ destroy_disp(isc_task_t *task, isc_event_t *event) { "shutting down; detaching from sock %p, task %p", disp->socket, disp->task[0]); /* XXXX */ + if (disp->sepool != NULL) { + isc_mempool_destroy(&disp->sepool); + (void)isc_mutex_destroy(&disp->sepool_lock); + } + if (disp->socket != NULL) isc_socket_detach(&disp->socket); while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) { @@ -784,6 +800,7 @@ new_portentry(dns_dispatch_t *disp, in_port_t port) { static void deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { dispportentry_t *portentry = *portentryp; + isc_boolean_t unlink = ISC_FALSE; dns_qid_t *qid; REQUIRE(disp->port_table != NULL); @@ -792,7 +809,10 @@ deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { qid = DNS_QID(disp); LOCK(&qid->lock); portentry->refs--; - if (portentry->refs == 0) { + unlink = ISC_TF(portentry->refs == 0); + UNLOCK(&qid->lock); + + if (unlink) { ISC_LIST_UNLINK(disp->port_table[portentry->port % DNS_DISPATCH_PORTTABLESIZE], portentry, link); @@ -800,7 +820,6 @@ deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { } *portentryp = NULL; - UNLOCK(&qid->lock); } /*% @@ -830,12 +849,12 @@ socket_search(dns_qid_t *qid, isc_sockaddr_t *dest, in_port_t port, /*% * Make a new socket for a single dispatch with a random port number. - * The caller must hold the disp->lock and qid->lock. + * The caller must hold the disp->lock */ static isc_result_t get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest, - isc_socketmgr_t *sockmgr, dns_qid_t *qid, - dispsocket_t **dispsockp, in_port_t *portp) + isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp, + in_port_t *portp) { int i; isc_uint32_t r; @@ -850,6 +869,7 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest, in_port_t *ports; unsigned int bindoptions; dispportentry_t *portentry = NULL; + dns_qid_t *qid; if (isc_sockaddr_pf(&disp->local) == AF_INET) { nports = disp->mgr->nv4ports; @@ -890,19 +910,27 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest, * very likely to fail in bind(2) or connect(2). */ localaddr = disp->local; + qid = DNS_QID(disp); + for (i = 0; i < 64; i++) { port = ports[dispatch_uniformrandom(DISP_ARC4CTX(disp), nports)]; isc_sockaddr_setport(&localaddr, port); + LOCK(&qid->lock); bucket = dns_hash(qid, dest, 0, port); - if (socket_search(qid, dest, port, bucket) != NULL) + if (socket_search(qid, dest, port, bucket) != NULL) { + UNLOCK(&qid->lock); continue; + } + UNLOCK(&qid->lock); bindoptions = 0; portentry = port_search(disp, port); + if (portentry != NULL) bindoptions |= ISC_SOCKET_REUSEADDRESS; - result = open_socket(sockmgr, &localaddr, bindoptions, &sock); + result = open_socket(sockmgr, &localaddr, bindoptions, &sock, + NULL); if (result == ISC_R_SUCCESS) { if (portentry == NULL) { portentry = new_portentry(disp, port); @@ -928,7 +956,9 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest, dispsock->host = *dest; dispsock->portentry = portentry; dispsock->bucket = bucket; + LOCK(&qid->lock); ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink); + UNLOCK(&qid->lock); *dispsockp = dispsock; *portp = port; } else { @@ -1063,6 +1093,7 @@ entry_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id, static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { + isc_mempool_t *bpool; INSIST(buf != NULL && len != 0); @@ -1077,8 +1108,9 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { INSIST(disp->mgr->buffers > 0); INSIST(len == disp->mgr->buffersize); disp->mgr->buffers--; - isc_mempool_put(disp->mgr->bpool, buf); + bpool = disp->mgr->bpool; UNLOCK(&disp->mgr->buffer_lock); + isc_mempool_put(bpool, buf); break; default: INSIST(0); @@ -1088,20 +1120,60 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { static void * allocate_udp_buffer(dns_dispatch_t *disp) { + isc_mempool_t *bpool; void *temp; LOCK(&disp->mgr->buffer_lock); - temp = isc_mempool_get(disp->mgr->bpool); - - if (temp != NULL) - disp->mgr->buffers++; + bpool = disp->mgr->bpool; + disp->mgr->buffers++; UNLOCK(&disp->mgr->buffer_lock); + temp = isc_mempool_get(bpool); + + if (temp == NULL) { + LOCK(&disp->mgr->buffer_lock); + disp->mgr->buffers--; + UNLOCK(&disp->mgr->buffer_lock); + } + return (temp); } static inline void -free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { +free_sevent(isc_event_t *ev) { + isc_mempool_t *pool = ev->ev_destroy_arg; + isc_socketevent_t *sev = (isc_socketevent_t *) ev; + isc_mempool_put(pool, sev); +} + +static inline isc_socketevent_t * +allocate_sevent(dns_dispatch_t *disp, isc_socket_t *socket, + isc_eventtype_t type, isc_taskaction_t action, const void *arg) +{ + isc_socketevent_t *ev; + void *deconst_arg; + + ev = isc_mempool_get(disp->sepool); + if (ev == NULL) + return (NULL); + DE_CONST(arg, deconst_arg); + ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, type, + action, deconst_arg, socket, + free_sevent, disp->sepool); + ev->result = ISC_R_UNSET; + ISC_LINK_INIT(ev, ev_link); + ISC_LIST_INIT(ev->bufferlist); + ev->region.base = NULL; + ev->n = 0; + ev->offset = 0; + ev->attributes = 0; + + return (ev); +} + + +static inline void +free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { if (disp->failsafe_ev == ev) { INSIST(disp->shutdown_out == 1); disp->shutdown_out = 0; @@ -1109,14 +1181,14 @@ free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { return; } - isc_mempool_put(disp->mgr->epool, ev); + isc_mempool_put(disp->mgr->depool, ev); } static inline dns_dispatchevent_t * -allocate_event(dns_dispatch_t *disp) { +allocate_devent(dns_dispatch_t *disp) { dns_dispatchevent_t *ev; - ev = isc_mempool_get(disp->mgr->epool); + ev = isc_mempool_get(disp->mgr->depool); if (ev == NULL) return (NULL); ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0, @@ -1381,7 +1453,7 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { sendresponse: queue_response = resp->item_out; - rev = allocate_event(resp->disp); + rev = allocate_devent(resp->disp); if (rev == NULL) { free_buffer(disp, ev->region.base, ev->region.length); goto unlock; @@ -1579,7 +1651,7 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { if (resp == NULL) goto unlock; queue_response = resp->item_out; - rev = allocate_event(disp); + rev = allocate_devent(disp); if (rev == NULL) goto unlock; @@ -1660,16 +1732,33 @@ startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { if (region.base == NULL) return (ISC_R_NOMEMORY); if (dispsock != NULL) { - res = isc_socket_recv(socket, ®ion, 1, - dispsock->task, udp_exrecv, - dispsock); + isc_task_t *dt = dispsock->task; + isc_socketevent_t *sev = + allocate_sevent(disp, socket, + ISC_SOCKEVENT_RECVDONE, + udp_exrecv, dispsock); + if (sev == NULL) { + free_buffer(disp, region.base, region.length); + return (ISC_R_NOMEMORY); + } + + res = isc_socket_recv2(socket, ®ion, 1, dt, sev, 0); if (res != ISC_R_SUCCESS) { free_buffer(disp, region.base, region.length); return (res); } } else { - res = isc_socket_recv(socket, ®ion, 1, - disp->task[0], udp_shrecv, disp); + isc_task_t *dt = disp->task[0]; + isc_socketevent_t *sev = + allocate_sevent(disp, socket, + ISC_SOCKEVENT_RECVDONE, + udp_shrecv, disp); + if (sev == NULL) { + free_buffer(disp, region.base, region.length); + return (ISC_R_NOMEMORY); + } + + res = isc_socket_recv2(socket, ®ion, 1, dt, sev, 0); if (res != ISC_R_SUCCESS) { free_buffer(disp, region.base, region.length); disp->shutdown_why = res; @@ -1709,16 +1798,16 @@ static isc_boolean_t destroy_mgr_ok(dns_dispatchmgr_t *mgr) { mgr_log(mgr, LVL(90), "destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, " - "epool=%d, rpool=%d, dpool=%d", + "depool=%d, rpool=%d, dpool=%d", MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list), - isc_mempool_getallocated(mgr->epool), + isc_mempool_getallocated(mgr->depool), isc_mempool_getallocated(mgr->rpool), isc_mempool_getallocated(mgr->dpool)); if (!MGR_IS_SHUTTINGDOWN(mgr)) return (ISC_FALSE); if (!ISC_LIST_EMPTY(mgr->list)) return (ISC_FALSE); - if (isc_mempool_getallocated(mgr->epool) != 0) + if (isc_mempool_getallocated(mgr->depool) != 0) return (ISC_FALSE); if (isc_mempool_getallocated(mgr->rpool) != 0) return (ISC_FALSE); @@ -1748,7 +1837,7 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { DESTROYLOCK(&mgr->arc4_lock); - isc_mempool_destroy(&mgr->epool); + isc_mempool_destroy(&mgr->depool); isc_mempool_destroy(&mgr->rpool); isc_mempool_destroy(&mgr->dpool); if (mgr->bpool != NULL) @@ -1756,7 +1845,11 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { if (mgr->spool != NULL) isc_mempool_destroy(&mgr->spool); - DESTROYLOCK(&mgr->pool_lock); + DESTROYLOCK(&mgr->spool_lock); + DESTROYLOCK(&mgr->bpool_lock); + DESTROYLOCK(&mgr->dpool_lock); + DESTROYLOCK(&mgr->rpool_lock); + DESTROYLOCK(&mgr->depool_lock); #ifdef BIND9 if (mgr->entropy != NULL) @@ -1787,19 +1880,14 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { static isc_result_t open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local, - unsigned int options, isc_socket_t **sockp) + unsigned int options, isc_socket_t **sockp, + isc_socket_t *dup_socket) { isc_socket_t *sock; isc_result_t result; sock = *sockp; - if (sock == NULL) { - result = isc_socket_create(mgr, isc_sockaddr_pf(local), - isc_sockettype_udp, &sock); - if (result != ISC_R_SUCCESS) - return (result); - isc_socket_setname(sock, "dispatcher", NULL); - } else { + if (sock != NULL) { #ifdef BIND9 result = isc_socket_open(sock); if (result != ISC_R_SUCCESS) @@ -1807,8 +1895,23 @@ open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local, #else INSIST(0); #endif + } else if (dup_socket != NULL) { + result = isc_socket_dup(dup_socket, &sock); + if (result != ISC_R_SUCCESS) + return (result); + + isc_socket_setname(sock, "dispatcher", NULL); + *sockp = sock; + return (ISC_R_SUCCESS); + } else { + result = isc_socket_create(mgr, isc_sockaddr_pf(local), + isc_sockettype_udp, &sock); + if (result != ISC_R_SUCCESS) + return (result); } + isc_socket_setname(sock, "dispatcher", NULL); + #ifndef ISC_ALLOW_MAPPED isc_socket_ipv6only(sock, ISC_TRUE); #endif @@ -1886,22 +1989,38 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy, if (result != ISC_R_SUCCESS) goto kill_arc4_lock; - result = isc_mutex_init(&mgr->pool_lock); + result = isc_mutex_init(&mgr->depool_lock); if (result != ISC_R_SUCCESS) goto kill_buffer_lock; - mgr->epool = NULL; + result = isc_mutex_init(&mgr->rpool_lock); + if (result != ISC_R_SUCCESS) + goto kill_depool_lock; + + result = isc_mutex_init(&mgr->dpool_lock); + if (result != ISC_R_SUCCESS) + goto kill_rpool_lock; + + result = isc_mutex_init(&mgr->bpool_lock); + if (result != ISC_R_SUCCESS) + goto kill_dpool_lock; + + result = isc_mutex_init(&mgr->spool_lock); + if (result != ISC_R_SUCCESS) + goto kill_bpool_lock; + + mgr->depool = NULL; if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t), - &mgr->epool) != ISC_R_SUCCESS) { + &mgr->depool) != ISC_R_SUCCESS) { result = ISC_R_NOMEMORY; - goto kill_pool_lock; + goto kill_spool_lock; } mgr->rpool = NULL; if (isc_mempool_create(mgr->mctx, sizeof(dns_dispentry_t), &mgr->rpool) != ISC_R_SUCCESS) { result = ISC_R_NOMEMORY; - goto kill_epool; + goto kill_depool; } mgr->dpool = NULL; @@ -1911,17 +2030,23 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy, goto kill_rpool; } - isc_mempool_setname(mgr->epool, "dispmgr_epool"); - isc_mempool_setfreemax(mgr->epool, 1024); - isc_mempool_associatelock(mgr->epool, &mgr->pool_lock); + isc_mempool_setname(mgr->depool, "dispmgr_depool"); + isc_mempool_setmaxalloc(mgr->depool, 32768); + isc_mempool_setfreemax(mgr->depool, 32768); + isc_mempool_associatelock(mgr->depool, &mgr->depool_lock); + isc_mempool_setfillcount(mgr->depool, 256); isc_mempool_setname(mgr->rpool, "dispmgr_rpool"); - isc_mempool_setfreemax(mgr->rpool, 1024); - isc_mempool_associatelock(mgr->rpool, &mgr->pool_lock); + isc_mempool_setmaxalloc(mgr->rpool, 32768); + isc_mempool_setfreemax(mgr->rpool, 32768); + isc_mempool_associatelock(mgr->rpool, &mgr->rpool_lock); + isc_mempool_setfillcount(mgr->rpool, 256); isc_mempool_setname(mgr->dpool, "dispmgr_dpool"); - isc_mempool_setfreemax(mgr->dpool, 1024); - isc_mempool_associatelock(mgr->dpool, &mgr->pool_lock); + isc_mempool_setmaxalloc(mgr->dpool, 32768); + isc_mempool_setfreemax(mgr->dpool, 32768); + isc_mempool_associatelock(mgr->dpool, &mgr->dpool_lock); + isc_mempool_setfillcount(mgr->dpool, 256); mgr->buffers = 0; mgr->buffersize = 0; @@ -1970,10 +2095,18 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy, isc_mempool_destroy(&mgr->dpool); kill_rpool: isc_mempool_destroy(&mgr->rpool); - kill_epool: - isc_mempool_destroy(&mgr->epool); - kill_pool_lock: - DESTROYLOCK(&mgr->pool_lock); + kill_depool: + isc_mempool_destroy(&mgr->depool); + kill_spool_lock: + DESTROYLOCK(&mgr->spool_lock); + kill_bpool_lock: + DESTROYLOCK(&mgr->bpool_lock); + kill_dpool_lock: + DESTROYLOCK(&mgr->dpool_lock); + kill_rpool_lock: + DESTROYLOCK(&mgr->rpool_lock); + kill_depool_lock: + DESTROYLOCK(&mgr->depool_lock); kill_buffer_lock: DESTROYLOCK(&mgr->buffer_lock); kill_arc4_lock: @@ -2127,6 +2260,7 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, */ if (maxbuffers > mgr->maxbuffers) { isc_mempool_setmaxalloc(mgr->bpool, maxbuffers); + isc_mempool_setfreemax(mgr->bpool, maxbuffers); mgr->maxbuffers = maxbuffers; } } else { @@ -2137,12 +2271,16 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, } isc_mempool_setname(mgr->bpool, "dispmgr_bpool"); isc_mempool_setmaxalloc(mgr->bpool, maxbuffers); - isc_mempool_associatelock(mgr->bpool, &mgr->pool_lock); + isc_mempool_setfreemax(mgr->bpool, maxbuffers); + isc_mempool_associatelock(mgr->bpool, &mgr->bpool_lock); + isc_mempool_setfillcount(mgr->bpool, 256); } /* Create or adjust socket pool */ if (mgr->spool != NULL) { - isc_mempool_setmaxalloc(mgr->spool, DNS_DISPATCH_POOLSOCKS * 2); + if (maxrequests < DNS_DISPATCH_POOLSOCKS * 2) + isc_mempool_setmaxalloc(mgr->spool, DNS_DISPATCH_POOLSOCKS * 2); + isc_mempool_setfreemax(mgr->spool, DNS_DISPATCH_POOLSOCKS * 2); UNLOCK(&mgr->buffer_lock); return (ISC_R_SUCCESS); } @@ -2154,7 +2292,9 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, } isc_mempool_setname(mgr->spool, "dispmgr_spool"); isc_mempool_setmaxalloc(mgr->spool, maxrequests); - isc_mempool_associatelock(mgr->spool, &mgr->pool_lock); + isc_mempool_setfreemax(mgr->spool, maxrequests); + isc_mempool_associatelock(mgr->spool, &mgr->spool_lock); + isc_mempool_setfillcount(mgr->spool, 256); result = qid_allocate(mgr, buckets, increment, &mgr->qid, ISC_TRUE); if (result != ISC_R_SUCCESS) @@ -2480,7 +2620,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, if (result != ISC_R_SUCCESS) goto deallocate; - disp->failsafe_ev = allocate_event(disp); + disp->failsafe_ev = allocate_devent(disp); if (disp->failsafe_ev == NULL) { result = ISC_R_NOMEMORY; goto kill_lock; @@ -2531,7 +2671,7 @@ dispatch_free(dns_dispatch_t **dispp) INSIST(ISC_LIST_EMPTY(disp->activesockets)); INSIST(ISC_LIST_EMPTY(disp->inactivesockets)); - isc_mempool_put(mgr->epool, disp->failsafe_ev); + isc_mempool_put(mgr->depool, disp->failsafe_ev); disp->failsafe_ev = NULL; if (disp->qid != NULL) @@ -2595,6 +2735,8 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, disp->socket = NULL; isc_socket_attach(sock, &disp->socket); + disp->sepool = NULL; + disp->ntasks = 1; disp->task[0] = NULL; result = isc_task_create(taskmgr, 0, &disp->task[0]); @@ -2646,13 +2788,13 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, } isc_result_t -dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, +dns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr, unsigned int buffersize, unsigned int maxbuffers, unsigned int maxrequests, unsigned int buckets, unsigned int increment, unsigned int attributes, unsigned int mask, - dns_dispatch_t **dispp) + dns_dispatch_t **dispp, dns_dispatch_t *dup_dispatch) { isc_result_t result; dns_dispatch_t *disp = NULL; @@ -2683,28 +2825,31 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, /* * See if we have a dispatcher that matches. */ - result = dispatch_find(mgr, localaddr, attributes, mask, &disp); - if (result == ISC_R_SUCCESS) { - disp->refcount++; - - if (disp->maxrequests < maxrequests) - disp->maxrequests = maxrequests; - - if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0 && - (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) - { - disp->attributes |= DNS_DISPATCHATTR_NOLISTEN; - if (disp->recv_pending != 0) - isc_socket_cancel(disp->socket, disp->task[0], - ISC_SOCKCANCEL_RECV); - } + if (dup_dispatch == NULL) { + result = dispatch_find(mgr, localaddr, attributes, mask, &disp); + if (result == ISC_R_SUCCESS) { + disp->refcount++; + + if (disp->maxrequests < maxrequests) + disp->maxrequests = maxrequests; + + if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0 + && (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) + { + disp->attributes |= DNS_DISPATCHATTR_NOLISTEN; + if (disp->recv_pending != 0) + isc_socket_cancel(disp->socket, + disp->task[0], + ISC_SOCKCANCEL_RECV); + } - UNLOCK(&disp->lock); - UNLOCK(&mgr->lock); + UNLOCK(&disp->lock); + UNLOCK(&mgr->lock); - *dispp = disp; + *dispp = disp; - return (ISC_R_SUCCESS); + return (ISC_R_SUCCESS); + } } createudp: @@ -2712,7 +2857,11 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, * Nope, create one. */ result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr, - maxrequests, attributes, &disp); + maxrequests, attributes, &disp, + dup_dispatch == NULL + ? NULL + : dup_dispatch->socket); + if (result != ISC_R_SUCCESS) { UNLOCK(&mgr->lock); return (result); @@ -2720,9 +2869,25 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, UNLOCK(&mgr->lock); *dispp = disp; + return (ISC_R_SUCCESS); } +isc_result_t +dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, + isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr, + unsigned int buffersize, + unsigned int maxbuffers, unsigned int maxrequests, + unsigned int buckets, unsigned int increment, + unsigned int attributes, unsigned int mask, + dns_dispatch_t **dispp) +{ + return (dns_dispatch_getudp_dup(mgr, sockmgr, taskmgr, localaddr, + buffersize, maxbuffers, maxrequests, + buckets, increment, attributes, + mask, dispp, NULL)); +} + /* * mgr should be locked. */ @@ -2734,7 +2899,7 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, static isc_result_t get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, isc_socketmgr_t *sockmgr, isc_sockaddr_t *localaddr, - isc_socket_t **sockp) + isc_socket_t **sockp, isc_socket_t *dup_socket) { unsigned int i, j; isc_socket_t *held[DNS_DISPATCH_HELD]; @@ -2774,7 +2939,7 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, nports)]; isc_sockaddr_setport(&localaddr_bound, prt); result = open_socket(sockmgr, &localaddr_bound, - 0, &sock); + 0, &sock, NULL); /* * Continue if the port choosen is already in use * or the OS has reserved it. @@ -2794,7 +2959,8 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, } else { /* Allow to reuse address for non-random ports. */ result = open_socket(sockmgr, localaddr, - ISC_SOCKET_REUSEADDRESS, &sock); + ISC_SOCKET_REUSEADDRESS, &sock, + dup_socket); if (result == ISC_R_SUCCESS) *sockp = sock; @@ -2806,7 +2972,7 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, i = 0; for (j = 0; j < 0xffffU; j++) { - result = open_socket(sockmgr, localaddr, 0, &sock); + result = open_socket(sockmgr, localaddr, 0, &sock, NULL); if (result != ISC_R_SUCCESS) goto end; else if (portavailable(mgr, sock, NULL)) @@ -2843,7 +3009,8 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_sockaddr_t *localaddr, unsigned int maxrequests, unsigned int attributes, - dns_dispatch_t **dispp) + dns_dispatch_t **dispp, + isc_socket_t *dup_socket) { isc_result_t result; dns_dispatch_t *disp; @@ -2859,9 +3026,21 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, return (result); if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) { - result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock); + result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock, + dup_socket); if (result != ISC_R_SUCCESS) goto deallocate_dispatch; + + if (isc_log_wouldlog(dns_lctx, 90)) { + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(localaddr, addrbuf, + ISC_SOCKADDR_FORMATSIZE); + mgr_log(mgr, LVL(90), "dns_dispatch_createudp: Created" + " UDP dispatch for %s with socket fd %d\n", + addrbuf, isc_socket_getfd(sock)); + } + } else { isc_sockaddr_t sa_any; @@ -2873,7 +3052,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, */ isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr)); if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) { - result = open_socket(sockmgr, localaddr, 0, &sock); + result = open_socket(sockmgr, localaddr, 0, &sock, NULL); if (sock != NULL) isc_socket_detach(&sock); if (result != ISC_R_SUCCESS) @@ -2925,6 +3104,24 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, goto kill_task; } + disp->sepool = NULL; + if (isc_mempool_create(mgr->mctx, sizeof(isc_socketevent_t), + &disp->sepool) != ISC_R_SUCCESS) + { + result = ISC_R_NOMEMORY; + goto kill_ctlevent; + } + + result = isc_mutex_init(&disp->sepool_lock); + if (result != ISC_R_SUCCESS) + goto kill_sepool; + + isc_mempool_setname(disp->sepool, "disp_sepool"); + isc_mempool_setmaxalloc(disp->sepool, 32768); + isc_mempool_setfreemax(disp->sepool, 32768); + isc_mempool_associatelock(disp->sepool, &disp->sepool_lock); + isc_mempool_setfillcount(disp->sepool, 16); + attributes &= ~DNS_DISPATCHATTR_TCP; attributes |= DNS_DISPATCHATTR_UDP; disp->attributes = attributes; @@ -2940,11 +3137,16 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, dispatch_log(disp, LVL(90), "created socket %p", disp->socket); *dispp = disp; + return (result); /* * Error returns. */ + kill_sepool: + isc_mempool_destroy(&disp->sepool); + kill_ctlevent: + isc_event_free(&disp->ctlevent); kill_task: for (i = 0; i < disp->ntasks; i++) isc_task_detach(&disp->task[i]); @@ -3061,7 +3263,7 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, oldestsocket = ISC_LIST_HEAD(disp->activesockets); oldestresp = oldestsocket->resp; if (oldestresp != NULL && !oldestresp->item_out) { - rev = allocate_event(oldestresp->disp); + rev = allocate_devent(oldestresp->disp); if (rev != NULL) { rev->buffer.base = NULL; rev->result = ISC_R_CANCELED; @@ -3088,16 +3290,14 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, } qid = DNS_QID(disp); - LOCK(&qid->lock); if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { /* * Get a separate UDP socket with a random port number. */ - result = get_dispsocket(disp, dest, sockmgr, qid, &dispsocket, + result = get_dispsocket(disp, dest, sockmgr, &dispsocket, &localport); if (result != ISC_R_SUCCESS) { - UNLOCK(&qid->lock); UNLOCK(&disp->lock); inc_stats(disp->mgr, dns_resstatscounter_dispsockfail); return (result); @@ -3109,6 +3309,7 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, /* * Try somewhat hard to find an unique ID. */ + LOCK(&qid->lock); id = (dns_messageid_t)dispatch_random(DISP_ARC4CTX(disp)); bucket = dns_hash(qid, dest, id, localport); ok = ISC_FALSE; @@ -3121,16 +3322,15 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, id &= 0x0000ffff; bucket = dns_hash(qid, dest, id, localport); } + UNLOCK(&qid->lock); if (!ok) { - UNLOCK(&qid->lock); UNLOCK(&disp->lock); return (ISC_R_NOMORE); } res = isc_mempool_get(disp->mgr->rpool); if (res == NULL) { - UNLOCK(&qid->lock); UNLOCK(&disp->lock); if (dispsocket != NULL) destroy_dispsocket(disp, &dispsocket); @@ -3155,6 +3355,8 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, ISC_LIST_INIT(res->items); ISC_LINK_INIT(res, link); res->magic = RESPONSE_MAGIC; + + LOCK(&qid->lock); ISC_LIST_APPEND(qid->qid_table[bucket], res, link); UNLOCK(&qid->lock); @@ -3302,7 +3504,7 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, res->item_out = ISC_FALSE; if (ev->buffer.base != NULL) free_buffer(disp, ev->buffer.base, ev->buffer.length); - free_event(disp, ev); + free_devent(disp, ev); } request_log(disp, res, LVL(90), "detaching from task %p", res->task); @@ -3322,7 +3524,7 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, ISC_LIST_UNLINK(res->items, ev, ev_link); if (ev->buffer.base != NULL) free_buffer(disp, ev->buffer.base, ev->buffer.length); - free_event(disp, ev); + free_devent(disp, ev); ev = ISC_LIST_HEAD(res->items); } res->magic = 0; @@ -3519,6 +3721,128 @@ dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) { isc_task_send(disp->task[0], ISC_EVENT_PTR(&newsevent)); } +dns_dispatch_t * +dns_dispatchset_get(dns_dispatchset_t *dset) { + dns_dispatch_t *disp; + + /* check that dispatch set is configured */ + if (dset == NULL || dset->ndisp == 0) + return (NULL); + + LOCK(&dset->lock); + disp = dset->dispatches[dset->cur]; + dset->cur++; + if (dset->cur == dset->ndisp) + dset->cur = 0; + UNLOCK(&dset->lock); + + return (disp); +} + +isc_result_t +dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, + isc_taskmgr_t *taskmgr, dns_dispatch_t *source, + dns_dispatchset_t **dsetp, int n) +{ + isc_result_t result; + dns_dispatchset_t *dset; + dns_dispatchmgr_t *mgr; + int i, j; + + REQUIRE(VALID_DISPATCH(source)); + REQUIRE((source->attributes & DNS_DISPATCHATTR_UDP) != 0); + REQUIRE(dsetp != NULL && *dsetp == NULL); + + mgr = source->mgr; + + dset = isc_mem_get(mctx, sizeof(dns_dispatchset_t)); + if (dset == NULL) + return (ISC_R_NOMEMORY); + memset(dset, 0, sizeof(*dset)); + + result = isc_mutex_init(&dset->lock); + if (result != ISC_R_SUCCESS) + goto fail_alloc; + + dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n); + if (dset == NULL) { + result = ISC_R_NOMEMORY; + goto fail_lock; + } + + isc_mem_attach(mctx, &dset->mctx); + dset->ndisp = n; + dset->cur = 0; + + dset->dispatches[0] = NULL; + dns_dispatch_attach(source, &dset->dispatches[0]); + + LOCK(&mgr->lock); + for (i = 1; i < n; i++) { + dset->dispatches[i] = NULL; + result = dispatch_createudp(mgr, sockmgr, taskmgr, + &source->local, + source->maxrequests, + source->attributes, + &dset->dispatches[i], + source->socket); + if (result != ISC_R_SUCCESS) + goto fail; + } + + UNLOCK(&mgr->lock); + *dsetp = dset; + + return (ISC_R_SUCCESS); + + fail: + UNLOCK(&mgr->lock); + + for (j = 0; j < i; j++) + dns_dispatch_detach(&(dset->dispatches[j])); + isc_mem_put(mctx, dset->dispatches, sizeof(dns_dispatch_t *) * n); + if (dset->mctx == mctx) + isc_mem_detach(&dset->mctx); + + fail_lock: + DESTROYLOCK(&dset->lock); + + fail_alloc: + isc_mem_put(mctx, dset, sizeof(dns_dispatchset_t)); + return (result); +} + +void +dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task) { + int i; + + REQUIRE(dset != NULL); + + for (i = 0; i < dset->ndisp; i++) { + isc_socket_t *sock; + sock = dns_dispatch_getsocket(dset->dispatches[i]); + isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL); + } +} + +void +dns_dispatchset_destroy(dns_dispatchset_t **dsetp) { + dns_dispatchset_t *dset; + int i; + + REQUIRE(dsetp != NULL && *dsetp != NULL); + + dset = *dsetp; + for (i = 0; i < dset->ndisp; i++) + dns_dispatch_detach(&(dset->dispatches[i])); + isc_mem_put(dset->mctx, dset->dispatches, + sizeof(dns_dispatch_t *) * dset->ndisp); + DESTROYLOCK(&dset->lock); + isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t)); + + *dsetp = NULL; +} + #if 0 void dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) { |