Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / contrib / bind-9.3 / lib / dns / request.c
1 /*
2  * Copyright (C) 2004, 2006  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000-2002  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: request.c,v 1.64.2.1.10.9 2006/08/21 00:50:48 marka Exp $ */
19
20 #include <config.h>
21
22 #include <isc/magic.h>
23 #include <isc/mem.h>
24 #include <isc/task.h>
25 #include <isc/timer.h>
26 #include <isc/util.h>
27
28 #include <dns/acl.h>
29 #include <dns/compress.h>
30 #include <dns/dispatch.h>
31 #include <dns/events.h>
32 #include <dns/log.h>
33 #include <dns/message.h>
34 #include <dns/rdata.h>
35 #include <dns/rdatastruct.h>
36 #include <dns/request.h>
37 #include <dns/result.h>
38 #include <dns/tsig.h>
39
40 #define REQUESTMGR_MAGIC        ISC_MAGIC('R', 'q', 'u', 'M')
41 #define VALID_REQUESTMGR(mgr)   ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC)
42
43 #define REQUEST_MAGIC           ISC_MAGIC('R', 'q', 'u', '!')
44 #define VALID_REQUEST(request)  ISC_MAGIC_VALID(request, REQUEST_MAGIC)
45
46 typedef ISC_LIST(dns_request_t) dns_requestlist_t;
47
48 #define DNS_REQUEST_NLOCKS 7
49
50 struct dns_requestmgr {
51         unsigned int                    magic;
52         isc_mutex_t                     lock;
53         isc_mem_t                      *mctx;
54
55         /* locked */
56         isc_int32_t                     eref;
57         isc_int32_t                     iref;
58         isc_timermgr_t                 *timermgr;
59         isc_socketmgr_t                *socketmgr;
60         isc_taskmgr_t                  *taskmgr;
61         dns_dispatchmgr_t              *dispatchmgr;
62         dns_dispatch_t                 *dispatchv4;
63         dns_dispatch_t                 *dispatchv6;
64         isc_boolean_t                   exiting;
65         isc_eventlist_t                 whenshutdown;
66         unsigned int                    hash;
67         isc_mutex_t                     locks[DNS_REQUEST_NLOCKS];
68         dns_requestlist_t               requests;
69 };
70
71 struct dns_request {
72         unsigned int                    magic;
73         unsigned int                    hash;
74         isc_mem_t                      *mctx;
75         isc_int32_t                     flags;
76         ISC_LINK(dns_request_t)         link;
77         isc_buffer_t                   *query;
78         isc_buffer_t                   *answer;
79         dns_requestevent_t             *event;
80         dns_dispatch_t                 *dispatch;
81         dns_dispentry_t                *dispentry;
82         isc_timer_t                    *timer;
83         dns_requestmgr_t               *requestmgr;
84         isc_buffer_t                   *tsig;
85         dns_tsigkey_t                  *tsigkey;
86         isc_event_t                     ctlevent;
87         isc_boolean_t                   canceling; /* ctlevent outstanding */
88         isc_sockaddr_t                  destaddr;
89         unsigned int                    udpcount;
90 };
91
92 #define DNS_REQUEST_F_CONNECTING 0x0001
93 #define DNS_REQUEST_F_SENDING 0x0002
94 #define DNS_REQUEST_F_CANCELED 0x0004   /* ctlevent received, or otherwise
95                                            synchronously canceled */
96 #define DNS_REQUEST_F_TIMEDOUT 0x0008   /* cancelled due to a timeout */
97 #define DNS_REQUEST_F_TCP 0x0010        /* This request used TCP */
98 #define DNS_REQUEST_CANCELED(r) \
99         (((r)->flags & DNS_REQUEST_F_CANCELED) != 0)
100 #define DNS_REQUEST_CONNECTING(r) \
101         (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
102 #define DNS_REQUEST_SENDING(r) \
103         (((r)->flags & DNS_REQUEST_F_SENDING) != 0)
104 #define DNS_REQUEST_TIMEDOUT(r) \
105         (((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0)
106
107
108 /***
109  *** Forward
110  ***/
111
112 static void mgr_destroy(dns_requestmgr_t *requestmgr);
113 static void mgr_shutdown(dns_requestmgr_t *requestmgr);
114 static unsigned int mgr_gethash(dns_requestmgr_t *requestmgr);
115 static void send_shutdown_events(dns_requestmgr_t *requestmgr);
116
117 static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer,
118                                unsigned int options, isc_mem_t *mctx);
119 static void req_senddone(isc_task_t *task, isc_event_t *event);
120 static void req_response(isc_task_t *task, isc_event_t *event);
121 static void req_timeout(isc_task_t *task, isc_event_t *event);
122 static void req_connected(isc_task_t *task, isc_event_t *event);
123 static void req_sendevent(dns_request_t *request, isc_result_t result);
124 static void req_cancel(dns_request_t *request);
125 static void req_destroy(dns_request_t *request);
126 static void req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
127 static void do_cancel(isc_task_t *task, isc_event_t *event);
128
129 /***
130  *** Public
131  ***/
132
133 isc_result_t
134 dns_requestmgr_create(isc_mem_t *mctx,
135                       isc_timermgr_t *timermgr,
136                       isc_socketmgr_t *socketmgr,
137                       isc_taskmgr_t *taskmgr,
138                       dns_dispatchmgr_t *dispatchmgr,
139                       dns_dispatch_t *dispatchv4,
140                       dns_dispatch_t *dispatchv6,
141                       dns_requestmgr_t **requestmgrp)
142 {
143         dns_requestmgr_t *requestmgr;
144         isc_socket_t *socket;
145         isc_result_t result;
146         int i;
147
148         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
149
150         REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
151         REQUIRE(timermgr != NULL);
152         REQUIRE(socketmgr != NULL);
153         REQUIRE(taskmgr != NULL);
154         REQUIRE(dispatchmgr != NULL);
155         if (dispatchv4 != NULL) {
156                 socket = dns_dispatch_getsocket(dispatchv4);
157                 REQUIRE(isc_socket_gettype(socket) == isc_sockettype_udp);
158         }
159         if (dispatchv6 != NULL) {
160                 socket = dns_dispatch_getsocket(dispatchv6);
161                 REQUIRE(isc_socket_gettype(socket) == isc_sockettype_udp);
162         }
163
164         requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
165         if (requestmgr == NULL)
166                 return (ISC_R_NOMEMORY);
167
168         result = isc_mutex_init(&requestmgr->lock);
169         if (result != ISC_R_SUCCESS) {
170                 isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
171                 return (result);
172         }
173         for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
174                 result = isc_mutex_init(&requestmgr->locks[i]);
175                 if (result != ISC_R_SUCCESS) {
176                         while (--i >= 0)
177                                 DESTROYLOCK(&requestmgr->locks[i]);
178                         DESTROYLOCK(&requestmgr->lock);
179                         isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
180                         return (result);
181                 }
182         }
183         requestmgr->timermgr = timermgr;
184         requestmgr->socketmgr = socketmgr;
185         requestmgr->taskmgr = taskmgr;
186         requestmgr->dispatchmgr = dispatchmgr;
187         requestmgr->dispatchv4 = NULL;
188         if (dispatchv4 != NULL)
189                 dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
190         requestmgr->dispatchv6 = NULL;
191         if (dispatchv6 != NULL)
192                 dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
193         requestmgr->mctx = NULL;
194         isc_mem_attach(mctx, &requestmgr->mctx);
195         requestmgr->eref = 1;   /* implict attach */
196         requestmgr->iref = 0;
197         ISC_LIST_INIT(requestmgr->whenshutdown);
198         ISC_LIST_INIT(requestmgr->requests);
199         requestmgr->exiting = ISC_FALSE;
200         requestmgr->hash = 0;
201         requestmgr->magic = REQUESTMGR_MAGIC;
202
203         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
204
205         *requestmgrp = requestmgr;
206         return (ISC_R_SUCCESS);
207 }
208
209 void
210 dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
211                             isc_event_t **eventp)
212 {
213         isc_task_t *clone;
214         isc_event_t *event;
215
216         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_whenshutdown");
217
218         REQUIRE(VALID_REQUESTMGR(requestmgr));
219         REQUIRE(eventp != NULL);
220
221         event = *eventp;
222         *eventp = NULL;
223
224         LOCK(&requestmgr->lock);
225
226         if (requestmgr->exiting) {
227                 /*
228                  * We're already shutdown.  Send the event.
229                  */
230                 event->ev_sender = requestmgr;
231                 isc_task_send(task, &event);
232         } else {
233                 clone = NULL;
234                 isc_task_attach(task, &clone);
235                 event->ev_sender = clone;
236                 ISC_LIST_APPEND(requestmgr->whenshutdown, event, ev_link);
237         }
238         UNLOCK(&requestmgr->lock);
239 }
240
241 void
242 dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
243
244         REQUIRE(VALID_REQUESTMGR(requestmgr));
245
246         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr);
247
248         LOCK(&requestmgr->lock);
249         mgr_shutdown(requestmgr);
250         UNLOCK(&requestmgr->lock);
251 }
252
253 static void
254 mgr_shutdown(dns_requestmgr_t *requestmgr) {
255         dns_request_t *request;
256
257         /*
258          * Caller holds lock.
259          */
260         if (!requestmgr->exiting) {
261                 requestmgr->exiting = ISC_TRUE;
262                 for (request = ISC_LIST_HEAD(requestmgr->requests);
263                      request != NULL;
264                      request = ISC_LIST_NEXT(request, link)) {
265                         dns_request_cancel(request);
266                 }
267                 if (requestmgr->iref == 0) {
268                         INSIST(ISC_LIST_EMPTY(requestmgr->requests));
269                         send_shutdown_events(requestmgr);
270                 }
271         }
272 }
273
274 static void
275 requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
276
277         /*
278          * Locked by caller.
279          */
280
281         REQUIRE(VALID_REQUESTMGR(source));
282         REQUIRE(targetp != NULL && *targetp == NULL);
283
284         REQUIRE(!source->exiting);
285
286         source->iref++;
287         *targetp = source;
288
289         req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d",
290                 source, source->eref, source->iref);
291 }
292
293 static void
294 requestmgr_detach(dns_requestmgr_t **requestmgrp) {
295         dns_requestmgr_t *requestmgr;
296         isc_boolean_t need_destroy = ISC_FALSE;
297
298         REQUIRE(requestmgrp != NULL);
299         requestmgr = *requestmgrp;
300         REQUIRE(VALID_REQUESTMGR(requestmgr));
301
302         *requestmgrp = NULL;
303         LOCK(&requestmgr->lock);
304         INSIST(requestmgr->iref > 0);
305         requestmgr->iref--;
306
307         req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d",
308                 requestmgr, requestmgr->eref, requestmgr->iref);
309
310         if (requestmgr->iref == 0 && requestmgr->exiting) {
311                 INSIST(ISC_LIST_HEAD(requestmgr->requests) == NULL);
312                 send_shutdown_events(requestmgr);
313                 if (requestmgr->eref == 0)
314                         need_destroy = ISC_TRUE;
315         }
316         UNLOCK(&requestmgr->lock);
317
318         if (need_destroy)
319                 mgr_destroy(requestmgr);
320 }
321
322 void
323 dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
324
325         REQUIRE(VALID_REQUESTMGR(source));
326         REQUIRE(targetp != NULL && *targetp == NULL);
327         REQUIRE(!source->exiting);
328
329         LOCK(&source->lock);
330         source->eref++;
331         *targetp = source;
332         UNLOCK(&source->lock);
333
334         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d",
335                 source, source->eref, source->iref);
336 }
337
338 void
339 dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) {
340         dns_requestmgr_t *requestmgr;
341         isc_boolean_t need_destroy = ISC_FALSE;
342
343         REQUIRE(requestmgrp != NULL);
344         requestmgr = *requestmgrp;
345         REQUIRE(VALID_REQUESTMGR(requestmgr));
346
347         LOCK(&requestmgr->lock);
348         INSIST(requestmgr->eref > 0);
349         requestmgr->eref--;
350
351         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d",
352                 requestmgr, requestmgr->eref, requestmgr->iref);
353
354         if (requestmgr->eref == 0 && requestmgr->iref == 0) {
355                 INSIST(requestmgr->exiting &&
356                        ISC_LIST_HEAD(requestmgr->requests) == NULL);
357                 need_destroy = ISC_TRUE;
358         }
359         UNLOCK(&requestmgr->lock);
360
361         if (need_destroy)
362                 mgr_destroy(requestmgr);
363
364         *requestmgrp = NULL;
365 }
366
367 static void
368 send_shutdown_events(dns_requestmgr_t *requestmgr) {
369         isc_event_t *event, *next_event;
370         isc_task_t *etask;
371
372         req_log(ISC_LOG_DEBUG(3), "send_shutdown_events: %p", requestmgr);
373
374         /*
375          * Caller must be holding the manager lock.
376          */
377         for (event = ISC_LIST_HEAD(requestmgr->whenshutdown);
378              event != NULL;
379              event = next_event) {
380                 next_event = ISC_LIST_NEXT(event, ev_link);
381                 ISC_LIST_UNLINK(requestmgr->whenshutdown, event, ev_link);
382                 etask = event->ev_sender;
383                 event->ev_sender = requestmgr;
384                 isc_task_sendanddetach(&etask, &event);
385         }
386 }
387
388 static void
389 mgr_destroy(dns_requestmgr_t *requestmgr) {
390         int i;
391         isc_mem_t *mctx;
392
393         req_log(ISC_LOG_DEBUG(3), "mgr_destroy");
394
395         REQUIRE(requestmgr->eref == 0);
396         REQUIRE(requestmgr->iref == 0);
397
398         DESTROYLOCK(&requestmgr->lock);
399         for (i = 0; i < DNS_REQUEST_NLOCKS; i++)
400                 DESTROYLOCK(&requestmgr->locks[i]);
401         if (requestmgr->dispatchv4 != NULL)
402                 dns_dispatch_detach(&requestmgr->dispatchv4);
403         if (requestmgr->dispatchv6 != NULL)
404                 dns_dispatch_detach(&requestmgr->dispatchv6);
405         requestmgr->magic = 0;
406         mctx = requestmgr->mctx;
407         isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
408         isc_mem_detach(&mctx);
409 }
410
411 static unsigned int
412 mgr_gethash(dns_requestmgr_t *requestmgr) {
413         req_log(ISC_LOG_DEBUG(3), "mgr_gethash");
414         /*
415          * Locked by caller.
416          */
417         requestmgr->hash++;
418         return (requestmgr->hash % DNS_REQUEST_NLOCKS);
419 }
420
421 static inline isc_result_t
422 req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) {
423         isc_region_t r;
424         isc_socket_t *socket;
425         isc_result_t result;
426
427         req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
428
429         REQUIRE(VALID_REQUEST(request));
430         socket = dns_dispatch_getsocket(request->dispatch);
431         isc_buffer_usedregion(request->query, &r);
432         result = isc_socket_sendto(socket, &r, task, req_senddone,
433                                   request, address, NULL);
434         if (result == ISC_R_SUCCESS)
435                 request->flags |= DNS_REQUEST_F_SENDING;
436         return (result);
437 }
438
439 static isc_result_t
440 new_request(isc_mem_t *mctx, dns_request_t **requestp) {
441         dns_request_t *request;
442
443         request = isc_mem_get(mctx, sizeof(*request));
444         if (request == NULL)
445                 return (ISC_R_NOMEMORY);
446
447         /*
448          * Zero structure.
449          */
450         request->magic = 0;
451         request->mctx = NULL;
452         request->flags = 0;
453         ISC_LINK_INIT(request, link);
454         request->query = NULL;
455         request->answer = NULL;
456         request->event = NULL;
457         request->dispatch = NULL;
458         request->dispentry = NULL;
459         request->timer = NULL;
460         request->requestmgr = NULL;
461         request->tsig = NULL;
462         request->tsigkey = NULL;
463         ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL,
464                        DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL,
465                        NULL, NULL);
466         request->canceling = ISC_FALSE;
467         request->udpcount = 0;
468
469         isc_mem_attach(mctx, &request->mctx);
470
471         request->magic = REQUEST_MAGIC;
472         *requestp = request;
473         return (ISC_R_SUCCESS);
474 }
475
476
477 static isc_boolean_t
478 isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) {
479         dns_acl_t *blackhole;
480         isc_netaddr_t netaddr;
481         int match;
482         isc_boolean_t drop = ISC_FALSE;
483         char netaddrstr[ISC_NETADDR_FORMATSIZE];
484
485         blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
486         if (blackhole != NULL) {
487                 isc_netaddr_fromsockaddr(&netaddr, destaddr);
488                 if (dns_acl_match(&netaddr, NULL, blackhole,
489                                   NULL, &match, NULL) == ISC_R_SUCCESS &&
490                     match > 0)
491                         drop = ISC_TRUE;
492         }
493         if (drop) {
494                 isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
495                 req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
496         }
497         return (drop);
498 }
499
500 static isc_result_t
501 create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
502                     isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
503 {
504         isc_result_t result;
505         isc_socket_t *socket = NULL;
506         isc_sockaddr_t src;
507         unsigned int attrs;
508         isc_sockaddr_t bind_any;
509
510         result = isc_socket_create(requestmgr->socketmgr,
511                                    isc_sockaddr_pf(destaddr),
512                                    isc_sockettype_tcp, &socket);
513         if (result != ISC_R_SUCCESS)
514                 return (result);
515 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
516         if (srcaddr == NULL) {
517                 isc_sockaddr_anyofpf(&bind_any,
518                                      isc_sockaddr_pf(destaddr));
519                 result = isc_socket_bind(socket, &bind_any);
520         } else {
521                 src = *srcaddr;
522                 isc_sockaddr_setport(&src, 0);
523                 result = isc_socket_bind(socket, &src);
524         }
525         if (result != ISC_R_SUCCESS)
526                 goto cleanup;
527 #endif
528         attrs = 0;
529         attrs |= DNS_DISPATCHATTR_TCP;
530         attrs |= DNS_DISPATCHATTR_PRIVATE;
531         if (isc_sockaddr_pf(destaddr) == AF_INET)
532                 attrs |= DNS_DISPATCHATTR_IPV4;
533         else
534                 attrs |= DNS_DISPATCHATTR_IPV6;
535         attrs |= DNS_DISPATCHATTR_MAKEQUERY;
536         result = dns_dispatch_createtcp(requestmgr->dispatchmgr,
537                                         socket, requestmgr->taskmgr,
538                                         4096, 2, 1, 1, 3, attrs,
539                                         dispatchp);
540 cleanup:
541         isc_socket_detach(&socket);
542         return (result);
543 }
544
545 static isc_result_t
546 find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
547                   isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
548 {
549         dns_dispatch_t *disp = NULL;
550         unsigned int attrs, attrmask;
551
552         if (srcaddr == NULL) {
553                 switch (isc_sockaddr_pf(destaddr)) {
554                 case PF_INET:
555                         disp = requestmgr->dispatchv4;
556                         break;
557
558                 case PF_INET6:
559                         disp = requestmgr->dispatchv6;
560                         break;
561
562                 default:
563                         return (ISC_R_NOTIMPLEMENTED);
564                 }
565                 if (disp == NULL)
566                         return (ISC_R_FAMILYNOSUPPORT);
567                 dns_dispatch_attach(disp, dispatchp);
568                 return (ISC_R_SUCCESS);
569         }
570         attrs = 0;
571         attrs |= DNS_DISPATCHATTR_UDP;
572         switch (isc_sockaddr_pf(srcaddr)) {
573         case PF_INET:
574                 attrs |= DNS_DISPATCHATTR_IPV4;
575                 break;
576
577         case PF_INET6:
578                 attrs |= DNS_DISPATCHATTR_IPV6;
579                 break;
580
581         default:
582                 return (ISC_R_NOTIMPLEMENTED);
583         }
584         attrmask = 0;
585         attrmask |= DNS_DISPATCHATTR_UDP;
586         attrmask |= DNS_DISPATCHATTR_TCP;
587         attrmask |= DNS_DISPATCHATTR_IPV4;
588         attrmask |= DNS_DISPATCHATTR_IPV6;
589         return (dns_dispatch_getudp(requestmgr->dispatchmgr,
590                                     requestmgr->socketmgr,
591                                     requestmgr->taskmgr,
592                                     srcaddr, 4096,
593                                     1000, 32768, 16411, 16433,
594                                     attrs, attrmask,
595                                     dispatchp));
596 }
597
598 static isc_result_t
599 get_dispatch(isc_boolean_t tcp, dns_requestmgr_t *requestmgr,
600              isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
601              dns_dispatch_t **dispatchp)
602 {
603         isc_result_t result;
604         if (tcp)
605                 result = create_tcp_dispatch(requestmgr, srcaddr,
606                                              destaddr, dispatchp);
607         else
608                 result = find_udp_dispatch(requestmgr, srcaddr,
609                                            destaddr, dispatchp);
610         return (result);
611 }
612
613 static isc_result_t
614 set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) {
615         isc_time_t expires;
616         isc_interval_t interval;
617         isc_result_t result;
618         isc_timertype_t timertype;
619
620         isc_interval_set(&interval, timeout, 0);
621         result = isc_time_nowplusinterval(&expires, &interval);
622         isc_interval_set(&interval, udpresend, 0);
623
624         timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once;
625         if (result == ISC_R_SUCCESS)
626                 result = isc_timer_reset(timer, timertype, &expires,
627                                          &interval, ISC_FALSE);
628         return (result);
629 }
630
631 isc_result_t
632 dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
633                       isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
634                       unsigned int options, unsigned int timeout,
635                       isc_task_t *task, isc_taskaction_t action, void *arg,
636                       dns_request_t **requestp)
637 {
638         return(dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
639                                       options, timeout, 0, 0, task, action,
640                                       arg, requestp));
641 }
642
643 isc_result_t
644 dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
645                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
646                        unsigned int options, unsigned int timeout,
647                        unsigned int udptimeout, isc_task_t *task,
648                        isc_taskaction_t action, void *arg,
649                        dns_request_t **requestp)
650 {
651         unsigned int udpretries = 0;
652
653         if (udptimeout != 0)
654                 udpretries = timeout / udptimeout;
655
656         return (dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
657                                        options, timeout, udptimeout,
658                                        udpretries, task, action, arg,
659                                        requestp));
660 }
661
662 isc_result_t
663 dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
664                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
665                        unsigned int options, unsigned int timeout,
666                        unsigned int udptimeout, unsigned int udpretries,
667                        isc_task_t *task, isc_taskaction_t action, void *arg,
668                        dns_request_t **requestp)
669 {
670         dns_request_t *request = NULL;
671         isc_task_t *tclone = NULL;
672         isc_socket_t *socket = NULL;
673         isc_result_t result;
674         isc_mem_t *mctx;
675         dns_messageid_t id;
676         isc_boolean_t tcp = ISC_FALSE;
677         isc_region_t r;
678
679         REQUIRE(VALID_REQUESTMGR(requestmgr));
680         REQUIRE(msgbuf != NULL);
681         REQUIRE(destaddr != NULL);
682         REQUIRE(task != NULL);
683         REQUIRE(action != NULL);
684         REQUIRE(requestp != NULL && *requestp == NULL);
685         REQUIRE(timeout > 0);
686         if (srcaddr != NULL) 
687                 REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
688
689         mctx = requestmgr->mctx;
690
691         req_log(ISC_LOG_DEBUG(3), "dns_request_createraw");
692
693         if (isblackholed(requestmgr->dispatchmgr, destaddr))
694                 return (DNS_R_BLACKHOLED);
695
696         request = NULL;
697         result = new_request(mctx, &request);
698         if (result != ISC_R_SUCCESS)
699                 return (result);
700
701         if (udptimeout == 0 && udpretries != 0) {
702                 udptimeout = timeout / (udpretries + 1);
703                 if (udptimeout == 0)
704                         udptimeout = 1;
705         }
706         request->udpcount = udpretries;
707
708         /*
709          * Create timer now.  We will set it below once.
710          */
711         result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
712                                   NULL, NULL, task, req_timeout, request,
713                                   &request->timer);
714         if (result != ISC_R_SUCCESS)
715                 goto cleanup;
716
717         request->event = (dns_requestevent_t *)
718                 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
719                                    action, arg, sizeof(dns_requestevent_t));
720         if (request->event == NULL) {
721                 result = ISC_R_NOMEMORY;
722                 goto cleanup;
723         }
724         isc_task_attach(task, &tclone);
725         request->event->ev_sender = task;
726         request->event->request = request;
727         request->event->result = ISC_R_FAILURE;
728
729         isc_buffer_usedregion(msgbuf, &r);
730         if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
731                 result = DNS_R_FORMERR;
732                 goto cleanup;
733         }
734                 
735         if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512)
736                 tcp = ISC_TRUE;
737
738         result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
739                               &request->dispatch);
740         if (result != ISC_R_SUCCESS)
741                 goto cleanup;
742
743         socket = dns_dispatch_getsocket(request->dispatch);
744         INSIST(socket != NULL);
745         result = dns_dispatch_addresponse(request->dispatch, destaddr, task,
746                                           req_response, request, &id,
747                                           &request->dispentry);
748         if (result != ISC_R_SUCCESS)
749                 goto cleanup;
750
751         result = isc_buffer_allocate(mctx, &request->query,
752                                      r.length + (tcp ? 2 : 0));
753         if (result != ISC_R_SUCCESS)
754                 goto cleanup;
755         if (tcp)
756                 isc_buffer_putuint16(request->query, (isc_uint16_t)r.length);
757         result = isc_buffer_copyregion(request->query, &r);
758         if (result != ISC_R_SUCCESS)
759                 goto cleanup;
760
761         /* Add message ID. */
762         isc_buffer_usedregion(request->query, &r);
763         if (tcp)
764                 isc_region_consume(&r, 2);
765         r.base[0] = (id>>8) & 0xff;
766         r.base[1] = id & 0xff;
767
768         LOCK(&requestmgr->lock);
769         if (requestmgr->exiting) {
770                 UNLOCK(&requestmgr->lock);
771                 result = ISC_R_SHUTTINGDOWN;
772                 goto cleanup;
773         }
774         requestmgr_attach(requestmgr, &request->requestmgr);
775         request->hash = mgr_gethash(requestmgr);
776         ISC_LIST_APPEND(requestmgr->requests, request, link);
777         UNLOCK(&requestmgr->lock);
778
779         result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
780         if (result != ISC_R_SUCCESS)
781                 goto unlink;
782
783         request->destaddr = *destaddr;
784         if (tcp) {
785                 result = isc_socket_connect(socket, destaddr, task,
786                                             req_connected, request);
787                 if (result != ISC_R_SUCCESS)
788                         goto unlink;
789                 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
790         } else {
791                 result = req_send(request, task, destaddr);
792                 if (result != ISC_R_SUCCESS)
793                         goto unlink;
794         }
795
796         req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p",
797                 request);
798         *requestp = request;
799         return (ISC_R_SUCCESS);
800
801  unlink:
802         LOCK(&requestmgr->lock);
803         ISC_LIST_UNLINK(requestmgr->requests, request, link);
804         UNLOCK(&requestmgr->lock);
805
806  cleanup:
807         if (tclone != NULL)
808                 isc_task_detach(&tclone);
809         req_destroy(request);
810         req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
811                 dns_result_totext(result));
812         return (result);
813 }
814
815 isc_result_t
816 dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
817                    isc_sockaddr_t *address, unsigned int options,
818                    dns_tsigkey_t *key,
819                    unsigned int timeout, isc_task_t *task,
820                    isc_taskaction_t action, void *arg,
821                    dns_request_t **requestp)
822 {
823         return (dns_request_createvia3(requestmgr, message, NULL, address,
824                                        options, key, timeout, 0, 0, task,
825                                        action, arg, requestp));
826 }
827
828 isc_result_t
829 dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message,
830                       isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
831                       unsigned int options, dns_tsigkey_t *key,
832                       unsigned int timeout, isc_task_t *task,
833                       isc_taskaction_t action, void *arg,
834                       dns_request_t **requestp)
835 {
836         return(dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
837                                       options, key, timeout, 0, 0, task,
838                                       action, arg, requestp));
839 }
840
841 isc_result_t
842 dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message,
843                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
844                        unsigned int options, dns_tsigkey_t *key,
845                        unsigned int timeout, unsigned int udptimeout,
846                        isc_task_t *task, isc_taskaction_t action, void *arg,
847                        dns_request_t **requestp)
848 {
849         unsigned int udpretries = 0;
850
851         if (udptimeout != 0)
852                 udpretries = timeout / udptimeout;
853         return (dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
854                                        options, key, timeout, udptimeout,
855                                        udpretries, task, action, arg,
856                                        requestp));
857 }
858                                         
859 isc_result_t
860 dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
861                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
862                        unsigned int options, dns_tsigkey_t *key,
863                        unsigned int timeout, unsigned int udptimeout,
864                        unsigned int udpretries, isc_task_t *task,
865                        isc_taskaction_t action, void *arg,
866                        dns_request_t **requestp)
867 {
868         dns_request_t *request = NULL;
869         isc_task_t *tclone = NULL;
870         isc_socket_t *socket = NULL;
871         isc_result_t result;
872         isc_mem_t *mctx;
873         dns_messageid_t id;
874         isc_boolean_t tcp;
875         isc_boolean_t setkey = ISC_TRUE;
876
877         REQUIRE(VALID_REQUESTMGR(requestmgr));
878         REQUIRE(message != NULL);
879         REQUIRE(destaddr != NULL);
880         REQUIRE(task != NULL);
881         REQUIRE(action != NULL);
882         REQUIRE(requestp != NULL && *requestp == NULL);
883         REQUIRE(timeout > 0);
884         if (srcaddr != NULL) 
885                 REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
886
887         mctx = requestmgr->mctx;
888
889         req_log(ISC_LOG_DEBUG(3), "dns_request_createvia");
890
891         if (isblackholed(requestmgr->dispatchmgr, destaddr))
892                 return (DNS_R_BLACKHOLED);
893
894         request = NULL;
895         result = new_request(mctx, &request);
896         if (result != ISC_R_SUCCESS)
897                 return (result);
898
899         if (udptimeout == 0 && udpretries != 0) {
900                 udptimeout = timeout / (udpretries + 1);
901                 if (udptimeout == 0)
902                         udptimeout = 1;
903         }
904         request->udpcount = udpretries;
905
906         /*
907          * Create timer now.  We will set it below once.
908          */
909         result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
910                                   NULL, NULL, task, req_timeout, request,
911                                   &request->timer);
912         if (result != ISC_R_SUCCESS)
913                 goto cleanup;
914
915         request->event = (dns_requestevent_t *)
916                 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
917                                    action, arg, sizeof(dns_requestevent_t));
918         if (request->event == NULL) {
919                 result = ISC_R_NOMEMORY;
920                 goto cleanup;
921         }
922         isc_task_attach(task, &tclone);
923         request->event->ev_sender = task;
924         request->event->request = request;
925         request->event->result = ISC_R_FAILURE;
926         if (key != NULL)
927                 dns_tsigkey_attach(key, &request->tsigkey);
928
929  use_tcp:
930         tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0);
931         result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
932                               &request->dispatch);
933         if (result != ISC_R_SUCCESS)
934                 goto cleanup;
935
936         socket = dns_dispatch_getsocket(request->dispatch);
937         INSIST(socket != NULL);
938         result = dns_dispatch_addresponse(request->dispatch, destaddr, task,
939                                           req_response, request, &id,
940                                           &request->dispentry);
941         if (result != ISC_R_SUCCESS)
942                 goto cleanup;
943
944         message->id = id;
945         if (setkey) {
946                 result = dns_message_settsigkey(message, request->tsigkey);
947                 if (result != ISC_R_SUCCESS)
948                         goto cleanup;
949         }
950         result = req_render(message, &request->query, options, mctx);
951         if (result == DNS_R_USETCP &&
952             (options & DNS_REQUESTOPT_TCP) == 0) {
953                 /*
954                  * Try again using TCP.
955                  */
956                 dns_message_renderreset(message);
957                 dns_dispatch_removeresponse(&request->dispentry, NULL);
958                 dns_dispatch_detach(&request->dispatch);
959                 socket = NULL;
960                 options |= DNS_REQUESTOPT_TCP;
961                 setkey = ISC_FALSE;
962                 goto use_tcp;
963         }
964         if (result != ISC_R_SUCCESS)
965                 goto cleanup;
966
967         result = dns_message_getquerytsig(message, mctx, &request->tsig);
968         if (result != ISC_R_SUCCESS)
969                 goto cleanup;
970
971         LOCK(&requestmgr->lock);
972         if (requestmgr->exiting) {
973                 UNLOCK(&requestmgr->lock);
974                 result = ISC_R_SHUTTINGDOWN;
975                 goto cleanup;
976         }
977         requestmgr_attach(requestmgr, &request->requestmgr);
978         request->hash = mgr_gethash(requestmgr);
979         ISC_LIST_APPEND(requestmgr->requests, request, link);
980         UNLOCK(&requestmgr->lock);
981
982         result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
983         if (result != ISC_R_SUCCESS)
984                 goto unlink;
985
986         request->destaddr = *destaddr;
987         if (tcp) {
988                 result = isc_socket_connect(socket, destaddr, task,
989                                             req_connected, request);
990                 if (result != ISC_R_SUCCESS)
991                         goto unlink;
992                 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
993         } else {
994                 result = req_send(request, task, destaddr);
995                 if (result != ISC_R_SUCCESS)
996                         goto unlink;
997         }
998
999         req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p",
1000                 request);
1001         *requestp = request;
1002         return (ISC_R_SUCCESS);
1003
1004  unlink:
1005         LOCK(&requestmgr->lock);
1006         ISC_LIST_UNLINK(requestmgr->requests, request, link);
1007         UNLOCK(&requestmgr->lock);
1008
1009  cleanup:
1010         if (tclone != NULL)
1011                 isc_task_detach(&tclone);
1012         req_destroy(request);
1013         req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s",
1014                 dns_result_totext(result));
1015         return (result);
1016 }
1017
1018 static isc_result_t
1019 req_render(dns_message_t *message, isc_buffer_t **bufferp,
1020            unsigned int options, isc_mem_t *mctx)
1021 {
1022         isc_buffer_t *buf1 = NULL;
1023         isc_buffer_t *buf2 = NULL;
1024         isc_result_t result;
1025         isc_region_t r;
1026         isc_boolean_t tcp = ISC_FALSE;
1027         dns_compress_t cctx;
1028         isc_boolean_t cleanup_cctx = ISC_FALSE;
1029
1030         REQUIRE(bufferp != NULL && *bufferp == NULL);
1031
1032         req_log(ISC_LOG_DEBUG(3), "request_render");
1033
1034         /*
1035          * Create buffer able to hold largest possible message.
1036          */
1037         result = isc_buffer_allocate(mctx, &buf1, 65535);
1038         if (result != ISC_R_SUCCESS)
1039                 return (result);
1040
1041         result = dns_compress_init(&cctx, -1, mctx);
1042         if (result != ISC_R_SUCCESS)
1043                 return (result);
1044         cleanup_cctx = ISC_TRUE;
1045
1046         /*
1047          * Render message.
1048          */
1049         result = dns_message_renderbegin(message, &cctx, buf1);
1050         if (result != ISC_R_SUCCESS)
1051                 goto cleanup;
1052         result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
1053         if (result != ISC_R_SUCCESS)
1054                 goto cleanup;
1055         result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
1056         if (result != ISC_R_SUCCESS)
1057                 goto cleanup;
1058         result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
1059         if (result != ISC_R_SUCCESS)
1060                 goto cleanup;
1061         result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
1062         if (result != ISC_R_SUCCESS)
1063                 goto cleanup;
1064         result = dns_message_renderend(message);
1065         if (result != ISC_R_SUCCESS)
1066                 goto cleanup;
1067
1068         dns_compress_invalidate(&cctx);
1069         cleanup_cctx = ISC_FALSE;
1070
1071         /*
1072          * Copy rendered message to exact sized buffer.
1073          */
1074         isc_buffer_usedregion(buf1, &r);
1075         if ((options & DNS_REQUESTOPT_TCP) != 0) {
1076                 tcp = ISC_TRUE;
1077         } else if (r.length > 512) {
1078                 result = DNS_R_USETCP;
1079                 goto cleanup;
1080         }
1081         result = isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0));
1082         if (result != ISC_R_SUCCESS)
1083                 goto cleanup;
1084         if (tcp)
1085                 isc_buffer_putuint16(buf2, (isc_uint16_t)r.length);
1086         result = isc_buffer_copyregion(buf2, &r);
1087         if (result != ISC_R_SUCCESS)
1088                 goto cleanup;
1089
1090         /*
1091          * Cleanup and return.
1092          */
1093         isc_buffer_free(&buf1);
1094         *bufferp = buf2;
1095         return (ISC_R_SUCCESS);
1096
1097  cleanup:
1098         dns_message_renderreset(message);
1099         if (buf1 != NULL)
1100                 isc_buffer_free(&buf1);
1101         if (buf2 != NULL)
1102                 isc_buffer_free(&buf2);
1103         if (cleanup_cctx)
1104                 dns_compress_invalidate(&cctx);
1105         return (result);
1106 }
1107
1108
1109 /*
1110  * If this request is no longer waiting for events,
1111  * send the completion event.  This will ultimately
1112  * cause the request to be destroyed.
1113  *
1114  * Requires:
1115  *      'request' is locked by the caller.
1116  */
1117 static void
1118 send_if_done(dns_request_t *request, isc_result_t result) {
1119         if (!DNS_REQUEST_CONNECTING(request) &&
1120             !DNS_REQUEST_SENDING(request) &&
1121             !request->canceling)
1122                 req_sendevent(request, result);
1123 }
1124
1125 /*
1126  * Handle the control event.
1127  */
1128 static void
1129 do_cancel(isc_task_t *task, isc_event_t *event) {
1130         dns_request_t *request = event->ev_arg;
1131         UNUSED(task);
1132         INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL);
1133         LOCK(&request->requestmgr->locks[request->hash]);
1134         request->canceling = ISC_FALSE;
1135         if (!DNS_REQUEST_CANCELED(request))
1136                 req_cancel(request);
1137         send_if_done(request, ISC_R_CANCELED);
1138         UNLOCK(&request->requestmgr->locks[request->hash]);     
1139 }
1140
1141 void
1142 dns_request_cancel(dns_request_t *request) {
1143         REQUIRE(VALID_REQUEST(request));
1144
1145         req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request);
1146
1147         REQUIRE(VALID_REQUEST(request));
1148
1149         LOCK(&request->requestmgr->locks[request->hash]);
1150         if (!request->canceling && !DNS_REQUEST_CANCELED(request)) {
1151                 isc_event_t *ev =  &request->ctlevent;
1152                 isc_task_send(request->event->ev_sender, &ev);
1153                 request->canceling = ISC_TRUE;
1154         }
1155         UNLOCK(&request->requestmgr->locks[request->hash]);
1156 }
1157
1158 isc_result_t
1159 dns_request_getresponse(dns_request_t *request, dns_message_t *message,
1160                         unsigned int options)
1161 {
1162         isc_result_t result;
1163
1164         REQUIRE(VALID_REQUEST(request));
1165         REQUIRE(request->answer != NULL);
1166
1167         req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p",
1168                 request);
1169
1170         result = dns_message_setquerytsig(message, request->tsig);
1171         if (result != ISC_R_SUCCESS)
1172                 return (result);
1173         result = dns_message_settsigkey(message, request->tsigkey);
1174         if (result != ISC_R_SUCCESS)
1175                 return (result);
1176         result = dns_message_parse(message, request->answer, options);
1177         if (result != ISC_R_SUCCESS)
1178                 return (result);
1179         if (request->tsigkey != NULL)
1180                 result = dns_tsig_verify(request->answer, message, NULL, NULL);
1181         return (result);
1182 }
1183
1184 isc_boolean_t
1185 dns_request_usedtcp(dns_request_t *request) {
1186         REQUIRE(VALID_REQUEST(request));
1187
1188         return (ISC_TF((request->flags & DNS_REQUEST_F_TCP) != 0));
1189 }
1190
1191 void
1192 dns_request_destroy(dns_request_t **requestp) {
1193         dns_request_t *request;
1194
1195         REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
1196
1197         request = *requestp;
1198
1199         req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request);
1200
1201         LOCK(&request->requestmgr->lock);
1202         LOCK(&request->requestmgr->locks[request->hash]);
1203         ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
1204         INSIST(!DNS_REQUEST_CONNECTING(request));
1205         INSIST(!DNS_REQUEST_SENDING(request));
1206         UNLOCK(&request->requestmgr->locks[request->hash]);
1207         UNLOCK(&request->requestmgr->lock);
1208
1209         /*
1210          * These should have been cleaned up by req_cancel() before
1211          * the completion event was sent.
1212          */
1213         INSIST(!ISC_LINK_LINKED(request, link));
1214         INSIST(request->dispentry == NULL);
1215         INSIST(request->dispatch == NULL);
1216         INSIST(request->timer == NULL);
1217
1218         req_destroy(request);
1219
1220         *requestp = NULL;
1221 }
1222
1223 /***
1224  *** Private: request.
1225  ***/
1226
1227 static void
1228 req_connected(isc_task_t *task, isc_event_t *event) {
1229         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1230         isc_result_t result;
1231         dns_request_t *request = event->ev_arg;
1232
1233         REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
1234         REQUIRE(VALID_REQUEST(request));
1235         REQUIRE(DNS_REQUEST_CONNECTING(request));
1236
1237         req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request);
1238
1239         LOCK(&request->requestmgr->locks[request->hash]);
1240         request->flags &= ~DNS_REQUEST_F_CONNECTING;
1241
1242         if (DNS_REQUEST_CANCELED(request)) {
1243                 /*
1244                  * Send delayed event.
1245                  */
1246                 if (DNS_REQUEST_TIMEDOUT(request))
1247                         send_if_done(request, ISC_R_TIMEDOUT);
1248                 else
1249                         send_if_done(request, ISC_R_CANCELED);
1250         } else {
1251                 dns_dispatch_starttcp(request->dispatch);
1252                 result = sevent->result;
1253                 if (result == ISC_R_SUCCESS)
1254                         result = req_send(request, task, NULL);
1255
1256                 if (result != ISC_R_SUCCESS) {
1257                         req_cancel(request);
1258                         send_if_done(request, ISC_R_CANCELED);
1259                 }
1260         }
1261         UNLOCK(&request->requestmgr->locks[request->hash]);
1262         isc_event_free(&event);
1263 }
1264
1265 static void
1266 req_senddone(isc_task_t *task, isc_event_t *event) {
1267         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1268         dns_request_t *request = event->ev_arg;
1269
1270         REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1271         REQUIRE(VALID_REQUEST(request));
1272         REQUIRE(DNS_REQUEST_SENDING(request));
1273
1274         req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
1275
1276         UNUSED(task);
1277
1278         LOCK(&request->requestmgr->locks[request->hash]);
1279         request->flags &= ~DNS_REQUEST_F_SENDING;
1280
1281         if (DNS_REQUEST_CANCELED(request)) {
1282                 /*
1283                  * Send delayed event.
1284                  */
1285                 if (DNS_REQUEST_TIMEDOUT(request))
1286                         send_if_done(request, ISC_R_TIMEDOUT);
1287                 else
1288                         send_if_done(request, ISC_R_CANCELED);
1289         } else if (sevent->result != ISC_R_SUCCESS) {
1290                         req_cancel(request);
1291                         send_if_done(request, ISC_R_CANCELED);
1292         }
1293         UNLOCK(&request->requestmgr->locks[request->hash]);
1294
1295         isc_event_free(&event);
1296 }
1297
1298 static void
1299 req_response(isc_task_t *task, isc_event_t *event) {
1300         isc_result_t result;
1301         dns_request_t *request = event->ev_arg;
1302         dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
1303         isc_region_t r;
1304
1305         REQUIRE(VALID_REQUEST(request));
1306         REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
1307
1308         UNUSED(task);
1309
1310         req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
1311                 dns_result_totext(devent->result));
1312
1313         LOCK(&request->requestmgr->locks[request->hash]);
1314         result = devent->result;
1315         if (result != ISC_R_SUCCESS)
1316                 goto done;
1317
1318         /*
1319          * Copy buffer to request.
1320          */
1321         isc_buffer_usedregion(&devent->buffer, &r);
1322         result = isc_buffer_allocate(request->mctx, &request->answer,
1323                                      r.length);
1324         if (result != ISC_R_SUCCESS)
1325                 goto done;
1326         result = isc_buffer_copyregion(request->answer, &r);
1327         if (result != ISC_R_SUCCESS)
1328                 isc_buffer_free(&request->answer);
1329  done:
1330         /*
1331          * Cleanup.
1332          */
1333         dns_dispatch_removeresponse(&request->dispentry, &devent);
1334         req_cancel(request);
1335         /*
1336          * Send completion event.
1337          */
1338         send_if_done(request, result);
1339         UNLOCK(&request->requestmgr->locks[request->hash]);
1340 }
1341
1342 static void
1343 req_timeout(isc_task_t *task, isc_event_t *event) {
1344         dns_request_t *request = event->ev_arg;
1345         isc_result_t result;
1346
1347         REQUIRE(VALID_REQUEST(request));
1348
1349         req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
1350
1351         UNUSED(task);
1352         LOCK(&request->requestmgr->locks[request->hash]);
1353         if (event->ev_type == ISC_TIMEREVENT_TICK &&
1354             request->udpcount-- != 0) {
1355                 if (! DNS_REQUEST_SENDING(request)) {
1356                         result = req_send(request, task, &request->destaddr);
1357                         if (result != ISC_R_SUCCESS) {
1358                                 req_cancel(request);
1359                                 send_if_done(request, result);
1360                         }
1361                 }
1362         } else {
1363                 request->flags |= DNS_REQUEST_F_TIMEDOUT;
1364                 req_cancel(request);
1365                 send_if_done(request, ISC_R_TIMEDOUT);
1366         }
1367         UNLOCK(&request->requestmgr->locks[request->hash]);
1368         isc_event_free(&event);
1369 }
1370
1371 static void
1372 req_sendevent(dns_request_t *request, isc_result_t result) {
1373         isc_task_t *task;
1374
1375         REQUIRE(VALID_REQUEST(request));
1376
1377         req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request);
1378
1379         /*
1380          * Lock held by caller.
1381          */
1382         task = request->event->ev_sender;
1383         request->event->ev_sender = request;
1384         request->event->result = result;
1385         isc_task_sendanddetach(&task, (isc_event_t **)&request->event);
1386 }
1387
1388 static void
1389 req_destroy(dns_request_t *request) {
1390         isc_mem_t *mctx;
1391
1392         REQUIRE(VALID_REQUEST(request));
1393
1394         req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request);
1395
1396         request->magic = 0;
1397         if (request->query != NULL)
1398                 isc_buffer_free(&request->query);
1399         if (request->answer != NULL)
1400                 isc_buffer_free(&request->answer);
1401         if (request->event != NULL)
1402                 isc_event_free((isc_event_t **)&request->event);
1403         if (request->dispentry != NULL)
1404                 dns_dispatch_removeresponse(&request->dispentry, NULL);
1405         if (request->dispatch != NULL)
1406                 dns_dispatch_detach(&request->dispatch);
1407         if (request->timer != NULL)
1408                 isc_timer_detach(&request->timer);
1409         if (request->tsig != NULL)
1410                 isc_buffer_free(&request->tsig);
1411         if (request->tsigkey != NULL)
1412                 dns_tsigkey_detach(&request->tsigkey);
1413         if (request->requestmgr != NULL)
1414                 requestmgr_detach(&request->requestmgr);
1415         mctx = request->mctx;
1416         isc_mem_put(mctx, request, sizeof(*request));
1417         isc_mem_detach(&mctx);
1418 }
1419
1420 /*
1421  * Stop the current request.  Must be called from the request's task.
1422  */
1423 static void
1424 req_cancel(dns_request_t *request) {
1425         isc_socket_t *socket;
1426
1427         REQUIRE(VALID_REQUEST(request));
1428
1429         req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request);
1430
1431         /*
1432          * Lock held by caller.
1433          */
1434         request->flags |= DNS_REQUEST_F_CANCELED;
1435
1436         if (request->timer != NULL)
1437                 isc_timer_detach(&request->timer);
1438         if (request->dispentry != NULL)
1439                 dns_dispatch_removeresponse(&request->dispentry, NULL);
1440         if (DNS_REQUEST_CONNECTING(request)) {
1441                 socket = dns_dispatch_getsocket(request->dispatch);
1442                 isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
1443         }
1444         if (DNS_REQUEST_SENDING(request)) {
1445                 socket = dns_dispatch_getsocket(request->dispatch);
1446                 isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
1447         }
1448         dns_dispatch_detach(&request->dispatch);
1449 }
1450
1451 static void
1452 req_log(int level, const char *fmt, ...) {
1453         va_list ap;
1454
1455         va_start(ap, fmt);
1456         isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1457                        DNS_LOGMODULE_REQUEST, level, fmt, ap);
1458         va_end(ap);
1459 }