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