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