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