xref: /minix/external/bsd/bind/dist/lib/dns/dispatch.c (revision fb9c64b2)
1 /*	$NetBSD: dispatch.c,v 1.10 2015/07/08 17:28:58 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1999-2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id: dispatch.c,v 1.175 2011/11/29 01:03:47 marka Exp  */
21 
22 /*! \file */
23 
24 #include <config.h>
25 
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 
31 #include <isc/entropy.h>
32 #include <isc/mem.h>
33 #include <isc/mutex.h>
34 #include <isc/portset.h>
35 #include <isc/print.h>
36 #include <isc/random.h>
37 #include <isc/socket.h>
38 #include <isc/stats.h>
39 #include <isc/string.h>
40 #include <isc/task.h>
41 #include <isc/time.h>
42 #include <isc/util.h>
43 
44 #include <dns/acl.h>
45 #include <dns/dispatch.h>
46 #include <dns/events.h>
47 #include <dns/log.h>
48 #include <dns/message.h>
49 #include <dns/portlist.h>
50 #include <dns/stats.h>
51 #include <dns/tcpmsg.h>
52 #include <dns/types.h>
53 
54 typedef ISC_LIST(dns_dispentry_t)	dns_displist_t;
55 
56 typedef struct dispsocket		dispsocket_t;
57 typedef ISC_LIST(dispsocket_t)		dispsocketlist_t;
58 
59 typedef struct dispportentry		dispportentry_t;
60 typedef ISC_LIST(dispportentry_t)	dispportlist_t;
61 
62 /* ARC4 Random generator state */
63 typedef struct arc4ctx {
64 	isc_uint8_t	i;
65 	isc_uint8_t	j;
66 	isc_uint8_t	s[256];
67 	int		count;
68 	isc_entropy_t	*entropy;	/*%< entropy source for ARC4 */
69 	isc_mutex_t	*lock;
70 } arc4ctx_t;
71 
72 typedef struct dns_qid {
73 	unsigned int	magic;
74 	unsigned int	qid_nbuckets;	/*%< hash table size */
75 	unsigned int	qid_increment;	/*%< id increment on collision */
76 	isc_mutex_t	lock;
77 	dns_displist_t	*qid_table;	/*%< the table itself */
78 	dispsocketlist_t *sock_table;	/*%< socket table */
79 } dns_qid_t;
80 
81 struct dns_dispatchmgr {
82 	/* Unlocked. */
83 	unsigned int			magic;
84 	isc_mem_t		       *mctx;
85 	dns_acl_t		       *blackhole;
86 	dns_portlist_t		       *portlist;
87 	isc_stats_t		       *stats;
88 	isc_entropy_t		       *entropy; /*%< entropy source */
89 
90 	/* Locked by "lock". */
91 	isc_mutex_t			lock;
92 	unsigned int			state;
93 	ISC_LIST(dns_dispatch_t)	list;
94 
95 	/* Locked by arc4_lock. */
96 	isc_mutex_t			arc4_lock;
97 	arc4ctx_t			arc4ctx;    /*%< ARC4 context for QID */
98 
99 	/* locked by buffer lock */
100 	dns_qid_t			*qid;
101 	isc_mutex_t			buffer_lock;
102 	unsigned int			buffers;    /*%< allocated buffers */
103 	unsigned int			buffersize; /*%< size of each buffer */
104 	unsigned int			maxbuffers; /*%< max buffers */
105 
106 	/* Locked internally. */
107 	isc_mutex_t			depool_lock;
108 	isc_mempool_t		       *depool;	/*%< pool for dispatch events */
109 	isc_mutex_t			rpool_lock;
110 	isc_mempool_t		       *rpool;	/*%< pool for replies */
111 	isc_mutex_t			dpool_lock;
112 	isc_mempool_t		       *dpool;  /*%< dispatch allocations */
113 	isc_mutex_t			bpool_lock;
114 	isc_mempool_t		       *bpool;	/*%< pool for buffers */
115 	isc_mutex_t			spool_lock;
116 	isc_mempool_t		       *spool;	/*%< pool for dispsocks */
117 
118 	/*%
119 	 * Locked by qid->lock if qid exists; otherwise, can be used without
120 	 * being locked.
121 	 * Memory footprint considerations: this is a simple implementation of
122 	 * available ports, i.e., an ordered array of the actual port numbers.
123 	 * This will require about 256KB of memory in the worst case (128KB for
124 	 * each of IPv4 and IPv6).  We could reduce it by representing it as a
125 	 * more sophisticated way such as a list (or array) of ranges that are
126 	 * searched to identify a specific port.  Our decision here is the saved
127 	 * memory isn't worth the implementation complexity, considering the
128 	 * fact that the whole BIND9 process (which is mainly named) already
129 	 * requires a pretty large memory footprint.  We may, however, have to
130 	 * revisit the decision when we want to use it as a separate module for
131 	 * an environment where memory requirement is severer.
132 	 */
133 	in_port_t	*v4ports;	/*%< available ports for IPv4 */
134 	unsigned int	nv4ports;	/*%< # of available ports for IPv4 */
135 	in_port_t	*v6ports;	/*%< available ports for IPv4 */
136 	unsigned int	nv6ports;	/*%< # of available ports for IPv4 */
137 };
138 
139 #define MGR_SHUTTINGDOWN		0x00000001U
140 #define MGR_IS_SHUTTINGDOWN(l)	(((l)->state & MGR_SHUTTINGDOWN) != 0)
141 
142 #define IS_PRIVATE(d)	(((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0)
143 
144 struct dns_dispentry {
145 	unsigned int			magic;
146 	dns_dispatch_t		       *disp;
147 	dns_messageid_t			id;
148 	in_port_t			port;
149 	unsigned int			bucket;
150 	isc_sockaddr_t			host;
151 	isc_task_t		       *task;
152 	isc_taskaction_t		action;
153 	void			       *arg;
154 	isc_boolean_t			item_out;
155 	dispsocket_t			*dispsocket;
156 	ISC_LIST(dns_dispatchevent_t)	items;
157 	ISC_LINK(dns_dispentry_t)	link;
158 };
159 
160 /*%
161  * Maximum number of dispatch sockets that can be pooled for reuse.  The
162  * appropriate value may vary, but experiments have shown a busy caching server
163  * may need more than 1000 sockets concurrently opened.  The maximum allowable
164  * number of dispatch sockets (per manager) will be set to the double of this
165  * value.
166  */
167 #ifndef DNS_DISPATCH_POOLSOCKS
168 #define DNS_DISPATCH_POOLSOCKS			2048
169 #endif
170 
171 /*%
172  * Quota to control the number of dispatch sockets.  If a dispatch has more
173  * than the quota of sockets, new queries will purge oldest ones, so that
174  * a massive number of outstanding queries won't prevent subsequent queries
175  * (especially if the older ones take longer time and result in timeout).
176  */
177 #ifndef DNS_DISPATCH_SOCKSQUOTA
178 #define DNS_DISPATCH_SOCKSQUOTA			3072
179 #endif
180 
181 struct dispsocket {
182 	unsigned int			magic;
183 	isc_socket_t			*socket;
184 	dns_dispatch_t			*disp;
185 	isc_sockaddr_t			host;
186 	in_port_t			localport; /* XXX: should be removed later */
187 	dispportentry_t			*portentry;
188 	dns_dispentry_t			*resp;
189 	isc_task_t			*task;
190 	ISC_LINK(dispsocket_t)		link;
191 	unsigned int			bucket;
192 	ISC_LINK(dispsocket_t)		blink;
193 };
194 
195 /*%
196  * A port table entry.  We remember every port we first open in a table with a
197  * reference counter so that we can 'reuse' the same port (with different
198  * destination addresses) using the SO_REUSEADDR socket option.
199  */
200 struct dispportentry {
201 	in_port_t			port;
202 	unsigned int			refs;
203 	ISC_LINK(struct dispportentry)	link;
204 };
205 
206 #ifndef DNS_DISPATCH_PORTTABLESIZE
207 #define DNS_DISPATCH_PORTTABLESIZE	1024
208 #endif
209 
210 #define INVALID_BUCKET		(0xffffdead)
211 
212 /*%
213  * Number of tasks for each dispatch that use separate sockets for different
214  * transactions.  This must be a power of 2 as it will divide 32 bit numbers
215  * to get an uniformly random tasks selection.  See get_dispsocket().
216  */
217 #define MAX_INTERNAL_TASKS	64
218 
219 struct dns_dispatch {
220 	/* Unlocked. */
221 	unsigned int		magic;		/*%< magic */
222 	dns_dispatchmgr_t      *mgr;		/*%< dispatch manager */
223 	int			ntasks;
224 	/*%
225 	 * internal task buckets.  We use multiple tasks to distribute various
226 	 * socket events well when using separate dispatch sockets.  We use the
227 	 * 1st task (task[0]) for internal control events.
228 	 */
229 	isc_task_t	       *task[MAX_INTERNAL_TASKS];
230 	isc_socket_t	       *socket;		/*%< isc socket attached to */
231 	isc_sockaddr_t		local;		/*%< local address */
232 	in_port_t		localport;	/*%< local UDP port */
233 	isc_dscp_t		dscp;		/*%< "listen-on" DSCP value */
234 	unsigned int		maxrequests;	/*%< max requests */
235 	isc_event_t	       *ctlevent;
236 
237 	isc_mutex_t		sepool_lock;
238 	isc_mempool_t	       *sepool;		/*%< pool for socket events */
239 
240 	/*% Locked by mgr->lock. */
241 	ISC_LINK(dns_dispatch_t) link;
242 
243 	/* Locked by "lock". */
244 	isc_mutex_t		lock;		/*%< locks all below */
245 	isc_sockettype_t	socktype;
246 	unsigned int		attributes;
247 	unsigned int		refcount;	/*%< number of users */
248 	dns_dispatchevent_t    *failsafe_ev;	/*%< failsafe cancel event */
249 	unsigned int		shutting_down : 1,
250 				shutdown_out : 1,
251 				connected : 1,
252 				tcpmsg_valid : 1,
253 				recv_pending : 1; /*%< is a recv() pending? */
254 	isc_result_t		shutdown_why;
255 	ISC_LIST(dispsocket_t)	activesockets;
256 	ISC_LIST(dispsocket_t)	inactivesockets;
257 	unsigned int		nsockets;
258 	unsigned int		requests;	/*%< how many requests we have */
259 	unsigned int		tcpbuffers;	/*%< allocated buffers */
260 	dns_tcpmsg_t		tcpmsg;		/*%< for tcp streams */
261 	dns_qid_t		*qid;
262 	arc4ctx_t		arc4ctx;	/*%< for QID/UDP port num */
263 	dispportlist_t		*port_table;	/*%< hold ports 'owned' by us */
264 	isc_mempool_t		*portpool;	/*%< port table entries  */
265 };
266 
267 #define QID_MAGIC		ISC_MAGIC('Q', 'i', 'd', ' ')
268 #define VALID_QID(e)		ISC_MAGIC_VALID((e), QID_MAGIC)
269 
270 #define RESPONSE_MAGIC		ISC_MAGIC('D', 'r', 's', 'p')
271 #define VALID_RESPONSE(e)	ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
272 
273 #define DISPSOCK_MAGIC		ISC_MAGIC('D', 's', 'o', 'c')
274 #define VALID_DISPSOCK(e)	ISC_MAGIC_VALID((e), DISPSOCK_MAGIC)
275 
276 #define DISPATCH_MAGIC		ISC_MAGIC('D', 'i', 's', 'p')
277 #define VALID_DISPATCH(e)	ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
278 
279 #define DNS_DISPATCHMGR_MAGIC	ISC_MAGIC('D', 'M', 'g', 'r')
280 #define VALID_DISPATCHMGR(e)	ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC)
281 
282 #define DNS_QID(disp) ((disp)->socktype == isc_sockettype_tcp) ? \
283 		       (disp)->qid : (disp)->mgr->qid
284 #define DISP_ARC4CTX(disp) ((disp)->socktype == isc_sockettype_udp) ? \
285 			(&(disp)->arc4ctx) : (&(disp)->mgr->arc4ctx)
286 
287 /*%
288  * Locking a query port buffer is a bit tricky.  We access the buffer without
289  * locking until qid is created.  Technically, there is a possibility of race
290  * between the creation of qid and access to the port buffer; in practice,
291  * however, this should be safe because qid isn't created until the first
292  * dispatch is created and there should be no contending situation until then.
293  */
294 #define PORTBUFLOCK(mgr) if ((mgr)->qid != NULL) LOCK(&((mgr)->qid->lock))
295 #define PORTBUFUNLOCK(mgr) if ((mgr)->qid != NULL) UNLOCK((&(mgr)->qid->lock))
296 
297 /*
298  * Statics.
299  */
300 static dns_dispentry_t *entry_search(dns_qid_t *, isc_sockaddr_t *,
301 				     dns_messageid_t, in_port_t, unsigned int);
302 static isc_boolean_t destroy_disp_ok(dns_dispatch_t *);
303 static void destroy_disp(isc_task_t *task, isc_event_t *event);
304 static void destroy_dispsocket(dns_dispatch_t *, dispsocket_t **);
305 static void deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *);
306 static void udp_exrecv(isc_task_t *, isc_event_t *);
307 static void udp_shrecv(isc_task_t *, isc_event_t *);
308 static void udp_recv(isc_event_t *, dns_dispatch_t *, dispsocket_t *);
309 static void tcp_recv(isc_task_t *, isc_event_t *);
310 static isc_result_t startrecv(dns_dispatch_t *, dispsocket_t *);
311 static isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t,
312 			     in_port_t);
313 static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
314 static void *allocate_udp_buffer(dns_dispatch_t *disp);
315 static inline void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
316 static inline dns_dispatchevent_t *allocate_devent(dns_dispatch_t *disp);
317 static void do_cancel(dns_dispatch_t *disp);
318 static dns_dispentry_t *linear_first(dns_qid_t *disp);
319 static dns_dispentry_t *linear_next(dns_qid_t *disp,
320 				    dns_dispentry_t *resp);
321 static void dispatch_free(dns_dispatch_t **dispp);
322 static isc_result_t get_udpsocket(dns_dispatchmgr_t *mgr,
323 				  dns_dispatch_t *disp,
324 				  isc_socketmgr_t *sockmgr,
325 				  isc_sockaddr_t *localaddr,
326 				  isc_socket_t **sockp,
327 				  isc_socket_t *dup_socket);
328 static isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr,
329 				       isc_socketmgr_t *sockmgr,
330 				       isc_taskmgr_t *taskmgr,
331 				       isc_sockaddr_t *localaddr,
332 				       unsigned int maxrequests,
333 				       unsigned int attributes,
334 				       dns_dispatch_t **dispp,
335 				       isc_socket_t *dup_socket);
336 static isc_boolean_t destroy_mgr_ok(dns_dispatchmgr_t *mgr);
337 static void destroy_mgr(dns_dispatchmgr_t **mgrp);
338 static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
339 				 unsigned int increment, dns_qid_t **qidp,
340 				 isc_boolean_t needaddrtable);
341 static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
342 static isc_result_t open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
343 				unsigned int options, isc_socket_t **sockp,
344 				isc_socket_t *dup_socket);
345 static isc_boolean_t portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
346 				   isc_sockaddr_t *sockaddrp);
347 
348 #define LVL(x) ISC_LOG_DEBUG(x)
349 
350 static void
351 mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...)
352      ISC_FORMAT_PRINTF(3, 4);
353 
354 static void
355 mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) {
356 	char msgbuf[2048];
357 	va_list ap;
358 
359 	if (! isc_log_wouldlog(dns_lctx, level))
360 		return;
361 
362 	va_start(ap, fmt);
363 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
364 	va_end(ap);
365 
366 	isc_log_write(dns_lctx,
367 		      DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
368 		      level, "dispatchmgr %p: %s", mgr, msgbuf);
369 }
370 
371 static inline void
372 inc_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
373 	if (mgr->stats != NULL)
374 		isc_stats_increment(mgr->stats, counter);
375 }
376 
377 static inline void
378 dec_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
379 	if (mgr->stats != NULL)
380 		isc_stats_decrement(mgr->stats, counter);
381 }
382 
383 static void
384 dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...)
385      ISC_FORMAT_PRINTF(3, 4);
386 
387 static void
388 dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) {
389 	char msgbuf[2048];
390 	va_list ap;
391 
392 	if (! isc_log_wouldlog(dns_lctx, level))
393 		return;
394 
395 	va_start(ap, fmt);
396 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
397 	va_end(ap);
398 
399 	isc_log_write(dns_lctx,
400 		      DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
401 		      level, "dispatch %p: %s", disp, msgbuf);
402 }
403 
404 static void
405 request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
406 	    int level, const char *fmt, ...)
407      ISC_FORMAT_PRINTF(4, 5);
408 
409 static void
410 request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
411 	    int level, const char *fmt, ...)
412 {
413 	char msgbuf[2048];
414 	char peerbuf[256];
415 	va_list ap;
416 
417 	if (! isc_log_wouldlog(dns_lctx, level))
418 		return;
419 
420 	va_start(ap, fmt);
421 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
422 	va_end(ap);
423 
424 	if (VALID_RESPONSE(resp)) {
425 		isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf));
426 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
427 			      DNS_LOGMODULE_DISPATCH, level,
428 			      "dispatch %p response %p %s: %s", disp, resp,
429 			      peerbuf, msgbuf);
430 	} else {
431 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
432 			      DNS_LOGMODULE_DISPATCH, level,
433 			      "dispatch %p req/resp %p: %s", disp, resp,
434 			      msgbuf);
435 	}
436 }
437 
438 /*%
439  * ARC4 random number generator derived from OpenBSD.
440  * Only dispatch_random() and dispatch_uniformrandom() are expected
441  * to be called from general dispatch routines; the rest of them are subroutines
442  * for these two.
443  *
444  * The original copyright follows:
445  * Copyright (c) 1996, David Mazieres <dm@uun.org>
446  * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
447  *
448  * Permission to use, copy, modify, and distribute this software for any
449  * purpose with or without fee is hereby granted, provided that the above
450  * copyright notice and this permission notice appear in all copies.
451  *
452  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
453  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
454  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
455  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
456  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
457  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
458  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
459  */
460 static void
461 dispatch_initrandom(arc4ctx_t *actx, isc_entropy_t *entropy,
462 		    isc_mutex_t *lock)
463 {
464 	int n;
465 	for (n = 0; n < 256; n++)
466 		actx->s[n] = n;
467 	actx->i = 0;
468 	actx->j = 0;
469 	actx->count = 0;
470 	actx->entropy = entropy; /* don't have to attach */
471 	actx->lock = lock;
472 }
473 
474 static void
475 dispatch_arc4addrandom(arc4ctx_t *actx, unsigned char *dat, int datlen) {
476 	int n;
477 	isc_uint8_t si;
478 
479 	actx->i--;
480 	for (n = 0; n < 256; n++) {
481 		actx->i = (actx->i + 1);
482 		si = actx->s[actx->i];
483 		actx->j = (actx->j + si + dat[n % datlen]);
484 		actx->s[actx->i] = actx->s[actx->j];
485 		actx->s[actx->j] = si;
486 	}
487 	actx->j = actx->i;
488 }
489 
490 static inline isc_uint8_t
491 dispatch_arc4get8(arc4ctx_t *actx) {
492 	isc_uint8_t si, sj;
493 
494 	actx->i = (actx->i + 1);
495 	si = actx->s[actx->i];
496 	actx->j = (actx->j + si);
497 	sj = actx->s[actx->j];
498 	actx->s[actx->i] = sj;
499 	actx->s[actx->j] = si;
500 
501 	return (actx->s[(si + sj) & 0xff]);
502 }
503 
504 static inline isc_uint16_t
505 dispatch_arc4get16(arc4ctx_t *actx) {
506 	isc_uint16_t val;
507 
508 	val = dispatch_arc4get8(actx) << 8;
509 	val |= dispatch_arc4get8(actx);
510 
511 	return (val);
512 }
513 
514 static void
515 dispatch_arc4stir(arc4ctx_t *actx) {
516 	int i;
517 	union {
518 		unsigned char rnd[128];
519 		isc_uint32_t rnd32[32];
520 	} rnd;
521 	isc_result_t result;
522 
523 	if (actx->entropy != NULL) {
524 		/*
525 		 * We accept any quality of random data to avoid blocking.
526 		 */
527 		result = isc_entropy_getdata(actx->entropy, rnd.rnd,
528 					     sizeof(rnd), NULL, 0);
529 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
530 	} else {
531 		for (i = 0; i < 32; i++)
532 			isc_random_get(&rnd.rnd32[i]);
533 	}
534 	dispatch_arc4addrandom(actx, rnd.rnd, sizeof(rnd.rnd));
535 
536 	/*
537 	 * Discard early keystream, as per recommendations in:
538 	 * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
539 	 */
540 	for (i = 0; i < 256; i++)
541 		(void)dispatch_arc4get8(actx);
542 
543 	/*
544 	 * Derived from OpenBSD's implementation.  The rationale is not clear,
545 	 * but should be conservative enough in safety, and reasonably large
546 	 * for efficiency.
547 	 */
548 	actx->count = 1600000;
549 }
550 
551 static isc_uint16_t
552 dispatch_random(arc4ctx_t *actx) {
553 	isc_uint16_t result;
554 
555 	if (actx->lock != NULL)
556 		LOCK(actx->lock);
557 
558 	actx->count -= sizeof(isc_uint16_t);
559 	if (actx->count <= 0)
560 		dispatch_arc4stir(actx);
561 	result = dispatch_arc4get16(actx);
562 
563 	if (actx->lock != NULL)
564 		UNLOCK(actx->lock);
565 
566 	return (result);
567 }
568 
569 static isc_uint16_t
570 dispatch_uniformrandom(arc4ctx_t *actx, isc_uint16_t upper_bound) {
571 	isc_uint16_t min, r;
572 
573 	if (upper_bound < 2)
574 		return (0);
575 
576 	/*
577 	 * Ensure the range of random numbers [min, 0xffff] be a multiple of
578 	 * upper_bound and contain at least a half of the 16 bit range.
579 	 */
580 
581 	if (upper_bound > 0x8000)
582 		min = 1 + ~upper_bound; /* 0x8000 - upper_bound */
583 	else
584 		min = (isc_uint16_t)(0x10000 % (isc_uint32_t)upper_bound);
585 
586 	/*
587 	 * This could theoretically loop forever but each retry has
588 	 * p > 0.5 (worst case, usually far better) of selecting a
589 	 * number inside the range we need, so it should rarely need
590 	 * to re-roll.
591 	 */
592 	for (;;) {
593 		r = dispatch_random(actx);
594 		if (r >= min)
595 			break;
596 	}
597 
598 	return (r % upper_bound);
599 }
600 
601 /*
602  * Return a hash of the destination and message id.
603  */
604 static isc_uint32_t
605 dns_hash(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
606 	 in_port_t port)
607 {
608 	unsigned int ret;
609 
610 	ret = isc_sockaddr_hash(dest, ISC_TRUE);
611 	ret ^= (id << 16) | port;
612 	ret %= qid->qid_nbuckets;
613 
614 	INSIST(ret < qid->qid_nbuckets);
615 
616 	return (ret);
617 }
618 
619 /*
620  * Find the first entry in 'qid'.  Returns NULL if there are no entries.
621  */
622 static dns_dispentry_t *
623 linear_first(dns_qid_t *qid) {
624 	dns_dispentry_t *ret;
625 	unsigned int bucket;
626 
627 	bucket = 0;
628 
629 	while (bucket < qid->qid_nbuckets) {
630 		ret = ISC_LIST_HEAD(qid->qid_table[bucket]);
631 		if (ret != NULL)
632 			return (ret);
633 		bucket++;
634 	}
635 
636 	return (NULL);
637 }
638 
639 /*
640  * Find the next entry after 'resp' in 'qid'.  Return NULL if there are
641  * no more entries.
642  */
643 static dns_dispentry_t *
644 linear_next(dns_qid_t *qid, dns_dispentry_t *resp) {
645 	dns_dispentry_t *ret;
646 	unsigned int bucket;
647 
648 	ret = ISC_LIST_NEXT(resp, link);
649 	if (ret != NULL)
650 		return (ret);
651 
652 	bucket = resp->bucket;
653 	bucket++;
654 	while (bucket < qid->qid_nbuckets) {
655 		ret = ISC_LIST_HEAD(qid->qid_table[bucket]);
656 		if (ret != NULL)
657 			return (ret);
658 		bucket++;
659 	}
660 
661 	return (NULL);
662 }
663 
664 /*
665  * The dispatch must be locked.
666  */
667 static isc_boolean_t
668 destroy_disp_ok(dns_dispatch_t *disp)
669 {
670 	if (disp->refcount != 0)
671 		return (ISC_FALSE);
672 
673 	if (disp->recv_pending != 0)
674 		return (ISC_FALSE);
675 
676 	if (!ISC_LIST_EMPTY(disp->activesockets))
677 		return (ISC_FALSE);
678 
679 	if (disp->shutting_down == 0)
680 		return (ISC_FALSE);
681 
682 	return (ISC_TRUE);
683 }
684 
685 /*
686  * Called when refcount reaches 0 (and safe to destroy).
687  *
688  * The dispatcher must be locked.
689  * The manager must not be locked.
690  */
691 static void
692 destroy_disp(isc_task_t *task, isc_event_t *event) {
693 	dns_dispatch_t *disp;
694 	dns_dispatchmgr_t *mgr;
695 	isc_boolean_t killmgr;
696 	dispsocket_t *dispsocket;
697 	int i;
698 
699 	INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL);
700 
701 	UNUSED(task);
702 
703 	disp = event->ev_arg;
704 	mgr = disp->mgr;
705 
706 	LOCK(&mgr->lock);
707 	ISC_LIST_UNLINK(mgr->list, disp, link);
708 
709 	dispatch_log(disp, LVL(90),
710 		     "shutting down; detaching from sock %p, task %p",
711 		     disp->socket, disp->task[0]); /* XXXX */
712 
713 	if (disp->sepool != NULL) {
714 		isc_mempool_destroy(&disp->sepool);
715 		(void)isc_mutex_destroy(&disp->sepool_lock);
716 	}
717 
718 	if (disp->socket != NULL)
719 		isc_socket_detach(&disp->socket);
720 	while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) {
721 		ISC_LIST_UNLINK(disp->inactivesockets, dispsocket, link);
722 		destroy_dispsocket(disp, &dispsocket);
723 	}
724 	for (i = 0; i < disp->ntasks; i++)
725 		isc_task_detach(&disp->task[i]);
726 	isc_event_free(&event);
727 
728 	dispatch_free(&disp);
729 
730 	killmgr = destroy_mgr_ok(mgr);
731 	UNLOCK(&mgr->lock);
732 	if (killmgr)
733 		destroy_mgr(&mgr);
734 }
735 
736 /*%
737  * Manipulate port table per dispatch: find an entry for a given port number,
738  * create a new entry, and decrement a given entry with possible clean-up.
739  */
740 static dispportentry_t *
741 port_search(dns_dispatch_t *disp, in_port_t port) {
742 	dispportentry_t *portentry;
743 
744 	REQUIRE(disp->port_table != NULL);
745 
746 	portentry = ISC_LIST_HEAD(disp->port_table[port %
747 						   DNS_DISPATCH_PORTTABLESIZE]);
748 	while (portentry != NULL) {
749 		if (portentry->port == port)
750 			return (portentry);
751 		portentry = ISC_LIST_NEXT(portentry, link);
752 	}
753 
754 	return (NULL);
755 }
756 
757 static dispportentry_t *
758 new_portentry(dns_dispatch_t *disp, in_port_t port) {
759 	dispportentry_t *portentry;
760 	dns_qid_t *qid;
761 
762 	REQUIRE(disp->port_table != NULL);
763 
764 	portentry = isc_mempool_get(disp->portpool);
765 	if (portentry == NULL)
766 		return (portentry);
767 
768 	portentry->port = port;
769 	portentry->refs = 1;
770 	ISC_LINK_INIT(portentry, link);
771 	qid = DNS_QID(disp);
772 	LOCK(&qid->lock);
773 	ISC_LIST_APPEND(disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE],
774 			portentry, link);
775 	UNLOCK(&qid->lock);
776 
777 	return (portentry);
778 }
779 
780 /*%
781  * The caller must not hold the qid->lock.
782  */
783 static void
784 deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) {
785 	dispportentry_t *portentry = *portentryp;
786 	dns_qid_t *qid;
787 
788 	REQUIRE(disp->port_table != NULL);
789 	REQUIRE(portentry != NULL && portentry->refs > 0);
790 
791 	qid = DNS_QID(disp);
792 	LOCK(&qid->lock);
793 	portentry->refs--;
794 
795 	if (portentry->refs == 0) {
796 		ISC_LIST_UNLINK(disp->port_table[portentry->port %
797 						 DNS_DISPATCH_PORTTABLESIZE],
798 				portentry, link);
799 		isc_mempool_put(disp->portpool, portentry);
800 	}
801 
802 	/*
803 	 * Set '*portentryp' to NULL inside the lock so that
804 	 * dispsock->portentry does not change in socket_search.
805 	 */
806 	*portentryp = NULL;
807 
808 	UNLOCK(&qid->lock);
809 }
810 
811 /*%
812  * Find a dispsocket for socket address 'dest', and port number 'port'.
813  * Return NULL if no such entry exists.  Requires qid->lock to be held.
814  */
815 static dispsocket_t *
816 socket_search(dns_qid_t *qid, isc_sockaddr_t *dest, in_port_t port,
817 	      unsigned int bucket)
818 {
819 	dispsocket_t *dispsock;
820 
821 	REQUIRE(VALID_QID(qid));
822 	REQUIRE(bucket < qid->qid_nbuckets);
823 
824 	dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]);
825 
826 	while (dispsock != NULL) {
827 		if (dispsock->portentry != NULL &&
828 		    dispsock->portentry->port == port &&
829 		    isc_sockaddr_equal(dest, &dispsock->host))
830 			return (dispsock);
831 		dispsock = ISC_LIST_NEXT(dispsock, blink);
832 	}
833 
834 	return (NULL);
835 }
836 
837 /*%
838  * Make a new socket for a single dispatch with a random port number.
839  * The caller must hold the disp->lock
840  */
841 static isc_result_t
842 get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
843 	       isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp,
844 	       in_port_t *portp)
845 {
846 	int i;
847 	isc_uint32_t r;
848 	dns_dispatchmgr_t *mgr = disp->mgr;
849 	isc_socket_t *sock = NULL;
850 	isc_result_t result = ISC_R_FAILURE;
851 	in_port_t port;
852 	isc_sockaddr_t localaddr;
853 	unsigned int bucket = 0;
854 	dispsocket_t *dispsock;
855 	unsigned int nports;
856 	in_port_t *ports;
857 	unsigned int bindoptions;
858 	dispportentry_t *portentry = NULL;
859 	dns_qid_t *qid;
860 
861 	if (isc_sockaddr_pf(&disp->local) == AF_INET) {
862 		nports = disp->mgr->nv4ports;
863 		ports = disp->mgr->v4ports;
864 	} else {
865 		nports = disp->mgr->nv6ports;
866 		ports = disp->mgr->v6ports;
867 	}
868 	if (nports == 0)
869 		return (ISC_R_ADDRNOTAVAIL);
870 
871 	dispsock = ISC_LIST_HEAD(disp->inactivesockets);
872 	if (dispsock != NULL) {
873 		ISC_LIST_UNLINK(disp->inactivesockets, dispsock, link);
874 		sock = dispsock->socket;
875 		dispsock->socket = NULL;
876 	} else {
877 		dispsock = isc_mempool_get(mgr->spool);
878 		if (dispsock == NULL)
879 			return (ISC_R_NOMEMORY);
880 
881 		disp->nsockets++;
882 		dispsock->socket = NULL;
883 		dispsock->disp = disp;
884 		dispsock->resp = NULL;
885 		dispsock->portentry = NULL;
886 		isc_random_get(&r);
887 		dispsock->task = NULL;
888 		isc_task_attach(disp->task[r % disp->ntasks], &dispsock->task);
889 		ISC_LINK_INIT(dispsock, link);
890 		ISC_LINK_INIT(dispsock, blink);
891 		dispsock->magic = DISPSOCK_MAGIC;
892 	}
893 
894 	/*
895 	 * Pick up a random UDP port and open a new socket with it.  Avoid
896 	 * choosing ports that share the same destination because it will be
897 	 * very likely to fail in bind(2) or connect(2).
898 	 */
899 	localaddr = disp->local;
900 	qid = DNS_QID(disp);
901 
902 	for (i = 0; i < 64; i++) {
903 		port = ports[dispatch_uniformrandom(DISP_ARC4CTX(disp),
904 							nports)];
905 		isc_sockaddr_setport(&localaddr, port);
906 
907 		LOCK(&qid->lock);
908 		bucket = dns_hash(qid, dest, 0, port);
909 		if (socket_search(qid, dest, port, bucket) != NULL) {
910 			UNLOCK(&qid->lock);
911 			continue;
912 		}
913 		UNLOCK(&qid->lock);
914 		bindoptions = 0;
915 		portentry = port_search(disp, port);
916 
917 		if (portentry != NULL)
918 			bindoptions |= ISC_SOCKET_REUSEADDRESS;
919 		result = open_socket(sockmgr, &localaddr, bindoptions, &sock,
920 				     NULL);
921 		if (result == ISC_R_SUCCESS) {
922 			if (portentry == NULL) {
923 				portentry = new_portentry(disp, port);
924 				if (portentry == NULL) {
925 					result = ISC_R_NOMEMORY;
926 					break;
927 				}
928 			} else {
929 				LOCK(&qid->lock);
930 				portentry->refs++;
931 				UNLOCK(&qid->lock);
932 			}
933 			break;
934 		} else if (result == ISC_R_NOPERM) {
935 			char buf[ISC_SOCKADDR_FORMATSIZE];
936 			isc_sockaddr_format(&localaddr, buf, sizeof(buf));
937 			dispatch_log(disp, ISC_LOG_WARNING,
938 				     "open_socket(%s) -> %s: continuing",
939 				     buf, isc_result_totext(result));
940 		} else if (result != ISC_R_ADDRINUSE)
941 			break;
942 	}
943 
944 	if (result == ISC_R_SUCCESS) {
945 		dispsock->socket = sock;
946 		dispsock->host = *dest;
947 		dispsock->portentry = portentry;
948 		dispsock->bucket = bucket;
949 		LOCK(&qid->lock);
950 		ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink);
951 		UNLOCK(&qid->lock);
952 		*dispsockp = dispsock;
953 		*portp = port;
954 	} else {
955 		/*
956 		 * We could keep it in the inactive list, but since this should
957 		 * be an exceptional case and might be resource shortage, we'd
958 		 * rather destroy it.
959 		 */
960 		if (sock != NULL)
961 			isc_socket_detach(&sock);
962 		destroy_dispsocket(disp, &dispsock);
963 	}
964 
965 	return (result);
966 }
967 
968 /*%
969  * Destroy a dedicated dispatch socket.
970  */
971 static void
972 destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) {
973 	dispsocket_t *dispsock;
974 	dns_qid_t *qid;
975 
976 	/*
977 	 * The dispatch must be locked.
978 	 */
979 
980 	REQUIRE(dispsockp != NULL && *dispsockp != NULL);
981 	dispsock = *dispsockp;
982 	REQUIRE(!ISC_LINK_LINKED(dispsock, link));
983 
984 	disp->nsockets--;
985 	dispsock->magic = 0;
986 	if (dispsock->portentry != NULL)
987 		deref_portentry(disp, &dispsock->portentry);
988 	if (dispsock->socket != NULL)
989 		isc_socket_detach(&dispsock->socket);
990 	if (ISC_LINK_LINKED(dispsock, blink)) {
991 		qid = DNS_QID(disp);
992 		LOCK(&qid->lock);
993 		ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
994 				blink);
995 		UNLOCK(&qid->lock);
996 	}
997 	if (dispsock->task != NULL)
998 		isc_task_detach(&dispsock->task);
999 	isc_mempool_put(disp->mgr->spool, dispsock);
1000 
1001 	*dispsockp = NULL;
1002 }
1003 
1004 /*%
1005  * Deactivate a dedicated dispatch socket.  Move it to the inactive list for
1006  * future reuse unless the total number of sockets are exceeding the maximum.
1007  */
1008 static void
1009 deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) {
1010 	isc_result_t result;
1011 	dns_qid_t *qid;
1012 
1013 	/*
1014 	 * The dispatch must be locked.
1015 	 */
1016 	ISC_LIST_UNLINK(disp->activesockets, dispsock, link);
1017 	if (dispsock->resp != NULL) {
1018 		INSIST(dispsock->resp->dispsocket == dispsock);
1019 		dispsock->resp->dispsocket = NULL;
1020 	}
1021 
1022 	INSIST(dispsock->portentry != NULL);
1023 	deref_portentry(disp, &dispsock->portentry);
1024 
1025 	if (disp->nsockets > DNS_DISPATCH_POOLSOCKS)
1026 		destroy_dispsocket(disp, &dispsock);
1027 	else {
1028 		result = isc_socket_close(dispsock->socket);
1029 
1030 		qid = DNS_QID(disp);
1031 		LOCK(&qid->lock);
1032 		ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
1033 				blink);
1034 		UNLOCK(&qid->lock);
1035 
1036 		if (result == ISC_R_SUCCESS)
1037 			ISC_LIST_APPEND(disp->inactivesockets, dispsock, link);
1038 		else {
1039 			/*
1040 			 * If the underlying system does not allow this
1041 			 * optimization, destroy this temporary structure (and
1042 			 * create a new one for a new transaction).
1043 			 */
1044 			INSIST(result == ISC_R_NOTIMPLEMENTED);
1045 			destroy_dispsocket(disp, &dispsock);
1046 		}
1047 	}
1048 }
1049 
1050 /*
1051  * Find an entry for query ID 'id', socket address 'dest', and port number
1052  * 'port'.
1053  * Return NULL if no such entry exists.
1054  */
1055 static dns_dispentry_t *
1056 entry_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
1057 	     in_port_t port, unsigned int bucket)
1058 {
1059 	dns_dispentry_t *res;
1060 
1061 	REQUIRE(VALID_QID(qid));
1062 	REQUIRE(bucket < qid->qid_nbuckets);
1063 
1064 	res = ISC_LIST_HEAD(qid->qid_table[bucket]);
1065 
1066 	while (res != NULL) {
1067 		if (res->id == id && isc_sockaddr_equal(dest, &res->host) &&
1068 		    res->port == port) {
1069 			return (res);
1070 		}
1071 		res = ISC_LIST_NEXT(res, link);
1072 	}
1073 
1074 	return (NULL);
1075 }
1076 
1077 static void
1078 free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
1079 	isc_mempool_t *bpool;
1080 	INSIST(buf != NULL && len != 0);
1081 
1082 
1083 	switch (disp->socktype) {
1084 	case isc_sockettype_tcp:
1085 		INSIST(disp->tcpbuffers > 0);
1086 		disp->tcpbuffers--;
1087 		isc_mem_put(disp->mgr->mctx, buf, len);
1088 		break;
1089 	case isc_sockettype_udp:
1090 		LOCK(&disp->mgr->buffer_lock);
1091 		INSIST(disp->mgr->buffers > 0);
1092 		INSIST(len == disp->mgr->buffersize);
1093 		disp->mgr->buffers--;
1094 		bpool = disp->mgr->bpool;
1095 		UNLOCK(&disp->mgr->buffer_lock);
1096 		isc_mempool_put(bpool, buf);
1097 		break;
1098 	default:
1099 		INSIST(0);
1100 		break;
1101 	}
1102 }
1103 
1104 static void *
1105 allocate_udp_buffer(dns_dispatch_t *disp) {
1106 	isc_mempool_t *bpool;
1107 	void *temp;
1108 
1109 	LOCK(&disp->mgr->buffer_lock);
1110 	bpool = disp->mgr->bpool;
1111 	disp->mgr->buffers++;
1112 	UNLOCK(&disp->mgr->buffer_lock);
1113 
1114 	temp = isc_mempool_get(bpool);
1115 
1116 	if (temp == NULL) {
1117 		LOCK(&disp->mgr->buffer_lock);
1118 		disp->mgr->buffers--;
1119 		UNLOCK(&disp->mgr->buffer_lock);
1120 	}
1121 
1122 	return (temp);
1123 }
1124 
1125 static inline void
1126 free_sevent(isc_event_t *ev) {
1127 	isc_mempool_t *pool = ev->ev_destroy_arg;
1128 	isc_socketevent_t *sev = (isc_socketevent_t *) ev;
1129 	isc_mempool_put(pool, sev);
1130 }
1131 
1132 static inline isc_socketevent_t *
1133 allocate_sevent(dns_dispatch_t *disp, isc_socket_t *socket,
1134 		isc_eventtype_t type, isc_taskaction_t action, const void *arg)
1135 {
1136 	isc_socketevent_t *ev;
1137 	void *deconst_arg;
1138 
1139 	ev = isc_mempool_get(disp->sepool);
1140 	if (ev == NULL)
1141 		return (NULL);
1142 	DE_CONST(arg, deconst_arg);
1143 	ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, type,
1144 		       action, deconst_arg, socket,
1145 		       free_sevent, disp->sepool);
1146 	ev->result = ISC_R_UNSET;
1147 	ISC_LINK_INIT(ev, ev_link);
1148 	ISC_LIST_INIT(ev->bufferlist);
1149 	ev->region.base = NULL;
1150 	ev->n = 0;
1151 	ev->offset = 0;
1152 	ev->attributes = 0;
1153 
1154 	return (ev);
1155 }
1156 
1157 
1158 static inline void
1159 free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
1160 	if (disp->failsafe_ev == ev) {
1161 		INSIST(disp->shutdown_out == 1);
1162 		disp->shutdown_out = 0;
1163 
1164 		return;
1165 	}
1166 
1167 	isc_mempool_put(disp->mgr->depool, ev);
1168 }
1169 
1170 static inline dns_dispatchevent_t *
1171 allocate_devent(dns_dispatch_t *disp) {
1172 	dns_dispatchevent_t *ev;
1173 
1174 	ev = isc_mempool_get(disp->mgr->depool);
1175 	if (ev == NULL)
1176 		return (NULL);
1177 	ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0,
1178 		       NULL, NULL, NULL, NULL, NULL);
1179 
1180 	return (ev);
1181 }
1182 
1183 static void
1184 udp_exrecv(isc_task_t *task, isc_event_t *ev) {
1185 	dispsocket_t *dispsock = ev->ev_arg;
1186 
1187 	UNUSED(task);
1188 
1189 	REQUIRE(VALID_DISPSOCK(dispsock));
1190 	udp_recv(ev, dispsock->disp, dispsock);
1191 }
1192 
1193 static void
1194 udp_shrecv(isc_task_t *task, isc_event_t *ev) {
1195 	dns_dispatch_t *disp = ev->ev_arg;
1196 
1197 	UNUSED(task);
1198 
1199 	REQUIRE(VALID_DISPATCH(disp));
1200 	udp_recv(ev, disp, NULL);
1201 }
1202 
1203 /*
1204  * General flow:
1205  *
1206  * If I/O result == CANCELED or error, free the buffer.
1207  *
1208  * If query, free the buffer, restart.
1209  *
1210  * If response:
1211  *	Allocate event, fill in details.
1212  *		If cannot allocate, free buffer, restart.
1213  *	find target.  If not found, free buffer, restart.
1214  *	if event queue is not empty, queue.  else, send.
1215  *	restart.
1216  */
1217 static void
1218 udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) {
1219 	isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
1220 	dns_messageid_t id;
1221 	isc_result_t dres;
1222 	isc_buffer_t source;
1223 	unsigned int flags;
1224 	dns_dispentry_t *resp = NULL;
1225 	dns_dispatchevent_t *rev;
1226 	unsigned int bucket;
1227 	isc_boolean_t killit;
1228 	isc_boolean_t queue_response;
1229 	dns_dispatchmgr_t *mgr;
1230 	dns_qid_t *qid;
1231 	isc_netaddr_t netaddr;
1232 	int match;
1233 	int result;
1234 	isc_boolean_t qidlocked = ISC_FALSE;
1235 
1236 	LOCK(&disp->lock);
1237 
1238 	mgr = disp->mgr;
1239 	qid = mgr->qid;
1240 
1241 	dispatch_log(disp, LVL(90),
1242 		     "got packet: requests %d, buffers %d, recvs %d",
1243 		     disp->requests, disp->mgr->buffers, disp->recv_pending);
1244 
1245 	if (dispsock == NULL && ev->ev_type == ISC_SOCKEVENT_RECVDONE) {
1246 		/*
1247 		 * Unless the receive event was imported from a listening
1248 		 * interface, in which case the event type is
1249 		 * DNS_EVENT_IMPORTRECVDONE, receive operation must be pending.
1250 		 */
1251 		INSIST(disp->recv_pending != 0);
1252 		disp->recv_pending = 0;
1253 	}
1254 
1255 	if (dispsock != NULL &&
1256 	    (ev->result == ISC_R_CANCELED || dispsock->resp == NULL)) {
1257 		/*
1258 		 * dispsock->resp can be NULL if this transaction was canceled
1259 		 * just after receiving a response.  Since this socket is
1260 		 * exclusively used and there should be at most one receive
1261 		 * event the canceled event should have been no effect.  So
1262 		 * we can (and should) deactivate the socket right now.
1263 		 */
1264 		deactivate_dispsocket(disp, dispsock);
1265 		dispsock = NULL;
1266 	}
1267 
1268 	if (disp->shutting_down) {
1269 		/*
1270 		 * This dispatcher is shutting down.
1271 		 */
1272 		free_buffer(disp, ev->region.base, ev->region.length);
1273 
1274 		isc_event_free(&ev_in);
1275 		ev = NULL;
1276 
1277 		killit = destroy_disp_ok(disp);
1278 		UNLOCK(&disp->lock);
1279 		if (killit)
1280 			isc_task_send(disp->task[0], &disp->ctlevent);
1281 
1282 		return;
1283 	}
1284 
1285 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1286 		if (dispsock != NULL) {
1287 			resp = dispsock->resp;
1288 			id = resp->id;
1289 			if (ev->result != ISC_R_SUCCESS) {
1290 				/*
1291 				 * This is most likely a network error on a
1292 				 * connected socket.  It makes no sense to
1293 				 * check the address or parse the packet, but it
1294 				 * will help to return the error to the caller.
1295 				 */
1296 				goto sendresponse;
1297 			}
1298 		} else {
1299 			free_buffer(disp, ev->region.base, ev->region.length);
1300 
1301 			isc_event_free(&ev_in);
1302 			UNLOCK(&disp->lock);
1303 			return;
1304 		}
1305 	} else if (ev->result != ISC_R_SUCCESS) {
1306 		free_buffer(disp, ev->region.base, ev->region.length);
1307 
1308 		if (ev->result != ISC_R_CANCELED)
1309 			dispatch_log(disp, ISC_LOG_ERROR,
1310 				     "odd socket result in udp_recv(): %s",
1311 				     isc_result_totext(ev->result));
1312 
1313 		isc_event_free(&ev_in);
1314 		UNLOCK(&disp->lock);
1315 		return;
1316 	}
1317 
1318 	/*
1319 	 * If this is from a blackholed address, drop it.
1320 	 */
1321 	isc_netaddr_fromsockaddr(&netaddr, &ev->address);
1322 	if (disp->mgr->blackhole != NULL &&
1323 	    dns_acl_match(&netaddr, NULL, disp->mgr->blackhole,
1324 			  NULL, &match, NULL) == ISC_R_SUCCESS &&
1325 	    match > 0)
1326 	{
1327 		if (isc_log_wouldlog(dns_lctx, LVL(10))) {
1328 			char netaddrstr[ISC_NETADDR_FORMATSIZE];
1329 			isc_netaddr_format(&netaddr, netaddrstr,
1330 					   sizeof(netaddrstr));
1331 			dispatch_log(disp, LVL(10),
1332 				     "blackholed packet from %s",
1333 				     netaddrstr);
1334 		}
1335 		free_buffer(disp, ev->region.base, ev->region.length);
1336 		goto restart;
1337 	}
1338 
1339 	/*
1340 	 * Peek into the buffer to see what we can see.
1341 	 */
1342 	isc_buffer_init(&source, ev->region.base, ev->region.length);
1343 	isc_buffer_add(&source, ev->n);
1344 	dres = dns_message_peekheader(&source, &id, &flags);
1345 	if (dres != ISC_R_SUCCESS) {
1346 		free_buffer(disp, ev->region.base, ev->region.length);
1347 		dispatch_log(disp, LVL(10), "got garbage packet");
1348 		goto restart;
1349 	}
1350 
1351 	dispatch_log(disp, LVL(92),
1352 		     "got valid DNS message header, /QR %c, id %u",
1353 		     ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id);
1354 
1355 	/*
1356 	 * Look at flags.  If query, drop it. If response,
1357 	 * look to see where it goes.
1358 	 */
1359 	if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
1360 		/* query */
1361 		free_buffer(disp, ev->region.base, ev->region.length);
1362 		goto restart;
1363 	}
1364 
1365 	/*
1366 	 * Search for the corresponding response.  If we are using an exclusive
1367 	 * socket, we've already identified it and we can skip the search; but
1368 	 * the ID and the address must match the expected ones.
1369 	 */
1370 	if (resp == NULL) {
1371 		bucket = dns_hash(qid, &ev->address, id, disp->localport);
1372 		LOCK(&qid->lock);
1373 		qidlocked = ISC_TRUE;
1374 		resp = entry_search(qid, &ev->address, id, disp->localport,
1375 				    bucket);
1376 		dispatch_log(disp, LVL(90),
1377 			     "search for response in bucket %d: %s",
1378 			     bucket, (resp == NULL ? "not found" : "found"));
1379 
1380 		if (resp == NULL) {
1381 			inc_stats(mgr, dns_resstatscounter_mismatch);
1382 			free_buffer(disp, ev->region.base, ev->region.length);
1383 			goto unlock;
1384 		}
1385 	} else if (resp->id != id || !isc_sockaddr_equal(&ev->address,
1386 							 &resp->host)) {
1387 		dispatch_log(disp, LVL(90),
1388 			     "response to an exclusive socket doesn't match");
1389 		inc_stats(mgr, dns_resstatscounter_mismatch);
1390 		free_buffer(disp, ev->region.base, ev->region.length);
1391 		goto unlock;
1392 	}
1393 
1394 	/*
1395 	 * Now that we have the original dispatch the query was sent
1396 	 * from check that the address and port the response was
1397 	 * sent to make sense.
1398 	 */
1399 	if (disp != resp->disp) {
1400 		isc_sockaddr_t a1;
1401 		isc_sockaddr_t a2;
1402 
1403 		/*
1404 		 * Check that the socket types and ports match.
1405 		 */
1406 		if (disp->socktype != resp->disp->socktype ||
1407 		    isc_sockaddr_getport(&disp->local) !=
1408 		    isc_sockaddr_getport(&resp->disp->local)) {
1409 			free_buffer(disp, ev->region.base, ev->region.length);
1410 			goto unlock;
1411 		}
1412 
1413 		/*
1414 		 * If each dispatch is bound to a different address
1415 		 * then fail.
1416 		 *
1417 		 * Note under Linux a packet can be sent out via IPv4 socket
1418 		 * and the response be received via a IPv6 socket.
1419 		 *
1420 		 * Requests sent out via IPv6 should always come back in
1421 		 * via IPv6.
1422 		 */
1423 		if (isc_sockaddr_pf(&resp->disp->local) == PF_INET6 &&
1424 		    isc_sockaddr_pf(&disp->local) != PF_INET6) {
1425 			free_buffer(disp, ev->region.base, ev->region.length);
1426 			goto unlock;
1427 		}
1428 		isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local));
1429 		isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local));
1430 		if (!isc_sockaddr_eqaddr(&disp->local, &resp->disp->local) &&
1431 		    !isc_sockaddr_eqaddr(&a1, &resp->disp->local) &&
1432 		    !isc_sockaddr_eqaddr(&a2, &disp->local)) {
1433 			free_buffer(disp, ev->region.base, ev->region.length);
1434 			goto unlock;
1435 		}
1436 	}
1437 
1438   sendresponse:
1439 	queue_response = resp->item_out;
1440 	rev = allocate_devent(resp->disp);
1441 	if (rev == NULL) {
1442 		free_buffer(disp, ev->region.base, ev->region.length);
1443 		goto unlock;
1444 	}
1445 
1446 	/*
1447 	 * At this point, rev contains the event we want to fill in, and
1448 	 * resp contains the information on the place to send it to.
1449 	 * Send the event off.
1450 	 */
1451 	isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length);
1452 	isc_buffer_add(&rev->buffer, ev->n);
1453 	rev->result = ev->result;
1454 	rev->id = id;
1455 	rev->addr = ev->address;
1456 	rev->pktinfo = ev->pktinfo;
1457 	rev->attributes = ev->attributes;
1458 	if (queue_response) {
1459 		ISC_LIST_APPEND(resp->items, rev, ev_link);
1460 	} else {
1461 		ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL,
1462 			       DNS_EVENT_DISPATCH,
1463 			       resp->action, resp->arg, resp, NULL, NULL);
1464 		request_log(disp, resp, LVL(90),
1465 			    "[a] Sent event %p buffer %p len %d to task %p",
1466 			    rev, rev->buffer.base, rev->buffer.length,
1467 			    resp->task);
1468 		resp->item_out = ISC_TRUE;
1469 		isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
1470 	}
1471  unlock:
1472 	if (qidlocked)
1473 		UNLOCK(&qid->lock);
1474 
1475 	/*
1476 	 * Restart recv() to get the next packet.
1477 	 */
1478  restart:
1479 	result = startrecv(disp, dispsock);
1480 	if (result != ISC_R_SUCCESS && dispsock != NULL) {
1481 		/*
1482 		 * XXX: wired. There seems to be no recovery process other than
1483 		 * deactivate this socket anyway (since we cannot start
1484 		 * receiving, we won't be able to receive a cancel event
1485 		 * from the user).
1486 		 */
1487 		deactivate_dispsocket(disp, dispsock);
1488 	}
1489 	isc_event_free(&ev_in);
1490 	UNLOCK(&disp->lock);
1491 }
1492 
1493 /*
1494  * General flow:
1495  *
1496  * If I/O result == CANCELED, EOF, or error, notify everyone as the
1497  * various queues drain.
1498  *
1499  * If query, restart.
1500  *
1501  * If response:
1502  *	Allocate event, fill in details.
1503  *		If cannot allocate, restart.
1504  *	find target.  If not found, restart.
1505  *	if event queue is not empty, queue.  else, send.
1506  *	restart.
1507  */
1508 static void
1509 tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
1510 	dns_dispatch_t *disp = ev_in->ev_arg;
1511 	dns_tcpmsg_t *tcpmsg = &disp->tcpmsg;
1512 	dns_messageid_t id;
1513 	isc_result_t dres;
1514 	unsigned int flags;
1515 	dns_dispentry_t *resp;
1516 	dns_dispatchevent_t *rev;
1517 	unsigned int bucket;
1518 	isc_boolean_t killit;
1519 	isc_boolean_t queue_response;
1520 	dns_qid_t *qid;
1521 	int level;
1522 	char buf[ISC_SOCKADDR_FORMATSIZE];
1523 
1524 	UNUSED(task);
1525 
1526 	REQUIRE(VALID_DISPATCH(disp));
1527 
1528 	qid = disp->qid;
1529 
1530 	dispatch_log(disp, LVL(90),
1531 		     "got TCP packet: requests %d, buffers %d, recvs %d",
1532 		     disp->requests, disp->tcpbuffers, disp->recv_pending);
1533 
1534 	LOCK(&disp->lock);
1535 
1536 	INSIST(disp->recv_pending != 0);
1537 	disp->recv_pending = 0;
1538 
1539 	if (disp->refcount == 0) {
1540 		/*
1541 		 * This dispatcher is shutting down.  Force cancelation.
1542 		 */
1543 		tcpmsg->result = ISC_R_CANCELED;
1544 	}
1545 
1546 	if (tcpmsg->result != ISC_R_SUCCESS) {
1547 		switch (tcpmsg->result) {
1548 		case ISC_R_CANCELED:
1549 			break;
1550 
1551 		case ISC_R_EOF:
1552 			dispatch_log(disp, LVL(90), "shutting down on EOF");
1553 			do_cancel(disp);
1554 			break;
1555 
1556 		case ISC_R_CONNECTIONRESET:
1557 			level = ISC_LOG_INFO;
1558 			goto logit;
1559 
1560 		default:
1561 			level = ISC_LOG_ERROR;
1562 		logit:
1563 			isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf));
1564 			dispatch_log(disp, level, "shutting down due to TCP "
1565 				     "receive error: %s: %s", buf,
1566 				     isc_result_totext(tcpmsg->result));
1567 			do_cancel(disp);
1568 			break;
1569 		}
1570 
1571 		/*
1572 		 * The event is statically allocated in the tcpmsg
1573 		 * structure, and destroy_disp() frees the tcpmsg, so we must
1574 		 * free the event *before* calling destroy_disp().
1575 		 */
1576 		isc_event_free(&ev_in);
1577 
1578 		disp->shutting_down = 1;
1579 		disp->shutdown_why = tcpmsg->result;
1580 
1581 		/*
1582 		 * If the recv() was canceled pass the word on.
1583 		 */
1584 		killit = destroy_disp_ok(disp);
1585 		UNLOCK(&disp->lock);
1586 		if (killit)
1587 			isc_task_send(disp->task[0], &disp->ctlevent);
1588 		return;
1589 	}
1590 
1591 	dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p",
1592 		     tcpmsg->result,
1593 		     tcpmsg->buffer.length, tcpmsg->buffer.base);
1594 
1595 	/*
1596 	 * Peek into the buffer to see what we can see.
1597 	 */
1598 	dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags);
1599 	if (dres != ISC_R_SUCCESS) {
1600 		dispatch_log(disp, LVL(10), "got garbage packet");
1601 		goto restart;
1602 	}
1603 
1604 	dispatch_log(disp, LVL(92),
1605 		     "got valid DNS message header, /QR %c, id %u",
1606 		     ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id);
1607 
1608 	/*
1609 	 * Allocate an event to send to the query or response client, and
1610 	 * allocate a new buffer for our use.
1611 	 */
1612 
1613 	/*
1614 	 * Look at flags.  If query, drop it. If response,
1615 	 * look to see where it goes.
1616 	 */
1617 	if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
1618 		/*
1619 		 * Query.
1620 		 */
1621 		goto restart;
1622 	}
1623 
1624 	/*
1625 	 * Response.
1626 	 */
1627 	bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport);
1628 	LOCK(&qid->lock);
1629 	resp = entry_search(qid, &tcpmsg->address, id, disp->localport, bucket);
1630 	dispatch_log(disp, LVL(90),
1631 		     "search for response in bucket %d: %s",
1632 		     bucket, (resp == NULL ? "not found" : "found"));
1633 
1634 	if (resp == NULL)
1635 		goto unlock;
1636 	queue_response = resp->item_out;
1637 	rev = allocate_devent(disp);
1638 	if (rev == NULL)
1639 		goto unlock;
1640 
1641 	/*
1642 	 * At this point, rev contains the event we want to fill in, and
1643 	 * resp contains the information on the place to send it to.
1644 	 * Send the event off.
1645 	 */
1646 	dns_tcpmsg_keepbuffer(tcpmsg, &rev->buffer);
1647 	disp->tcpbuffers++;
1648 	rev->result = ISC_R_SUCCESS;
1649 	rev->id = id;
1650 	rev->addr = tcpmsg->address;
1651 	if (queue_response) {
1652 		ISC_LIST_APPEND(resp->items, rev, ev_link);
1653 	} else {
1654 		ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH,
1655 			       resp->action, resp->arg, resp, NULL, NULL);
1656 		request_log(disp, resp, LVL(90),
1657 			    "[b] Sent event %p buffer %p len %d to task %p",
1658 			    rev, rev->buffer.base, rev->buffer.length,
1659 			    resp->task);
1660 		resp->item_out = ISC_TRUE;
1661 		isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
1662 	}
1663  unlock:
1664 	UNLOCK(&qid->lock);
1665 
1666 	/*
1667 	 * Restart recv() to get the next packet.
1668 	 */
1669  restart:
1670 	(void)startrecv(disp, NULL);
1671 
1672 	isc_event_free(&ev_in);
1673 	UNLOCK(&disp->lock);
1674 }
1675 
1676 /*
1677  * disp must be locked.
1678  */
1679 static isc_result_t
1680 startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) {
1681 	isc_result_t res;
1682 	isc_region_t region;
1683 	isc_socket_t *socket;
1684 
1685 	if (disp->shutting_down == 1)
1686 		return (ISC_R_SUCCESS);
1687 
1688 	if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
1689 		return (ISC_R_SUCCESS);
1690 
1691 	if (disp->recv_pending != 0 && dispsock == NULL)
1692 		return (ISC_R_SUCCESS);
1693 
1694 	if (disp->mgr->buffers >= disp->mgr->maxbuffers)
1695 		return (ISC_R_NOMEMORY);
1696 
1697 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
1698 	    dispsock == NULL)
1699 		return (ISC_R_SUCCESS);
1700 
1701 	if (dispsock != NULL)
1702 		socket = dispsock->socket;
1703 	else
1704 		socket = disp->socket;
1705 	INSIST(socket != NULL);
1706 
1707 	switch (disp->socktype) {
1708 		/*
1709 		 * UDP reads are always maximal.
1710 		 */
1711 	case isc_sockettype_udp:
1712 		region.length = disp->mgr->buffersize;
1713 		region.base = allocate_udp_buffer(disp);
1714 		if (region.base == NULL)
1715 			return (ISC_R_NOMEMORY);
1716 		if (dispsock != NULL) {
1717 			isc_task_t *dt = dispsock->task;
1718 			isc_socketevent_t *sev =
1719 				allocate_sevent(disp, socket,
1720 						ISC_SOCKEVENT_RECVDONE,
1721 						udp_exrecv, dispsock);
1722 			if (sev == NULL) {
1723 				free_buffer(disp, region.base, region.length);
1724 				return (ISC_R_NOMEMORY);
1725 			}
1726 
1727 			res = isc_socket_recv2(socket, &region, 1, dt, sev, 0);
1728 			if (res != ISC_R_SUCCESS) {
1729 				free_buffer(disp, region.base, region.length);
1730 				return (res);
1731 			}
1732 		} else {
1733 			isc_task_t *dt = disp->task[0];
1734 			isc_socketevent_t *sev =
1735 				allocate_sevent(disp, socket,
1736 						ISC_SOCKEVENT_RECVDONE,
1737 						udp_shrecv, disp);
1738 			if (sev == NULL) {
1739 				free_buffer(disp, region.base, region.length);
1740 				return (ISC_R_NOMEMORY);
1741 			}
1742 
1743 			res = isc_socket_recv2(socket, &region, 1, dt, sev, 0);
1744 			if (res != ISC_R_SUCCESS) {
1745 				free_buffer(disp, region.base, region.length);
1746 				disp->shutdown_why = res;
1747 				disp->shutting_down = 1;
1748 				do_cancel(disp);
1749 				return (ISC_R_SUCCESS); /* recover by cancel */
1750 			}
1751 			INSIST(disp->recv_pending == 0);
1752 			disp->recv_pending = 1;
1753 		}
1754 		break;
1755 
1756 	case isc_sockettype_tcp:
1757 		res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task[0],
1758 					     tcp_recv, disp);
1759 		if (res != ISC_R_SUCCESS) {
1760 			disp->shutdown_why = res;
1761 			disp->shutting_down = 1;
1762 			do_cancel(disp);
1763 			return (ISC_R_SUCCESS); /* recover by cancel */
1764 		}
1765 		INSIST(disp->recv_pending == 0);
1766 		disp->recv_pending = 1;
1767 		break;
1768 	default:
1769 		INSIST(0);
1770 		break;
1771 	}
1772 
1773 	return (ISC_R_SUCCESS);
1774 }
1775 
1776 /*
1777  * Mgr must be locked when calling this function.
1778  */
1779 static isc_boolean_t
1780 destroy_mgr_ok(dns_dispatchmgr_t *mgr) {
1781 	mgr_log(mgr, LVL(90),
1782 		"destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, "
1783 		"depool=%d, rpool=%d, dpool=%d",
1784 		MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list),
1785 		isc_mempool_getallocated(mgr->depool),
1786 		isc_mempool_getallocated(mgr->rpool),
1787 		isc_mempool_getallocated(mgr->dpool));
1788 	if (!MGR_IS_SHUTTINGDOWN(mgr))
1789 		return (ISC_FALSE);
1790 	if (!ISC_LIST_EMPTY(mgr->list))
1791 		return (ISC_FALSE);
1792 	if (isc_mempool_getallocated(mgr->depool) != 0)
1793 		return (ISC_FALSE);
1794 	if (isc_mempool_getallocated(mgr->rpool) != 0)
1795 		return (ISC_FALSE);
1796 	if (isc_mempool_getallocated(mgr->dpool) != 0)
1797 		return (ISC_FALSE);
1798 
1799 	return (ISC_TRUE);
1800 }
1801 
1802 /*
1803  * Mgr must be unlocked when calling this function.
1804  */
1805 static void
1806 destroy_mgr(dns_dispatchmgr_t **mgrp) {
1807 	isc_mem_t *mctx;
1808 	dns_dispatchmgr_t *mgr;
1809 
1810 	mgr = *mgrp;
1811 	*mgrp = NULL;
1812 
1813 	mctx = mgr->mctx;
1814 
1815 	mgr->magic = 0;
1816 	mgr->mctx = NULL;
1817 	DESTROYLOCK(&mgr->lock);
1818 	mgr->state = 0;
1819 
1820 	DESTROYLOCK(&mgr->arc4_lock);
1821 
1822 	isc_mempool_destroy(&mgr->depool);
1823 	isc_mempool_destroy(&mgr->rpool);
1824 	isc_mempool_destroy(&mgr->dpool);
1825 	if (mgr->bpool != NULL)
1826 		isc_mempool_destroy(&mgr->bpool);
1827 	if (mgr->spool != NULL)
1828 		isc_mempool_destroy(&mgr->spool);
1829 
1830 	DESTROYLOCK(&mgr->spool_lock);
1831 	DESTROYLOCK(&mgr->bpool_lock);
1832 	DESTROYLOCK(&mgr->dpool_lock);
1833 	DESTROYLOCK(&mgr->rpool_lock);
1834 	DESTROYLOCK(&mgr->depool_lock);
1835 
1836 	if (mgr->entropy != NULL)
1837 		isc_entropy_detach(&mgr->entropy);
1838 	if (mgr->qid != NULL)
1839 		qid_destroy(mctx, &mgr->qid);
1840 
1841 	DESTROYLOCK(&mgr->buffer_lock);
1842 
1843 	if (mgr->blackhole != NULL)
1844 		dns_acl_detach(&mgr->blackhole);
1845 
1846 	if (mgr->stats != NULL)
1847 		isc_stats_detach(&mgr->stats);
1848 
1849 	if (mgr->v4ports != NULL) {
1850 		isc_mem_put(mctx, mgr->v4ports,
1851 			    mgr->nv4ports * sizeof(in_port_t));
1852 	}
1853 	if (mgr->v6ports != NULL) {
1854 		isc_mem_put(mctx, mgr->v6ports,
1855 			    mgr->nv6ports * sizeof(in_port_t));
1856 	}
1857 	isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
1858 	isc_mem_detach(&mctx);
1859 }
1860 
1861 static isc_result_t
1862 open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
1863 	    unsigned int options, isc_socket_t **sockp,
1864 	    isc_socket_t *dup_socket)
1865 {
1866 	isc_socket_t *sock;
1867 	isc_result_t result;
1868 
1869 	sock = *sockp;
1870 	if (sock != NULL) {
1871 		result = isc_socket_open(sock);
1872 		if (result != ISC_R_SUCCESS)
1873 			return (result);
1874 	} else if (dup_socket != NULL) {
1875 		result = isc_socket_dup(dup_socket, &sock);
1876 		if (result != ISC_R_SUCCESS)
1877 			return (result);
1878 
1879 		isc_socket_setname(sock, "dispatcher", NULL);
1880 		*sockp = sock;
1881 		return (ISC_R_SUCCESS);
1882 	} else {
1883 		result = isc_socket_create(mgr, isc_sockaddr_pf(local),
1884 					isc_sockettype_udp, &sock);
1885 		if (result != ISC_R_SUCCESS)
1886 			return (result);
1887 	}
1888 
1889 	isc_socket_setname(sock, "dispatcher", NULL);
1890 
1891 #ifndef ISC_ALLOW_MAPPED
1892 	isc_socket_ipv6only(sock, ISC_TRUE);
1893 #endif
1894 	result = isc_socket_bind(sock, local, options);
1895 	if (result != ISC_R_SUCCESS) {
1896 		if (*sockp == NULL)
1897 			isc_socket_detach(&sock);
1898 		else {
1899 			isc_socket_close(sock);
1900 		}
1901 		return (result);
1902 	}
1903 
1904 	*sockp = sock;
1905 	return (ISC_R_SUCCESS);
1906 }
1907 
1908 /*%
1909  * Create a temporary port list to set the initial default set of dispatch
1910  * ports: [1024, 65535].  This is almost meaningless as the application will
1911  * normally set the ports explicitly, but is provided to fill some minor corner
1912  * cases.
1913  */
1914 static isc_result_t
1915 create_default_portset(isc_mem_t *mctx, isc_portset_t **portsetp) {
1916 	isc_result_t result;
1917 
1918 	result = isc_portset_create(mctx, portsetp);
1919 	if (result != ISC_R_SUCCESS)
1920 		return (result);
1921 	isc_portset_addrange(*portsetp, 1024, 65535);
1922 
1923 	return (ISC_R_SUCCESS);
1924 }
1925 
1926 /*
1927  * Publics.
1928  */
1929 
1930 isc_result_t
1931 dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
1932 		       dns_dispatchmgr_t **mgrp)
1933 {
1934 	dns_dispatchmgr_t *mgr;
1935 	isc_result_t result;
1936 	isc_portset_t *v4portset = NULL;
1937 	isc_portset_t *v6portset = NULL;
1938 
1939 	REQUIRE(mctx != NULL);
1940 	REQUIRE(mgrp != NULL && *mgrp == NULL);
1941 
1942 	mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
1943 	if (mgr == NULL)
1944 		return (ISC_R_NOMEMORY);
1945 
1946 	mgr->mctx = NULL;
1947 	isc_mem_attach(mctx, &mgr->mctx);
1948 
1949 	mgr->blackhole = NULL;
1950 	mgr->stats = NULL;
1951 
1952 	result = isc_mutex_init(&mgr->lock);
1953 	if (result != ISC_R_SUCCESS)
1954 		goto deallocate;
1955 
1956 	result = isc_mutex_init(&mgr->arc4_lock);
1957 	if (result != ISC_R_SUCCESS)
1958 		goto kill_lock;
1959 
1960 	result = isc_mutex_init(&mgr->buffer_lock);
1961 	if (result != ISC_R_SUCCESS)
1962 		goto kill_arc4_lock;
1963 
1964 	result = isc_mutex_init(&mgr->depool_lock);
1965 	if (result != ISC_R_SUCCESS)
1966 		goto kill_buffer_lock;
1967 
1968 	result = isc_mutex_init(&mgr->rpool_lock);
1969 	if (result != ISC_R_SUCCESS)
1970 		goto kill_depool_lock;
1971 
1972 	result = isc_mutex_init(&mgr->dpool_lock);
1973 	if (result != ISC_R_SUCCESS)
1974 		goto kill_rpool_lock;
1975 
1976 	result = isc_mutex_init(&mgr->bpool_lock);
1977 	if (result != ISC_R_SUCCESS)
1978 		goto kill_dpool_lock;
1979 
1980 	result = isc_mutex_init(&mgr->spool_lock);
1981 	if (result != ISC_R_SUCCESS)
1982 		goto kill_bpool_lock;
1983 
1984 	mgr->depool = NULL;
1985 	if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t),
1986 			       &mgr->depool) != ISC_R_SUCCESS) {
1987 		result = ISC_R_NOMEMORY;
1988 		goto kill_spool_lock;
1989 	}
1990 
1991 	mgr->rpool = NULL;
1992 	if (isc_mempool_create(mgr->mctx, sizeof(dns_dispentry_t),
1993 			       &mgr->rpool) != ISC_R_SUCCESS) {
1994 		result = ISC_R_NOMEMORY;
1995 		goto kill_depool;
1996 	}
1997 
1998 	mgr->dpool = NULL;
1999 	if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatch_t),
2000 			       &mgr->dpool) != ISC_R_SUCCESS) {
2001 		result = ISC_R_NOMEMORY;
2002 		goto kill_rpool;
2003 	}
2004 
2005 	isc_mempool_setname(mgr->depool, "dispmgr_depool");
2006 	isc_mempool_setmaxalloc(mgr->depool, 32768);
2007 	isc_mempool_setfreemax(mgr->depool, 32768);
2008 	isc_mempool_associatelock(mgr->depool, &mgr->depool_lock);
2009 	isc_mempool_setfillcount(mgr->depool, 32);
2010 
2011 	isc_mempool_setname(mgr->rpool, "dispmgr_rpool");
2012 	isc_mempool_setmaxalloc(mgr->rpool, 32768);
2013 	isc_mempool_setfreemax(mgr->rpool, 32768);
2014 	isc_mempool_associatelock(mgr->rpool, &mgr->rpool_lock);
2015 	isc_mempool_setfillcount(mgr->rpool, 32);
2016 
2017 	isc_mempool_setname(mgr->dpool, "dispmgr_dpool");
2018 	isc_mempool_setmaxalloc(mgr->dpool, 32768);
2019 	isc_mempool_setfreemax(mgr->dpool, 32768);
2020 	isc_mempool_associatelock(mgr->dpool, &mgr->dpool_lock);
2021 	isc_mempool_setfillcount(mgr->dpool, 32);
2022 
2023 	mgr->buffers = 0;
2024 	mgr->buffersize = 0;
2025 	mgr->maxbuffers = 0;
2026 	mgr->bpool = NULL;
2027 	mgr->spool = NULL;
2028 	mgr->entropy = NULL;
2029 	mgr->qid = NULL;
2030 	mgr->state = 0;
2031 	ISC_LIST_INIT(mgr->list);
2032 	mgr->v4ports = NULL;
2033 	mgr->v6ports = NULL;
2034 	mgr->nv4ports = 0;
2035 	mgr->nv6ports = 0;
2036 	mgr->magic = DNS_DISPATCHMGR_MAGIC;
2037 
2038 	result = create_default_portset(mctx, &v4portset);
2039 	if (result == ISC_R_SUCCESS) {
2040 		result = create_default_portset(mctx, &v6portset);
2041 		if (result == ISC_R_SUCCESS) {
2042 			result = dns_dispatchmgr_setavailports(mgr,
2043 							       v4portset,
2044 							       v6portset);
2045 		}
2046 	}
2047 	if (v4portset != NULL)
2048 		isc_portset_destroy(mctx, &v4portset);
2049 	if (v6portset != NULL)
2050 		isc_portset_destroy(mctx, &v6portset);
2051 	if (result != ISC_R_SUCCESS)
2052 		goto kill_dpool;
2053 
2054 	if (entropy != NULL)
2055 		isc_entropy_attach(entropy, &mgr->entropy);
2056 
2057 	dispatch_initrandom(&mgr->arc4ctx, mgr->entropy, &mgr->arc4_lock);
2058 
2059 	*mgrp = mgr;
2060 	return (ISC_R_SUCCESS);
2061 
2062  kill_dpool:
2063 	isc_mempool_destroy(&mgr->dpool);
2064  kill_rpool:
2065 	isc_mempool_destroy(&mgr->rpool);
2066  kill_depool:
2067 	isc_mempool_destroy(&mgr->depool);
2068  kill_spool_lock:
2069 	DESTROYLOCK(&mgr->spool_lock);
2070  kill_bpool_lock:
2071 	DESTROYLOCK(&mgr->bpool_lock);
2072  kill_dpool_lock:
2073 	DESTROYLOCK(&mgr->dpool_lock);
2074  kill_rpool_lock:
2075 	DESTROYLOCK(&mgr->rpool_lock);
2076  kill_depool_lock:
2077 	DESTROYLOCK(&mgr->depool_lock);
2078  kill_buffer_lock:
2079 	DESTROYLOCK(&mgr->buffer_lock);
2080  kill_arc4_lock:
2081 	DESTROYLOCK(&mgr->arc4_lock);
2082  kill_lock:
2083 	DESTROYLOCK(&mgr->lock);
2084  deallocate:
2085 	isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
2086 	isc_mem_detach(&mctx);
2087 
2088 	return (result);
2089 }
2090 
2091 void
2092 dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) {
2093 	REQUIRE(VALID_DISPATCHMGR(mgr));
2094 	if (mgr->blackhole != NULL)
2095 		dns_acl_detach(&mgr->blackhole);
2096 	dns_acl_attach(blackhole, &mgr->blackhole);
2097 }
2098 
2099 dns_acl_t *
2100 dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) {
2101 	REQUIRE(VALID_DISPATCHMGR(mgr));
2102 	return (mgr->blackhole);
2103 }
2104 
2105 void
2106 dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr,
2107 				 dns_portlist_t *portlist)
2108 {
2109 	REQUIRE(VALID_DISPATCHMGR(mgr));
2110 	UNUSED(portlist);
2111 
2112 	/* This function is deprecated: use dns_dispatchmgr_setavailports(). */
2113 	return;
2114 }
2115 
2116 dns_portlist_t *
2117 dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) {
2118 	REQUIRE(VALID_DISPATCHMGR(mgr));
2119 	return (NULL);		/* this function is deprecated */
2120 }
2121 
2122 isc_result_t
2123 dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
2124 			      isc_portset_t *v6portset)
2125 {
2126 	in_port_t *v4ports, *v6ports, p;
2127 	unsigned int nv4ports, nv6ports, i4, i6;
2128 
2129 	REQUIRE(VALID_DISPATCHMGR(mgr));
2130 
2131 	nv4ports = isc_portset_nports(v4portset);
2132 	nv6ports = isc_portset_nports(v6portset);
2133 
2134 	v4ports = NULL;
2135 	if (nv4ports != 0) {
2136 		v4ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv4ports);
2137 		if (v4ports == NULL)
2138 			return (ISC_R_NOMEMORY);
2139 	}
2140 	v6ports = NULL;
2141 	if (nv6ports != 0) {
2142 		v6ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv6ports);
2143 		if (v6ports == NULL) {
2144 			if (v4ports != NULL) {
2145 				isc_mem_put(mgr->mctx, v4ports,
2146 					    sizeof(in_port_t) *
2147 					    isc_portset_nports(v4portset));
2148 			}
2149 			return (ISC_R_NOMEMORY);
2150 		}
2151 	}
2152 
2153 	p = 0;
2154 	i4 = 0;
2155 	i6 = 0;
2156 	do {
2157 		if (isc_portset_isset(v4portset, p)) {
2158 			INSIST(i4 < nv4ports);
2159 			v4ports[i4++] = p;
2160 		}
2161 		if (isc_portset_isset(v6portset, p)) {
2162 			INSIST(i6 < nv6ports);
2163 			v6ports[i6++] = p;
2164 		}
2165 	} while (p++ < 65535);
2166 	INSIST(i4 == nv4ports && i6 == nv6ports);
2167 
2168 	PORTBUFLOCK(mgr);
2169 	if (mgr->v4ports != NULL) {
2170 		isc_mem_put(mgr->mctx, mgr->v4ports,
2171 			    mgr->nv4ports * sizeof(in_port_t));
2172 	}
2173 	mgr->v4ports = v4ports;
2174 	mgr->nv4ports = nv4ports;
2175 
2176 	if (mgr->v6ports != NULL) {
2177 		isc_mem_put(mgr->mctx, mgr->v6ports,
2178 			    mgr->nv6ports * sizeof(in_port_t));
2179 	}
2180 	mgr->v6ports = v6ports;
2181 	mgr->nv6ports = nv6ports;
2182 	PORTBUFUNLOCK(mgr);
2183 
2184 	return (ISC_R_SUCCESS);
2185 }
2186 
2187 static isc_result_t
2188 dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
2189 		       unsigned int buffersize, unsigned int maxbuffers,
2190 		       unsigned int maxrequests, unsigned int buckets,
2191 		       unsigned int increment)
2192 {
2193 	isc_result_t result;
2194 
2195 	REQUIRE(VALID_DISPATCHMGR(mgr));
2196 	REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
2197 	REQUIRE(maxbuffers > 0);
2198 	REQUIRE(buckets < 2097169);  /* next prime > 65536 * 32 */
2199 	REQUIRE(increment > buckets);
2200 
2201 	/*
2202 	 * Keep some number of items around.  This should be a config
2203 	 * option.  For now, keep 8, but later keep at least two even
2204 	 * if the caller wants less.  This allows us to ensure certain
2205 	 * things, like an event can be "freed" and the next allocation
2206 	 * will always succeed.
2207 	 *
2208 	 * Note that if limits are placed on anything here, we use one
2209 	 * event internally, so the actual limit should be "wanted + 1."
2210 	 *
2211 	 * XXXMLG
2212 	 */
2213 
2214 	if (maxbuffers < 8)
2215 		maxbuffers = 8;
2216 
2217 	LOCK(&mgr->buffer_lock);
2218 
2219 	/* Create or adjust buffer pool */
2220 	if (mgr->bpool != NULL) {
2221 		/*
2222 		 * We only increase the maxbuffers to avoid accidental buffer
2223 		 * shortage.  Ideally we'd separate the manager-wide maximum
2224 		 * from per-dispatch limits and respect the latter within the
2225 		 * global limit.  But at this moment that's deemed to be
2226 		 * overkilling and isn't worth additional implementation
2227 		 * complexity.
2228 		 */
2229 		if (maxbuffers > mgr->maxbuffers) {
2230 			isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
2231 			isc_mempool_setfreemax(mgr->bpool, maxbuffers);
2232 			mgr->maxbuffers = maxbuffers;
2233 		}
2234 	} else {
2235 		result = isc_mempool_create(mgr->mctx, buffersize, &mgr->bpool);
2236 		if (result != ISC_R_SUCCESS) {
2237 			UNLOCK(&mgr->buffer_lock);
2238 			return (result);
2239 		}
2240 		isc_mempool_setname(mgr->bpool, "dispmgr_bpool");
2241 		isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
2242 		isc_mempool_setfreemax(mgr->bpool, maxbuffers);
2243 		isc_mempool_associatelock(mgr->bpool, &mgr->bpool_lock);
2244 		isc_mempool_setfillcount(mgr->bpool, 32);
2245 	}
2246 
2247 	/* Create or adjust socket pool */
2248 	if (mgr->spool != NULL) {
2249 		if (maxrequests < DNS_DISPATCH_POOLSOCKS * 2) {
2250 			isc_mempool_setmaxalloc(mgr->spool,
2251 						DNS_DISPATCH_POOLSOCKS * 2);
2252 			isc_mempool_setfreemax(mgr->spool,
2253 					       DNS_DISPATCH_POOLSOCKS * 2);
2254 		}
2255 		UNLOCK(&mgr->buffer_lock);
2256 		return (ISC_R_SUCCESS);
2257 	}
2258 	result = isc_mempool_create(mgr->mctx, sizeof(dispsocket_t),
2259 				    &mgr->spool);
2260 	if (result != ISC_R_SUCCESS) {
2261 		UNLOCK(&mgr->buffer_lock);
2262 		goto cleanup;
2263 	}
2264 	isc_mempool_setname(mgr->spool, "dispmgr_spool");
2265 	isc_mempool_setmaxalloc(mgr->spool, maxrequests);
2266 	isc_mempool_setfreemax(mgr->spool, maxrequests);
2267 	isc_mempool_associatelock(mgr->spool, &mgr->spool_lock);
2268 	isc_mempool_setfillcount(mgr->spool, 32);
2269 
2270 	result = qid_allocate(mgr, buckets, increment, &mgr->qid, ISC_TRUE);
2271 	if (result != ISC_R_SUCCESS)
2272 		goto cleanup;
2273 
2274 	mgr->buffersize = buffersize;
2275 	mgr->maxbuffers = maxbuffers;
2276 	UNLOCK(&mgr->buffer_lock);
2277 	return (ISC_R_SUCCESS);
2278 
2279  cleanup:
2280 	isc_mempool_destroy(&mgr->bpool);
2281 	if (mgr->spool != NULL)
2282 		isc_mempool_destroy(&mgr->spool);
2283 	UNLOCK(&mgr->buffer_lock);
2284 	return (result);
2285 }
2286 
2287 void
2288 dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) {
2289 	dns_dispatchmgr_t *mgr;
2290 	isc_boolean_t killit;
2291 
2292 	REQUIRE(mgrp != NULL);
2293 	REQUIRE(VALID_DISPATCHMGR(*mgrp));
2294 
2295 	mgr = *mgrp;
2296 	*mgrp = NULL;
2297 
2298 	LOCK(&mgr->lock);
2299 	mgr->state |= MGR_SHUTTINGDOWN;
2300 
2301 	killit = destroy_mgr_ok(mgr);
2302 	UNLOCK(&mgr->lock);
2303 
2304 	mgr_log(mgr, LVL(90), "destroy: killit=%d", killit);
2305 
2306 	if (killit)
2307 		destroy_mgr(&mgr);
2308 }
2309 
2310 void
2311 dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) {
2312 	REQUIRE(VALID_DISPATCHMGR(mgr));
2313 	REQUIRE(ISC_LIST_EMPTY(mgr->list));
2314 	REQUIRE(mgr->stats == NULL);
2315 
2316 	isc_stats_attach(stats, &mgr->stats);
2317 }
2318 
2319 static int
2320 port_cmp(const void *key, const void *ent) {
2321 	in_port_t p1 = *(const in_port_t *)key;
2322 	in_port_t p2 = *(const in_port_t *)ent;
2323 
2324 	if (p1 < p2)
2325 		return (-1);
2326 	else if (p1 == p2)
2327 		return (0);
2328 	else
2329 		return (1);
2330 }
2331 
2332 static isc_boolean_t
2333 portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
2334 	      isc_sockaddr_t *sockaddrp)
2335 {
2336 	isc_sockaddr_t sockaddr;
2337 	isc_result_t result;
2338 	in_port_t *ports, port;
2339 	unsigned int nports;
2340 	isc_boolean_t available = ISC_FALSE;
2341 
2342 	REQUIRE(sock != NULL || sockaddrp != NULL);
2343 
2344 	PORTBUFLOCK(mgr);
2345 	if (sock != NULL) {
2346 		sockaddrp = &sockaddr;
2347 		result = isc_socket_getsockname(sock, sockaddrp);
2348 		if (result != ISC_R_SUCCESS)
2349 			goto unlock;
2350 	}
2351 
2352 	if (isc_sockaddr_pf(sockaddrp) == AF_INET) {
2353 		ports = mgr->v4ports;
2354 		nports = mgr->nv4ports;
2355 	} else {
2356 		ports = mgr->v6ports;
2357 		nports = mgr->nv6ports;
2358 	}
2359 	if (ports == NULL)
2360 		goto unlock;
2361 
2362 	port = isc_sockaddr_getport(sockaddrp);
2363 	if (bsearch(&port, ports, nports, sizeof(in_port_t), port_cmp) != NULL)
2364 		available = ISC_TRUE;
2365 
2366 unlock:
2367 	PORTBUFUNLOCK(mgr);
2368 	return (available);
2369 }
2370 
2371 #define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))
2372 
2373 static isc_boolean_t
2374 local_addr_match(dns_dispatch_t *disp, isc_sockaddr_t *addr) {
2375 	isc_sockaddr_t sockaddr;
2376 	isc_result_t result;
2377 
2378 	REQUIRE(disp->socket != NULL);
2379 
2380 	if (addr == NULL)
2381 		return (ISC_TRUE);
2382 
2383 	/*
2384 	 * Don't match wildcard ports unless the port is available in the
2385 	 * current configuration.
2386 	 */
2387 	if (isc_sockaddr_getport(addr) == 0 &&
2388 	    isc_sockaddr_getport(&disp->local) == 0 &&
2389 	    !portavailable(disp->mgr, disp->socket, NULL)) {
2390 		return (ISC_FALSE);
2391 	}
2392 
2393 	/*
2394 	 * Check if we match the binding <address,port>.
2395 	 * Wildcard ports match/fail here.
2396 	 */
2397 	if (isc_sockaddr_equal(&disp->local, addr))
2398 		return (ISC_TRUE);
2399 	if (isc_sockaddr_getport(addr) == 0)
2400 		return (ISC_FALSE);
2401 
2402 	/*
2403 	 * Check if we match a bound wildcard port <address,port>.
2404 	 */
2405 	if (!isc_sockaddr_eqaddr(&disp->local, addr))
2406 		return (ISC_FALSE);
2407 	result = isc_socket_getsockname(disp->socket, &sockaddr);
2408 	if (result != ISC_R_SUCCESS)
2409 		return (ISC_FALSE);
2410 
2411 	return (isc_sockaddr_equal(&sockaddr, addr));
2412 }
2413 
2414 /*
2415  * Requires mgr be locked.
2416  *
2417  * No dispatcher can be locked by this thread when calling this function.
2418  *
2419  *
2420  * NOTE:
2421  *	If a matching dispatcher is found, it is locked after this function
2422  *	returns, and must be unlocked by the caller.
2423  */
2424 static isc_result_t
2425 dispatch_find(dns_dispatchmgr_t *mgr, isc_sockaddr_t *local,
2426 	      unsigned int attributes, unsigned int mask,
2427 	      dns_dispatch_t **dispp)
2428 {
2429 	dns_dispatch_t *disp;
2430 	isc_result_t result;
2431 
2432 	/*
2433 	 * Make certain that we will not match a private or exclusive dispatch.
2434 	 */
2435 	attributes &= ~(DNS_DISPATCHATTR_PRIVATE|DNS_DISPATCHATTR_EXCLUSIVE);
2436 	mask |= (DNS_DISPATCHATTR_PRIVATE|DNS_DISPATCHATTR_EXCLUSIVE);
2437 
2438 	disp = ISC_LIST_HEAD(mgr->list);
2439 	while (disp != NULL) {
2440 		LOCK(&disp->lock);
2441 		if ((disp->shutting_down == 0)
2442 		    && ATTRMATCH(disp->attributes, attributes, mask)
2443 		    && local_addr_match(disp, local))
2444 			break;
2445 		UNLOCK(&disp->lock);
2446 		disp = ISC_LIST_NEXT(disp, link);
2447 	}
2448 
2449 	if (disp == NULL) {
2450 		result = ISC_R_NOTFOUND;
2451 		goto out;
2452 	}
2453 
2454 	*dispp = disp;
2455 	result = ISC_R_SUCCESS;
2456  out:
2457 
2458 	return (result);
2459 }
2460 
2461 static isc_result_t
2462 qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
2463 	     unsigned int increment, dns_qid_t **qidp,
2464 	     isc_boolean_t needsocktable)
2465 {
2466 	dns_qid_t *qid;
2467 	unsigned int i;
2468 	isc_result_t result;
2469 
2470 	REQUIRE(VALID_DISPATCHMGR(mgr));
2471 	REQUIRE(buckets < 2097169);  /* next prime > 65536 * 32 */
2472 	REQUIRE(increment > buckets);
2473 	REQUIRE(qidp != NULL && *qidp == NULL);
2474 
2475 	qid = isc_mem_get(mgr->mctx, sizeof(*qid));
2476 	if (qid == NULL)
2477 		return (ISC_R_NOMEMORY);
2478 
2479 	qid->qid_table = isc_mem_get(mgr->mctx,
2480 				     buckets * sizeof(dns_displist_t));
2481 	if (qid->qid_table == NULL) {
2482 		isc_mem_put(mgr->mctx, qid, sizeof(*qid));
2483 		return (ISC_R_NOMEMORY);
2484 	}
2485 
2486 	qid->sock_table = NULL;
2487 	if (needsocktable) {
2488 		qid->sock_table = isc_mem_get(mgr->mctx, buckets *
2489 					      sizeof(dispsocketlist_t));
2490 		if (qid->sock_table == NULL) {
2491 			isc_mem_put(mgr->mctx, qid->qid_table,
2492 				    buckets * sizeof(dns_displist_t));
2493 			isc_mem_put(mgr->mctx, qid, sizeof(*qid));
2494 			return (ISC_R_NOMEMORY);
2495 		}
2496 	}
2497 
2498 	result = isc_mutex_init(&qid->lock);
2499 	if (result != ISC_R_SUCCESS) {
2500 		if (qid->sock_table != NULL) {
2501 			isc_mem_put(mgr->mctx, qid->sock_table,
2502 				    buckets * sizeof(dispsocketlist_t));
2503 		}
2504 		isc_mem_put(mgr->mctx, qid->qid_table,
2505 			    buckets * sizeof(dns_displist_t));
2506 		isc_mem_put(mgr->mctx, qid, sizeof(*qid));
2507 		return (result);
2508 	}
2509 
2510 	for (i = 0; i < buckets; i++) {
2511 		ISC_LIST_INIT(qid->qid_table[i]);
2512 		if (qid->sock_table != NULL)
2513 			ISC_LIST_INIT(qid->sock_table[i]);
2514 	}
2515 
2516 	qid->qid_nbuckets = buckets;
2517 	qid->qid_increment = increment;
2518 	qid->magic = QID_MAGIC;
2519 	*qidp = qid;
2520 	return (ISC_R_SUCCESS);
2521 }
2522 
2523 static void
2524 qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
2525 	dns_qid_t *qid;
2526 
2527 	REQUIRE(qidp != NULL);
2528 	qid = *qidp;
2529 
2530 	REQUIRE(VALID_QID(qid));
2531 
2532 	*qidp = NULL;
2533 	qid->magic = 0;
2534 	isc_mem_put(mctx, qid->qid_table,
2535 		    qid->qid_nbuckets * sizeof(dns_displist_t));
2536 	if (qid->sock_table != NULL) {
2537 		isc_mem_put(mctx, qid->sock_table,
2538 			    qid->qid_nbuckets * sizeof(dispsocketlist_t));
2539 	}
2540 	DESTROYLOCK(&qid->lock);
2541 	isc_mem_put(mctx, qid, sizeof(*qid));
2542 }
2543 
2544 /*
2545  * Allocate and set important limits.
2546  */
2547 static isc_result_t
2548 dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests,
2549 		  dns_dispatch_t **dispp)
2550 {
2551 	dns_dispatch_t *disp;
2552 	isc_result_t result;
2553 
2554 	REQUIRE(VALID_DISPATCHMGR(mgr));
2555 	REQUIRE(dispp != NULL && *dispp == NULL);
2556 
2557 	/*
2558 	 * Set up the dispatcher, mostly.  Don't bother setting some of
2559 	 * the options that are controlled by tcp vs. udp, etc.
2560 	 */
2561 
2562 	disp = isc_mempool_get(mgr->dpool);
2563 	if (disp == NULL)
2564 		return (ISC_R_NOMEMORY);
2565 
2566 	disp->magic = 0;
2567 	disp->mgr = mgr;
2568 	disp->maxrequests = maxrequests;
2569 	disp->attributes = 0;
2570 	ISC_LINK_INIT(disp, link);
2571 	disp->refcount = 1;
2572 	disp->recv_pending = 0;
2573 	memset(&disp->local, 0, sizeof(disp->local));
2574 	disp->localport = 0;
2575 	disp->shutting_down = 0;
2576 	disp->shutdown_out = 0;
2577 	disp->connected = 0;
2578 	disp->tcpmsg_valid = 0;
2579 	disp->shutdown_why = ISC_R_UNEXPECTED;
2580 	disp->requests = 0;
2581 	disp->tcpbuffers = 0;
2582 	disp->qid = NULL;
2583 	ISC_LIST_INIT(disp->activesockets);
2584 	ISC_LIST_INIT(disp->inactivesockets);
2585 	disp->nsockets = 0;
2586 	dispatch_initrandom(&disp->arc4ctx, mgr->entropy, NULL);
2587 	disp->port_table = NULL;
2588 	disp->portpool = NULL;
2589 	disp->dscp = -1;
2590 
2591 	result = isc_mutex_init(&disp->lock);
2592 	if (result != ISC_R_SUCCESS)
2593 		goto deallocate;
2594 
2595 	disp->failsafe_ev = allocate_devent(disp);
2596 	if (disp->failsafe_ev == NULL) {
2597 		result = ISC_R_NOMEMORY;
2598 		goto kill_lock;
2599 	}
2600 
2601 	disp->magic = DISPATCH_MAGIC;
2602 
2603 	*dispp = disp;
2604 	return (ISC_R_SUCCESS);
2605 
2606 	/*
2607 	 * error returns
2608 	 */
2609  kill_lock:
2610 	DESTROYLOCK(&disp->lock);
2611  deallocate:
2612 	isc_mempool_put(mgr->dpool, disp);
2613 
2614 	return (result);
2615 }
2616 
2617 
2618 /*
2619  * MUST be unlocked, and not used by anything.
2620  */
2621 static void
2622 dispatch_free(dns_dispatch_t **dispp) {
2623 	dns_dispatch_t *disp;
2624 	dns_dispatchmgr_t *mgr;
2625 	int i;
2626 
2627 	REQUIRE(VALID_DISPATCH(*dispp));
2628 	disp = *dispp;
2629 	*dispp = NULL;
2630 
2631 	mgr = disp->mgr;
2632 	REQUIRE(VALID_DISPATCHMGR(mgr));
2633 
2634 	if (disp->tcpmsg_valid) {
2635 		dns_tcpmsg_invalidate(&disp->tcpmsg);
2636 		disp->tcpmsg_valid = 0;
2637 	}
2638 
2639 	INSIST(disp->tcpbuffers == 0);
2640 	INSIST(disp->requests == 0);
2641 	INSIST(disp->recv_pending == 0);
2642 	INSIST(ISC_LIST_EMPTY(disp->activesockets));
2643 	INSIST(ISC_LIST_EMPTY(disp->inactivesockets));
2644 
2645 	isc_mempool_put(mgr->depool, disp->failsafe_ev);
2646 	disp->failsafe_ev = NULL;
2647 
2648 	if (disp->qid != NULL)
2649 		qid_destroy(mgr->mctx, &disp->qid);
2650 
2651 	if (disp->port_table != NULL) {
2652 		for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++)
2653 			INSIST(ISC_LIST_EMPTY(disp->port_table[i]));
2654 		isc_mem_put(mgr->mctx, disp->port_table,
2655 			    sizeof(disp->port_table[0]) *
2656 			    DNS_DISPATCH_PORTTABLESIZE);
2657 	}
2658 
2659 	if (disp->portpool != NULL)
2660 		isc_mempool_destroy(&disp->portpool);
2661 
2662 	disp->mgr = NULL;
2663 	DESTROYLOCK(&disp->lock);
2664 	disp->magic = 0;
2665 	isc_mempool_put(mgr->dpool, disp);
2666 }
2667 
2668 isc_result_t
2669 dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
2670 		       isc_taskmgr_t *taskmgr, unsigned int buffersize,
2671 		       unsigned int maxbuffers, unsigned int maxrequests,
2672 		       unsigned int buckets, unsigned int increment,
2673 		       unsigned int attributes, dns_dispatch_t **dispp)
2674 {
2675 	isc_result_t result;
2676 	dns_dispatch_t *disp;
2677 
2678 	UNUSED(maxbuffers);
2679 	UNUSED(buffersize);
2680 
2681 	REQUIRE(VALID_DISPATCHMGR(mgr));
2682 	REQUIRE(isc_socket_gettype(sock) == isc_sockettype_tcp);
2683 	REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0);
2684 	REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0);
2685 
2686 	attributes |= DNS_DISPATCHATTR_PRIVATE;  /* XXXMLG */
2687 
2688 	LOCK(&mgr->lock);
2689 
2690 	/*
2691 	 * dispatch_allocate() checks mgr for us.
2692 	 * qid_allocate() checks buckets and increment for us.
2693 	 */
2694 	disp = NULL;
2695 	result = dispatch_allocate(mgr, maxrequests, &disp);
2696 	if (result != ISC_R_SUCCESS) {
2697 		UNLOCK(&mgr->lock);
2698 		return (result);
2699 	}
2700 
2701 	result = qid_allocate(mgr, buckets, increment, &disp->qid, ISC_FALSE);
2702 	if (result != ISC_R_SUCCESS)
2703 		goto deallocate_dispatch;
2704 
2705 	disp->socktype = isc_sockettype_tcp;
2706 	disp->socket = NULL;
2707 	isc_socket_attach(sock, &disp->socket);
2708 
2709 	disp->sepool = NULL;
2710 
2711 	disp->ntasks = 1;
2712 	disp->task[0] = NULL;
2713 	result = isc_task_create(taskmgr, 0, &disp->task[0]);
2714 	if (result != ISC_R_SUCCESS)
2715 		goto kill_socket;
2716 
2717 	disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
2718 					    DNS_EVENT_DISPATCHCONTROL,
2719 					    destroy_disp, disp,
2720 					    sizeof(isc_event_t));
2721 	if (disp->ctlevent == NULL) {
2722 		result = ISC_R_NOMEMORY;
2723 		goto kill_task;
2724 	}
2725 
2726 	isc_task_setname(disp->task[0], "tcpdispatch", disp);
2727 
2728 	dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg);
2729 	disp->tcpmsg_valid = 1;
2730 
2731 	disp->attributes = attributes;
2732 
2733 	/*
2734 	 * Append it to the dispatcher list.
2735 	 */
2736 	ISC_LIST_APPEND(mgr->list, disp, link);
2737 	UNLOCK(&mgr->lock);
2738 
2739 	mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp);
2740 	dispatch_log(disp, LVL(90), "created task %p", disp->task[0]);
2741 
2742 	*dispp = disp;
2743 
2744 	return (ISC_R_SUCCESS);
2745 
2746 	/*
2747 	 * Error returns.
2748 	 */
2749  kill_task:
2750 	isc_task_detach(&disp->task[0]);
2751  kill_socket:
2752 	isc_socket_detach(&disp->socket);
2753  deallocate_dispatch:
2754 	dispatch_free(&disp);
2755 
2756 	UNLOCK(&mgr->lock);
2757 
2758 	return (result);
2759 }
2760 
2761 isc_result_t
2762 dns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
2763 		    isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
2764 		    unsigned int buffersize,
2765 		    unsigned int maxbuffers, unsigned int maxrequests,
2766 		    unsigned int buckets, unsigned int increment,
2767 		    unsigned int attributes, unsigned int mask,
2768 		    dns_dispatch_t **dispp, dns_dispatch_t *dup_dispatch)
2769 {
2770 	isc_result_t result;
2771 	dns_dispatch_t *disp = NULL;
2772 
2773 	REQUIRE(VALID_DISPATCHMGR(mgr));
2774 	REQUIRE(sockmgr != NULL);
2775 	REQUIRE(localaddr != NULL);
2776 	REQUIRE(taskmgr != NULL);
2777 	REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
2778 	REQUIRE(maxbuffers > 0);
2779 	REQUIRE(buckets < 2097169);  /* next prime > 65536 * 32 */
2780 	REQUIRE(increment > buckets);
2781 	REQUIRE(dispp != NULL && *dispp == NULL);
2782 	REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0);
2783 
2784 	result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers,
2785 					maxrequests, buckets, increment);
2786 	if (result != ISC_R_SUCCESS)
2787 		return (result);
2788 
2789 	LOCK(&mgr->lock);
2790 
2791 	if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
2792 		REQUIRE(isc_sockaddr_getport(localaddr) == 0);
2793 		goto createudp;
2794 	}
2795 
2796 	/*
2797 	 * See if we have a dispatcher that matches.
2798 	 */
2799 	if (dup_dispatch == NULL) {
2800 		result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
2801 		if (result == ISC_R_SUCCESS) {
2802 			disp->refcount++;
2803 
2804 			if (disp->maxrequests < maxrequests)
2805 				disp->maxrequests = maxrequests;
2806 
2807 			if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0
2808 			    && (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
2809 			{
2810 				disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
2811 				if (disp->recv_pending != 0)
2812 					isc_socket_cancel(disp->socket,
2813 							  disp->task[0],
2814 							  ISC_SOCKCANCEL_RECV);
2815 			}
2816 
2817 			UNLOCK(&disp->lock);
2818 			UNLOCK(&mgr->lock);
2819 
2820 			*dispp = disp;
2821 
2822 			return (ISC_R_SUCCESS);
2823 		}
2824 	}
2825 
2826  createudp:
2827 	/*
2828 	 * Nope, create one.
2829 	 */
2830 	result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr,
2831 				    maxrequests, attributes, &disp,
2832 				    dup_dispatch == NULL
2833 					    ? NULL
2834 					    : dup_dispatch->socket);
2835 
2836 	if (result != ISC_R_SUCCESS) {
2837 		UNLOCK(&mgr->lock);
2838 		return (result);
2839 	}
2840 
2841 	UNLOCK(&mgr->lock);
2842 	*dispp = disp;
2843 
2844 	return (ISC_R_SUCCESS);
2845 }
2846 
2847 isc_result_t
2848 dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
2849 		    isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
2850 		    unsigned int buffersize,
2851 		    unsigned int maxbuffers, unsigned int maxrequests,
2852 		    unsigned int buckets, unsigned int increment,
2853 		    unsigned int attributes, unsigned int mask,
2854 		    dns_dispatch_t **dispp)
2855 {
2856 	return (dns_dispatch_getudp_dup(mgr, sockmgr, taskmgr, localaddr,
2857 					buffersize, maxbuffers, maxrequests,
2858 					buckets, increment, attributes,
2859 					mask, dispp, NULL));
2860 }
2861 
2862 /*
2863  * mgr should be locked.
2864  */
2865 
2866 #ifndef DNS_DISPATCH_HELD
2867 #define DNS_DISPATCH_HELD 20U
2868 #endif
2869 
2870 static isc_result_t
2871 get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp,
2872 	      isc_socketmgr_t *sockmgr, isc_sockaddr_t *localaddr,
2873 	      isc_socket_t **sockp, isc_socket_t *dup_socket)
2874 {
2875 	unsigned int i, j;
2876 	isc_socket_t *held[DNS_DISPATCH_HELD];
2877 	isc_sockaddr_t localaddr_bound;
2878 	isc_socket_t *sock = NULL;
2879 	isc_result_t result = ISC_R_SUCCESS;
2880 	isc_boolean_t anyport;
2881 
2882 	INSIST(sockp != NULL && *sockp == NULL);
2883 
2884 	localaddr_bound = *localaddr;
2885 	anyport = ISC_TF(isc_sockaddr_getport(localaddr) == 0);
2886 
2887 	if (anyport) {
2888 		unsigned int nports;
2889 		in_port_t *ports;
2890 
2891 		/*
2892 		 * If no port is specified, we first try to pick up a random
2893 		 * port by ourselves.
2894 		 */
2895 		if (isc_sockaddr_pf(localaddr) == AF_INET) {
2896 			nports = disp->mgr->nv4ports;
2897 			ports = disp->mgr->v4ports;
2898 		} else {
2899 			nports = disp->mgr->nv6ports;
2900 			ports = disp->mgr->v6ports;
2901 		}
2902 		if (nports == 0)
2903 			return (ISC_R_ADDRNOTAVAIL);
2904 
2905 		for (i = 0; i < 1024; i++) {
2906 			in_port_t prt;
2907 
2908 			prt = ports[dispatch_uniformrandom(
2909 					DISP_ARC4CTX(disp),
2910 					nports)];
2911 			isc_sockaddr_setport(&localaddr_bound, prt);
2912 			result = open_socket(sockmgr, &localaddr_bound,
2913 					     0, &sock, NULL);
2914 			/*
2915 			 * Continue if the port choosen is already in use
2916 			 * or the OS has reserved it.
2917 			 */
2918 			if (result == ISC_R_NOPERM ||
2919 			    result == ISC_R_ADDRINUSE)
2920 				continue;
2921 			disp->localport = prt;
2922 			*sockp = sock;
2923 			return (result);
2924 		}
2925 
2926 		/*
2927 		 * If this fails 1024 times, we then ask the kernel for
2928 		 * choosing one.
2929 		 */
2930 	} else {
2931 		/* Allow to reuse address for non-random ports. */
2932 		result = open_socket(sockmgr, localaddr,
2933 				     ISC_SOCKET_REUSEADDRESS, &sock,
2934 				     dup_socket);
2935 
2936 		if (result == ISC_R_SUCCESS)
2937 			*sockp = sock;
2938 
2939 		return (result);
2940 	}
2941 
2942 	memset(held, 0, sizeof(held));
2943 	i = 0;
2944 
2945 	for (j = 0; j < 0xffffU; j++) {
2946 		result = open_socket(sockmgr, localaddr, 0, &sock, NULL);
2947 		if (result != ISC_R_SUCCESS)
2948 			goto end;
2949 		else if (portavailable(mgr, sock, NULL))
2950 			break;
2951 		if (held[i] != NULL)
2952 			isc_socket_detach(&held[i]);
2953 		held[i++] = sock;
2954 		sock = NULL;
2955 		if (i == DNS_DISPATCH_HELD)
2956 			i = 0;
2957 	}
2958 	if (j == 0xffffU) {
2959 		mgr_log(mgr, ISC_LOG_ERROR,
2960 			"avoid-v%s-udp-ports: unable to allocate "
2961 			"an available port",
2962 			isc_sockaddr_pf(localaddr) == AF_INET ? "4" : "6");
2963 		result = ISC_R_FAILURE;
2964 		goto end;
2965 	}
2966 	*sockp = sock;
2967 
2968 end:
2969 	for (i = 0; i < DNS_DISPATCH_HELD; i++) {
2970 		if (held[i] != NULL)
2971 			isc_socket_detach(&held[i]);
2972 	}
2973 
2974 	return (result);
2975 }
2976 
2977 static isc_result_t
2978 dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
2979 		   isc_taskmgr_t *taskmgr,
2980 		   isc_sockaddr_t *localaddr,
2981 		   unsigned int maxrequests,
2982 		   unsigned int attributes,
2983 		   dns_dispatch_t **dispp,
2984 		   isc_socket_t *dup_socket)
2985 {
2986 	isc_result_t result;
2987 	dns_dispatch_t *disp;
2988 	isc_socket_t *sock = NULL;
2989 	int i = 0;
2990 
2991 	/*
2992 	 * dispatch_allocate() checks mgr for us.
2993 	 */
2994 	disp = NULL;
2995 	result = dispatch_allocate(mgr, maxrequests, &disp);
2996 	if (result != ISC_R_SUCCESS)
2997 		return (result);
2998 
2999 	disp->socktype = isc_sockettype_udp;
3000 
3001 	if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) {
3002 		result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock,
3003 				       dup_socket);
3004 		if (result != ISC_R_SUCCESS)
3005 			goto deallocate_dispatch;
3006 
3007 		if (isc_log_wouldlog(dns_lctx, 90)) {
3008 			char addrbuf[ISC_SOCKADDR_FORMATSIZE];
3009 
3010 			isc_sockaddr_format(localaddr, addrbuf,
3011 					    ISC_SOCKADDR_FORMATSIZE);
3012 			mgr_log(mgr, LVL(90), "dns_dispatch_createudp: Created"
3013 				" UDP dispatch for %s with socket fd %d\n",
3014 				addrbuf, isc_socket_getfd(sock));
3015 		}
3016 
3017 	} else {
3018 		isc_sockaddr_t sa_any;
3019 
3020 		/*
3021 		 * For dispatches using exclusive sockets with a specific
3022 		 * source address, we only check if the specified address is
3023 		 * available on the system.  Query sockets will be created later
3024 		 * on demand.
3025 		 */
3026 		isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr));
3027 		if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) {
3028 			result = open_socket(sockmgr, localaddr, 0, &sock, NULL);
3029 			if (sock != NULL)
3030 				isc_socket_detach(&sock);
3031 			if (result != ISC_R_SUCCESS)
3032 				goto deallocate_dispatch;
3033 		}
3034 
3035 		disp->port_table = isc_mem_get(mgr->mctx,
3036 					       sizeof(disp->port_table[0]) *
3037 					       DNS_DISPATCH_PORTTABLESIZE);
3038 		if (disp->port_table == NULL)
3039 			goto deallocate_dispatch;
3040 		for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++)
3041 			ISC_LIST_INIT(disp->port_table[i]);
3042 
3043 		result = isc_mempool_create(mgr->mctx, sizeof(dispportentry_t),
3044 					    &disp->portpool);
3045 		if (result != ISC_R_SUCCESS)
3046 			goto deallocate_dispatch;
3047 		isc_mempool_setname(disp->portpool, "disp_portpool");
3048 		isc_mempool_setfreemax(disp->portpool, 128);
3049 	}
3050 	disp->socket = sock;
3051 	disp->local = *localaddr;
3052 
3053 	if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
3054 		disp->ntasks = MAX_INTERNAL_TASKS;
3055 	else
3056 		disp->ntasks = 1;
3057 	for (i = 0; i < disp->ntasks; i++) {
3058 		disp->task[i] = NULL;
3059 		result = isc_task_create(taskmgr, 0, &disp->task[i]);
3060 		if (result != ISC_R_SUCCESS) {
3061 			while (--i >= 0) {
3062 				isc_task_shutdown(disp->task[i]);
3063 				isc_task_detach(&disp->task[i]);
3064 			}
3065 			goto kill_socket;
3066 		}
3067 		isc_task_setname(disp->task[i], "udpdispatch", disp);
3068 	}
3069 
3070 	disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
3071 					    DNS_EVENT_DISPATCHCONTROL,
3072 					    destroy_disp, disp,
3073 					    sizeof(isc_event_t));
3074 	if (disp->ctlevent == NULL) {
3075 		result = ISC_R_NOMEMORY;
3076 		goto kill_task;
3077 	}
3078 
3079 	disp->sepool = NULL;
3080 	if (isc_mempool_create(mgr->mctx, sizeof(isc_socketevent_t),
3081 			       &disp->sepool) != ISC_R_SUCCESS)
3082 	{
3083 		result = ISC_R_NOMEMORY;
3084 		goto kill_ctlevent;
3085 	}
3086 
3087 	result = isc_mutex_init(&disp->sepool_lock);
3088 	if (result != ISC_R_SUCCESS)
3089 		goto kill_sepool;
3090 
3091 	isc_mempool_setname(disp->sepool, "disp_sepool");
3092 	isc_mempool_setmaxalloc(disp->sepool, 32768);
3093 	isc_mempool_setfreemax(disp->sepool, 32768);
3094 	isc_mempool_associatelock(disp->sepool, &disp->sepool_lock);
3095 	isc_mempool_setfillcount(disp->sepool, 16);
3096 
3097 	attributes &= ~DNS_DISPATCHATTR_TCP;
3098 	attributes |= DNS_DISPATCHATTR_UDP;
3099 	disp->attributes = attributes;
3100 
3101 	/*
3102 	 * Append it to the dispatcher list.
3103 	 */
3104 	ISC_LIST_APPEND(mgr->list, disp, link);
3105 
3106 	mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp);
3107 	dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); /* XXX */
3108 	if (disp->socket != NULL)
3109 		dispatch_log(disp, LVL(90), "created socket %p", disp->socket);
3110 
3111 	*dispp = disp;
3112 
3113 	return (result);
3114 
3115 	/*
3116 	 * Error returns.
3117 	 */
3118  kill_sepool:
3119 	isc_mempool_destroy(&disp->sepool);
3120  kill_ctlevent:
3121 	isc_event_free(&disp->ctlevent);
3122  kill_task:
3123 	for (i = 0; i < disp->ntasks; i++)
3124 		isc_task_detach(&disp->task[i]);
3125  kill_socket:
3126 	if (disp->socket != NULL)
3127 		isc_socket_detach(&disp->socket);
3128  deallocate_dispatch:
3129 	dispatch_free(&disp);
3130 
3131 	return (result);
3132 }
3133 
3134 void
3135 dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) {
3136 	REQUIRE(VALID_DISPATCH(disp));
3137 	REQUIRE(dispp != NULL && *dispp == NULL);
3138 
3139 	LOCK(&disp->lock);
3140 	disp->refcount++;
3141 	UNLOCK(&disp->lock);
3142 
3143 	*dispp = disp;
3144 }
3145 
3146 /*
3147  * It is important to lock the manager while we are deleting the dispatch,
3148  * since dns_dispatch_getudp will call dispatch_find, which returns to
3149  * the caller a dispatch but does not attach to it until later.  _getudp
3150  * locks the manager, however, so locking it here will keep us from attaching
3151  * to a dispatcher that is in the process of going away.
3152  */
3153 void
3154 dns_dispatch_detach(dns_dispatch_t **dispp) {
3155 	dns_dispatch_t *disp;
3156 	dispsocket_t *dispsock;
3157 	isc_boolean_t killit;
3158 
3159 	REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp));
3160 
3161 	disp = *dispp;
3162 	*dispp = NULL;
3163 
3164 	LOCK(&disp->lock);
3165 
3166 	INSIST(disp->refcount > 0);
3167 	disp->refcount--;
3168 	if (disp->refcount == 0) {
3169 		if (disp->recv_pending > 0)
3170 			isc_socket_cancel(disp->socket, disp->task[0],
3171 					  ISC_SOCKCANCEL_RECV);
3172 		for (dispsock = ISC_LIST_HEAD(disp->activesockets);
3173 		     dispsock != NULL;
3174 		     dispsock = ISC_LIST_NEXT(dispsock, link)) {
3175 			isc_socket_cancel(dispsock->socket, dispsock->task,
3176 					  ISC_SOCKCANCEL_RECV);
3177 		}
3178 		disp->shutting_down = 1;
3179 	}
3180 
3181 	dispatch_log(disp, LVL(90), "detach: refcount %d", disp->refcount);
3182 
3183 	killit = destroy_disp_ok(disp);
3184 	UNLOCK(&disp->lock);
3185 	if (killit)
3186 		isc_task_send(disp->task[0], &disp->ctlevent);
3187 }
3188 
3189 isc_result_t
3190 dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
3191 			  isc_task_t *task, isc_taskaction_t action, void *arg,
3192 			  dns_messageid_t *idp, dns_dispentry_t **resp,
3193 			  isc_socketmgr_t *sockmgr)
3194 {
3195 	return (dns_dispatch_addresponse3(disp, 0, dest, task, action, arg,
3196 					  idp, resp, sockmgr));
3197 }
3198 
3199 isc_result_t
3200 dns_dispatch_addresponse3(dns_dispatch_t *disp, unsigned int options,
3201 			  isc_sockaddr_t *dest, isc_task_t *task,
3202 			  isc_taskaction_t action, void *arg,
3203 			  dns_messageid_t *idp, dns_dispentry_t **resp,
3204 			  isc_socketmgr_t *sockmgr)
3205 {
3206 	dns_dispentry_t *res;
3207 	unsigned int bucket;
3208 	in_port_t localport = 0;
3209 	dns_messageid_t id;
3210 	int i;
3211 	isc_boolean_t ok;
3212 	dns_qid_t *qid;
3213 	dispsocket_t *dispsocket = NULL;
3214 	isc_result_t result;
3215 
3216 	REQUIRE(VALID_DISPATCH(disp));
3217 	REQUIRE(task != NULL);
3218 	REQUIRE(dest != NULL);
3219 	REQUIRE(resp != NULL && *resp == NULL);
3220 	REQUIRE(idp != NULL);
3221 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
3222 		REQUIRE(sockmgr != NULL);
3223 
3224 	LOCK(&disp->lock);
3225 
3226 	if (disp->shutting_down == 1) {
3227 		UNLOCK(&disp->lock);
3228 		return (ISC_R_SHUTTINGDOWN);
3229 	}
3230 
3231 	if (disp->requests >= disp->maxrequests) {
3232 		UNLOCK(&disp->lock);
3233 		return (ISC_R_QUOTA);
3234 	}
3235 
3236 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
3237 	    disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) {
3238 		dispsocket_t *oldestsocket;
3239 		dns_dispentry_t *oldestresp;
3240 		dns_dispatchevent_t *rev;
3241 
3242 		/*
3243 		 * Kill oldest outstanding query if the number of sockets
3244 		 * exceeds the quota to keep the room for new queries.
3245 		 */
3246 		oldestsocket = ISC_LIST_HEAD(disp->activesockets);
3247 		oldestresp = oldestsocket->resp;
3248 		if (oldestresp != NULL && !oldestresp->item_out) {
3249 			rev = allocate_devent(oldestresp->disp);
3250 			if (rev != NULL) {
3251 				rev->buffer.base = NULL;
3252 				rev->result = ISC_R_CANCELED;
3253 				rev->id = oldestresp->id;
3254 				ISC_EVENT_INIT(rev, sizeof(*rev), 0,
3255 					       NULL, DNS_EVENT_DISPATCH,
3256 					       oldestresp->action,
3257 					       oldestresp->arg, oldestresp,
3258 					       NULL, NULL);
3259 				oldestresp->item_out = ISC_TRUE;
3260 				isc_task_send(oldestresp->task,
3261 					      ISC_EVENT_PTR(&rev));
3262 				inc_stats(disp->mgr,
3263 					  dns_resstatscounter_dispabort);
3264 			}
3265 		}
3266 
3267 		/*
3268 		 * Move this entry to the tail so that it won't (easily) be
3269 		 * examined before actually being canceled.
3270 		 */
3271 		ISC_LIST_UNLINK(disp->activesockets, oldestsocket, link);
3272 		ISC_LIST_APPEND(disp->activesockets, oldestsocket, link);
3273 	}
3274 
3275 	qid = DNS_QID(disp);
3276 
3277 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
3278 		/*
3279 		 * Get a separate UDP socket with a random port number.
3280 		 */
3281 		result = get_dispsocket(disp, dest, sockmgr, &dispsocket,
3282 					&localport);
3283 		if (result != ISC_R_SUCCESS) {
3284 			UNLOCK(&disp->lock);
3285 			inc_stats(disp->mgr, dns_resstatscounter_dispsockfail);
3286 			return (result);
3287 		}
3288 	} else {
3289 		localport = disp->localport;
3290 	}
3291 
3292 	/*
3293 	 * Try somewhat hard to find an unique ID unless FIXEDID is set
3294 	 * in which case we use the id passed in via *idp.
3295 	 */
3296 	LOCK(&qid->lock);
3297 	if ((options & DNS_DISPATCHOPT_FIXEDID) != 0)
3298 		id = *idp;
3299 	else
3300 		id = (dns_messageid_t)dispatch_random(DISP_ARC4CTX(disp));
3301 	ok = ISC_FALSE;
3302 	i = 0;
3303 	do {
3304 		bucket = dns_hash(qid, dest, id, localport);
3305 		if (entry_search(qid, dest, id, localport, bucket) == NULL) {
3306 			ok = ISC_TRUE;
3307 			break;
3308 		}
3309 		if ((disp->attributes & DNS_DISPATCHATTR_FIXEDID) != 0)
3310 			break;
3311 		id += qid->qid_increment;
3312 		id &= 0x0000ffff;
3313 	} while (i++ < 64);
3314 	UNLOCK(&qid->lock);
3315 
3316 	if (!ok) {
3317 		UNLOCK(&disp->lock);
3318 		return (ISC_R_NOMORE);
3319 	}
3320 
3321 	res = isc_mempool_get(disp->mgr->rpool);
3322 	if (res == NULL) {
3323 		if (dispsocket != NULL)
3324 			destroy_dispsocket(disp, &dispsocket);
3325 		UNLOCK(&disp->lock);
3326 		return (ISC_R_NOMEMORY);
3327 	}
3328 
3329 	disp->refcount++;
3330 	disp->requests++;
3331 	res->task = NULL;
3332 	isc_task_attach(task, &res->task);
3333 	res->disp = disp;
3334 	res->id = id;
3335 	res->port = localport;
3336 	res->bucket = bucket;
3337 	res->host = *dest;
3338 	res->action = action;
3339 	res->arg = arg;
3340 	res->dispsocket = dispsocket;
3341 	if (dispsocket != NULL)
3342 		dispsocket->resp = res;
3343 	res->item_out = ISC_FALSE;
3344 	ISC_LIST_INIT(res->items);
3345 	ISC_LINK_INIT(res, link);
3346 	res->magic = RESPONSE_MAGIC;
3347 
3348 	LOCK(&qid->lock);
3349 	ISC_LIST_APPEND(qid->qid_table[bucket], res, link);
3350 	UNLOCK(&qid->lock);
3351 
3352 	inc_stats(disp->mgr, (qid == disp->mgr->qid) ?
3353 			     dns_resstatscounter_disprequdp :
3354 			     dns_resstatscounter_dispreqtcp);
3355 
3356 	request_log(disp, res, LVL(90),
3357 		    "attached to task %p", res->task);
3358 
3359 	if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) ||
3360 	    ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0)) {
3361 		result = startrecv(disp, dispsocket);
3362 		if (result != ISC_R_SUCCESS) {
3363 			LOCK(&qid->lock);
3364 			ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
3365 			UNLOCK(&qid->lock);
3366 
3367 			if (dispsocket != NULL)
3368 				destroy_dispsocket(disp, &dispsocket);
3369 
3370 			disp->refcount--;
3371 			disp->requests--;
3372 
3373 			dec_stats(disp->mgr, (qid == disp->mgr->qid) ?
3374 					     dns_resstatscounter_disprequdp :
3375 					     dns_resstatscounter_dispreqtcp);
3376 
3377 			UNLOCK(&disp->lock);
3378 			isc_task_detach(&res->task);
3379 			isc_mempool_put(disp->mgr->rpool, res);
3380 			return (result);
3381 		}
3382 	}
3383 
3384 	if (dispsocket != NULL)
3385 		ISC_LIST_APPEND(disp->activesockets, dispsocket, link);
3386 
3387 	UNLOCK(&disp->lock);
3388 
3389 	*idp = id;
3390 	*resp = res;
3391 
3392 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
3393 		INSIST(res->dispsocket != NULL);
3394 
3395 	return (ISC_R_SUCCESS);
3396 }
3397 
3398 isc_result_t
3399 dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
3400 			 isc_task_t *task, isc_taskaction_t action, void *arg,
3401 			 dns_messageid_t *idp, dns_dispentry_t **resp)
3402 {
3403 	REQUIRE(VALID_DISPATCH(disp));
3404 	REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0);
3405 
3406 	return (dns_dispatch_addresponse3(disp, 0, dest, task, action, arg,
3407 					  idp, resp, NULL));
3408 }
3409 
3410 void
3411 dns_dispatch_starttcp(dns_dispatch_t *disp) {
3412 
3413 	REQUIRE(VALID_DISPATCH(disp));
3414 
3415 	dispatch_log(disp, LVL(90), "starttcp %p", disp->task[0]);
3416 
3417 	LOCK(&disp->lock);
3418 	disp->attributes |= DNS_DISPATCHATTR_CONNECTED;
3419 	(void)startrecv(disp, NULL);
3420 	UNLOCK(&disp->lock);
3421 }
3422 
3423 void
3424 dns_dispatch_removeresponse(dns_dispentry_t **resp,
3425 			    dns_dispatchevent_t **sockevent)
3426 {
3427 	dns_dispatchmgr_t *mgr;
3428 	dns_dispatch_t *disp;
3429 	dns_dispentry_t *res;
3430 	dispsocket_t *dispsock;
3431 	dns_dispatchevent_t *ev;
3432 	unsigned int bucket;
3433 	isc_boolean_t killit;
3434 	unsigned int n;
3435 	isc_eventlist_t events;
3436 	dns_qid_t *qid;
3437 
3438 	REQUIRE(resp != NULL);
3439 	REQUIRE(VALID_RESPONSE(*resp));
3440 
3441 	res = *resp;
3442 	*resp = NULL;
3443 
3444 	disp = res->disp;
3445 	REQUIRE(VALID_DISPATCH(disp));
3446 	mgr = disp->mgr;
3447 	REQUIRE(VALID_DISPATCHMGR(mgr));
3448 
3449 	qid = DNS_QID(disp);
3450 
3451 	if (sockevent != NULL) {
3452 		REQUIRE(*sockevent != NULL);
3453 		ev = *sockevent;
3454 		*sockevent = NULL;
3455 	} else {
3456 		ev = NULL;
3457 	}
3458 
3459 	LOCK(&disp->lock);
3460 
3461 	INSIST(disp->requests > 0);
3462 	disp->requests--;
3463 	dec_stats(disp->mgr, (qid == disp->mgr->qid) ?
3464 			     dns_resstatscounter_disprequdp :
3465 			     dns_resstatscounter_dispreqtcp);
3466 	INSIST(disp->refcount > 0);
3467 	disp->refcount--;
3468 	if (disp->refcount == 0) {
3469 		if (disp->recv_pending > 0)
3470 			isc_socket_cancel(disp->socket, disp->task[0],
3471 					  ISC_SOCKCANCEL_RECV);
3472 		for (dispsock = ISC_LIST_HEAD(disp->activesockets);
3473 		     dispsock != NULL;
3474 		     dispsock = ISC_LIST_NEXT(dispsock, link)) {
3475 			isc_socket_cancel(dispsock->socket, dispsock->task,
3476 					  ISC_SOCKCANCEL_RECV);
3477 		}
3478 		disp->shutting_down = 1;
3479 	}
3480 
3481 	bucket = res->bucket;
3482 
3483 	LOCK(&qid->lock);
3484 	ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
3485 	UNLOCK(&qid->lock);
3486 
3487 	if (ev == NULL && res->item_out) {
3488 		/*
3489 		 * We've posted our event, but the caller hasn't gotten it
3490 		 * yet.  Take it back.
3491 		 */
3492 		ISC_LIST_INIT(events);
3493 		n = isc_task_unsend(res->task, res, DNS_EVENT_DISPATCH,
3494 				    NULL, &events);
3495 		/*
3496 		 * We had better have gotten it back.
3497 		 */
3498 		INSIST(n == 1);
3499 		ev = (dns_dispatchevent_t *)ISC_LIST_HEAD(events);
3500 	}
3501 
3502 	if (ev != NULL) {
3503 		REQUIRE(res->item_out == ISC_TRUE);
3504 		res->item_out = ISC_FALSE;
3505 		if (ev->buffer.base != NULL)
3506 			free_buffer(disp, ev->buffer.base, ev->buffer.length);
3507 		free_devent(disp, ev);
3508 	}
3509 
3510 	request_log(disp, res, LVL(90), "detaching from task %p", res->task);
3511 	isc_task_detach(&res->task);
3512 
3513 	if (res->dispsocket != NULL) {
3514 		isc_socket_cancel(res->dispsocket->socket,
3515 				  res->dispsocket->task, ISC_SOCKCANCEL_RECV);
3516 		res->dispsocket->resp = NULL;
3517 	}
3518 
3519 	/*
3520 	 * Free any buffered requests as well
3521 	 */
3522 	ev = ISC_LIST_HEAD(res->items);
3523 	while (ev != NULL) {
3524 		ISC_LIST_UNLINK(res->items, ev, ev_link);
3525 		if (ev->buffer.base != NULL)
3526 			free_buffer(disp, ev->buffer.base, ev->buffer.length);
3527 		free_devent(disp, ev);
3528 		ev = ISC_LIST_HEAD(res->items);
3529 	}
3530 	res->magic = 0;
3531 	isc_mempool_put(disp->mgr->rpool, res);
3532 	if (disp->shutting_down == 1)
3533 		do_cancel(disp);
3534 	else
3535 		(void)startrecv(disp, NULL);
3536 
3537 	killit = destroy_disp_ok(disp);
3538 	UNLOCK(&disp->lock);
3539 	if (killit)
3540 		isc_task_send(disp->task[0], &disp->ctlevent);
3541 }
3542 
3543 static void
3544 do_cancel(dns_dispatch_t *disp) {
3545 	dns_dispatchevent_t *ev;
3546 	dns_dispentry_t *resp;
3547 	dns_qid_t *qid;
3548 
3549 	if (disp->shutdown_out == 1)
3550 		return;
3551 
3552 	qid = DNS_QID(disp);
3553 
3554 	/*
3555 	 * Search for the first response handler without packets outstanding
3556 	 * unless a specific hander is given.
3557 	 */
3558 	LOCK(&qid->lock);
3559 	for (resp = linear_first(qid);
3560 	     resp != NULL && resp->item_out;
3561 	     /* Empty. */)
3562 		resp = linear_next(qid, resp);
3563 
3564 	/*
3565 	 * No one to send the cancel event to, so nothing to do.
3566 	 */
3567 	if (resp == NULL)
3568 		goto unlock;
3569 
3570 	/*
3571 	 * Send the shutdown failsafe event to this resp.
3572 	 */
3573 	ev = disp->failsafe_ev;
3574 	ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH,
3575 		       resp->action, resp->arg, resp, NULL, NULL);
3576 	ev->result = disp->shutdown_why;
3577 	ev->buffer.base = NULL;
3578 	ev->buffer.length = 0;
3579 	disp->shutdown_out = 1;
3580 	request_log(disp, resp, LVL(10),
3581 		    "cancel: failsafe event %p -> task %p",
3582 		    ev, resp->task);
3583 	resp->item_out = ISC_TRUE;
3584 	isc_task_send(resp->task, ISC_EVENT_PTR(&ev));
3585  unlock:
3586 	UNLOCK(&qid->lock);
3587 }
3588 
3589 isc_socket_t *
3590 dns_dispatch_getsocket(dns_dispatch_t *disp) {
3591 	REQUIRE(VALID_DISPATCH(disp));
3592 
3593 	return (disp->socket);
3594 }
3595 
3596 isc_socket_t *
3597 dns_dispatch_getentrysocket(dns_dispentry_t *resp) {
3598 	REQUIRE(VALID_RESPONSE(resp));
3599 
3600 	if (resp->dispsocket != NULL)
3601 		return (resp->dispsocket->socket);
3602 	else
3603 		return (NULL);
3604 }
3605 
3606 isc_result_t
3607 dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) {
3608 
3609 	REQUIRE(VALID_DISPATCH(disp));
3610 	REQUIRE(addrp != NULL);
3611 
3612 	if (disp->socktype == isc_sockettype_udp) {
3613 		*addrp = disp->local;
3614 		return (ISC_R_SUCCESS);
3615 	}
3616 	return (ISC_R_NOTIMPLEMENTED);
3617 }
3618 
3619 void
3620 dns_dispatch_cancel(dns_dispatch_t *disp) {
3621 	REQUIRE(VALID_DISPATCH(disp));
3622 
3623 	LOCK(&disp->lock);
3624 
3625 	if (disp->shutting_down == 1) {
3626 		UNLOCK(&disp->lock);
3627 		return;
3628 	}
3629 
3630 	disp->shutdown_why = ISC_R_CANCELED;
3631 	disp->shutting_down = 1;
3632 	do_cancel(disp);
3633 
3634 	UNLOCK(&disp->lock);
3635 
3636 	return;
3637 }
3638 
3639 unsigned int
3640 dns_dispatch_getattributes(dns_dispatch_t *disp) {
3641 	REQUIRE(VALID_DISPATCH(disp));
3642 
3643 	/*
3644 	 * We don't bother locking disp here; it's the caller's responsibility
3645 	 * to use only non volatile flags.
3646 	 */
3647 	return (disp->attributes);
3648 }
3649 
3650 void
3651 dns_dispatch_changeattributes(dns_dispatch_t *disp,
3652 			      unsigned int attributes, unsigned int mask)
3653 {
3654 	REQUIRE(VALID_DISPATCH(disp));
3655 	/* Exclusive attribute can only be set on creation */
3656 	REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0);
3657 	/* Also, a dispatch with randomport specified cannot start listening */
3658 	REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0 ||
3659 		(attributes & DNS_DISPATCHATTR_NOLISTEN) == 0);
3660 
3661 	/* XXXMLG
3662 	 * Should check for valid attributes here!
3663 	 */
3664 
3665 	LOCK(&disp->lock);
3666 
3667 	if ((mask & DNS_DISPATCHATTR_NOLISTEN) != 0) {
3668 		if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 &&
3669 		    (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) {
3670 			disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN;
3671 			(void)startrecv(disp, NULL);
3672 		} else if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN)
3673 			   == 0 &&
3674 			   (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) {
3675 			disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
3676 			if (disp->recv_pending != 0)
3677 				isc_socket_cancel(disp->socket, disp->task[0],
3678 						  ISC_SOCKCANCEL_RECV);
3679 		}
3680 	}
3681 
3682 	disp->attributes &= ~mask;
3683 	disp->attributes |= (attributes & mask);
3684 	UNLOCK(&disp->lock);
3685 }
3686 
3687 void
3688 dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) {
3689 	void *buf;
3690 	isc_socketevent_t *sevent, *newsevent;
3691 
3692 	REQUIRE(VALID_DISPATCH(disp));
3693 	REQUIRE((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0);
3694 	REQUIRE(event != NULL);
3695 
3696 	sevent = (isc_socketevent_t *)event;
3697 
3698 	INSIST(sevent->n <= disp->mgr->buffersize);
3699 	newsevent = (isc_socketevent_t *)
3700 		    isc_event_allocate(disp->mgr->mctx, NULL,
3701 				      DNS_EVENT_IMPORTRECVDONE, udp_shrecv,
3702 				      disp, sizeof(isc_socketevent_t));
3703 	if (newsevent == NULL)
3704 		return;
3705 
3706 	buf = allocate_udp_buffer(disp);
3707 	if (buf == NULL) {
3708 		isc_event_free(ISC_EVENT_PTR(&newsevent));
3709 		return;
3710 	}
3711 	memmove(buf, sevent->region.base, sevent->n);
3712 	newsevent->region.base = buf;
3713 	newsevent->region.length = disp->mgr->buffersize;
3714 	newsevent->n = sevent->n;
3715 	newsevent->result = sevent->result;
3716 	newsevent->address = sevent->address;
3717 	newsevent->timestamp = sevent->timestamp;
3718 	newsevent->pktinfo = sevent->pktinfo;
3719 	newsevent->attributes = sevent->attributes;
3720 
3721 	isc_task_send(disp->task[0], ISC_EVENT_PTR(&newsevent));
3722 }
3723 
3724 dns_dispatch_t *
3725 dns_dispatchset_get(dns_dispatchset_t *dset) {
3726 	dns_dispatch_t *disp;
3727 
3728 	/* check that dispatch set is configured */
3729 	if (dset == NULL || dset->ndisp == 0)
3730 		return (NULL);
3731 
3732 	LOCK(&dset->lock);
3733 	disp = dset->dispatches[dset->cur];
3734 	dset->cur++;
3735 	if (dset->cur == dset->ndisp)
3736 		dset->cur = 0;
3737 	UNLOCK(&dset->lock);
3738 
3739 	return (disp);
3740 }
3741 
3742 isc_result_t
3743 dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr,
3744 		       isc_taskmgr_t *taskmgr, dns_dispatch_t *source,
3745 		       dns_dispatchset_t **dsetp, int n)
3746 {
3747 	isc_result_t result;
3748 	dns_dispatchset_t *dset;
3749 	dns_dispatchmgr_t *mgr;
3750 	int i, j;
3751 
3752 	REQUIRE(VALID_DISPATCH(source));
3753 	REQUIRE((source->attributes & DNS_DISPATCHATTR_UDP) != 0);
3754 	REQUIRE(dsetp != NULL && *dsetp == NULL);
3755 
3756 	mgr = source->mgr;
3757 
3758 	dset = isc_mem_get(mctx, sizeof(dns_dispatchset_t));
3759 	if (dset == NULL)
3760 		return (ISC_R_NOMEMORY);
3761 	memset(dset, 0, sizeof(*dset));
3762 
3763 	result = isc_mutex_init(&dset->lock);
3764 	if (result != ISC_R_SUCCESS)
3765 		goto fail_alloc;
3766 
3767 	dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n);
3768 	if (dset->dispatches == NULL) {
3769 		result = ISC_R_NOMEMORY;
3770 		goto fail_lock;
3771 	}
3772 
3773 	isc_mem_attach(mctx, &dset->mctx);
3774 	dset->ndisp = n;
3775 	dset->cur = 0;
3776 
3777 	dset->dispatches[0] = NULL;
3778 	dns_dispatch_attach(source, &dset->dispatches[0]);
3779 
3780 	LOCK(&mgr->lock);
3781 	for (i = 1; i < n; i++) {
3782 		dset->dispatches[i] = NULL;
3783 		result = dispatch_createudp(mgr, sockmgr, taskmgr,
3784 					    &source->local,
3785 					    source->maxrequests,
3786 					    source->attributes,
3787 					    &dset->dispatches[i],
3788 					    source->socket);
3789 		if (result != ISC_R_SUCCESS)
3790 			goto fail;
3791 	}
3792 
3793 	UNLOCK(&mgr->lock);
3794 	*dsetp = dset;
3795 
3796 	return (ISC_R_SUCCESS);
3797 
3798  fail:
3799 	UNLOCK(&mgr->lock);
3800 
3801 	for (j = 0; j < i; j++)
3802 		dns_dispatch_detach(&(dset->dispatches[j]));
3803 	isc_mem_put(mctx, dset->dispatches, sizeof(dns_dispatch_t *) * n);
3804 	if (dset->mctx == mctx)
3805 		isc_mem_detach(&dset->mctx);
3806 
3807  fail_lock:
3808 	DESTROYLOCK(&dset->lock);
3809 
3810  fail_alloc:
3811 	isc_mem_put(mctx, dset, sizeof(dns_dispatchset_t));
3812 	return (result);
3813 }
3814 
3815 void
3816 dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task) {
3817 	int i;
3818 
3819 	REQUIRE(dset != NULL);
3820 
3821 	for (i = 0; i < dset->ndisp; i++) {
3822 		isc_socket_t *sock;
3823 		sock = dns_dispatch_getsocket(dset->dispatches[i]);
3824 		isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
3825 	}
3826 }
3827 
3828 void
3829 dns_dispatchset_destroy(dns_dispatchset_t **dsetp) {
3830 	dns_dispatchset_t *dset;
3831 	int i;
3832 
3833 	REQUIRE(dsetp != NULL && *dsetp != NULL);
3834 
3835 	dset = *dsetp;
3836 	for (i = 0; i < dset->ndisp; i++)
3837 		dns_dispatch_detach(&(dset->dispatches[i]));
3838 	isc_mem_put(dset->mctx, dset->dispatches,
3839 		    sizeof(dns_dispatch_t *) * dset->ndisp);
3840 	DESTROYLOCK(&dset->lock);
3841 	isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t));
3842 
3843 	*dsetp = NULL;
3844 }
3845 
3846 void
3847 dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp) {
3848 	REQUIRE(VALID_DISPATCH(disp));
3849 	disp->dscp = dscp;
3850 }
3851 
3852 isc_dscp_t
3853 dns_dispatch_getdscp(dns_dispatch_t *disp) {
3854 	REQUIRE(VALID_DISPATCH(disp));
3855 	return (disp->dscp);
3856 }
3857 
3858 #if 0
3859 void
3860 dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) {
3861 	dns_dispatch_t *disp;
3862 	char foo[1024];
3863 
3864 	disp = ISC_LIST_HEAD(mgr->list);
3865 	while (disp != NULL) {
3866 		isc_sockaddr_format(&disp->local, foo, sizeof(foo));
3867 		printf("\tdispatch %p, addr %s\n", disp, foo);
3868 		disp = ISC_LIST_NEXT(disp, link);
3869 	}
3870 }
3871 #endif
3872