Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / request.c
blob77ad040f3faab7dacd2337e1305c5c021474558a
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: request.c,v 1.85 2009/09/01 00:22:26 jinmei Exp */
22 /*! \file */
24 #include <config.h>
26 #include <isc/magic.h>
27 #include <isc/mem.h>
28 #include <isc/task.h>
29 #include <isc/timer.h>
30 #include <isc/util.h>
32 #include <dns/acl.h>
33 #include <dns/compress.h>
34 #include <dns/dispatch.h>
35 #include <dns/events.h>
36 #include <dns/log.h>
37 #include <dns/message.h>
38 #include <dns/rdata.h>
39 #include <dns/rdatastruct.h>
40 #include <dns/request.h>
41 #include <dns/result.h>
42 #include <dns/tsig.h>
44 #define REQUESTMGR_MAGIC ISC_MAGIC('R', 'q', 'u', 'M')
45 #define VALID_REQUESTMGR(mgr) ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC)
47 #define REQUEST_MAGIC ISC_MAGIC('R', 'q', 'u', '!')
48 #define VALID_REQUEST(request) ISC_MAGIC_VALID(request, REQUEST_MAGIC)
50 typedef ISC_LIST(dns_request_t) dns_requestlist_t;
52 #define DNS_REQUEST_NLOCKS 7
54 struct dns_requestmgr {
55 unsigned int magic;
56 isc_mutex_t lock;
57 isc_mem_t *mctx;
59 /* locked */
60 isc_int32_t eref;
61 isc_int32_t iref;
62 isc_timermgr_t *timermgr;
63 isc_socketmgr_t *socketmgr;
64 isc_taskmgr_t *taskmgr;
65 dns_dispatchmgr_t *dispatchmgr;
66 dns_dispatch_t *dispatchv4;
67 dns_dispatch_t *dispatchv6;
68 isc_boolean_t exiting;
69 isc_eventlist_t whenshutdown;
70 unsigned int hash;
71 isc_mutex_t locks[DNS_REQUEST_NLOCKS];
72 dns_requestlist_t requests;
75 struct dns_request {
76 unsigned int magic;
77 unsigned int hash;
78 isc_mem_t *mctx;
79 isc_int32_t flags;
80 ISC_LINK(dns_request_t) link;
81 isc_buffer_t *query;
82 isc_buffer_t *answer;
83 dns_requestevent_t *event;
84 dns_dispatch_t *dispatch;
85 dns_dispentry_t *dispentry;
86 isc_timer_t *timer;
87 dns_requestmgr_t *requestmgr;
88 isc_buffer_t *tsig;
89 dns_tsigkey_t *tsigkey;
90 isc_event_t ctlevent;
91 isc_boolean_t canceling; /* ctlevent outstanding */
92 isc_sockaddr_t destaddr;
93 unsigned int udpcount;
96 #define DNS_REQUEST_F_CONNECTING 0x0001
97 #define DNS_REQUEST_F_SENDING 0x0002
98 #define DNS_REQUEST_F_CANCELED 0x0004 /*%< ctlevent received, or otherwise
99 synchronously canceled */
100 #define DNS_REQUEST_F_TIMEDOUT 0x0008 /*%< canceled due to a timeout */
101 #define DNS_REQUEST_F_TCP 0x0010 /*%< This request used TCP */
102 #define DNS_REQUEST_CANCELED(r) \
103 (((r)->flags & DNS_REQUEST_F_CANCELED) != 0)
104 #define DNS_REQUEST_CONNECTING(r) \
105 (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
106 #define DNS_REQUEST_SENDING(r) \
107 (((r)->flags & DNS_REQUEST_F_SENDING) != 0)
108 #define DNS_REQUEST_TIMEDOUT(r) \
109 (((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0)
112 /***
113 *** Forward
114 ***/
116 static void mgr_destroy(dns_requestmgr_t *requestmgr);
117 static void mgr_shutdown(dns_requestmgr_t *requestmgr);
118 static unsigned int mgr_gethash(dns_requestmgr_t *requestmgr);
119 static void send_shutdown_events(dns_requestmgr_t *requestmgr);
121 static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer,
122 unsigned int options, isc_mem_t *mctx);
123 static void req_senddone(isc_task_t *task, isc_event_t *event);
124 static void req_response(isc_task_t *task, isc_event_t *event);
125 static void req_timeout(isc_task_t *task, isc_event_t *event);
126 static isc_socket_t * req_getsocket(dns_request_t *request);
127 static void req_connected(isc_task_t *task, isc_event_t *event);
128 static void req_sendevent(dns_request_t *request, isc_result_t result);
129 static void req_cancel(dns_request_t *request);
130 static void req_destroy(dns_request_t *request);
131 static void req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
132 static void do_cancel(isc_task_t *task, isc_event_t *event);
134 /***
135 *** Public
136 ***/
138 isc_result_t
139 dns_requestmgr_create(isc_mem_t *mctx,
140 isc_timermgr_t *timermgr,
141 isc_socketmgr_t *socketmgr,
142 isc_taskmgr_t *taskmgr,
143 dns_dispatchmgr_t *dispatchmgr,
144 dns_dispatch_t *dispatchv4,
145 dns_dispatch_t *dispatchv6,
146 dns_requestmgr_t **requestmgrp)
148 dns_requestmgr_t *requestmgr;
149 isc_socket_t *socket;
150 isc_result_t result;
151 int i;
152 unsigned int dispattr;
154 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
156 REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
157 REQUIRE(timermgr != NULL);
158 REQUIRE(socketmgr != NULL);
159 REQUIRE(taskmgr != NULL);
160 REQUIRE(dispatchmgr != NULL);
161 UNUSED(socket);
162 if (dispatchv4 != NULL) {
163 dispattr = dns_dispatch_getattributes(dispatchv4);
164 REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
166 if (dispatchv6 != NULL) {
167 dispattr = dns_dispatch_getattributes(dispatchv6);
168 REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
171 requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
172 if (requestmgr == NULL)
173 return (ISC_R_NOMEMORY);
175 result = isc_mutex_init(&requestmgr->lock);
176 if (result != ISC_R_SUCCESS) {
177 isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
178 return (result);
180 for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
181 result = isc_mutex_init(&requestmgr->locks[i]);
182 if (result != ISC_R_SUCCESS) {
183 while (--i >= 0)
184 DESTROYLOCK(&requestmgr->locks[i]);
185 DESTROYLOCK(&requestmgr->lock);
186 isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
187 return (result);
190 requestmgr->timermgr = timermgr;
191 requestmgr->socketmgr = socketmgr;
192 requestmgr->taskmgr = taskmgr;
193 requestmgr->dispatchmgr = dispatchmgr;
194 requestmgr->dispatchv4 = NULL;
195 if (dispatchv4 != NULL)
196 dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
197 requestmgr->dispatchv6 = NULL;
198 if (dispatchv6 != NULL)
199 dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
200 requestmgr->mctx = NULL;
201 isc_mem_attach(mctx, &requestmgr->mctx);
202 requestmgr->eref = 1; /* implicit attach */
203 requestmgr->iref = 0;
204 ISC_LIST_INIT(requestmgr->whenshutdown);
205 ISC_LIST_INIT(requestmgr->requests);
206 requestmgr->exiting = ISC_FALSE;
207 requestmgr->hash = 0;
208 requestmgr->magic = REQUESTMGR_MAGIC;
210 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
212 *requestmgrp = requestmgr;
213 return (ISC_R_SUCCESS);
216 void
217 dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
218 isc_event_t **eventp)
220 isc_task_t *clone;
221 isc_event_t *event;
223 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_whenshutdown");
225 REQUIRE(VALID_REQUESTMGR(requestmgr));
226 REQUIRE(eventp != NULL);
228 event = *eventp;
229 *eventp = NULL;
231 LOCK(&requestmgr->lock);
233 if (requestmgr->exiting) {
235 * We're already shutdown. Send the event.
237 event->ev_sender = requestmgr;
238 isc_task_send(task, &event);
239 } else {
240 clone = NULL;
241 isc_task_attach(task, &clone);
242 event->ev_sender = clone;
243 ISC_LIST_APPEND(requestmgr->whenshutdown, event, ev_link);
245 UNLOCK(&requestmgr->lock);
248 void
249 dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
251 REQUIRE(VALID_REQUESTMGR(requestmgr));
253 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr);
255 LOCK(&requestmgr->lock);
256 mgr_shutdown(requestmgr);
257 UNLOCK(&requestmgr->lock);
260 static void
261 mgr_shutdown(dns_requestmgr_t *requestmgr) {
262 dns_request_t *request;
265 * Caller holds lock.
267 if (!requestmgr->exiting) {
268 requestmgr->exiting = ISC_TRUE;
269 for (request = ISC_LIST_HEAD(requestmgr->requests);
270 request != NULL;
271 request = ISC_LIST_NEXT(request, link)) {
272 dns_request_cancel(request);
274 if (requestmgr->iref == 0) {
275 INSIST(ISC_LIST_EMPTY(requestmgr->requests));
276 send_shutdown_events(requestmgr);
281 static void
282 requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
285 * Locked by caller.
288 REQUIRE(VALID_REQUESTMGR(source));
289 REQUIRE(targetp != NULL && *targetp == NULL);
291 REQUIRE(!source->exiting);
293 source->iref++;
294 *targetp = source;
296 req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d",
297 source, source->eref, source->iref);
300 static void
301 requestmgr_detach(dns_requestmgr_t **requestmgrp) {
302 dns_requestmgr_t *requestmgr;
303 isc_boolean_t need_destroy = ISC_FALSE;
305 REQUIRE(requestmgrp != NULL);
306 requestmgr = *requestmgrp;
307 REQUIRE(VALID_REQUESTMGR(requestmgr));
309 *requestmgrp = NULL;
310 LOCK(&requestmgr->lock);
311 INSIST(requestmgr->iref > 0);
312 requestmgr->iref--;
314 req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d",
315 requestmgr, requestmgr->eref, requestmgr->iref);
317 if (requestmgr->iref == 0 && requestmgr->exiting) {
318 INSIST(ISC_LIST_HEAD(requestmgr->requests) == NULL);
319 send_shutdown_events(requestmgr);
320 if (requestmgr->eref == 0)
321 need_destroy = ISC_TRUE;
323 UNLOCK(&requestmgr->lock);
325 if (need_destroy)
326 mgr_destroy(requestmgr);
329 void
330 dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
332 REQUIRE(VALID_REQUESTMGR(source));
333 REQUIRE(targetp != NULL && *targetp == NULL);
334 REQUIRE(!source->exiting);
336 LOCK(&source->lock);
337 source->eref++;
338 *targetp = source;
339 UNLOCK(&source->lock);
341 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d",
342 source, source->eref, source->iref);
345 void
346 dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) {
347 dns_requestmgr_t *requestmgr;
348 isc_boolean_t need_destroy = ISC_FALSE;
350 REQUIRE(requestmgrp != NULL);
351 requestmgr = *requestmgrp;
352 REQUIRE(VALID_REQUESTMGR(requestmgr));
354 LOCK(&requestmgr->lock);
355 INSIST(requestmgr->eref > 0);
356 requestmgr->eref--;
358 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d",
359 requestmgr, requestmgr->eref, requestmgr->iref);
361 if (requestmgr->eref == 0 && requestmgr->iref == 0) {
362 INSIST(requestmgr->exiting &&
363 ISC_LIST_HEAD(requestmgr->requests) == NULL);
364 need_destroy = ISC_TRUE;
366 UNLOCK(&requestmgr->lock);
368 if (need_destroy)
369 mgr_destroy(requestmgr);
371 *requestmgrp = NULL;
374 static void
375 send_shutdown_events(dns_requestmgr_t *requestmgr) {
376 isc_event_t *event, *next_event;
377 isc_task_t *etask;
379 req_log(ISC_LOG_DEBUG(3), "send_shutdown_events: %p", requestmgr);
382 * Caller must be holding the manager lock.
384 for (event = ISC_LIST_HEAD(requestmgr->whenshutdown);
385 event != NULL;
386 event = next_event) {
387 next_event = ISC_LIST_NEXT(event, ev_link);
388 ISC_LIST_UNLINK(requestmgr->whenshutdown, event, ev_link);
389 etask = event->ev_sender;
390 event->ev_sender = requestmgr;
391 isc_task_sendanddetach(&etask, &event);
395 static void
396 mgr_destroy(dns_requestmgr_t *requestmgr) {
397 int i;
398 isc_mem_t *mctx;
400 req_log(ISC_LOG_DEBUG(3), "mgr_destroy");
402 REQUIRE(requestmgr->eref == 0);
403 REQUIRE(requestmgr->iref == 0);
405 DESTROYLOCK(&requestmgr->lock);
406 for (i = 0; i < DNS_REQUEST_NLOCKS; i++)
407 DESTROYLOCK(&requestmgr->locks[i]);
408 if (requestmgr->dispatchv4 != NULL)
409 dns_dispatch_detach(&requestmgr->dispatchv4);
410 if (requestmgr->dispatchv6 != NULL)
411 dns_dispatch_detach(&requestmgr->dispatchv6);
412 requestmgr->magic = 0;
413 mctx = requestmgr->mctx;
414 isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
415 isc_mem_detach(&mctx);
418 static unsigned int
419 mgr_gethash(dns_requestmgr_t *requestmgr) {
420 req_log(ISC_LOG_DEBUG(3), "mgr_gethash");
422 * Locked by caller.
424 requestmgr->hash++;
425 return (requestmgr->hash % DNS_REQUEST_NLOCKS);
428 static inline isc_result_t
429 req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) {
430 isc_region_t r;
431 isc_socket_t *socket;
432 isc_result_t result;
433 unsigned int dispattr;
435 req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
437 REQUIRE(VALID_REQUEST(request));
438 dispattr = dns_dispatch_getattributes(request->dispatch);
439 socket = req_getsocket(request);
440 isc_buffer_usedregion(request->query, &r);
442 * We could connect the socket when we are using an exclusive dispatch
443 * as we do in resolver.c, but we prefer implementation simplicity
444 * at this moment.
446 result = isc_socket_sendto(socket, &r, task, req_senddone,
447 request, address, NULL);
448 if (result == ISC_R_SUCCESS)
449 request->flags |= DNS_REQUEST_F_SENDING;
450 return (result);
453 static isc_result_t
454 new_request(isc_mem_t *mctx, dns_request_t **requestp)
456 dns_request_t *request;
458 request = isc_mem_get(mctx, sizeof(*request));
459 if (request == NULL)
460 return (ISC_R_NOMEMORY);
463 * Zero structure.
465 request->magic = 0;
466 request->mctx = NULL;
467 request->flags = 0;
468 ISC_LINK_INIT(request, link);
469 request->query = NULL;
470 request->answer = NULL;
471 request->event = NULL;
472 request->dispatch = NULL;
473 request->dispentry = NULL;
474 request->timer = NULL;
475 request->requestmgr = NULL;
476 request->tsig = NULL;
477 request->tsigkey = NULL;
478 ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL,
479 DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL,
480 NULL, NULL);
481 request->canceling = ISC_FALSE;
482 request->udpcount = 0;
484 isc_mem_attach(mctx, &request->mctx);
486 request->magic = REQUEST_MAGIC;
487 *requestp = request;
488 return (ISC_R_SUCCESS);
492 static isc_boolean_t
493 isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) {
494 dns_acl_t *blackhole;
495 isc_netaddr_t netaddr;
496 int match;
497 isc_boolean_t drop = ISC_FALSE;
498 char netaddrstr[ISC_NETADDR_FORMATSIZE];
500 blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
501 if (blackhole != NULL) {
502 isc_netaddr_fromsockaddr(&netaddr, destaddr);
503 if (dns_acl_match(&netaddr, NULL, blackhole,
504 NULL, &match, NULL) == ISC_R_SUCCESS &&
505 match > 0)
506 drop = ISC_TRUE;
508 if (drop) {
509 isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
510 req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
512 return (drop);
515 static isc_result_t
516 create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
517 isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
519 isc_result_t result;
520 isc_socket_t *socket = NULL;
521 isc_sockaddr_t src;
522 unsigned int attrs;
523 isc_sockaddr_t bind_any;
525 result = isc_socket_create(requestmgr->socketmgr,
526 isc_sockaddr_pf(destaddr),
527 isc_sockettype_tcp, &socket);
528 if (result != ISC_R_SUCCESS)
529 return (result);
530 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
531 if (srcaddr == NULL) {
532 isc_sockaddr_anyofpf(&bind_any,
533 isc_sockaddr_pf(destaddr));
534 result = isc_socket_bind(socket, &bind_any, 0);
535 } else {
536 src = *srcaddr;
537 isc_sockaddr_setport(&src, 0);
538 result = isc_socket_bind(socket, &src, 0);
540 if (result != ISC_R_SUCCESS)
541 goto cleanup;
542 #endif
543 attrs = 0;
544 attrs |= DNS_DISPATCHATTR_TCP;
545 attrs |= DNS_DISPATCHATTR_PRIVATE;
546 if (isc_sockaddr_pf(destaddr) == AF_INET)
547 attrs |= DNS_DISPATCHATTR_IPV4;
548 else
549 attrs |= DNS_DISPATCHATTR_IPV6;
550 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
551 result = dns_dispatch_createtcp(requestmgr->dispatchmgr,
552 socket, requestmgr->taskmgr,
553 4096, 2, 1, 1, 3, attrs,
554 dispatchp);
555 cleanup:
556 isc_socket_detach(&socket);
557 return (result);
560 static isc_result_t
561 find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
562 isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
564 dns_dispatch_t *disp = NULL;
565 unsigned int attrs, attrmask;
567 if (srcaddr == NULL) {
568 switch (isc_sockaddr_pf(destaddr)) {
569 case PF_INET:
570 disp = requestmgr->dispatchv4;
571 break;
573 case PF_INET6:
574 disp = requestmgr->dispatchv6;
575 break;
577 default:
578 return (ISC_R_NOTIMPLEMENTED);
580 if (disp == NULL)
581 return (ISC_R_FAMILYNOSUPPORT);
582 dns_dispatch_attach(disp, dispatchp);
583 return (ISC_R_SUCCESS);
585 attrs = 0;
586 attrs |= DNS_DISPATCHATTR_UDP;
587 switch (isc_sockaddr_pf(srcaddr)) {
588 case PF_INET:
589 attrs |= DNS_DISPATCHATTR_IPV4;
590 break;
592 case PF_INET6:
593 attrs |= DNS_DISPATCHATTR_IPV6;
594 break;
596 default:
597 return (ISC_R_NOTIMPLEMENTED);
599 attrmask = 0;
600 attrmask |= DNS_DISPATCHATTR_UDP;
601 attrmask |= DNS_DISPATCHATTR_TCP;
602 attrmask |= DNS_DISPATCHATTR_IPV4;
603 attrmask |= DNS_DISPATCHATTR_IPV6;
604 return (dns_dispatch_getudp(requestmgr->dispatchmgr,
605 requestmgr->socketmgr,
606 requestmgr->taskmgr,
607 srcaddr, 4096,
608 1000, 32768, 16411, 16433,
609 attrs, attrmask,
610 dispatchp));
613 static isc_result_t
614 get_dispatch(isc_boolean_t tcp, dns_requestmgr_t *requestmgr,
615 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
616 dns_dispatch_t **dispatchp)
618 isc_result_t result;
619 if (tcp)
620 result = create_tcp_dispatch(requestmgr, srcaddr,
621 destaddr, dispatchp);
622 else
623 result = find_udp_dispatch(requestmgr, srcaddr,
624 destaddr, dispatchp);
625 return (result);
628 static isc_result_t
629 set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) {
630 isc_time_t expires;
631 isc_interval_t interval;
632 isc_result_t result;
633 isc_timertype_t timertype;
635 isc_interval_set(&interval, timeout, 0);
636 result = isc_time_nowplusinterval(&expires, &interval);
637 isc_interval_set(&interval, udpresend, 0);
639 timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once;
640 if (result == ISC_R_SUCCESS)
641 result = isc_timer_reset(timer, timertype, &expires,
642 &interval, ISC_FALSE);
643 return (result);
646 isc_result_t
647 dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
648 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
649 unsigned int options, unsigned int timeout,
650 isc_task_t *task, isc_taskaction_t action, void *arg,
651 dns_request_t **requestp)
653 return(dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
654 options, timeout, 0, 0, task, action,
655 arg, requestp));
658 isc_result_t
659 dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
660 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
661 unsigned int options, unsigned int timeout,
662 unsigned int udptimeout, isc_task_t *task,
663 isc_taskaction_t action, void *arg,
664 dns_request_t **requestp)
666 unsigned int udpretries = 0;
668 if (udptimeout != 0)
669 udpretries = timeout / udptimeout;
671 return (dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
672 options, timeout, udptimeout,
673 udpretries, task, action, arg,
674 requestp));
677 isc_result_t
678 dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
679 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
680 unsigned int options, unsigned int timeout,
681 unsigned int udptimeout, unsigned int udpretries,
682 isc_task_t *task, isc_taskaction_t action, void *arg,
683 dns_request_t **requestp)
685 dns_request_t *request = NULL;
686 isc_task_t *tclone = NULL;
687 isc_socket_t *socket = NULL;
688 isc_result_t result;
689 isc_mem_t *mctx;
690 dns_messageid_t id;
691 isc_boolean_t tcp = ISC_FALSE;
692 isc_region_t r;
694 REQUIRE(VALID_REQUESTMGR(requestmgr));
695 REQUIRE(msgbuf != NULL);
696 REQUIRE(destaddr != NULL);
697 REQUIRE(task != NULL);
698 REQUIRE(action != NULL);
699 REQUIRE(requestp != NULL && *requestp == NULL);
700 REQUIRE(timeout > 0);
701 if (srcaddr != NULL)
702 REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
704 mctx = requestmgr->mctx;
706 req_log(ISC_LOG_DEBUG(3), "dns_request_createraw");
708 if (isblackholed(requestmgr->dispatchmgr, destaddr))
709 return (DNS_R_BLACKHOLED);
711 request = NULL;
712 result = new_request(mctx, &request);
713 if (result != ISC_R_SUCCESS)
714 return (result);
716 if (udptimeout == 0 && udpretries != 0) {
717 udptimeout = timeout / (udpretries + 1);
718 if (udptimeout == 0)
719 udptimeout = 1;
721 request->udpcount = udpretries;
724 * Create timer now. We will set it below once.
726 result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
727 NULL, NULL, task, req_timeout, request,
728 &request->timer);
729 if (result != ISC_R_SUCCESS)
730 goto cleanup;
732 request->event = (dns_requestevent_t *)
733 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
734 action, arg, sizeof(dns_requestevent_t));
735 if (request->event == NULL) {
736 result = ISC_R_NOMEMORY;
737 goto cleanup;
739 isc_task_attach(task, &tclone);
740 request->event->ev_sender = task;
741 request->event->request = request;
742 request->event->result = ISC_R_FAILURE;
744 isc_buffer_usedregion(msgbuf, &r);
745 if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
746 result = DNS_R_FORMERR;
747 goto cleanup;
750 if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512)
751 tcp = ISC_TRUE;
753 result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
754 &request->dispatch);
755 if (result != ISC_R_SUCCESS)
756 goto cleanup;
758 result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
759 req_response, request, &id,
760 &request->dispentry,
761 requestmgr->socketmgr);
762 if (result != ISC_R_SUCCESS)
763 goto cleanup;
765 socket = req_getsocket(request);
766 INSIST(socket != NULL);
768 result = isc_buffer_allocate(mctx, &request->query,
769 r.length + (tcp ? 2 : 0));
770 if (result != ISC_R_SUCCESS)
771 goto cleanup;
772 if (tcp)
773 isc_buffer_putuint16(request->query, (isc_uint16_t)r.length);
774 result = isc_buffer_copyregion(request->query, &r);
775 if (result != ISC_R_SUCCESS)
776 goto cleanup;
778 /* Add message ID. */
779 isc_buffer_usedregion(request->query, &r);
780 if (tcp)
781 isc_region_consume(&r, 2);
782 r.base[0] = (id>>8) & 0xff;
783 r.base[1] = id & 0xff;
785 LOCK(&requestmgr->lock);
786 if (requestmgr->exiting) {
787 UNLOCK(&requestmgr->lock);
788 result = ISC_R_SHUTTINGDOWN;
789 goto cleanup;
791 requestmgr_attach(requestmgr, &request->requestmgr);
792 request->hash = mgr_gethash(requestmgr);
793 ISC_LIST_APPEND(requestmgr->requests, request, link);
794 UNLOCK(&requestmgr->lock);
796 result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
797 if (result != ISC_R_SUCCESS)
798 goto unlink;
800 request->destaddr = *destaddr;
801 if (tcp) {
802 result = isc_socket_connect(socket, destaddr, task,
803 req_connected, request);
804 if (result != ISC_R_SUCCESS)
805 goto unlink;
806 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
807 } else {
808 result = req_send(request, task, destaddr);
809 if (result != ISC_R_SUCCESS)
810 goto unlink;
813 req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p",
814 request);
815 *requestp = request;
816 return (ISC_R_SUCCESS);
818 unlink:
819 LOCK(&requestmgr->lock);
820 ISC_LIST_UNLINK(requestmgr->requests, request, link);
821 UNLOCK(&requestmgr->lock);
823 cleanup:
824 if (tclone != NULL)
825 isc_task_detach(&tclone);
826 req_destroy(request);
827 req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
828 dns_result_totext(result));
829 return (result);
832 isc_result_t
833 dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
834 isc_sockaddr_t *address, unsigned int options,
835 dns_tsigkey_t *key,
836 unsigned int timeout, isc_task_t *task,
837 isc_taskaction_t action, void *arg,
838 dns_request_t **requestp)
840 return (dns_request_createvia3(requestmgr, message, NULL, address,
841 options, key, timeout, 0, 0, task,
842 action, arg, requestp));
845 isc_result_t
846 dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message,
847 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
848 unsigned int options, dns_tsigkey_t *key,
849 unsigned int timeout, isc_task_t *task,
850 isc_taskaction_t action, void *arg,
851 dns_request_t **requestp)
853 return(dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
854 options, key, timeout, 0, 0, task,
855 action, arg, requestp));
858 isc_result_t
859 dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message,
860 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
861 unsigned int options, dns_tsigkey_t *key,
862 unsigned int timeout, unsigned int udptimeout,
863 isc_task_t *task, isc_taskaction_t action, void *arg,
864 dns_request_t **requestp)
866 unsigned int udpretries = 0;
868 if (udptimeout != 0)
869 udpretries = timeout / udptimeout;
870 return (dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
871 options, key, timeout, udptimeout,
872 udpretries, task, action, arg,
873 requestp));
876 isc_result_t
877 dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
878 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
879 unsigned int options, dns_tsigkey_t *key,
880 unsigned int timeout, unsigned int udptimeout,
881 unsigned int udpretries, isc_task_t *task,
882 isc_taskaction_t action, void *arg,
883 dns_request_t **requestp)
885 dns_request_t *request = NULL;
886 isc_task_t *tclone = NULL;
887 isc_socket_t *socket = NULL;
888 isc_result_t result;
889 isc_mem_t *mctx;
890 dns_messageid_t id;
891 isc_boolean_t tcp;
892 isc_boolean_t setkey = ISC_TRUE;
894 REQUIRE(VALID_REQUESTMGR(requestmgr));
895 REQUIRE(message != NULL);
896 REQUIRE(destaddr != NULL);
897 REQUIRE(task != NULL);
898 REQUIRE(action != NULL);
899 REQUIRE(requestp != NULL && *requestp == NULL);
900 REQUIRE(timeout > 0);
901 if (srcaddr != NULL)
902 REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
904 mctx = requestmgr->mctx;
906 req_log(ISC_LOG_DEBUG(3), "dns_request_createvia");
908 if (isblackholed(requestmgr->dispatchmgr, destaddr))
909 return (DNS_R_BLACKHOLED);
911 request = NULL;
912 result = new_request(mctx, &request);
913 if (result != ISC_R_SUCCESS)
914 return (result);
916 if (udptimeout == 0 && udpretries != 0) {
917 udptimeout = timeout / (udpretries + 1);
918 if (udptimeout == 0)
919 udptimeout = 1;
921 request->udpcount = udpretries;
924 * Create timer now. We will set it below once.
926 result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
927 NULL, NULL, task, req_timeout, request,
928 &request->timer);
929 if (result != ISC_R_SUCCESS)
930 goto cleanup;
932 request->event = (dns_requestevent_t *)
933 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
934 action, arg, sizeof(dns_requestevent_t));
935 if (request->event == NULL) {
936 result = ISC_R_NOMEMORY;
937 goto cleanup;
939 isc_task_attach(task, &tclone);
940 request->event->ev_sender = task;
941 request->event->request = request;
942 request->event->result = ISC_R_FAILURE;
943 if (key != NULL)
944 dns_tsigkey_attach(key, &request->tsigkey);
946 use_tcp:
947 tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0);
948 result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
949 &request->dispatch);
950 if (result != ISC_R_SUCCESS)
951 goto cleanup;
953 result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
954 req_response, request, &id,
955 &request->dispentry,
956 requestmgr->socketmgr);
957 if (result != ISC_R_SUCCESS)
958 goto cleanup;
959 socket = req_getsocket(request);
960 INSIST(socket != NULL);
962 message->id = id;
963 if (setkey) {
964 result = dns_message_settsigkey(message, request->tsigkey);
965 if (result != ISC_R_SUCCESS)
966 goto cleanup;
968 result = req_render(message, &request->query, options, mctx);
969 if (result == DNS_R_USETCP &&
970 (options & DNS_REQUESTOPT_TCP) == 0) {
972 * Try again using TCP.
974 dns_message_renderreset(message);
975 dns_dispatch_removeresponse(&request->dispentry, NULL);
976 dns_dispatch_detach(&request->dispatch);
977 socket = NULL;
978 options |= DNS_REQUESTOPT_TCP;
979 setkey = ISC_FALSE;
980 goto use_tcp;
982 if (result != ISC_R_SUCCESS)
983 goto cleanup;
985 result = dns_message_getquerytsig(message, mctx, &request->tsig);
986 if (result != ISC_R_SUCCESS)
987 goto cleanup;
989 LOCK(&requestmgr->lock);
990 if (requestmgr->exiting) {
991 UNLOCK(&requestmgr->lock);
992 result = ISC_R_SHUTTINGDOWN;
993 goto cleanup;
995 requestmgr_attach(requestmgr, &request->requestmgr);
996 request->hash = mgr_gethash(requestmgr);
997 ISC_LIST_APPEND(requestmgr->requests, request, link);
998 UNLOCK(&requestmgr->lock);
1000 result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
1001 if (result != ISC_R_SUCCESS)
1002 goto unlink;
1004 request->destaddr = *destaddr;
1005 if (tcp) {
1006 result = isc_socket_connect(socket, destaddr, task,
1007 req_connected, request);
1008 if (result != ISC_R_SUCCESS)
1009 goto unlink;
1010 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
1011 } else {
1012 result = req_send(request, task, destaddr);
1013 if (result != ISC_R_SUCCESS)
1014 goto unlink;
1017 req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p",
1018 request);
1019 *requestp = request;
1020 return (ISC_R_SUCCESS);
1022 unlink:
1023 LOCK(&requestmgr->lock);
1024 ISC_LIST_UNLINK(requestmgr->requests, request, link);
1025 UNLOCK(&requestmgr->lock);
1027 cleanup:
1028 if (tclone != NULL)
1029 isc_task_detach(&tclone);
1030 req_destroy(request);
1031 req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s",
1032 dns_result_totext(result));
1033 return (result);
1036 static isc_result_t
1037 req_render(dns_message_t *message, isc_buffer_t **bufferp,
1038 unsigned int options, isc_mem_t *mctx)
1040 isc_buffer_t *buf1 = NULL;
1041 isc_buffer_t *buf2 = NULL;
1042 isc_result_t result;
1043 isc_region_t r;
1044 isc_boolean_t tcp = ISC_FALSE;
1045 dns_compress_t cctx;
1046 isc_boolean_t cleanup_cctx = ISC_FALSE;
1048 REQUIRE(bufferp != NULL && *bufferp == NULL);
1050 req_log(ISC_LOG_DEBUG(3), "request_render");
1053 * Create buffer able to hold largest possible message.
1055 result = isc_buffer_allocate(mctx, &buf1, 65535);
1056 if (result != ISC_R_SUCCESS)
1057 return (result);
1059 result = dns_compress_init(&cctx, -1, mctx);
1060 if (result != ISC_R_SUCCESS)
1061 return (result);
1062 cleanup_cctx = ISC_TRUE;
1065 * Render message.
1067 result = dns_message_renderbegin(message, &cctx, buf1);
1068 if (result != ISC_R_SUCCESS)
1069 goto cleanup;
1070 result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
1071 if (result != ISC_R_SUCCESS)
1072 goto cleanup;
1073 result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
1074 if (result != ISC_R_SUCCESS)
1075 goto cleanup;
1076 result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
1077 if (result != ISC_R_SUCCESS)
1078 goto cleanup;
1079 result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
1080 if (result != ISC_R_SUCCESS)
1081 goto cleanup;
1082 result = dns_message_renderend(message);
1083 if (result != ISC_R_SUCCESS)
1084 goto cleanup;
1086 dns_compress_invalidate(&cctx);
1087 cleanup_cctx = ISC_FALSE;
1090 * Copy rendered message to exact sized buffer.
1092 isc_buffer_usedregion(buf1, &r);
1093 if ((options & DNS_REQUESTOPT_TCP) != 0) {
1094 tcp = ISC_TRUE;
1095 } else if (r.length > 512) {
1096 result = DNS_R_USETCP;
1097 goto cleanup;
1099 result = isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0));
1100 if (result != ISC_R_SUCCESS)
1101 goto cleanup;
1102 if (tcp)
1103 isc_buffer_putuint16(buf2, (isc_uint16_t)r.length);
1104 result = isc_buffer_copyregion(buf2, &r);
1105 if (result != ISC_R_SUCCESS)
1106 goto cleanup;
1109 * Cleanup and return.
1111 isc_buffer_free(&buf1);
1112 *bufferp = buf2;
1113 return (ISC_R_SUCCESS);
1115 cleanup:
1116 dns_message_renderreset(message);
1117 if (buf1 != NULL)
1118 isc_buffer_free(&buf1);
1119 if (buf2 != NULL)
1120 isc_buffer_free(&buf2);
1121 if (cleanup_cctx)
1122 dns_compress_invalidate(&cctx);
1123 return (result);
1128 * If this request is no longer waiting for events,
1129 * send the completion event. This will ultimately
1130 * cause the request to be destroyed.
1132 * Requires:
1133 * 'request' is locked by the caller.
1135 static void
1136 send_if_done(dns_request_t *request, isc_result_t result) {
1137 if (!DNS_REQUEST_CONNECTING(request) &&
1138 !DNS_REQUEST_SENDING(request) &&
1139 !request->canceling)
1140 req_sendevent(request, result);
1144 * Handle the control event.
1146 static void
1147 do_cancel(isc_task_t *task, isc_event_t *event) {
1148 dns_request_t *request = event->ev_arg;
1149 UNUSED(task);
1150 INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL);
1151 LOCK(&request->requestmgr->locks[request->hash]);
1152 request->canceling = ISC_FALSE;
1153 if (!DNS_REQUEST_CANCELED(request))
1154 req_cancel(request);
1155 send_if_done(request, ISC_R_CANCELED);
1156 UNLOCK(&request->requestmgr->locks[request->hash]);
1159 void
1160 dns_request_cancel(dns_request_t *request) {
1161 REQUIRE(VALID_REQUEST(request));
1163 req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request);
1165 REQUIRE(VALID_REQUEST(request));
1167 LOCK(&request->requestmgr->locks[request->hash]);
1168 if (!request->canceling && !DNS_REQUEST_CANCELED(request)) {
1169 isc_event_t *ev = &request->ctlevent;
1170 isc_task_send(request->event->ev_sender, &ev);
1171 request->canceling = ISC_TRUE;
1173 UNLOCK(&request->requestmgr->locks[request->hash]);
1176 isc_result_t
1177 dns_request_getresponse(dns_request_t *request, dns_message_t *message,
1178 unsigned int options)
1180 isc_result_t result;
1182 REQUIRE(VALID_REQUEST(request));
1183 REQUIRE(request->answer != NULL);
1185 req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p",
1186 request);
1188 result = dns_message_setquerytsig(message, request->tsig);
1189 if (result != ISC_R_SUCCESS)
1190 return (result);
1191 result = dns_message_settsigkey(message, request->tsigkey);
1192 if (result != ISC_R_SUCCESS)
1193 return (result);
1194 result = dns_message_parse(message, request->answer, options);
1195 if (result != ISC_R_SUCCESS)
1196 return (result);
1197 if (request->tsigkey != NULL)
1198 result = dns_tsig_verify(request->answer, message, NULL, NULL);
1199 return (result);
1202 isc_boolean_t
1203 dns_request_usedtcp(dns_request_t *request) {
1204 REQUIRE(VALID_REQUEST(request));
1206 return (ISC_TF((request->flags & DNS_REQUEST_F_TCP) != 0));
1209 void
1210 dns_request_destroy(dns_request_t **requestp) {
1211 dns_request_t *request;
1213 REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
1215 request = *requestp;
1217 req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request);
1219 LOCK(&request->requestmgr->lock);
1220 LOCK(&request->requestmgr->locks[request->hash]);
1221 ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
1222 INSIST(!DNS_REQUEST_CONNECTING(request));
1223 INSIST(!DNS_REQUEST_SENDING(request));
1224 UNLOCK(&request->requestmgr->locks[request->hash]);
1225 UNLOCK(&request->requestmgr->lock);
1228 * These should have been cleaned up by req_cancel() before
1229 * the completion event was sent.
1231 INSIST(!ISC_LINK_LINKED(request, link));
1232 INSIST(request->dispentry == NULL);
1233 INSIST(request->dispatch == NULL);
1234 INSIST(request->timer == NULL);
1236 req_destroy(request);
1238 *requestp = NULL;
1241 /***
1242 *** Private: request.
1243 ***/
1245 static isc_socket_t *
1246 req_getsocket(dns_request_t *request) {
1247 unsigned int dispattr;
1248 isc_socket_t *socket;
1250 dispattr = dns_dispatch_getattributes(request->dispatch);
1251 if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1252 INSIST(request->dispentry != NULL);
1253 socket = dns_dispatch_getentrysocket(request->dispentry);
1254 } else
1255 socket = dns_dispatch_getsocket(request->dispatch);
1257 return (socket);
1260 static void
1261 req_connected(isc_task_t *task, isc_event_t *event) {
1262 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1263 isc_result_t result;
1264 dns_request_t *request = event->ev_arg;
1266 REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
1267 REQUIRE(VALID_REQUEST(request));
1268 REQUIRE(DNS_REQUEST_CONNECTING(request));
1270 req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request);
1272 LOCK(&request->requestmgr->locks[request->hash]);
1273 request->flags &= ~DNS_REQUEST_F_CONNECTING;
1275 if (DNS_REQUEST_CANCELED(request)) {
1277 * Send delayed event.
1279 if (DNS_REQUEST_TIMEDOUT(request))
1280 send_if_done(request, ISC_R_TIMEDOUT);
1281 else
1282 send_if_done(request, ISC_R_CANCELED);
1283 } else {
1284 dns_dispatch_starttcp(request->dispatch);
1285 result = sevent->result;
1286 if (result == ISC_R_SUCCESS)
1287 result = req_send(request, task, NULL);
1289 if (result != ISC_R_SUCCESS) {
1290 req_cancel(request);
1291 send_if_done(request, ISC_R_CANCELED);
1294 UNLOCK(&request->requestmgr->locks[request->hash]);
1295 isc_event_free(&event);
1298 static void
1299 req_senddone(isc_task_t *task, isc_event_t *event) {
1300 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1301 dns_request_t *request = event->ev_arg;
1303 REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1304 REQUIRE(VALID_REQUEST(request));
1305 REQUIRE(DNS_REQUEST_SENDING(request));
1307 req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
1309 UNUSED(task);
1311 LOCK(&request->requestmgr->locks[request->hash]);
1312 request->flags &= ~DNS_REQUEST_F_SENDING;
1314 if (DNS_REQUEST_CANCELED(request)) {
1316 * Send delayed event.
1318 if (DNS_REQUEST_TIMEDOUT(request))
1319 send_if_done(request, ISC_R_TIMEDOUT);
1320 else
1321 send_if_done(request, ISC_R_CANCELED);
1322 } else if (sevent->result != ISC_R_SUCCESS) {
1323 req_cancel(request);
1324 send_if_done(request, ISC_R_CANCELED);
1326 UNLOCK(&request->requestmgr->locks[request->hash]);
1328 isc_event_free(&event);
1331 static void
1332 req_response(isc_task_t *task, isc_event_t *event) {
1333 isc_result_t result;
1334 dns_request_t *request = event->ev_arg;
1335 dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
1336 isc_region_t r;
1338 REQUIRE(VALID_REQUEST(request));
1339 REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
1341 UNUSED(task);
1343 req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
1344 dns_result_totext(devent->result));
1346 LOCK(&request->requestmgr->locks[request->hash]);
1347 result = devent->result;
1348 if (result != ISC_R_SUCCESS)
1349 goto done;
1352 * Copy buffer to request.
1354 isc_buffer_usedregion(&devent->buffer, &r);
1355 result = isc_buffer_allocate(request->mctx, &request->answer,
1356 r.length);
1357 if (result != ISC_R_SUCCESS)
1358 goto done;
1359 result = isc_buffer_copyregion(request->answer, &r);
1360 if (result != ISC_R_SUCCESS)
1361 isc_buffer_free(&request->answer);
1362 done:
1364 * Cleanup.
1366 dns_dispatch_removeresponse(&request->dispentry, &devent);
1367 req_cancel(request);
1369 * Send completion event.
1371 send_if_done(request, result);
1372 UNLOCK(&request->requestmgr->locks[request->hash]);
1375 static void
1376 req_timeout(isc_task_t *task, isc_event_t *event) {
1377 dns_request_t *request = event->ev_arg;
1378 isc_result_t result;
1380 REQUIRE(VALID_REQUEST(request));
1382 req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
1384 UNUSED(task);
1385 LOCK(&request->requestmgr->locks[request->hash]);
1386 if (event->ev_type == ISC_TIMEREVENT_TICK &&
1387 request->udpcount-- != 0) {
1388 if (! DNS_REQUEST_SENDING(request)) {
1389 result = req_send(request, task, &request->destaddr);
1390 if (result != ISC_R_SUCCESS) {
1391 req_cancel(request);
1392 send_if_done(request, result);
1395 } else {
1396 request->flags |= DNS_REQUEST_F_TIMEDOUT;
1397 req_cancel(request);
1398 send_if_done(request, ISC_R_TIMEDOUT);
1400 UNLOCK(&request->requestmgr->locks[request->hash]);
1401 isc_event_free(&event);
1404 static void
1405 req_sendevent(dns_request_t *request, isc_result_t result) {
1406 isc_task_t *task;
1408 REQUIRE(VALID_REQUEST(request));
1410 req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request);
1413 * Lock held by caller.
1415 task = request->event->ev_sender;
1416 request->event->ev_sender = request;
1417 request->event->result = result;
1418 isc_task_sendanddetach(&task, (isc_event_t **)&request->event);
1421 static void
1422 req_destroy(dns_request_t *request) {
1423 isc_mem_t *mctx;
1425 REQUIRE(VALID_REQUEST(request));
1427 req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request);
1429 request->magic = 0;
1430 if (request->query != NULL)
1431 isc_buffer_free(&request->query);
1432 if (request->answer != NULL)
1433 isc_buffer_free(&request->answer);
1434 if (request->event != NULL)
1435 isc_event_free((isc_event_t **)&request->event);
1436 if (request->dispentry != NULL)
1437 dns_dispatch_removeresponse(&request->dispentry, NULL);
1438 if (request->dispatch != NULL)
1439 dns_dispatch_detach(&request->dispatch);
1440 if (request->timer != NULL)
1441 isc_timer_detach(&request->timer);
1442 if (request->tsig != NULL)
1443 isc_buffer_free(&request->tsig);
1444 if (request->tsigkey != NULL)
1445 dns_tsigkey_detach(&request->tsigkey);
1446 if (request->requestmgr != NULL)
1447 requestmgr_detach(&request->requestmgr);
1448 mctx = request->mctx;
1449 isc_mem_put(mctx, request, sizeof(*request));
1450 isc_mem_detach(&mctx);
1454 * Stop the current request. Must be called from the request's task.
1456 static void
1457 req_cancel(dns_request_t *request) {
1458 isc_socket_t *socket;
1459 unsigned int dispattr;
1461 REQUIRE(VALID_REQUEST(request));
1463 req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request);
1466 * Lock held by caller.
1468 request->flags |= DNS_REQUEST_F_CANCELED;
1470 if (request->timer != NULL)
1471 isc_timer_detach(&request->timer);
1472 dispattr = dns_dispatch_getattributes(request->dispatch);
1473 socket = NULL;
1474 if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) {
1475 if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1476 if (request->dispentry != NULL) {
1477 socket = dns_dispatch_getentrysocket(
1478 request->dispentry);
1480 } else
1481 socket = dns_dispatch_getsocket(request->dispatch);
1482 if (DNS_REQUEST_CONNECTING(request) && socket != NULL)
1483 isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
1484 if (DNS_REQUEST_SENDING(request) && socket != NULL)
1485 isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
1487 if (request->dispentry != NULL)
1488 dns_dispatch_removeresponse(&request->dispentry, NULL);
1489 dns_dispatch_detach(&request->dispatch);
1492 static void
1493 req_log(int level, const char *fmt, ...) {
1494 va_list ap;
1496 va_start(ap, fmt);
1497 isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1498 DNS_LOGMODULE_REQUEST, level, fmt, ap);
1499 va_end(ap);