Merge from vendor branch FILE:
[dragonfly.git] / contrib / bind-9.3 / lib / dns / dispatch.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and 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.101.2.6.2.10 2004/09/01 04:27:41 marka Exp $ */
19
20 #include <config.h>
21
22 #include <stdlib.h>
23
24 #include <isc/entropy.h>
25 #include <isc/lfsr.h>
26 #include <isc/mem.h>
27 #include <isc/mutex.h>
28 #include <isc/print.h>
29 #include <isc/string.h>
30 #include <isc/task.h>
31 #include <isc/util.h>
32
33 #include <dns/acl.h>
34 #include <dns/dispatch.h>
35 #include <dns/events.h>
36 #include <dns/log.h>
37 #include <dns/message.h>
38 #include <dns/portlist.h>
39 #include <dns/tcpmsg.h>
40 #include <dns/types.h>
41
42 typedef ISC_LIST(dns_dispentry_t)       dns_displist_t;
43
44 typedef struct dns_qid {
45         unsigned int    magic;
46         unsigned int    qid_nbuckets;   /* hash table size */
47         unsigned int    qid_increment;  /* id increment on collision */
48         isc_mutex_t     lock;
49         isc_lfsr_t      qid_lfsr1;      /* state generator info */
50         isc_lfsr_t      qid_lfsr2;      /* state generator info */
51         dns_displist_t  *qid_table;     /* the table itself */
52 } dns_qid_t;
53
54 struct dns_dispatchmgr {
55         /* Unlocked. */
56         unsigned int                    magic;
57         isc_mem_t                      *mctx;
58         dns_acl_t                      *blackhole;
59         dns_portlist_t                 *portlist;
60
61         /* Locked by "lock". */
62         isc_mutex_t                     lock;
63         unsigned int                    state;
64         ISC_LIST(dns_dispatch_t)        list;
65
66         /* locked by buffer lock */
67         dns_qid_t                       *qid;
68         isc_mutex_t                     buffer_lock;
69         unsigned int                    buffers;    /* allocated buffers */
70         unsigned int                    buffersize; /* size of each buffer */
71         unsigned int                    maxbuffers; /* max buffers */
72
73         /* Locked internally. */
74         isc_mutex_t                     pool_lock;
75         isc_mempool_t                  *epool;  /* memory pool for events */
76         isc_mempool_t                  *rpool;  /* memory pool for replies */
77         isc_mempool_t                  *dpool;  /* dispatch allocations */
78         isc_mempool_t                  *bpool;  /* memory pool for buffers */
79
80         isc_entropy_t                  *entropy; /* entropy source */
81 };
82
83 #define MGR_SHUTTINGDOWN                0x00000001U
84 #define MGR_IS_SHUTTINGDOWN(l)  (((l)->state & MGR_SHUTTINGDOWN) != 0)
85
86 #define IS_PRIVATE(d)   (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0)
87
88 struct dns_dispentry {
89         unsigned int                    magic;
90         dns_dispatch_t                 *disp;
91         dns_messageid_t                 id;
92         unsigned int                    bucket;
93         isc_sockaddr_t                  host;
94         isc_task_t                     *task;
95         isc_taskaction_t                action;
96         void                           *arg;
97         isc_boolean_t                   item_out;
98         ISC_LIST(dns_dispatchevent_t)   items;
99         ISC_LINK(dns_dispentry_t)       link;
100 };
101
102 #define INVALID_BUCKET          (0xffffdead)
103
104 struct dns_dispatch {
105         /* Unlocked. */
106         unsigned int            magic;          /* magic */
107         dns_dispatchmgr_t      *mgr;            /* dispatch manager */
108         isc_task_t             *task;           /* internal task */
109         isc_socket_t           *socket;         /* isc socket attached to */
110         isc_sockaddr_t          local;          /* local address */
111         unsigned int            maxrequests;    /* max requests */
112         isc_event_t            *ctlevent;
113
114         /* Locked by mgr->lock. */
115         ISC_LINK(dns_dispatch_t) link;
116
117         /* Locked by "lock". */
118         isc_mutex_t             lock;           /* locks all below */
119         isc_sockettype_t        socktype;
120         unsigned int            attributes;
121         unsigned int            refcount;       /* number of users */
122         dns_dispatchevent_t    *failsafe_ev;    /* failsafe cancel event */
123         unsigned int            shutting_down : 1,
124                                 shutdown_out : 1,
125                                 connected : 1,
126                                 tcpmsg_valid : 1,
127                                 recv_pending : 1; /* is a recv() pending? */
128         isc_result_t            shutdown_why;
129         unsigned int            requests;       /* how many requests we have */
130         unsigned int            tcpbuffers;     /* allocated buffers */
131         dns_tcpmsg_t            tcpmsg;         /* for tcp streams */
132         dns_qid_t               *qid;
133 };
134
135 #define QID_MAGIC               ISC_MAGIC('Q', 'i', 'd', ' ')
136 #define VALID_QID(e)            ISC_MAGIC_VALID((e), QID_MAGIC)
137
138 #define RESPONSE_MAGIC          ISC_MAGIC('D', 'r', 's', 'p')
139 #define VALID_RESPONSE(e)       ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
140
141 #define DISPATCH_MAGIC          ISC_MAGIC('D', 'i', 's', 'p')
142 #define VALID_DISPATCH(e)       ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
143
144 #define DNS_DISPATCHMGR_MAGIC   ISC_MAGIC('D', 'M', 'g', 'r')
145 #define VALID_DISPATCHMGR(e)    ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC)
146
147 #define DNS_QID(disp) ((disp)->socktype == isc_sockettype_tcp) ? \
148                        (disp)->qid : (disp)->mgr->qid
149 /*
150  * Statics.
151  */
152 static dns_dispentry_t *bucket_search(dns_qid_t *, isc_sockaddr_t *,
153                                       dns_messageid_t, unsigned int);
154 static isc_boolean_t destroy_disp_ok(dns_dispatch_t *);
155 static void destroy_disp(isc_task_t *task, isc_event_t *event);
156 static void udp_recv(isc_task_t *, isc_event_t *);
157 static void tcp_recv(isc_task_t *, isc_event_t *);
158 static void startrecv(dns_dispatch_t *);
159 static dns_messageid_t dns_randomid(dns_qid_t *);
160 static isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t);
161 static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
162 static void *allocate_udp_buffer(dns_dispatch_t *disp);
163 static inline void free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
164 static inline dns_dispatchevent_t *allocate_event(dns_dispatch_t *disp);
165 static void do_cancel(dns_dispatch_t *disp);
166 static dns_dispentry_t *linear_first(dns_qid_t *disp);
167 static dns_dispentry_t *linear_next(dns_qid_t *disp,
168                                     dns_dispentry_t *resp);
169 static void dispatch_free(dns_dispatch_t **dispp);
170 static isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr,
171                                        isc_socketmgr_t *sockmgr,
172                                        isc_taskmgr_t *taskmgr,
173                                        isc_sockaddr_t *localaddr,
174                                        unsigned int maxrequests,
175                                        unsigned int attributes,
176                                        dns_dispatch_t **dispp);
177 static isc_boolean_t destroy_mgr_ok(dns_dispatchmgr_t *mgr);
178 static void destroy_mgr(dns_dispatchmgr_t **mgrp);
179 static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
180                                  unsigned int increment, dns_qid_t **qidp);
181 static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
182
183 #define LVL(x) ISC_LOG_DEBUG(x)
184
185 static void
186 mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...)
187      ISC_FORMAT_PRINTF(3, 4);
188
189 static void
190 mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) {
191         char msgbuf[2048];
192         va_list ap;
193
194         if (! isc_log_wouldlog(dns_lctx, level))
195                 return;
196
197         va_start(ap, fmt);
198         vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
199         va_end(ap);
200
201         isc_log_write(dns_lctx,
202                       DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
203                       level, "dispatchmgr %p: %s", mgr, msgbuf);
204 }
205
206 static void
207 dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...)
208      ISC_FORMAT_PRINTF(3, 4);
209
210 static void
211 dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) {
212         char msgbuf[2048];
213         va_list ap;
214
215         if (! isc_log_wouldlog(dns_lctx, level))
216                 return;
217
218         va_start(ap, fmt);
219         vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
220         va_end(ap);
221
222         isc_log_write(dns_lctx,
223                       DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
224                       level, "dispatch %p: %s", disp, msgbuf);
225 }
226
227 static void
228 request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
229             int level, const char *fmt, ...)
230      ISC_FORMAT_PRINTF(4, 5);
231
232 static void
233 request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
234             int level, const char *fmt, ...)
235 {
236         char msgbuf[2048];
237         char peerbuf[256];
238         va_list ap;
239
240         if (! isc_log_wouldlog(dns_lctx, level))
241                 return;
242
243         va_start(ap, fmt);
244         vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
245         va_end(ap);
246
247         if (VALID_RESPONSE(resp)) {
248                 isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf));
249                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
250                               DNS_LOGMODULE_DISPATCH, level,
251                               "dispatch %p response %p %s: %s", disp, resp,
252                               peerbuf, msgbuf);
253         } else {
254                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
255                               DNS_LOGMODULE_DISPATCH, level,
256                               "dispatch %p req/resp %p: %s", disp, resp,
257                               msgbuf);
258         }
259 }
260
261 static void
262 reseed_lfsr(isc_lfsr_t *lfsr, void *arg)
263 {
264         dns_dispatchmgr_t *mgr = arg;
265         isc_result_t result;
266         isc_uint32_t val;
267
268         REQUIRE(VALID_DISPATCHMGR(mgr));
269
270         if (mgr->entropy != NULL) {
271                 result = isc_entropy_getdata(mgr->entropy, &val, sizeof(val),
272                                              NULL, 0);
273                 INSIST(result == ISC_R_SUCCESS);
274                 lfsr->count = (val & 0x1f) + 32;
275                 lfsr->state = val;
276                 return;
277         }
278
279         lfsr->count = (random() & 0x1f) + 32;   /* From 32 to 63 states */
280         lfsr->state = random();
281 }
282
283 /*
284  * Return an unpredictable message ID.
285  */
286 static dns_messageid_t
287 dns_randomid(dns_qid_t *qid) {
288         isc_uint32_t id;
289
290         id = isc_lfsr_generate32(&qid->qid_lfsr1, &qid->qid_lfsr2);
291
292         return (dns_messageid_t)(id & 0xFFFF);
293 }
294
295 /*
296  * Return a hash of the destination and message id.
297  */
298 static isc_uint32_t
299 dns_hash(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id) {
300         unsigned int ret;
301
302         ret = isc_sockaddr_hash(dest, ISC_TRUE);
303         ret ^= id;
304         ret %= qid->qid_nbuckets;
305
306         INSIST(ret < qid->qid_nbuckets);
307
308         return (ret);
309 }
310
311 /*
312  * Find the first entry in 'qid'.  Returns NULL if there are no entries.
313  */
314 static dns_dispentry_t *
315 linear_first(dns_qid_t *qid) {
316         dns_dispentry_t *ret;
317         unsigned int bucket;
318
319         bucket = 0;
320
321         while (bucket < qid->qid_nbuckets) {
322                 ret = ISC_LIST_HEAD(qid->qid_table[bucket]);
323                 if (ret != NULL)
324                         return (ret);
325                 bucket++;
326         }
327
328         return (NULL);
329 }
330
331 /*
332  * Find the next entry after 'resp' in 'qid'.  Return NULL if there are
333  * no more entries.
334  */
335 static dns_dispentry_t *
336 linear_next(dns_qid_t *qid, dns_dispentry_t *resp) {
337         dns_dispentry_t *ret;
338         unsigned int bucket;
339
340         ret = ISC_LIST_NEXT(resp, link);
341         if (ret != NULL)
342                 return (ret);
343
344         bucket = resp->bucket;
345         bucket++;
346         while (bucket < qid->qid_nbuckets) {
347                 ret = ISC_LIST_HEAD(qid->qid_table[bucket]);
348                 if (ret != NULL)
349                         return (ret);
350                 bucket++;
351         }
352
353         return (NULL);
354 }
355
356 /*
357  * The dispatch must be locked.
358  */
359 static isc_boolean_t
360 destroy_disp_ok(dns_dispatch_t *disp)
361 {
362         if (disp->refcount != 0)
363                 return (ISC_FALSE);
364
365         if (disp->recv_pending != 0)
366                 return (ISC_FALSE);
367
368         if (disp->shutting_down == 0)
369                 return (ISC_FALSE);
370
371         return (ISC_TRUE);
372 }
373
374
375 /*
376  * Called when refcount reaches 0 (and safe to destroy).
377  *
378  * The dispatcher must not be locked.
379  * The manager must be locked.
380  */
381 static void
382 destroy_disp(isc_task_t *task, isc_event_t *event) {
383         dns_dispatch_t *disp;
384         dns_dispatchmgr_t *mgr;
385         isc_boolean_t killmgr;
386
387         INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL);
388
389         UNUSED(task);
390
391         disp = event->ev_arg;
392         mgr = disp->mgr;
393
394         LOCK(&mgr->lock);
395         ISC_LIST_UNLINK(mgr->list, disp, link);
396
397         dispatch_log(disp, LVL(90),
398                      "shutting down; detaching from sock %p, task %p",
399                      disp->socket, disp->task);
400
401         isc_socket_detach(&disp->socket);
402         isc_task_detach(&disp->task);
403         isc_event_free(&event);
404
405         dispatch_free(&disp);
406
407         killmgr = destroy_mgr_ok(mgr);
408         UNLOCK(&mgr->lock);
409         if (killmgr)
410                 destroy_mgr(&mgr);
411 }
412
413
414 /*
415  * Find an entry for query ID 'id' and socket address 'dest' in 'qid'.
416  * Return NULL if no such entry exists.
417  */
418 static dns_dispentry_t *
419 bucket_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
420               unsigned int bucket)
421 {
422         dns_dispentry_t *res;
423
424         REQUIRE(bucket < qid->qid_nbuckets);
425
426         res = ISC_LIST_HEAD(qid->qid_table[bucket]);
427
428         while (res != NULL) {
429                 if ((res->id == id) && isc_sockaddr_equal(dest, &res->host))
430                         return (res);
431                 res = ISC_LIST_NEXT(res, link);
432         }
433
434         return (NULL);
435 }
436
437 static void
438 free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
439         INSIST(buf != NULL && len != 0);
440
441
442         switch (disp->socktype) {
443         case isc_sockettype_tcp:
444                 INSIST(disp->tcpbuffers > 0);
445                 disp->tcpbuffers--;
446                 isc_mem_put(disp->mgr->mctx, buf, len);
447                 break;
448         case isc_sockettype_udp:
449                 LOCK(&disp->mgr->buffer_lock);
450                 INSIST(disp->mgr->buffers > 0);
451                 INSIST(len == disp->mgr->buffersize);
452                 disp->mgr->buffers--;
453                 isc_mempool_put(disp->mgr->bpool, buf);
454                 UNLOCK(&disp->mgr->buffer_lock);
455                 break;
456         default:
457                 INSIST(0);
458                 break;
459         }
460 }
461
462 static void *
463 allocate_udp_buffer(dns_dispatch_t *disp) {
464         void *temp;
465
466         LOCK(&disp->mgr->buffer_lock);
467         temp = isc_mempool_get(disp->mgr->bpool);
468
469         if (temp != NULL)
470                 disp->mgr->buffers++;
471         UNLOCK(&disp->mgr->buffer_lock);
472
473         return (temp);
474 }
475
476 static inline void
477 free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
478         if (disp->failsafe_ev == ev) {
479                 INSIST(disp->shutdown_out == 1);
480                 disp->shutdown_out = 0;
481
482                 return;
483         }
484
485         isc_mempool_put(disp->mgr->epool, ev);
486 }
487
488 static inline dns_dispatchevent_t *
489 allocate_event(dns_dispatch_t *disp) {
490         dns_dispatchevent_t *ev;
491
492         ev = isc_mempool_get(disp->mgr->epool);
493         if (ev == NULL)
494                 return (NULL);
495         ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0,
496                        NULL, NULL, NULL, NULL, NULL);
497
498         return (ev);
499 }
500
501 /*
502  * General flow:
503  *
504  * If I/O result == CANCELED or error, free the buffer.
505  *
506  * If query, free the buffer, restart.
507  *
508  * If response:
509  *      Allocate event, fill in details.
510  *              If cannot allocate, free buffer, restart.
511  *      find target.  If not found, free buffer, restart.
512  *      if event queue is not empty, queue.  else, send.
513  *      restart.
514  */
515 static void
516 udp_recv(isc_task_t *task, isc_event_t *ev_in) {
517         isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
518         dns_dispatch_t *disp = ev_in->ev_arg;
519         dns_messageid_t id;
520         isc_result_t dres;
521         isc_buffer_t source;
522         unsigned int flags;
523         dns_dispentry_t *resp;
524         dns_dispatchevent_t *rev;
525         unsigned int bucket;
526         isc_boolean_t killit;
527         isc_boolean_t queue_response;
528         dns_dispatchmgr_t *mgr;
529         dns_qid_t *qid;
530         isc_netaddr_t netaddr;
531         int match;
532
533         UNUSED(task);
534
535         LOCK(&disp->lock);
536
537         mgr = disp->mgr;
538         qid = mgr->qid;
539
540         dispatch_log(disp, LVL(90),
541                      "got packet: requests %d, buffers %d, recvs %d",
542                      disp->requests, disp->mgr->buffers, disp->recv_pending);
543
544         if (ev->ev_type == ISC_SOCKEVENT_RECVDONE) {
545                 /*
546                  * Unless the receive event was imported from a listening
547                  * interface, in which case the event type is
548                  * DNS_EVENT_IMPORTRECVDONE, receive operation must be pending.
549                  */
550                 INSIST(disp->recv_pending != 0);
551                 disp->recv_pending = 0;
552         }
553
554         if (disp->shutting_down) {
555                 /*
556                  * This dispatcher is shutting down.
557                  */
558                 free_buffer(disp, ev->region.base, ev->region.length);
559
560                 isc_event_free(&ev_in);
561                 ev = NULL;
562
563                 killit = destroy_disp_ok(disp);
564                 UNLOCK(&disp->lock);
565                 if (killit)
566                         isc_task_send(disp->task, &disp->ctlevent);
567
568                 return;
569         }
570
571         if (ev->result != ISC_R_SUCCESS) {
572                 free_buffer(disp, ev->region.base, ev->region.length);
573
574                 if (ev->result != ISC_R_CANCELED)
575                         dispatch_log(disp, ISC_LOG_ERROR,
576                                      "odd socket result in udp_recv(): %s",
577                                      isc_result_totext(ev->result));
578
579                 UNLOCK(&disp->lock);
580                 isc_event_free(&ev_in);
581                 return;
582         }
583
584         /*
585          * If this is from a blackholed address, drop it.
586          */
587         isc_netaddr_fromsockaddr(&netaddr, &ev->address);
588         if (disp->mgr->blackhole != NULL &&
589             dns_acl_match(&netaddr, NULL, disp->mgr->blackhole,
590                           NULL, &match, NULL) == ISC_R_SUCCESS &&
591             match > 0)
592         {
593                 if (isc_log_wouldlog(dns_lctx, LVL(10))) {
594                         char netaddrstr[ISC_NETADDR_FORMATSIZE];
595                         isc_netaddr_format(&netaddr, netaddrstr,
596                                            sizeof(netaddrstr));
597                         dispatch_log(disp, LVL(10),
598                                      "blackholed packet from %s",
599                                      netaddrstr);
600                 }
601                 free_buffer(disp, ev->region.base, ev->region.length);
602                 goto restart;
603         }
604
605         /*
606          * Peek into the buffer to see what we can see.
607          */
608         isc_buffer_init(&source, ev->region.base, ev->region.length);
609         isc_buffer_add(&source, ev->n);
610         dres = dns_message_peekheader(&source, &id, &flags);
611         if (dres != ISC_R_SUCCESS) {
612                 free_buffer(disp, ev->region.base, ev->region.length);
613                 dispatch_log(disp, LVL(10), "got garbage packet");
614                 goto restart;
615         }
616
617         dispatch_log(disp, LVL(92),
618                      "got valid DNS message header, /QR %c, id %u",
619                      ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id);
620
621         /*
622          * Look at flags.  If query, drop it. If response,
623          * look to see where it goes.
624          */
625         queue_response = ISC_FALSE;
626         if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
627                 /* query */
628                 free_buffer(disp, ev->region.base, ev->region.length);
629                 goto restart;
630         }
631
632         /* response */
633         bucket = dns_hash(qid, &ev->address, id);
634         LOCK(&qid->lock);
635         resp = bucket_search(qid, &ev->address, id, bucket);
636         dispatch_log(disp, LVL(90),
637                      "search for response in bucket %d: %s",
638                      bucket, (resp == NULL ? "not found" : "found"));
639
640         if (resp == NULL) {
641                 free_buffer(disp, ev->region.base, ev->region.length);
642                 goto unlock;
643         } 
644         queue_response = resp->item_out;
645         rev = allocate_event(resp->disp);
646         if (rev == NULL) {
647                 free_buffer(disp, ev->region.base, ev->region.length);
648                 goto unlock;
649         }
650
651         /*
652          * At this point, rev contains the event we want to fill in, and
653          * resp contains the information on the place to send it to.
654          * Send the event off.
655          */
656         isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length);
657         isc_buffer_add(&rev->buffer, ev->n);
658         rev->result = ISC_R_SUCCESS;
659         rev->id = id;
660         rev->addr = ev->address;
661         rev->pktinfo = ev->pktinfo;
662         rev->attributes = ev->attributes;
663         if (queue_response) {
664                 ISC_LIST_APPEND(resp->items, rev, ev_link);
665         } else {
666                 ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL,
667                                DNS_EVENT_DISPATCH,
668                                resp->action, resp->arg, resp, NULL, NULL);
669                 request_log(disp, resp, LVL(90),
670                             "[a] Sent event %p buffer %p len %d to task %p",
671                             rev, rev->buffer.base, rev->buffer.length,
672                             resp->task);
673                 resp->item_out = ISC_TRUE;
674                 isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
675         }
676  unlock:
677         UNLOCK(&qid->lock);
678
679         /*
680          * Restart recv() to get the next packet.
681          */
682  restart:
683         startrecv(disp);
684
685         UNLOCK(&disp->lock);
686
687         isc_event_free(&ev_in);
688 }
689
690 /*
691  * General flow:
692  *
693  * If I/O result == CANCELED, EOF, or error, notify everyone as the
694  * various queues drain.
695  *
696  * If query, restart.
697  *
698  * If response:
699  *      Allocate event, fill in details.
700  *              If cannot allocate, restart.
701  *      find target.  If not found, restart.
702  *      if event queue is not empty, queue.  else, send.
703  *      restart.
704  */
705 static void
706 tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
707         dns_dispatch_t *disp = ev_in->ev_arg;
708         dns_tcpmsg_t *tcpmsg = &disp->tcpmsg;
709         dns_messageid_t id;
710         isc_result_t dres;
711         unsigned int flags;
712         dns_dispentry_t *resp;
713         dns_dispatchevent_t *rev;
714         unsigned int bucket;
715         isc_boolean_t killit;
716         isc_boolean_t queue_response;
717         dns_qid_t *qid;
718         int level;
719         char buf[ISC_SOCKADDR_FORMATSIZE];
720
721         UNUSED(task);
722
723         REQUIRE(VALID_DISPATCH(disp));
724
725         qid = disp->qid;
726
727         dispatch_log(disp, LVL(90),
728                      "got TCP packet: requests %d, buffers %d, recvs %d",
729                      disp->requests, disp->tcpbuffers, disp->recv_pending);
730
731         LOCK(&disp->lock);
732
733         INSIST(disp->recv_pending != 0);
734         disp->recv_pending = 0;
735
736         if (disp->refcount == 0) {
737                 /*
738                  * This dispatcher is shutting down.  Force cancelation.
739                  */
740                 tcpmsg->result = ISC_R_CANCELED;
741         }
742
743         if (tcpmsg->result != ISC_R_SUCCESS) {
744                 switch (tcpmsg->result) {
745                 case ISC_R_CANCELED:
746                         break;
747                         
748                 case ISC_R_EOF:
749                         dispatch_log(disp, LVL(90), "shutting down on EOF");
750                         do_cancel(disp);
751                         break;
752
753                 case ISC_R_CONNECTIONRESET:
754                         level = ISC_LOG_INFO;
755                         goto logit;
756
757                 default:
758                         level = ISC_LOG_ERROR;
759                 logit:
760                         isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf));
761                         dispatch_log(disp, level, "shutting down due to TCP "
762                                      "receive error: %s: %s", buf,
763                                      isc_result_totext(tcpmsg->result));
764                         do_cancel(disp);
765                         break;
766                 }
767
768                 /*
769                  * The event is statically allocated in the tcpmsg
770                  * structure, and destroy_disp() frees the tcpmsg, so we must
771                  * free the event *before* calling destroy_disp().
772                  */
773                 isc_event_free(&ev_in);
774
775                 disp->shutting_down = 1;
776                 disp->shutdown_why = tcpmsg->result;
777
778                 /*
779                  * If the recv() was canceled pass the word on.
780                  */
781                 killit = destroy_disp_ok(disp);
782                 UNLOCK(&disp->lock);
783                 if (killit)
784                         isc_task_send(disp->task, &disp->ctlevent);
785                 return;
786         }
787
788         dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p",
789                      tcpmsg->result,
790                      tcpmsg->buffer.length, tcpmsg->buffer.base);
791
792         /*
793          * Peek into the buffer to see what we can see.
794          */
795         dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags);
796         if (dres != ISC_R_SUCCESS) {
797                 dispatch_log(disp, LVL(10), "got garbage packet");
798                 goto restart;
799         }
800
801         dispatch_log(disp, LVL(92),
802                      "got valid DNS message header, /QR %c, id %u",
803                      ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id);
804
805         /*
806          * Allocate an event to send to the query or response client, and
807          * allocate a new buffer for our use.
808          */
809
810         /*
811          * Look at flags.  If query, drop it. If response,
812          * look to see where it goes.
813          */
814         queue_response = ISC_FALSE;
815         if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
816                 /*
817                  * Query.
818                  */
819                 goto restart;
820         }
821
822         /*
823          * Response.
824          */
825         bucket = dns_hash(qid, &tcpmsg->address, id);
826         LOCK(&qid->lock);
827         resp = bucket_search(qid, &tcpmsg->address, id, bucket);
828         dispatch_log(disp, LVL(90),
829                      "search for response in bucket %d: %s",
830                      bucket, (resp == NULL ? "not found" : "found"));
831
832         if (resp == NULL)
833                 goto unlock;
834         queue_response = resp->item_out;
835         rev = allocate_event(disp);
836         if (rev == NULL)
837                 goto unlock;
838
839         /*
840          * At this point, rev contains the event we want to fill in, and
841          * resp contains the information on the place to send it to.
842          * Send the event off.
843          */
844         dns_tcpmsg_keepbuffer(tcpmsg, &rev->buffer);
845         disp->tcpbuffers++;
846         rev->result = ISC_R_SUCCESS;
847         rev->id = id;
848         rev->addr = tcpmsg->address;
849         if (queue_response) {
850                 ISC_LIST_APPEND(resp->items, rev, ev_link);
851         } else {
852                 ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH,
853                                resp->action, resp->arg, resp, NULL, NULL);
854                 request_log(disp, resp, LVL(90),
855                             "[b] Sent event %p buffer %p len %d to task %p",
856                             rev, rev->buffer.base, rev->buffer.length,
857                             resp->task);
858                 resp->item_out = ISC_TRUE;
859                 isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
860         }
861  unlock:
862         UNLOCK(&qid->lock);
863
864         /*
865          * Restart recv() to get the next packet.
866          */
867  restart:
868         startrecv(disp);
869
870         UNLOCK(&disp->lock);
871
872         isc_event_free(&ev_in);
873 }
874
875 /*
876  * disp must be locked.
877  */
878 static void
879 startrecv(dns_dispatch_t *disp) {
880         isc_result_t res;
881         isc_region_t region;
882
883         if (disp->shutting_down == 1)
884                 return;
885
886         if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
887                 return;
888
889         if (disp->recv_pending != 0)
890                 return;
891
892         if (disp->mgr->buffers >= disp->mgr->maxbuffers)
893                 return;
894
895         switch (disp->socktype) {
896                 /*
897                  * UDP reads are always maximal.
898                  */
899         case isc_sockettype_udp:
900                 region.length = disp->mgr->buffersize;
901                 region.base = allocate_udp_buffer(disp);
902                 if (region.base == NULL)
903                         return;
904                 res = isc_socket_recv(disp->socket, &region, 1,
905                                       disp->task, udp_recv, disp);
906                 if (res != ISC_R_SUCCESS) {
907                         free_buffer(disp, region.base, region.length);
908                         disp->shutdown_why = res;
909                         disp->shutting_down = 1;
910                         do_cancel(disp);
911                         return;
912                 }
913                 INSIST(disp->recv_pending == 0);
914                 disp->recv_pending = 1;
915                 break;
916
917         case isc_sockettype_tcp:
918                 res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task,
919                                              tcp_recv, disp);
920                 if (res != ISC_R_SUCCESS) {
921                         disp->shutdown_why = res;
922                         disp->shutting_down = 1;
923                         do_cancel(disp);
924                         return;
925                 }
926                 INSIST(disp->recv_pending == 0);
927                 disp->recv_pending = 1;
928                 break;
929         }
930 }
931
932 /*
933  * Mgr must be locked when calling this function.
934  */
935 static isc_boolean_t
936 destroy_mgr_ok(dns_dispatchmgr_t *mgr) {
937         mgr_log(mgr, LVL(90),
938                 "destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, "
939                 "epool=%d, rpool=%d, dpool=%d",
940                 MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list),
941                 isc_mempool_getallocated(mgr->epool),
942                 isc_mempool_getallocated(mgr->rpool),
943                 isc_mempool_getallocated(mgr->dpool));
944         if (!MGR_IS_SHUTTINGDOWN(mgr))
945                 return (ISC_FALSE);
946         if (!ISC_LIST_EMPTY(mgr->list))
947                 return (ISC_FALSE);
948         if (isc_mempool_getallocated(mgr->epool) != 0)
949                 return (ISC_FALSE);
950         if (isc_mempool_getallocated(mgr->rpool) != 0)
951                 return (ISC_FALSE);
952         if (isc_mempool_getallocated(mgr->dpool) != 0)
953                 return (ISC_FALSE);
954
955         return (ISC_TRUE);
956 }
957
958 /*
959  * Mgr must be unlocked when calling this function.
960  */
961 static void
962 destroy_mgr(dns_dispatchmgr_t **mgrp) {
963         isc_mem_t *mctx;
964         dns_dispatchmgr_t *mgr;
965
966         mgr = *mgrp;
967         *mgrp = NULL;
968
969         mctx = mgr->mctx;
970
971         mgr->magic = 0;
972         mgr->mctx = NULL;
973         DESTROYLOCK(&mgr->lock);
974         mgr->state = 0;
975
976         isc_mempool_destroy(&mgr->epool);
977         isc_mempool_destroy(&mgr->rpool);
978         isc_mempool_destroy(&mgr->dpool);
979         isc_mempool_destroy(&mgr->bpool);
980
981         DESTROYLOCK(&mgr->pool_lock);
982
983         if (mgr->entropy != NULL)
984                 isc_entropy_detach(&mgr->entropy);
985         if (mgr->qid != NULL)
986                 qid_destroy(mctx, &mgr->qid);
987
988         DESTROYLOCK(&mgr->buffer_lock);
989
990         if (mgr->blackhole != NULL)
991                 dns_acl_detach(&mgr->blackhole);
992
993         if (mgr->portlist != NULL)
994                 dns_portlist_detach(&mgr->portlist);
995
996         isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
997         isc_mem_detach(&mctx);
998 }
999
1000 static isc_result_t
1001 create_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
1002               isc_socket_t **sockp)
1003 {
1004         isc_socket_t *sock;
1005         isc_result_t result;
1006
1007         sock = NULL;
1008         result = isc_socket_create(mgr, isc_sockaddr_pf(local),
1009                                    isc_sockettype_udp, &sock);
1010         if (result != ISC_R_SUCCESS)
1011                 return (result);
1012
1013 #ifndef ISC_ALLOW_MAPPED
1014         isc_socket_ipv6only(sock, ISC_TRUE);
1015 #endif
1016         result = isc_socket_bind(sock, local);
1017         if (result != ISC_R_SUCCESS) {
1018                 isc_socket_detach(&sock);
1019                 return (result);
1020         }
1021
1022         *sockp = sock;
1023         return (ISC_R_SUCCESS);
1024 }
1025
1026 /*
1027  * Publics.
1028  */
1029
1030 isc_result_t
1031 dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
1032                        dns_dispatchmgr_t **mgrp)
1033 {
1034         dns_dispatchmgr_t *mgr;
1035         isc_result_t result;
1036
1037         REQUIRE(mctx != NULL);
1038         REQUIRE(mgrp != NULL && *mgrp == NULL);
1039
1040         mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
1041         if (mgr == NULL)
1042                 return (ISC_R_NOMEMORY);
1043
1044         mgr->mctx = NULL;
1045         isc_mem_attach(mctx, &mgr->mctx);
1046
1047         mgr->blackhole = NULL;
1048         mgr->portlist = NULL;
1049
1050         result = isc_mutex_init(&mgr->lock);
1051         if (result != ISC_R_SUCCESS)
1052                 goto deallocate;
1053
1054         result = isc_mutex_init(&mgr->buffer_lock);
1055         if (result != ISC_R_SUCCESS)
1056                 goto kill_lock;
1057
1058         result = isc_mutex_init(&mgr->pool_lock);
1059         if (result != ISC_R_SUCCESS)
1060                 goto kill_buffer_lock;
1061
1062         mgr->epool = NULL;
1063         if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t),
1064                                &mgr->epool) != ISC_R_SUCCESS) {
1065                 result = ISC_R_NOMEMORY;
1066                 goto kill_pool_lock;
1067         }
1068
1069         mgr->rpool = NULL;
1070         if (isc_mempool_create(mgr->mctx, sizeof(dns_dispentry_t),
1071                                &mgr->rpool) != ISC_R_SUCCESS) {
1072                 result = ISC_R_NOMEMORY;
1073                 goto kill_epool;
1074         }
1075
1076         mgr->dpool = NULL;
1077         if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatch_t),
1078                                &mgr->dpool) != ISC_R_SUCCESS) {
1079                 result = ISC_R_NOMEMORY;
1080                 goto kill_rpool;
1081         }
1082
1083         isc_mempool_setname(mgr->epool, "dispmgr_epool");
1084         isc_mempool_setfreemax(mgr->epool, 1024);
1085         isc_mempool_associatelock(mgr->epool, &mgr->pool_lock);
1086
1087         isc_mempool_setname(mgr->rpool, "dispmgr_rpool");
1088         isc_mempool_setfreemax(mgr->rpool, 1024);
1089         isc_mempool_associatelock(mgr->rpool, &mgr->pool_lock);
1090
1091         isc_mempool_setname(mgr->dpool, "dispmgr_dpool");
1092         isc_mempool_setfreemax(mgr->dpool, 1024);
1093         isc_mempool_associatelock(mgr->dpool, &mgr->pool_lock);
1094
1095         mgr->buffers = 0;
1096         mgr->buffersize = 0;
1097         mgr->maxbuffers = 0;
1098         mgr->bpool = NULL;
1099         mgr->entropy = NULL;
1100         mgr->qid = NULL;
1101         mgr->state = 0;
1102         ISC_LIST_INIT(mgr->list);
1103         mgr->magic = DNS_DISPATCHMGR_MAGIC;
1104
1105         if (entropy != NULL)
1106                 isc_entropy_attach(entropy, &mgr->entropy);
1107
1108         *mgrp = mgr;
1109         return (ISC_R_SUCCESS);
1110
1111  kill_rpool:
1112         isc_mempool_destroy(&mgr->rpool);
1113  kill_epool:
1114         isc_mempool_destroy(&mgr->epool);
1115  kill_pool_lock:
1116         DESTROYLOCK(&mgr->pool_lock);
1117  kill_buffer_lock:
1118         DESTROYLOCK(&mgr->buffer_lock);
1119  kill_lock:
1120         DESTROYLOCK(&mgr->lock);
1121  deallocate:
1122         isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
1123         isc_mem_detach(&mctx);
1124
1125         return (result);
1126 }
1127
1128 void
1129 dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) {
1130         REQUIRE(VALID_DISPATCHMGR(mgr));
1131         if (mgr->blackhole != NULL)
1132                 dns_acl_detach(&mgr->blackhole);
1133         dns_acl_attach(blackhole, &mgr->blackhole);
1134 }
1135
1136 dns_acl_t *
1137 dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) {
1138         REQUIRE(VALID_DISPATCHMGR(mgr));
1139         return (mgr->blackhole);
1140 }
1141
1142 void
1143 dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr,
1144                                  dns_portlist_t *portlist)
1145 {
1146         REQUIRE(VALID_DISPATCHMGR(mgr));
1147         if (mgr->portlist != NULL)
1148                 dns_portlist_detach(&mgr->portlist);
1149         if (portlist != NULL)
1150                 dns_portlist_attach(portlist, &mgr->portlist);
1151 }
1152
1153 dns_portlist_t *
1154 dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) {
1155         REQUIRE(VALID_DISPATCHMGR(mgr));
1156         return (mgr->portlist);
1157 }
1158
1159 static isc_result_t
1160 dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
1161                         unsigned int buffersize, unsigned int maxbuffers,
1162                         unsigned int buckets, unsigned int increment)
1163 {
1164         isc_result_t result;
1165
1166         REQUIRE(VALID_DISPATCHMGR(mgr));
1167         REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
1168         REQUIRE(maxbuffers > 0);
1169         REQUIRE(buckets < 2097169);  /* next prime > 65536 * 32 */
1170         REQUIRE(increment > buckets);
1171
1172         /*
1173          * Keep some number of items around.  This should be a config
1174          * option.  For now, keep 8, but later keep at least two even
1175          * if the caller wants less.  This allows us to ensure certain
1176          * things, like an event can be "freed" and the next allocation
1177          * will always succeed.
1178          *
1179          * Note that if limits are placed on anything here, we use one
1180          * event internally, so the actual limit should be "wanted + 1."
1181          *
1182          * XXXMLG
1183          */
1184
1185         if (maxbuffers < 8)
1186                 maxbuffers = 8;
1187
1188         LOCK(&mgr->buffer_lock);
1189         if (mgr->bpool != NULL) {
1190                 isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
1191                 mgr->maxbuffers = maxbuffers;
1192                 UNLOCK(&mgr->buffer_lock);
1193                 return (ISC_R_SUCCESS);
1194         }
1195
1196         if (isc_mempool_create(mgr->mctx, buffersize,
1197                                &mgr->bpool) != ISC_R_SUCCESS) {
1198                 return (ISC_R_NOMEMORY);
1199         }
1200
1201         isc_mempool_setname(mgr->bpool, "dispmgr_bpool");
1202         isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
1203         isc_mempool_associatelock(mgr->bpool, &mgr->pool_lock);
1204
1205         result = qid_allocate(mgr, buckets, increment, &mgr->qid);
1206         if (result != ISC_R_SUCCESS)
1207                 goto cleanup;
1208
1209         mgr->buffersize = buffersize;
1210         mgr->maxbuffers = maxbuffers;
1211         UNLOCK(&mgr->buffer_lock);
1212         return (ISC_R_SUCCESS);
1213
1214  cleanup:
1215         isc_mempool_destroy(&mgr->bpool);
1216         UNLOCK(&mgr->buffer_lock);
1217         return (ISC_R_NOMEMORY);
1218 }
1219
1220 void
1221 dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) {
1222         dns_dispatchmgr_t *mgr;
1223         isc_boolean_t killit;
1224
1225         REQUIRE(mgrp != NULL);
1226         REQUIRE(VALID_DISPATCHMGR(*mgrp));
1227
1228         mgr = *mgrp;
1229         *mgrp = NULL;
1230
1231         LOCK(&mgr->lock);
1232         mgr->state |= MGR_SHUTTINGDOWN;
1233
1234         killit = destroy_mgr_ok(mgr);
1235         UNLOCK(&mgr->lock);
1236
1237         mgr_log(mgr, LVL(90), "destroy: killit=%d", killit);
1238
1239         if (killit)
1240                 destroy_mgr(&mgr);
1241 }
1242
1243 static isc_boolean_t
1244 blacklisted(dns_dispatchmgr_t *mgr, isc_socket_t *sock) {
1245         isc_sockaddr_t sockaddr;
1246         isc_result_t result;
1247
1248         if (mgr->portlist == NULL)
1249                 return (ISC_FALSE);
1250
1251         result = isc_socket_getsockname(sock, &sockaddr);
1252         if (result != ISC_R_SUCCESS)
1253                 return (ISC_FALSE);
1254
1255         if (mgr->portlist != NULL &&
1256             dns_portlist_match(mgr->portlist, isc_sockaddr_pf(&sockaddr),
1257                                isc_sockaddr_getport(&sockaddr)))
1258                 return (ISC_TRUE);
1259         return (ISC_FALSE);
1260 }
1261
1262 #define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))
1263
1264 static isc_boolean_t
1265 local_addr_match(dns_dispatch_t *disp, isc_sockaddr_t *addr) {
1266         isc_sockaddr_t sockaddr;
1267         isc_result_t result;
1268
1269         if (addr == NULL)
1270                 return (ISC_TRUE);
1271
1272         /*
1273          * Don't match wildcard ports against newly blacklisted ports.
1274          */
1275         if (disp->mgr->portlist != NULL &&
1276             isc_sockaddr_getport(addr) == 0 &&
1277             isc_sockaddr_getport(&disp->local) == 0 &&
1278             blacklisted(disp->mgr, disp->socket))
1279                 return (ISC_FALSE);
1280
1281         /*
1282          * Check if we match the binding <address,port>.
1283          * Wildcard ports match/fail here.
1284          */
1285         if (isc_sockaddr_equal(&disp->local, addr))
1286                 return (ISC_TRUE);
1287         if (isc_sockaddr_getport(addr) == 0)
1288                 return (ISC_FALSE);
1289
1290         /*
1291          * Check if we match a bound wildcard port <address,port>.
1292          */
1293         if (!isc_sockaddr_eqaddr(&disp->local, addr))
1294                 return (ISC_FALSE);
1295         result = isc_socket_getsockname(disp->socket, &sockaddr);
1296         if (result != ISC_R_SUCCESS)
1297                 return (ISC_FALSE);
1298
1299         return (isc_sockaddr_equal(&sockaddr, addr));
1300 }
1301
1302 /*
1303  * Requires mgr be locked.
1304  *
1305  * No dispatcher can be locked by this thread when calling this function.
1306  *
1307  *
1308  * NOTE:
1309  *      If a matching dispatcher is found, it is locked after this function
1310  *      returns, and must be unlocked by the caller.
1311  */
1312 static isc_result_t
1313 dispatch_find(dns_dispatchmgr_t *mgr, isc_sockaddr_t *local,
1314               unsigned int attributes, unsigned int mask,
1315               dns_dispatch_t **dispp)
1316 {
1317         dns_dispatch_t *disp;
1318         isc_result_t result;
1319
1320         /*
1321          * Make certain that we will not match a private dispatch.
1322          */
1323         attributes &= ~DNS_DISPATCHATTR_PRIVATE;
1324         mask |= DNS_DISPATCHATTR_PRIVATE;
1325
1326         disp = ISC_LIST_HEAD(mgr->list);
1327         while (disp != NULL) {
1328                 LOCK(&disp->lock);
1329                 if ((disp->shutting_down == 0)
1330                     && ATTRMATCH(disp->attributes, attributes, mask)
1331                     && local_addr_match(disp, local))
1332                         break;
1333                 UNLOCK(&disp->lock);
1334                 disp = ISC_LIST_NEXT(disp, link);
1335         }
1336
1337         if (disp == NULL) {
1338                 result = ISC_R_NOTFOUND;
1339                 goto out;
1340         }
1341
1342         *dispp = disp;
1343         result = ISC_R_SUCCESS;
1344  out:
1345
1346         return (result);
1347 }
1348
1349 static isc_result_t
1350 qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
1351              unsigned int increment, dns_qid_t **qidp)
1352 {
1353         dns_qid_t *qid;
1354         unsigned int i;
1355
1356         REQUIRE(VALID_DISPATCHMGR(mgr));
1357         REQUIRE(buckets < 2097169);  /* next prime > 65536 * 32 */
1358         REQUIRE(increment > buckets);
1359         REQUIRE(qidp != NULL && *qidp == NULL);
1360
1361         qid = isc_mem_get(mgr->mctx, sizeof(*qid));
1362         if (qid == NULL)
1363                 return (ISC_R_NOMEMORY);
1364
1365         qid->qid_table = isc_mem_get(mgr->mctx,
1366                                      buckets * sizeof(dns_displist_t));
1367         if (qid->qid_table == NULL) {
1368                 isc_mem_put(mgr->mctx, qid, sizeof(*qid));
1369                 return (ISC_R_NOMEMORY);
1370         }
1371
1372         if (isc_mutex_init(&qid->lock) != ISC_R_SUCCESS) {
1373                 UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init failed");
1374                 isc_mem_put(mgr->mctx, qid->qid_table,
1375                             buckets * sizeof(dns_displist_t));
1376                 isc_mem_put(mgr->mctx, qid, sizeof(*qid));
1377                 return (ISC_R_UNEXPECTED);
1378         }
1379
1380         for (i = 0; i < buckets; i++)
1381                 ISC_LIST_INIT(qid->qid_table[i]);
1382
1383         qid->qid_nbuckets = buckets;
1384         qid->qid_increment = increment;
1385         qid->magic = QID_MAGIC;
1386
1387         /*
1388          * Initialize to a 32-bit LFSR.  Both of these are from Applied
1389          * Cryptography.
1390          *
1391          * lfsr1:
1392          *      x^32 + x^7 + x^5 + x^3 + x^2 + x + 1
1393          *
1394          * lfsr2:
1395          *      x^32 + x^7 + x^6 + x^2 + 1
1396          */
1397         isc_lfsr_init(&qid->qid_lfsr1, 0, 32, 0x80000057U,
1398                       0, reseed_lfsr, mgr);
1399         isc_lfsr_init(&qid->qid_lfsr2, 0, 32, 0x80000062U,
1400                       0, reseed_lfsr, mgr);
1401         *qidp = qid;
1402         return (ISC_R_SUCCESS);
1403 }
1404
1405 static void
1406 qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
1407         dns_qid_t *qid;
1408
1409         REQUIRE(qidp != NULL);
1410         qid = *qidp;
1411
1412         REQUIRE(VALID_QID(qid));
1413
1414         *qidp = NULL;
1415         qid->magic = 0;
1416         isc_mem_put(mctx, qid->qid_table,
1417                     qid->qid_nbuckets * sizeof(dns_displist_t));
1418         DESTROYLOCK(&qid->lock);
1419         isc_mem_put(mctx, qid, sizeof(*qid));
1420 }
1421
1422 /*
1423  * Allocate and set important limits.
1424  */
1425 static isc_result_t
1426 dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests,
1427                   dns_dispatch_t **dispp)
1428 {
1429         dns_dispatch_t *disp;
1430         isc_result_t res;
1431
1432         REQUIRE(VALID_DISPATCHMGR(mgr));
1433         REQUIRE(dispp != NULL && *dispp == NULL);
1434
1435         /*
1436          * Set up the dispatcher, mostly.  Don't bother setting some of
1437          * the options that are controlled by tcp vs. udp, etc.
1438          */
1439
1440         disp = isc_mempool_get(mgr->dpool);
1441         if (disp == NULL)
1442                 return (ISC_R_NOMEMORY);
1443
1444         disp->magic = 0;
1445         disp->mgr = mgr;
1446         disp->maxrequests = maxrequests;
1447         disp->attributes = 0;
1448         ISC_LINK_INIT(disp, link);
1449         disp->refcount = 1;
1450         disp->recv_pending = 0;
1451         memset(&disp->local, 0, sizeof(disp->local));
1452         disp->shutting_down = 0;
1453         disp->shutdown_out = 0;
1454         disp->connected = 0;
1455         disp->tcpmsg_valid = 0;
1456         disp->shutdown_why = ISC_R_UNEXPECTED;
1457         disp->requests = 0;
1458         disp->tcpbuffers = 0;
1459         disp->qid = NULL;
1460
1461         if (isc_mutex_init(&disp->lock) != ISC_R_SUCCESS) {
1462                 res = ISC_R_UNEXPECTED;
1463                 UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init failed");
1464                 goto deallocate;
1465         }
1466
1467         disp->failsafe_ev = allocate_event(disp);
1468         if (disp->failsafe_ev == NULL) {
1469                 res = ISC_R_NOMEMORY;
1470                 goto kill_lock;
1471         }
1472
1473         disp->magic = DISPATCH_MAGIC;
1474
1475         *dispp = disp;
1476         return (ISC_R_SUCCESS);
1477
1478         /*
1479          * error returns
1480          */
1481  kill_lock:
1482         DESTROYLOCK(&disp->lock);
1483  deallocate:
1484         isc_mempool_put(mgr->dpool, disp);
1485
1486         return (res);
1487 }
1488
1489
1490 /*
1491  * MUST be unlocked, and not used by anthing.
1492  */
1493 static void
1494 dispatch_free(dns_dispatch_t **dispp)
1495 {
1496         dns_dispatch_t *disp;
1497         dns_dispatchmgr_t *mgr;
1498
1499         REQUIRE(VALID_DISPATCH(*dispp));
1500         disp = *dispp;
1501         *dispp = NULL;
1502
1503         mgr = disp->mgr;
1504         REQUIRE(VALID_DISPATCHMGR(mgr));
1505
1506         if (disp->tcpmsg_valid) {
1507                 dns_tcpmsg_invalidate(&disp->tcpmsg);
1508                 disp->tcpmsg_valid = 0;
1509         }
1510
1511         INSIST(disp->tcpbuffers == 0);
1512         INSIST(disp->requests == 0);
1513         INSIST(disp->recv_pending == 0);
1514
1515         isc_mempool_put(mgr->epool, disp->failsafe_ev);
1516         disp->failsafe_ev = NULL;
1517
1518         if (disp->qid != NULL)
1519                 qid_destroy(mgr->mctx, &disp->qid);
1520         disp->mgr = NULL;
1521         DESTROYLOCK(&disp->lock);
1522         disp->magic = 0;
1523         isc_mempool_put(mgr->dpool, disp);
1524 }
1525
1526 isc_result_t
1527 dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
1528                        isc_taskmgr_t *taskmgr, unsigned int buffersize,
1529                        unsigned int maxbuffers, unsigned int maxrequests,
1530                        unsigned int buckets, unsigned int increment,
1531                        unsigned int attributes, dns_dispatch_t **dispp)
1532 {
1533         isc_result_t result;
1534         dns_dispatch_t *disp;
1535
1536         UNUSED(maxbuffers);
1537         UNUSED(buffersize);
1538
1539         REQUIRE(VALID_DISPATCHMGR(mgr));
1540         REQUIRE(isc_socket_gettype(sock) == isc_sockettype_tcp);
1541         REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0);
1542         REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0);
1543
1544         attributes |= DNS_DISPATCHATTR_PRIVATE;  /* XXXMLG */
1545
1546         LOCK(&mgr->lock);
1547
1548         /*
1549          * dispatch_allocate() checks mgr for us.
1550          * qid_allocate() checks buckets and increment for us.
1551          */
1552         disp = NULL;
1553         result = dispatch_allocate(mgr, maxrequests, &disp);
1554         if (result != ISC_R_SUCCESS) {
1555                 UNLOCK(&mgr->lock);
1556                 return (result);
1557         }
1558
1559         result = qid_allocate(mgr, buckets, increment, &disp->qid);
1560         if (result != ISC_R_SUCCESS)
1561                 goto deallocate_dispatch;
1562
1563         disp->socktype = isc_sockettype_tcp;
1564         disp->socket = NULL;
1565         isc_socket_attach(sock, &disp->socket);
1566
1567         disp->task = NULL;
1568         result = isc_task_create(taskmgr, 0, &disp->task);
1569         if (result != ISC_R_SUCCESS)
1570                 goto kill_socket;
1571
1572         disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
1573                                             DNS_EVENT_DISPATCHCONTROL,
1574                                             destroy_disp, disp,
1575                                             sizeof(isc_event_t));
1576         if (disp->ctlevent == NULL)
1577                 goto kill_task;
1578
1579         isc_task_setname(disp->task, "tcpdispatch", disp);
1580
1581         dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg);
1582         disp->tcpmsg_valid = 1;
1583
1584         disp->attributes = attributes;
1585
1586         /*
1587          * Append it to the dispatcher list.
1588          */
1589         ISC_LIST_APPEND(mgr->list, disp, link);
1590         UNLOCK(&mgr->lock);
1591
1592         mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp);
1593         dispatch_log(disp, LVL(90), "created task %p", disp->task);
1594
1595         *dispp = disp;
1596
1597         return (ISC_R_SUCCESS);
1598
1599         /*
1600          * Error returns.
1601          */
1602  kill_task:
1603         isc_task_detach(&disp->task);
1604  kill_socket:
1605         isc_socket_detach(&disp->socket);
1606  deallocate_dispatch:
1607         dispatch_free(&disp);
1608
1609         UNLOCK(&mgr->lock);
1610
1611         return (result);
1612 }
1613
1614 isc_result_t
1615 dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
1616                     isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
1617                     unsigned int buffersize,
1618                     unsigned int maxbuffers, unsigned int maxrequests,
1619                     unsigned int buckets, unsigned int increment,
1620                     unsigned int attributes, unsigned int mask,
1621                     dns_dispatch_t **dispp)
1622 {
1623         isc_result_t result;
1624         dns_dispatch_t *disp;
1625
1626         REQUIRE(VALID_DISPATCHMGR(mgr));
1627         REQUIRE(sockmgr != NULL);
1628         REQUIRE(localaddr != NULL);
1629         REQUIRE(taskmgr != NULL);
1630         REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
1631         REQUIRE(maxbuffers > 0);
1632         REQUIRE(buckets < 2097169);  /* next prime > 65536 * 32 */
1633         REQUIRE(increment > buckets);
1634         REQUIRE(dispp != NULL && *dispp == NULL);
1635         REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0);
1636
1637         result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers,
1638                                         buckets, increment);
1639         if (result != ISC_R_SUCCESS)
1640                 return (result);
1641
1642         LOCK(&mgr->lock);
1643
1644         /*
1645          * First, see if we have a dispatcher that matches.
1646          */
1647         disp = NULL;
1648         result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
1649         if (result == ISC_R_SUCCESS) {
1650                 disp->refcount++;
1651
1652                 if (disp->maxrequests < maxrequests)
1653                         disp->maxrequests = maxrequests;
1654
1655                 if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0 &&
1656                     (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
1657                 {
1658                         disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
1659                         if (disp->recv_pending != 0)
1660                                 isc_socket_cancel(disp->socket, disp->task,
1661                                                   ISC_SOCKCANCEL_RECV);
1662                 }
1663
1664                 UNLOCK(&disp->lock);
1665                 UNLOCK(&mgr->lock);
1666
1667                 *dispp = disp;
1668
1669                 return (ISC_R_SUCCESS);
1670         }
1671
1672         /*
1673          * Nope, create one.
1674          */
1675         result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr,
1676                                     maxrequests, attributes, &disp);
1677         if (result != ISC_R_SUCCESS) {
1678                 UNLOCK(&mgr->lock);
1679                 return (result);
1680         }
1681
1682         UNLOCK(&mgr->lock);
1683         *dispp = disp;
1684         return (ISC_R_SUCCESS);
1685 }
1686
1687 /*
1688  * mgr should be locked.
1689  */
1690 static isc_result_t
1691 dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
1692                    isc_taskmgr_t *taskmgr,
1693                    isc_sockaddr_t *localaddr,
1694                    unsigned int maxrequests,
1695                    unsigned int attributes,
1696                    dns_dispatch_t **dispp)
1697 {
1698         isc_result_t result;
1699         dns_dispatch_t *disp;
1700         isc_socket_t *sock;
1701
1702         /*
1703          * dispatch_allocate() checks mgr for us.
1704          */
1705         disp = NULL;
1706         result = dispatch_allocate(mgr, maxrequests, &disp);
1707         if (result != ISC_R_SUCCESS)
1708                 return (result);
1709
1710         /*
1711          * This assumes that the IP stack will *not* quickly reallocate
1712          * the same port.  If it does continually reallocate the same port
1713          * then we need a mechanism to hold all the blacklisted sockets
1714          * until we find a usable socket.
1715          */
1716  getsocket:
1717         result = create_socket(sockmgr, localaddr, &sock);
1718         if (result != ISC_R_SUCCESS)
1719                 goto deallocate_dispatch;
1720         if (isc_sockaddr_getport(localaddr) == 0 && blacklisted(mgr, sock)) {
1721                 isc_socket_detach(&sock);
1722                 goto getsocket;
1723         }
1724
1725         disp->socktype = isc_sockettype_udp;
1726         disp->socket = sock;
1727         disp->local = *localaddr;
1728
1729         disp->task = NULL;
1730         result = isc_task_create(taskmgr, 0, &disp->task);
1731         if (result != ISC_R_SUCCESS)
1732                 goto kill_socket;
1733
1734         disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
1735                                             DNS_EVENT_DISPATCHCONTROL,
1736                                             destroy_disp, disp,
1737                                             sizeof(isc_event_t));
1738         if (disp->ctlevent == NULL)
1739                 goto kill_task;
1740
1741         isc_task_setname(disp->task, "udpdispatch", disp);
1742
1743         attributes &= ~DNS_DISPATCHATTR_TCP;
1744         attributes |= DNS_DISPATCHATTR_UDP;
1745         disp->attributes = attributes;
1746
1747         /*
1748          * Append it to the dispatcher list.
1749          */
1750         ISC_LIST_APPEND(mgr->list, disp, link);
1751
1752         mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp);
1753         dispatch_log(disp, LVL(90), "created task %p", disp->task);
1754         dispatch_log(disp, LVL(90), "created socket %p", disp->socket);
1755
1756         *dispp = disp;
1757
1758         return (ISC_R_SUCCESS);
1759
1760         /*
1761          * Error returns.
1762          */
1763  kill_task:
1764         isc_task_detach(&disp->task);
1765  kill_socket:
1766         isc_socket_detach(&disp->socket);
1767  deallocate_dispatch:
1768         dispatch_free(&disp);
1769
1770         return (result);
1771 }
1772
1773 void
1774 dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) {
1775         REQUIRE(VALID_DISPATCH(disp));
1776         REQUIRE(dispp != NULL && *dispp == NULL);
1777
1778         LOCK(&disp->lock);
1779         disp->refcount++;
1780         UNLOCK(&disp->lock);
1781
1782         *dispp = disp;
1783 }
1784
1785 /*
1786  * It is important to lock the manager while we are deleting the dispatch,
1787  * since dns_dispatch_getudp will call dispatch_find, which returns to
1788  * the caller a dispatch but does not attach to it until later.  _getudp
1789  * locks the manager, however, so locking it here will keep us from attaching
1790  * to a dispatcher that is in the process of going away.
1791  */
1792 void
1793 dns_dispatch_detach(dns_dispatch_t **dispp) {
1794         dns_dispatch_t *disp;
1795         isc_boolean_t killit;
1796
1797         REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp));
1798
1799         disp = *dispp;
1800         *dispp = NULL;
1801
1802         LOCK(&disp->lock);
1803
1804         INSIST(disp->refcount > 0);
1805         disp->refcount--;
1806         killit = ISC_FALSE;
1807         if (disp->refcount == 0) {
1808                 if (disp->recv_pending > 0)
1809                         isc_socket_cancel(disp->socket, disp->task,
1810                                           ISC_SOCKCANCEL_RECV);
1811                 disp->shutting_down = 1;
1812         }
1813
1814         dispatch_log(disp, LVL(90), "detach: refcount %d", disp->refcount);
1815
1816         killit = destroy_disp_ok(disp);
1817         UNLOCK(&disp->lock);
1818         if (killit)
1819                 isc_task_send(disp->task, &disp->ctlevent);
1820 }
1821
1822 isc_result_t
1823 dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
1824                          isc_task_t *task, isc_taskaction_t action, void *arg,
1825                          dns_messageid_t *idp, dns_dispentry_t **resp)
1826 {
1827         dns_dispentry_t *res;
1828         unsigned int bucket;
1829         dns_messageid_t id;
1830         int i;
1831         isc_boolean_t ok;
1832         dns_qid_t *qid;
1833
1834         REQUIRE(VALID_DISPATCH(disp));
1835         REQUIRE(task != NULL);
1836         REQUIRE(dest != NULL);
1837         REQUIRE(resp != NULL && *resp == NULL);
1838         REQUIRE(idp != NULL);
1839
1840         LOCK(&disp->lock);
1841
1842         if (disp->shutting_down == 1) {
1843                 UNLOCK(&disp->lock);
1844                 return (ISC_R_SHUTTINGDOWN);
1845         }
1846
1847         if (disp->requests >= disp->maxrequests) {
1848                 UNLOCK(&disp->lock);
1849                 return (ISC_R_QUOTA);
1850         }
1851
1852         /*
1853          * Try somewhat hard to find an unique ID.
1854          */
1855         qid = DNS_QID(disp);
1856         LOCK(&qid->lock);
1857         id = dns_randomid(qid);
1858         bucket = dns_hash(qid, dest, id);
1859         ok = ISC_FALSE;
1860         for (i = 0; i < 64; i++) {
1861                 if (bucket_search(qid, dest, id, bucket) == NULL) {
1862                         ok = ISC_TRUE;
1863                         break;
1864                 }
1865                 id += qid->qid_increment;
1866                 id &= 0x0000ffff;
1867                 bucket = dns_hash(qid, dest, id);
1868         }
1869
1870         if (!ok) {
1871                 UNLOCK(&qid->lock);
1872                 UNLOCK(&disp->lock);
1873                 return (ISC_R_NOMORE);
1874         }
1875
1876         res = isc_mempool_get(disp->mgr->rpool);
1877         if (res == NULL) {
1878                 UNLOCK(&qid->lock);
1879                 UNLOCK(&disp->lock);
1880                 return (ISC_R_NOMEMORY);
1881         }
1882
1883         disp->refcount++;
1884         disp->requests++;
1885         res->task = NULL;
1886         isc_task_attach(task, &res->task);
1887         res->disp = disp;
1888         res->id = id;
1889         res->bucket = bucket;
1890         res->host = *dest;
1891         res->action = action;
1892         res->arg = arg;
1893         res->item_out = ISC_FALSE;
1894         ISC_LIST_INIT(res->items);
1895         ISC_LINK_INIT(res, link);
1896         res->magic = RESPONSE_MAGIC;
1897         ISC_LIST_APPEND(qid->qid_table[bucket], res, link);
1898         UNLOCK(&qid->lock);
1899
1900         request_log(disp, res, LVL(90),
1901                     "attached to task %p", res->task);
1902
1903         if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) ||
1904             ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0))
1905                 startrecv(disp);
1906
1907         UNLOCK(&disp->lock);
1908
1909         *idp = id;
1910         *resp = res;
1911
1912         return (ISC_R_SUCCESS);
1913 }
1914
1915 void
1916 dns_dispatch_starttcp(dns_dispatch_t *disp) {
1917
1918         REQUIRE(VALID_DISPATCH(disp));
1919
1920         dispatch_log(disp, LVL(90), "starttcp %p", disp->task);
1921
1922         LOCK(&disp->lock);
1923         disp->attributes |= DNS_DISPATCHATTR_CONNECTED;
1924         startrecv(disp);
1925         UNLOCK(&disp->lock);
1926 }
1927
1928 void
1929 dns_dispatch_removeresponse(dns_dispentry_t **resp,
1930                             dns_dispatchevent_t **sockevent)
1931 {
1932         dns_dispatchmgr_t *mgr;
1933         dns_dispatch_t *disp;
1934         dns_dispentry_t *res;
1935         dns_dispatchevent_t *ev;
1936         unsigned int bucket;
1937         isc_boolean_t killit;
1938         unsigned int n;
1939         isc_eventlist_t events;
1940         dns_qid_t *qid;
1941
1942         REQUIRE(resp != NULL);
1943         REQUIRE(VALID_RESPONSE(*resp));
1944
1945         res = *resp;
1946         *resp = NULL;
1947
1948         disp = res->disp;
1949         REQUIRE(VALID_DISPATCH(disp));
1950         mgr = disp->mgr;
1951         REQUIRE(VALID_DISPATCHMGR(mgr));
1952
1953         qid = DNS_QID(disp);
1954
1955         if (sockevent != NULL) {
1956                 REQUIRE(*sockevent != NULL);
1957                 ev = *sockevent;
1958                 *sockevent = NULL;
1959         } else {
1960                 ev = NULL;
1961         }
1962
1963         LOCK(&disp->lock);
1964
1965         INSIST(disp->requests > 0);
1966         disp->requests--;
1967         INSIST(disp->refcount > 0);
1968         disp->refcount--;
1969         killit = ISC_FALSE;
1970         if (disp->refcount == 0) {
1971                 if (disp->recv_pending > 0)
1972                         isc_socket_cancel(disp->socket, disp->task,
1973                                           ISC_SOCKCANCEL_RECV);
1974                 disp->shutting_down = 1;
1975         }
1976
1977         bucket = res->bucket;
1978
1979         LOCK(&qid->lock);
1980         ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
1981         UNLOCK(&qid->lock);
1982
1983         if (ev == NULL && res->item_out) {
1984                 /*
1985                  * We've posted our event, but the caller hasn't gotten it
1986                  * yet.  Take it back.
1987                  */
1988                 ISC_LIST_INIT(events);
1989                 n = isc_task_unsend(res->task, res, DNS_EVENT_DISPATCH,
1990                                     NULL, &events);
1991                 /*
1992                  * We had better have gotten it back.
1993                  */
1994                 INSIST(n == 1);
1995                 ev = (dns_dispatchevent_t *)ISC_LIST_HEAD(events);
1996         }
1997
1998         if (ev != NULL) {
1999                 REQUIRE(res->item_out == ISC_TRUE);
2000                 res->item_out = ISC_FALSE;
2001                 if (ev->buffer.base != NULL)
2002                         free_buffer(disp, ev->buffer.base, ev->buffer.length);
2003                 free_event(disp, ev);
2004         }
2005
2006         request_log(disp, res, LVL(90), "detaching from task %p", res->task);
2007         isc_task_detach(&res->task);
2008
2009         /*
2010          * Free any buffered requests as well
2011          */
2012         ev = ISC_LIST_HEAD(res->items);
2013         while (ev != NULL) {
2014                 ISC_LIST_UNLINK(res->items, ev, ev_link);
2015                 if (ev->buffer.base != NULL)
2016                         free_buffer(disp, ev->buffer.base, ev->buffer.length);
2017                 free_event(disp, ev);
2018                 ev = ISC_LIST_HEAD(res->items);
2019         }
2020         res->magic = 0;
2021         isc_mempool_put(disp->mgr->rpool, res);
2022         if (disp->shutting_down == 1)
2023                 do_cancel(disp);
2024         else
2025                 startrecv(disp);
2026
2027         killit = destroy_disp_ok(disp);
2028         UNLOCK(&disp->lock);
2029         if (killit)
2030                 isc_task_send(disp->task, &disp->ctlevent);
2031 }
2032
2033 static void
2034 do_cancel(dns_dispatch_t *disp) {
2035         dns_dispatchevent_t *ev;
2036         dns_dispentry_t *resp;
2037         dns_qid_t *qid;
2038
2039         if (disp->shutdown_out == 1)
2040                 return;
2041
2042         qid = DNS_QID(disp);
2043
2044         /*
2045          * Search for the first response handler without packets outstanding.
2046          */
2047         LOCK(&qid->lock);
2048         for (resp = linear_first(qid);
2049              resp != NULL && resp->item_out != ISC_FALSE;
2050              /* Empty. */)
2051                 resp = linear_next(qid, resp);
2052         /*
2053          * No one to send the cancel event to, so nothing to do.
2054          */
2055         if (resp == NULL)
2056                 goto unlock;
2057
2058         /*
2059          * Send the shutdown failsafe event to this resp.
2060          */
2061         ev = disp->failsafe_ev;
2062         ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH,
2063                        resp->action, resp->arg, resp, NULL, NULL);
2064         ev->result = disp->shutdown_why;
2065         ev->buffer.base = NULL;
2066         ev->buffer.length = 0;
2067         disp->shutdown_out = 1;
2068         request_log(disp, resp, LVL(10),
2069                     "cancel: failsafe event %p -> task %p",
2070                     ev, resp->task);
2071         resp->item_out = ISC_TRUE;
2072         isc_task_send(resp->task, ISC_EVENT_PTR(&ev));
2073  unlock:
2074         UNLOCK(&qid->lock);
2075 }
2076
2077 isc_socket_t *
2078 dns_dispatch_getsocket(dns_dispatch_t *disp) {
2079         REQUIRE(VALID_DISPATCH(disp));
2080
2081         return (disp->socket);
2082 }
2083
2084 isc_result_t
2085 dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) {
2086
2087         REQUIRE(VALID_DISPATCH(disp));
2088         REQUIRE(addrp != NULL);
2089
2090         if (disp->socktype == isc_sockettype_udp) {
2091                 *addrp = disp->local;
2092                 return (ISC_R_SUCCESS);
2093         }
2094         return (ISC_R_NOTIMPLEMENTED);
2095 }
2096
2097 void
2098 dns_dispatch_cancel(dns_dispatch_t *disp) {
2099         REQUIRE(VALID_DISPATCH(disp));
2100
2101         LOCK(&disp->lock);
2102
2103         if (disp->shutting_down == 1) {
2104                 UNLOCK(&disp->lock);
2105                 return;
2106         }
2107
2108         disp->shutdown_why = ISC_R_CANCELED;
2109         disp->shutting_down = 1;
2110         do_cancel(disp);
2111
2112         UNLOCK(&disp->lock);
2113
2114         return;
2115 }
2116
2117 void
2118 dns_dispatch_changeattributes(dns_dispatch_t *disp,
2119                               unsigned int attributes, unsigned int mask)
2120 {
2121         REQUIRE(VALID_DISPATCH(disp));
2122
2123         /* XXXMLG
2124          * Should check for valid attributes here!
2125          */
2126
2127         LOCK(&disp->lock);
2128
2129         if ((mask & DNS_DISPATCHATTR_NOLISTEN) != 0) {
2130                 if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 &&
2131                     (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) {
2132                         disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN;
2133                         startrecv(disp);
2134                 } else if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN)
2135                            == 0 &&
2136                            (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) {
2137                         disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
2138                         if (disp->recv_pending != 0)
2139                                 isc_socket_cancel(disp->socket, disp->task,
2140                                                   ISC_SOCKCANCEL_RECV);
2141                 }
2142         }
2143
2144         disp->attributes &= ~mask;
2145         disp->attributes |= (attributes & mask);
2146         UNLOCK(&disp->lock);
2147 }
2148
2149 void
2150 dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) {
2151         void *buf;
2152         isc_socketevent_t *sevent, *newsevent;
2153
2154         REQUIRE(VALID_DISPATCH(disp));
2155         REQUIRE((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0);
2156         REQUIRE(event != NULL);
2157
2158         sevent = (isc_socketevent_t *)event;
2159
2160         INSIST(sevent->n <= disp->mgr->buffersize);
2161         newsevent = (isc_socketevent_t *)
2162                     isc_event_allocate(disp->mgr->mctx, NULL,
2163                                       DNS_EVENT_IMPORTRECVDONE, udp_recv,
2164                                       disp, sizeof(isc_socketevent_t));
2165         if (newsevent == NULL)
2166                 return;
2167
2168         buf = allocate_udp_buffer(disp);
2169         if (buf == NULL) {
2170                 isc_event_free(ISC_EVENT_PTR(&newsevent));
2171                 return;
2172         }
2173         memcpy(buf, sevent->region.base, sevent->n);
2174         newsevent->region.base = buf;
2175         newsevent->region.length = disp->mgr->buffersize;
2176         newsevent->n = sevent->n;
2177         newsevent->result = sevent->result;
2178         newsevent->address = sevent->address;
2179         newsevent->timestamp = sevent->timestamp;
2180         newsevent->pktinfo = sevent->pktinfo;
2181         newsevent->attributes = sevent->attributes;
2182         
2183         isc_task_send(disp->task, ISC_EVENT_PTR(&newsevent));
2184 }
2185
2186 #if 0
2187 void
2188 dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) {
2189         dns_dispatch_t *disp;
2190         char foo[1024];
2191
2192         disp = ISC_LIST_HEAD(mgr->list);
2193         while (disp != NULL) {
2194                 isc_sockaddr_format(&disp->local, foo, sizeof(foo));
2195                 printf("\tdispatch %p, addr %s\n", disp, foo);
2196                 disp = ISC_LIST_NEXT(disp, link);
2197         }
2198 }
2199 #endif