]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/lib/dns/request.c
Update BIND to 9.9.8
[FreeBSD/stable/9.git] / contrib / bind9 / lib / dns / request.c
1 /*
2  * Copyright (C) 2004-2015  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$ */
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 *sock;
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(sock);
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 *sock;
430         isc_result_t result;
431
432         req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
433
434         REQUIRE(VALID_REQUEST(request));
435         sock = req_getsocket(request);
436         isc_buffer_usedregion(request->query, &r);
437         /*
438          * We could connect the socket when we are using an exclusive dispatch
439          * as we do in resolver.c, but we prefer implementation simplicity
440          * at this moment.
441          */
442         result = isc_socket_sendto(sock, &r, task, req_senddone,
443                                   request, address, NULL);
444         if (result == ISC_R_SUCCESS)
445                 request->flags |= DNS_REQUEST_F_SENDING;
446         return (result);
447 }
448
449 static isc_result_t
450 new_request(isc_mem_t *mctx, dns_request_t **requestp)
451 {
452         dns_request_t *request;
453
454         request = isc_mem_get(mctx, sizeof(*request));
455         if (request == NULL)
456                 return (ISC_R_NOMEMORY);
457
458         /*
459          * Zero structure.
460          */
461         request->magic = 0;
462         request->mctx = NULL;
463         request->flags = 0;
464         ISC_LINK_INIT(request, link);
465         request->query = NULL;
466         request->answer = NULL;
467         request->event = NULL;
468         request->dispatch = NULL;
469         request->dispentry = NULL;
470         request->timer = NULL;
471         request->requestmgr = NULL;
472         request->tsig = NULL;
473         request->tsigkey = NULL;
474         ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL,
475                        DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL,
476                        NULL, NULL);
477         request->canceling = ISC_FALSE;
478         request->udpcount = 0;
479
480         isc_mem_attach(mctx, &request->mctx);
481
482         request->magic = REQUEST_MAGIC;
483         *requestp = request;
484         return (ISC_R_SUCCESS);
485 }
486
487
488 static isc_boolean_t
489 isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) {
490         dns_acl_t *blackhole;
491         isc_netaddr_t netaddr;
492         int match;
493         isc_boolean_t drop = ISC_FALSE;
494         char netaddrstr[ISC_NETADDR_FORMATSIZE];
495
496         blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
497         if (blackhole != NULL) {
498                 isc_netaddr_fromsockaddr(&netaddr, destaddr);
499                 if (dns_acl_match(&netaddr, NULL, blackhole,
500                                   NULL, &match, NULL) == ISC_R_SUCCESS &&
501                     match > 0)
502                         drop = ISC_TRUE;
503         }
504         if (drop) {
505                 isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
506                 req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
507         }
508         return (drop);
509 }
510
511 static isc_result_t
512 create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
513                     isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
514 {
515         isc_result_t result;
516         isc_socket_t *sock = NULL;
517         isc_sockaddr_t src;
518         unsigned int attrs;
519         isc_sockaddr_t bind_any;
520
521         result = isc_socket_create(requestmgr->socketmgr,
522                                    isc_sockaddr_pf(destaddr),
523                                    isc_sockettype_tcp, &sock);
524         if (result != ISC_R_SUCCESS)
525                 return (result);
526 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
527         if (srcaddr == NULL) {
528                 isc_sockaddr_anyofpf(&bind_any,
529                                      isc_sockaddr_pf(destaddr));
530                 result = isc_socket_bind(sock, &bind_any, 0);
531         } else {
532                 src = *srcaddr;
533                 isc_sockaddr_setport(&src, 0);
534                 result = isc_socket_bind(sock, &src, 0);
535         }
536         if (result != ISC_R_SUCCESS)
537                 goto cleanup;
538 #endif
539         attrs = 0;
540         attrs |= DNS_DISPATCHATTR_TCP;
541         attrs |= DNS_DISPATCHATTR_PRIVATE;
542         if (isc_sockaddr_pf(destaddr) == AF_INET)
543                 attrs |= DNS_DISPATCHATTR_IPV4;
544         else
545                 attrs |= DNS_DISPATCHATTR_IPV6;
546         attrs |= DNS_DISPATCHATTR_MAKEQUERY;
547         result = dns_dispatch_createtcp(requestmgr->dispatchmgr,
548                                         sock, requestmgr->taskmgr,
549                                         4096, 2, 1, 1, 3, attrs,
550                                         dispatchp);
551 cleanup:
552         isc_socket_detach(&sock);
553         return (result);
554 }
555
556 static isc_result_t
557 find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
558                   isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
559 {
560         dns_dispatch_t *disp = NULL;
561         unsigned int attrs, attrmask;
562
563         if (srcaddr == NULL) {
564                 switch (isc_sockaddr_pf(destaddr)) {
565                 case PF_INET:
566                         disp = requestmgr->dispatchv4;
567                         break;
568
569                 case PF_INET6:
570                         disp = requestmgr->dispatchv6;
571                         break;
572
573                 default:
574                         return (ISC_R_NOTIMPLEMENTED);
575                 }
576                 if (disp == NULL)
577                         return (ISC_R_FAMILYNOSUPPORT);
578                 dns_dispatch_attach(disp, dispatchp);
579                 return (ISC_R_SUCCESS);
580         }
581         attrs = 0;
582         attrs |= DNS_DISPATCHATTR_UDP;
583         switch (isc_sockaddr_pf(srcaddr)) {
584         case PF_INET:
585                 attrs |= DNS_DISPATCHATTR_IPV4;
586                 break;
587
588         case PF_INET6:
589                 attrs |= DNS_DISPATCHATTR_IPV6;
590                 break;
591
592         default:
593                 return (ISC_R_NOTIMPLEMENTED);
594         }
595         attrmask = 0;
596         attrmask |= DNS_DISPATCHATTR_UDP;
597         attrmask |= DNS_DISPATCHATTR_TCP;
598         attrmask |= DNS_DISPATCHATTR_IPV4;
599         attrmask |= DNS_DISPATCHATTR_IPV6;
600         return (dns_dispatch_getudp(requestmgr->dispatchmgr,
601                                     requestmgr->socketmgr,
602                                     requestmgr->taskmgr,
603                                     srcaddr, 4096,
604                                     1000, 32768, 16411, 16433,
605                                     attrs, attrmask,
606                                     dispatchp));
607 }
608
609 static isc_result_t
610 get_dispatch(isc_boolean_t tcp, dns_requestmgr_t *requestmgr,
611              isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
612              dns_dispatch_t **dispatchp)
613 {
614         isc_result_t result;
615         if (tcp)
616                 result = create_tcp_dispatch(requestmgr, srcaddr,
617                                              destaddr, dispatchp);
618         else
619                 result = find_udp_dispatch(requestmgr, srcaddr,
620                                            destaddr, dispatchp);
621         return (result);
622 }
623
624 static isc_result_t
625 set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) {
626         isc_time_t expires;
627         isc_interval_t interval;
628         isc_result_t result;
629         isc_timertype_t timertype;
630
631         isc_interval_set(&interval, timeout, 0);
632         result = isc_time_nowplusinterval(&expires, &interval);
633         isc_interval_set(&interval, udpresend, 0);
634
635         timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once;
636         if (result == ISC_R_SUCCESS)
637                 result = isc_timer_reset(timer, timertype, &expires,
638                                          &interval, ISC_FALSE);
639         return (result);
640 }
641
642 isc_result_t
643 dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
644                       isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
645                       unsigned int options, unsigned int timeout,
646                       isc_task_t *task, isc_taskaction_t action, void *arg,
647                       dns_request_t **requestp)
648 {
649         return(dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
650                                       options, timeout, 0, 0, task, action,
651                                       arg, requestp));
652 }
653
654 isc_result_t
655 dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
656                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
657                        unsigned int options, unsigned int timeout,
658                        unsigned int udptimeout, isc_task_t *task,
659                        isc_taskaction_t action, void *arg,
660                        dns_request_t **requestp)
661 {
662         unsigned int udpretries = 0;
663
664         if (udptimeout != 0)
665                 udpretries = timeout / udptimeout;
666
667         return (dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
668                                        options, timeout, udptimeout,
669                                        udpretries, task, action, arg,
670                                        requestp));
671 }
672
673 isc_result_t
674 dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
675                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
676                        unsigned int options, unsigned int timeout,
677                        unsigned int udptimeout, unsigned int udpretries,
678                        isc_task_t *task, isc_taskaction_t action, void *arg,
679                        dns_request_t **requestp)
680 {
681         dns_request_t *request = NULL;
682         isc_task_t *tclone = NULL;
683         isc_socket_t *sock = NULL;
684         isc_result_t result;
685         isc_mem_t *mctx;
686         dns_messageid_t id;
687         isc_boolean_t tcp = ISC_FALSE;
688         isc_region_t r;
689         unsigned int dispopt = 0;
690
691         REQUIRE(VALID_REQUESTMGR(requestmgr));
692         REQUIRE(msgbuf != NULL);
693         REQUIRE(destaddr != NULL);
694         REQUIRE(task != NULL);
695         REQUIRE(action != NULL);
696         REQUIRE(requestp != NULL && *requestp == NULL);
697         REQUIRE(timeout > 0);
698         if (srcaddr != NULL)
699                 REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
700
701         mctx = requestmgr->mctx;
702
703         req_log(ISC_LOG_DEBUG(3), "dns_request_createraw");
704
705         if (isblackholed(requestmgr->dispatchmgr, destaddr))
706                 return (DNS_R_BLACKHOLED);
707
708         request = NULL;
709         result = new_request(mctx, &request);
710         if (result != ISC_R_SUCCESS)
711                 return (result);
712
713         if (udptimeout == 0 && udpretries != 0) {
714                 udptimeout = timeout / (udpretries + 1);
715                 if (udptimeout == 0)
716                         udptimeout = 1;
717         }
718         request->udpcount = udpretries;
719
720         /*
721          * Create timer now.  We will set it below once.
722          */
723         result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
724                                   NULL, NULL, task, req_timeout, request,
725                                   &request->timer);
726         if (result != ISC_R_SUCCESS)
727                 goto cleanup;
728
729         request->event = (dns_requestevent_t *)
730                 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
731                                    action, arg, sizeof(dns_requestevent_t));
732         if (request->event == NULL) {
733                 result = ISC_R_NOMEMORY;
734                 goto cleanup;
735         }
736         isc_task_attach(task, &tclone);
737         request->event->ev_sender = task;
738         request->event->request = request;
739         request->event->result = ISC_R_FAILURE;
740
741         isc_buffer_usedregion(msgbuf, &r);
742         if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
743                 result = DNS_R_FORMERR;
744                 goto cleanup;
745         }
746
747         if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512)
748                 tcp = ISC_TRUE;
749
750         result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
751                               &request->dispatch);
752         if (result != ISC_R_SUCCESS)
753                 goto cleanup;
754
755         if ((options & DNS_REQUESTOPT_FIXEDID) != 0) {
756                 id = (r.base[0] << 8) | r.base[1];
757                 dispopt |= DNS_DISPATCHOPT_FIXEDID;
758         }
759
760         result = dns_dispatch_addresponse3(request->dispatch, dispopt,
761                                            destaddr, task, req_response,
762                                            request, &id, &request->dispentry,
763                                            requestmgr->socketmgr);
764         if (result != ISC_R_SUCCESS)
765                 goto cleanup;
766
767         sock = req_getsocket(request);
768         INSIST(sock != NULL);
769
770         result = isc_buffer_allocate(mctx, &request->query,
771                                      r.length + (tcp ? 2 : 0));
772         if (result != ISC_R_SUCCESS)
773                 goto cleanup;
774         if (tcp)
775                 isc_buffer_putuint16(request->query, (isc_uint16_t)r.length);
776         result = isc_buffer_copyregion(request->query, &r);
777         if (result != ISC_R_SUCCESS)
778                 goto cleanup;
779
780         /* Add message ID. */
781         isc_buffer_usedregion(request->query, &r);
782         if (tcp)
783                 isc_region_consume(&r, 2);
784         r.base[0] = (id>>8) & 0xff;
785         r.base[1] = id & 0xff;
786
787         LOCK(&requestmgr->lock);
788         if (requestmgr->exiting) {
789                 UNLOCK(&requestmgr->lock);
790                 result = ISC_R_SHUTTINGDOWN;
791                 goto cleanup;
792         }
793         requestmgr_attach(requestmgr, &request->requestmgr);
794         request->hash = mgr_gethash(requestmgr);
795         ISC_LIST_APPEND(requestmgr->requests, request, link);
796         UNLOCK(&requestmgr->lock);
797
798         result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
799         if (result != ISC_R_SUCCESS)
800                 goto unlink;
801
802         request->destaddr = *destaddr;
803         if (tcp) {
804                 result = isc_socket_connect(sock, destaddr, task,
805                                             req_connected, request);
806                 if (result != ISC_R_SUCCESS)
807                         goto unlink;
808                 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
809         } else {
810                 result = req_send(request, task, destaddr);
811                 if (result != ISC_R_SUCCESS)
812                         goto unlink;
813         }
814
815         req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p",
816                 request);
817         *requestp = request;
818         return (ISC_R_SUCCESS);
819
820  unlink:
821         LOCK(&requestmgr->lock);
822         ISC_LIST_UNLINK(requestmgr->requests, request, link);
823         UNLOCK(&requestmgr->lock);
824
825  cleanup:
826         if (tclone != NULL)
827                 isc_task_detach(&tclone);
828         req_destroy(request);
829         req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
830                 dns_result_totext(result));
831         return (result);
832 }
833
834 isc_result_t
835 dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
836                    isc_sockaddr_t *address, unsigned int options,
837                    dns_tsigkey_t *key,
838                    unsigned int timeout, isc_task_t *task,
839                    isc_taskaction_t action, void *arg,
840                    dns_request_t **requestp)
841 {
842         return (dns_request_createvia3(requestmgr, message, NULL, address,
843                                        options, key, timeout, 0, 0, task,
844                                        action, arg, requestp));
845 }
846
847 isc_result_t
848 dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message,
849                       isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
850                       unsigned int options, dns_tsigkey_t *key,
851                       unsigned int timeout, isc_task_t *task,
852                       isc_taskaction_t action, void *arg,
853                       dns_request_t **requestp)
854 {
855         return(dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
856                                       options, key, timeout, 0, 0, task,
857                                       action, arg, requestp));
858 }
859
860 isc_result_t
861 dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message,
862                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
863                        unsigned int options, dns_tsigkey_t *key,
864                        unsigned int timeout, unsigned int udptimeout,
865                        isc_task_t *task, isc_taskaction_t action, void *arg,
866                        dns_request_t **requestp)
867 {
868         unsigned int udpretries = 0;
869
870         if (udptimeout != 0)
871                 udpretries = timeout / udptimeout;
872         return (dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
873                                        options, key, timeout, udptimeout,
874                                        udpretries, task, action, arg,
875                                        requestp));
876 }
877
878 isc_result_t
879 dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
880                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
881                        unsigned int options, dns_tsigkey_t *key,
882                        unsigned int timeout, unsigned int udptimeout,
883                        unsigned int udpretries, isc_task_t *task,
884                        isc_taskaction_t action, void *arg,
885                        dns_request_t **requestp)
886 {
887         dns_request_t *request = NULL;
888         isc_task_t *tclone = NULL;
889         isc_socket_t *sock = NULL;
890         isc_result_t result;
891         isc_mem_t *mctx;
892         dns_messageid_t id;
893         isc_boolean_t tcp;
894         isc_boolean_t settsigkey = ISC_TRUE;
895
896         REQUIRE(VALID_REQUESTMGR(requestmgr));
897         REQUIRE(message != NULL);
898         REQUIRE(destaddr != NULL);
899         REQUIRE(task != NULL);
900         REQUIRE(action != NULL);
901         REQUIRE(requestp != NULL && *requestp == NULL);
902         REQUIRE(timeout > 0);
903
904         mctx = requestmgr->mctx;
905
906         req_log(ISC_LOG_DEBUG(3), "dns_request_createvia");
907
908         if (srcaddr != NULL &&
909             isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr))
910                 return (ISC_R_FAMILYMISMATCH);
911
912         if (isblackholed(requestmgr->dispatchmgr, destaddr))
913                 return (DNS_R_BLACKHOLED);
914
915         request = NULL;
916         result = new_request(mctx, &request);
917         if (result != ISC_R_SUCCESS)
918                 return (result);
919
920         if (udptimeout == 0 && udpretries != 0) {
921                 udptimeout = timeout / (udpretries + 1);
922                 if (udptimeout == 0)
923                         udptimeout = 1;
924         }
925         request->udpcount = udpretries;
926
927         /*
928          * Create timer now.  We will set it below once.
929          */
930         result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
931                                   NULL, NULL, task, req_timeout, request,
932                                   &request->timer);
933         if (result != ISC_R_SUCCESS)
934                 goto cleanup;
935
936         request->event = (dns_requestevent_t *)
937                 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
938                                    action, arg, sizeof(dns_requestevent_t));
939         if (request->event == NULL) {
940                 result = ISC_R_NOMEMORY;
941                 goto cleanup;
942         }
943         isc_task_attach(task, &tclone);
944         request->event->ev_sender = task;
945         request->event->request = request;
946         request->event->result = ISC_R_FAILURE;
947         if (key != NULL)
948                 dns_tsigkey_attach(key, &request->tsigkey);
949
950  use_tcp:
951         tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0);
952         result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
953                               &request->dispatch);
954         if (result != ISC_R_SUCCESS)
955                 goto cleanup;
956
957         result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
958                                            req_response, request, &id,
959                                            &request->dispentry,
960                                            requestmgr->socketmgr);
961         if (result != ISC_R_SUCCESS)
962                 goto cleanup;
963         sock = req_getsocket(request);
964         INSIST(sock != NULL);
965
966         message->id = id;
967         if (settsigkey) {
968                 result = dns_message_settsigkey(message, request->tsigkey);
969                 if (result != ISC_R_SUCCESS)
970                         goto cleanup;
971         }
972         result = req_render(message, &request->query, options, mctx);
973         if (result == DNS_R_USETCP &&
974             (options & DNS_REQUESTOPT_TCP) == 0) {
975                 /*
976                  * Try again using TCP.
977                  */
978                 dns_message_renderreset(message);
979                 dns_dispatch_removeresponse(&request->dispentry, NULL);
980                 dns_dispatch_detach(&request->dispatch);
981                 sock = NULL;
982                 options |= DNS_REQUESTOPT_TCP;
983                 settsigkey = ISC_FALSE;
984                 goto use_tcp;
985         }
986         if (result != ISC_R_SUCCESS)
987                 goto cleanup;
988
989         result = dns_message_getquerytsig(message, mctx, &request->tsig);
990         if (result != ISC_R_SUCCESS)
991                 goto cleanup;
992
993         LOCK(&requestmgr->lock);
994         if (requestmgr->exiting) {
995                 UNLOCK(&requestmgr->lock);
996                 result = ISC_R_SHUTTINGDOWN;
997                 goto cleanup;
998         }
999         requestmgr_attach(requestmgr, &request->requestmgr);
1000         request->hash = mgr_gethash(requestmgr);
1001         ISC_LIST_APPEND(requestmgr->requests, request, link);
1002         UNLOCK(&requestmgr->lock);
1003
1004         result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
1005         if (result != ISC_R_SUCCESS)
1006                 goto unlink;
1007
1008         request->destaddr = *destaddr;
1009         if (tcp) {
1010                 result = isc_socket_connect(sock, destaddr, task,
1011                                             req_connected, request);
1012                 if (result != ISC_R_SUCCESS)
1013                         goto unlink;
1014                 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
1015         } else {
1016                 result = req_send(request, task, destaddr);
1017                 if (result != ISC_R_SUCCESS)
1018                         goto unlink;
1019         }
1020
1021         req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p",
1022                 request);
1023         *requestp = request;
1024         return (ISC_R_SUCCESS);
1025
1026  unlink:
1027         LOCK(&requestmgr->lock);
1028         ISC_LIST_UNLINK(requestmgr->requests, request, link);
1029         UNLOCK(&requestmgr->lock);
1030
1031  cleanup:
1032         if (tclone != NULL)
1033                 isc_task_detach(&tclone);
1034         req_destroy(request);
1035         req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s",
1036                 dns_result_totext(result));
1037         return (result);
1038 }
1039
1040 static isc_result_t
1041 req_render(dns_message_t *message, isc_buffer_t **bufferp,
1042            unsigned int options, isc_mem_t *mctx)
1043 {
1044         isc_buffer_t *buf1 = NULL;
1045         isc_buffer_t *buf2 = NULL;
1046         isc_result_t result;
1047         isc_region_t r;
1048         isc_boolean_t tcp = ISC_FALSE;
1049         dns_compress_t cctx;
1050         isc_boolean_t cleanup_cctx = ISC_FALSE;
1051
1052         REQUIRE(bufferp != NULL && *bufferp == NULL);
1053
1054         req_log(ISC_LOG_DEBUG(3), "request_render");
1055
1056         /*
1057          * Create buffer able to hold largest possible message.
1058          */
1059         result = isc_buffer_allocate(mctx, &buf1, 65535);
1060         if (result != ISC_R_SUCCESS)
1061                 return (result);
1062
1063         result = dns_compress_init(&cctx, -1, mctx);
1064         if (result != ISC_R_SUCCESS)
1065                 return (result);
1066         cleanup_cctx = ISC_TRUE;
1067
1068         if ((options & DNS_REQUESTOPT_CASE) != 0)
1069                 dns_compress_setsensitive(&cctx, ISC_TRUE);
1070
1071         /*
1072          * Render message.
1073          */
1074         result = dns_message_renderbegin(message, &cctx, buf1);
1075         if (result != ISC_R_SUCCESS)
1076                 goto cleanup;
1077         result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
1078         if (result != ISC_R_SUCCESS)
1079                 goto cleanup;
1080         result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
1081         if (result != ISC_R_SUCCESS)
1082                 goto cleanup;
1083         result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
1084         if (result != ISC_R_SUCCESS)
1085                 goto cleanup;
1086         result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
1087         if (result != ISC_R_SUCCESS)
1088                 goto cleanup;
1089         result = dns_message_renderend(message);
1090         if (result != ISC_R_SUCCESS)
1091                 goto cleanup;
1092
1093         dns_compress_invalidate(&cctx);
1094         cleanup_cctx = ISC_FALSE;
1095
1096         /*
1097          * Copy rendered message to exact sized buffer.
1098          */
1099         isc_buffer_usedregion(buf1, &r);
1100         if ((options & DNS_REQUESTOPT_TCP) != 0) {
1101                 tcp = ISC_TRUE;
1102         } else if (r.length > 512) {
1103                 result = DNS_R_USETCP;
1104                 goto cleanup;
1105         }
1106         result = isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0));
1107         if (result != ISC_R_SUCCESS)
1108                 goto cleanup;
1109         if (tcp)
1110                 isc_buffer_putuint16(buf2, (isc_uint16_t)r.length);
1111         result = isc_buffer_copyregion(buf2, &r);
1112         if (result != ISC_R_SUCCESS)
1113                 goto cleanup;
1114
1115         /*
1116          * Cleanup and return.
1117          */
1118         isc_buffer_free(&buf1);
1119         *bufferp = buf2;
1120         return (ISC_R_SUCCESS);
1121
1122  cleanup:
1123         dns_message_renderreset(message);
1124         if (buf1 != NULL)
1125                 isc_buffer_free(&buf1);
1126         if (buf2 != NULL)
1127                 isc_buffer_free(&buf2);
1128         if (cleanup_cctx)
1129                 dns_compress_invalidate(&cctx);
1130         return (result);
1131 }
1132
1133
1134 /*
1135  * If this request is no longer waiting for events,
1136  * send the completion event.  This will ultimately
1137  * cause the request to be destroyed.
1138  *
1139  * Requires:
1140  *      'request' is locked by the caller.
1141  */
1142 static void
1143 send_if_done(dns_request_t *request, isc_result_t result) {
1144         if (request->event != NULL && !request->canceling)
1145                 req_sendevent(request, result);
1146 }
1147
1148 /*
1149  * Handle the control event.
1150  */
1151 static void
1152 do_cancel(isc_task_t *task, isc_event_t *event) {
1153         dns_request_t *request = event->ev_arg;
1154         UNUSED(task);
1155         INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL);
1156         LOCK(&request->requestmgr->locks[request->hash]);
1157         request->canceling = ISC_FALSE;
1158         if (!DNS_REQUEST_CANCELED(request))
1159                 req_cancel(request);
1160         send_if_done(request, ISC_R_CANCELED);
1161         UNLOCK(&request->requestmgr->locks[request->hash]);
1162 }
1163
1164 void
1165 dns_request_cancel(dns_request_t *request) {
1166         REQUIRE(VALID_REQUEST(request));
1167
1168         req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request);
1169
1170         REQUIRE(VALID_REQUEST(request));
1171
1172         LOCK(&request->requestmgr->locks[request->hash]);
1173         if (!request->canceling && !DNS_REQUEST_CANCELED(request)) {
1174                 isc_event_t *ev =  &request->ctlevent;
1175                 isc_task_send(request->event->ev_sender, &ev);
1176                 request->canceling = ISC_TRUE;
1177         }
1178         UNLOCK(&request->requestmgr->locks[request->hash]);
1179 }
1180
1181 isc_result_t
1182 dns_request_getresponse(dns_request_t *request, dns_message_t *message,
1183                         unsigned int options)
1184 {
1185         isc_result_t result;
1186
1187         REQUIRE(VALID_REQUEST(request));
1188         REQUIRE(request->answer != NULL);
1189
1190         req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p",
1191                 request);
1192
1193         result = dns_message_setquerytsig(message, request->tsig);
1194         if (result != ISC_R_SUCCESS)
1195                 return (result);
1196         result = dns_message_settsigkey(message, request->tsigkey);
1197         if (result != ISC_R_SUCCESS)
1198                 return (result);
1199         result = dns_message_parse(message, request->answer, options);
1200         if (result != ISC_R_SUCCESS)
1201                 return (result);
1202         if (request->tsigkey != NULL)
1203                 result = dns_tsig_verify(request->answer, message, NULL, NULL);
1204         return (result);
1205 }
1206
1207 isc_boolean_t
1208 dns_request_usedtcp(dns_request_t *request) {
1209         REQUIRE(VALID_REQUEST(request));
1210
1211         return (ISC_TF((request->flags & DNS_REQUEST_F_TCP) != 0));
1212 }
1213
1214 void
1215 dns_request_destroy(dns_request_t **requestp) {
1216         dns_request_t *request;
1217
1218         REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
1219
1220         request = *requestp;
1221
1222         req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request);
1223
1224         LOCK(&request->requestmgr->lock);
1225         LOCK(&request->requestmgr->locks[request->hash]);
1226         ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
1227         INSIST(!DNS_REQUEST_CONNECTING(request));
1228         INSIST(!DNS_REQUEST_SENDING(request));
1229         UNLOCK(&request->requestmgr->locks[request->hash]);
1230         UNLOCK(&request->requestmgr->lock);
1231
1232         /*
1233          * These should have been cleaned up by req_cancel() before
1234          * the completion event was sent.
1235          */
1236         INSIST(!ISC_LINK_LINKED(request, link));
1237         INSIST(request->dispentry == NULL);
1238         INSIST(request->dispatch == NULL);
1239         INSIST(request->timer == NULL);
1240
1241         req_destroy(request);
1242
1243         *requestp = NULL;
1244 }
1245
1246 /***
1247  *** Private: request.
1248  ***/
1249
1250 static isc_socket_t *
1251 req_getsocket(dns_request_t *request) {
1252         unsigned int dispattr;
1253         isc_socket_t *sock;
1254
1255         dispattr = dns_dispatch_getattributes(request->dispatch);
1256         if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1257                 INSIST(request->dispentry != NULL);
1258                 sock = dns_dispatch_getentrysocket(request->dispentry);
1259         } else
1260                 sock = dns_dispatch_getsocket(request->dispatch);
1261
1262         return (sock);
1263 }
1264
1265 static void
1266 req_connected(isc_task_t *task, isc_event_t *event) {
1267         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1268         isc_result_t result;
1269         dns_request_t *request = event->ev_arg;
1270
1271         REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
1272         REQUIRE(VALID_REQUEST(request));
1273         REQUIRE(DNS_REQUEST_CONNECTING(request));
1274
1275         req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request);
1276
1277         LOCK(&request->requestmgr->locks[request->hash]);
1278         request->flags &= ~DNS_REQUEST_F_CONNECTING;
1279
1280         if (DNS_REQUEST_CANCELED(request)) {
1281                 /*
1282                  * Send delayed event.
1283                  */
1284                 if (DNS_REQUEST_TIMEDOUT(request))
1285                         send_if_done(request, ISC_R_TIMEDOUT);
1286                 else
1287                         send_if_done(request, ISC_R_CANCELED);
1288         } else {
1289                 dns_dispatch_starttcp(request->dispatch);
1290                 result = sevent->result;
1291                 if (result == ISC_R_SUCCESS)
1292                         result = req_send(request, task, NULL);
1293
1294                 if (result != ISC_R_SUCCESS) {
1295                         req_cancel(request);
1296                         send_if_done(request, ISC_R_CANCELED);
1297                 }
1298         }
1299         UNLOCK(&request->requestmgr->locks[request->hash]);
1300         isc_event_free(&event);
1301 }
1302
1303 static void
1304 req_senddone(isc_task_t *task, isc_event_t *event) {
1305         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1306         dns_request_t *request = event->ev_arg;
1307
1308         REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1309         REQUIRE(VALID_REQUEST(request));
1310         REQUIRE(DNS_REQUEST_SENDING(request));
1311
1312         req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
1313
1314         UNUSED(task);
1315
1316         LOCK(&request->requestmgr->locks[request->hash]);
1317         request->flags &= ~DNS_REQUEST_F_SENDING;
1318
1319         if (DNS_REQUEST_CANCELED(request)) {
1320                 /*
1321                  * Send delayed event.
1322                  */
1323                 if (DNS_REQUEST_TIMEDOUT(request))
1324                         send_if_done(request, ISC_R_TIMEDOUT);
1325                 else
1326                         send_if_done(request, ISC_R_CANCELED);
1327         } else if (sevent->result != ISC_R_SUCCESS) {
1328                 req_cancel(request);
1329                 send_if_done(request, ISC_R_CANCELED);
1330         }
1331         UNLOCK(&request->requestmgr->locks[request->hash]);
1332
1333         isc_event_free(&event);
1334 }
1335
1336 static void
1337 req_response(isc_task_t *task, isc_event_t *event) {
1338         isc_result_t result;
1339         dns_request_t *request = event->ev_arg;
1340         dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
1341         isc_region_t r;
1342
1343         REQUIRE(VALID_REQUEST(request));
1344         REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
1345
1346         UNUSED(task);
1347
1348         req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
1349                 dns_result_totext(devent->result));
1350
1351         LOCK(&request->requestmgr->locks[request->hash]);
1352         result = devent->result;
1353         if (result != ISC_R_SUCCESS)
1354                 goto done;
1355
1356         /*
1357          * Copy buffer to request.
1358          */
1359         isc_buffer_usedregion(&devent->buffer, &r);
1360         result = isc_buffer_allocate(request->mctx, &request->answer,
1361                                      r.length);
1362         if (result != ISC_R_SUCCESS)
1363                 goto done;
1364         result = isc_buffer_copyregion(request->answer, &r);
1365         if (result != ISC_R_SUCCESS)
1366                 isc_buffer_free(&request->answer);
1367  done:
1368         /*
1369          * Cleanup.
1370          */
1371         dns_dispatch_removeresponse(&request->dispentry, &devent);
1372         req_cancel(request);
1373         /*
1374          * Send completion event.
1375          */
1376         send_if_done(request, result);
1377         UNLOCK(&request->requestmgr->locks[request->hash]);
1378 }
1379
1380 static void
1381 req_timeout(isc_task_t *task, isc_event_t *event) {
1382         dns_request_t *request = event->ev_arg;
1383         isc_result_t result;
1384
1385         REQUIRE(VALID_REQUEST(request));
1386
1387         req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
1388
1389         UNUSED(task);
1390         LOCK(&request->requestmgr->locks[request->hash]);
1391         if (event->ev_type == ISC_TIMEREVENT_TICK &&
1392             request->udpcount-- != 0) {
1393                 if (! DNS_REQUEST_SENDING(request)) {
1394                         result = req_send(request, task, &request->destaddr);
1395                         if (result != ISC_R_SUCCESS) {
1396                                 req_cancel(request);
1397                                 send_if_done(request, result);
1398                         }
1399                 }
1400         } else {
1401                 request->flags |= DNS_REQUEST_F_TIMEDOUT;
1402                 req_cancel(request);
1403                 send_if_done(request, ISC_R_TIMEDOUT);
1404         }
1405         UNLOCK(&request->requestmgr->locks[request->hash]);
1406         isc_event_free(&event);
1407 }
1408
1409 static void
1410 req_sendevent(dns_request_t *request, isc_result_t result) {
1411         isc_task_t *task;
1412
1413         REQUIRE(VALID_REQUEST(request));
1414
1415         req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request);
1416
1417         /*
1418          * Lock held by caller.
1419          */
1420         task = request->event->ev_sender;
1421         request->event->ev_sender = request;
1422         request->event->result = result;
1423         isc_task_sendanddetach(&task, (isc_event_t **)&request->event);
1424 }
1425
1426 static void
1427 req_destroy(dns_request_t *request) {
1428         isc_mem_t *mctx;
1429
1430         REQUIRE(VALID_REQUEST(request));
1431
1432         req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request);
1433
1434         request->magic = 0;
1435         if (request->query != NULL)
1436                 isc_buffer_free(&request->query);
1437         if (request->answer != NULL)
1438                 isc_buffer_free(&request->answer);
1439         if (request->event != NULL)
1440                 isc_event_free((isc_event_t **)&request->event);
1441         if (request->dispentry != NULL)
1442                 dns_dispatch_removeresponse(&request->dispentry, NULL);
1443         if (request->dispatch != NULL)
1444                 dns_dispatch_detach(&request->dispatch);
1445         if (request->timer != NULL)
1446                 isc_timer_detach(&request->timer);
1447         if (request->tsig != NULL)
1448                 isc_buffer_free(&request->tsig);
1449         if (request->tsigkey != NULL)
1450                 dns_tsigkey_detach(&request->tsigkey);
1451         if (request->requestmgr != NULL)
1452                 requestmgr_detach(&request->requestmgr);
1453         mctx = request->mctx;
1454         isc_mem_put(mctx, request, sizeof(*request));
1455         isc_mem_detach(&mctx);
1456 }
1457
1458 /*
1459  * Stop the current request.  Must be called from the request's task.
1460  */
1461 static void
1462 req_cancel(dns_request_t *request) {
1463         isc_socket_t *sock;
1464         unsigned int dispattr;
1465
1466         REQUIRE(VALID_REQUEST(request));
1467
1468         req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request);
1469
1470         /*
1471          * Lock held by caller.
1472          */
1473         request->flags |= DNS_REQUEST_F_CANCELED;
1474
1475         if (request->timer != NULL)
1476                 isc_timer_detach(&request->timer);
1477         dispattr = dns_dispatch_getattributes(request->dispatch);
1478         sock = NULL;
1479         if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) {
1480                 if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1481                         if (request->dispentry != NULL) {
1482                                 sock = dns_dispatch_getentrysocket(
1483                                         request->dispentry);
1484                         }
1485                 } else
1486                         sock = dns_dispatch_getsocket(request->dispatch);
1487                 if (DNS_REQUEST_CONNECTING(request) && sock != NULL)
1488                         isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT);
1489                 if (DNS_REQUEST_SENDING(request) && sock != NULL)
1490                         isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND);
1491         }
1492         if (request->dispentry != NULL)
1493                 dns_dispatch_removeresponse(&request->dispentry, NULL);
1494         dns_dispatch_detach(&request->dispatch);
1495 }
1496
1497 static void
1498 req_log(int level, const char *fmt, ...) {
1499         va_list ap;
1500
1501         va_start(ap, fmt);
1502         isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1503                        DNS_LOGMODULE_REQUEST, level, fmt, ap);
1504         va_end(ap);
1505 }