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