diff options
Diffstat (limited to 'lib/dns/dispatch.c')
| -rw-r--r-- | lib/dns/dispatch.c | 534 | 
1 files changed, 429 insertions, 105 deletions
| diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 9848ac28a64a3..5063914a9b296 100644 --- a/lib/dns/dispatch.c +++ b/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) { | 
