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