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