Detect FPU by checking CPUID features.
[dragonfly.git] / contrib / bind-9.5.2 / lib / dns / request.c
blobcb1ac34d4e7f3b93ec8d39701d83b62ee6891e11
1 /*
2 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2002 Internet Software Consortium.
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.
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.
18 /* $Id: request.c,v 1.79.128.5 2009/01/19 23:47:02 tbox Exp $ */
20 /*! \file */
22 #include <config.h>
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>
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>
42 #define REQUESTMGR_MAGIC ISC_MAGIC('R', 'q', 'u', 'M')
43 #define VALID_REQUESTMGR(mgr) ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC)
45 #define REQUEST_MAGIC ISC_MAGIC('R', 'q', 'u', '!')
46 #define VALID_REQUEST(request) ISC_MAGIC_VALID(request, REQUEST_MAGIC)
48 typedef ISC_LIST(dns_request_t) dns_requestlist_t;
50 #define DNS_REQUEST_NLOCKS 7
52 struct dns_requestmgr {
53 unsigned int magic;
54 isc_mutex_t lock;
55 isc_mem_t *mctx;
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;
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;
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)
110 /***
111 *** Forward
112 ***/
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);
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);
132 /***
133 *** Public
134 ***/
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)
146 dns_requestmgr_t *requestmgr;
147 isc_socket_t *socket;
148 isc_result_t result;
149 int i;
150 unsigned int dispattr;
152 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
154 REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
155 REQUIRE(timermgr != NULL);
156 REQUIRE(socketmgr != NULL);
157 REQUIRE(taskmgr != NULL);
158 REQUIRE(dispatchmgr != NULL);
159 UNUSED(socket);
160 if (dispatchv4 != NULL) {
161 dispattr = dns_dispatch_getattributes(dispatchv4);
162 REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
164 if (dispatchv6 != NULL) {
165 dispattr = dns_dispatch_getattributes(dispatchv6);
166 REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
169 requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
170 if (requestmgr == NULL)
171 return (ISC_R_NOMEMORY);
173 result = isc_mutex_init(&requestmgr->lock);
174 if (result != ISC_R_SUCCESS) {
175 isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
176 return (result);
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);
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;
208 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
210 *requestmgrp = requestmgr;
211 return (ISC_R_SUCCESS);
214 void
215 dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
216 isc_event_t **eventp)
218 isc_task_t *clone;
219 isc_event_t *event;
221 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_whenshutdown");
223 REQUIRE(VALID_REQUESTMGR(requestmgr));
224 REQUIRE(eventp != NULL);
226 event = *eventp;
227 *eventp = NULL;
229 LOCK(&requestmgr->lock);
231 if (requestmgr->exiting) {
233 * We're already shutdown. Send the event.
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);
243 UNLOCK(&requestmgr->lock);
246 void
247 dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
249 REQUIRE(VALID_REQUESTMGR(requestmgr));
251 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr);
253 LOCK(&requestmgr->lock);
254 mgr_shutdown(requestmgr);
255 UNLOCK(&requestmgr->lock);
258 static void
259 mgr_shutdown(dns_requestmgr_t *requestmgr) {
260 dns_request_t *request;
263 * Caller holds lock.
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);
272 if (requestmgr->iref == 0) {
273 INSIST(ISC_LIST_EMPTY(requestmgr->requests));
274 send_shutdown_events(requestmgr);
279 static void
280 requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
283 * Locked by caller.
286 REQUIRE(VALID_REQUESTMGR(source));
287 REQUIRE(targetp != NULL && *targetp == NULL);
289 REQUIRE(!source->exiting);
291 source->iref++;
292 *targetp = source;
294 req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d",
295 source, source->eref, source->iref);
298 static void
299 requestmgr_detach(dns_requestmgr_t **requestmgrp) {
300 dns_requestmgr_t *requestmgr;
301 isc_boolean_t need_destroy = ISC_FALSE;
303 REQUIRE(requestmgrp != NULL);
304 requestmgr = *requestmgrp;
305 REQUIRE(VALID_REQUESTMGR(requestmgr));
307 *requestmgrp = NULL;
308 LOCK(&requestmgr->lock);
309 INSIST(requestmgr->iref > 0);
310 requestmgr->iref--;
312 req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d",
313 requestmgr, requestmgr->eref, requestmgr->iref);
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;
321 UNLOCK(&requestmgr->lock);
323 if (need_destroy)
324 mgr_destroy(requestmgr);
327 void
328 dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
330 REQUIRE(VALID_REQUESTMGR(source));
331 REQUIRE(targetp != NULL && *targetp == NULL);
332 REQUIRE(!source->exiting);
334 LOCK(&source->lock);
335 source->eref++;
336 *targetp = source;
337 UNLOCK(&source->lock);
339 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d",
340 source, source->eref, source->iref);
343 void
344 dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) {
345 dns_requestmgr_t *requestmgr;
346 isc_boolean_t need_destroy = ISC_FALSE;
348 REQUIRE(requestmgrp != NULL);
349 requestmgr = *requestmgrp;
350 REQUIRE(VALID_REQUESTMGR(requestmgr));
352 LOCK(&requestmgr->lock);
353 INSIST(requestmgr->eref > 0);
354 requestmgr->eref--;
356 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d",
357 requestmgr, requestmgr->eref, requestmgr->iref);
359 if (requestmgr->eref == 0 && requestmgr->iref == 0) {
360 INSIST(requestmgr->exiting &&
361 ISC_LIST_HEAD(requestmgr->requests) == NULL);
362 need_destroy = ISC_TRUE;
364 UNLOCK(&requestmgr->lock);
366 if (need_destroy)
367 mgr_destroy(requestmgr);
369 *requestmgrp = NULL;
372 static void
373 send_shutdown_events(dns_requestmgr_t *requestmgr) {
374 isc_event_t *event, *next_event;
375 isc_task_t *etask;
377 req_log(ISC_LOG_DEBUG(3), "send_shutdown_events: %p", requestmgr);
380 * Caller must be holding the manager lock.
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);
393 static void
394 mgr_destroy(dns_requestmgr_t *requestmgr) {
395 int i;
396 isc_mem_t *mctx;
398 req_log(ISC_LOG_DEBUG(3), "mgr_destroy");
400 REQUIRE(requestmgr->eref == 0);
401 REQUIRE(requestmgr->iref == 0);
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);
416 static unsigned int
417 mgr_gethash(dns_requestmgr_t *requestmgr) {
418 req_log(ISC_LOG_DEBUG(3), "mgr_gethash");
420 * Locked by caller.
422 requestmgr->hash++;
423 return (requestmgr->hash % DNS_REQUEST_NLOCKS);
426 static inline isc_result_t
427 req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) {
428 isc_region_t r;
429 isc_socket_t *socket;
430 isc_result_t result;
431 unsigned int dispattr;
433 req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
435 REQUIRE(VALID_REQUEST(request));
436 dispattr = dns_dispatch_getattributes(request->dispatch);
437 socket = req_getsocket(request);
438 isc_buffer_usedregion(request->query, &r);
440 * We could connect the socket when we are using an exclusive dispatch
441 * as we do in resolver.c, but we prefer implementation simplicity
442 * at this moment.
444 result = isc_socket_sendto(socket, &r, task, req_senddone,
445 request, address, NULL);
446 if (result == ISC_R_SUCCESS)
447 request->flags |= DNS_REQUEST_F_SENDING;
448 return (result);
451 static isc_result_t
452 new_request(isc_mem_t *mctx, dns_request_t **requestp) {
453 dns_request_t *request;
455 request = isc_mem_get(mctx, sizeof(*request));
456 if (request == NULL)
457 return (ISC_R_NOMEMORY);
460 * Zero structure.
462 request->magic = 0;
463 request->mctx = NULL;
464 request->flags = 0;
465 ISC_LINK_INIT(request, link);
466 request->query = NULL;
467 request->answer = NULL;
468 request->event = NULL;
469 request->dispatch = NULL;
470 request->dispentry = NULL;
471 request->timer = NULL;
472 request->requestmgr = NULL;
473 request->tsig = NULL;
474 request->tsigkey = NULL;
475 ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL,
476 DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL,
477 NULL, NULL);
478 request->canceling = ISC_FALSE;
479 request->udpcount = 0;
481 isc_mem_attach(mctx, &request->mctx);
483 request->magic = REQUEST_MAGIC;
484 *requestp = request;
485 return (ISC_R_SUCCESS);
489 static isc_boolean_t
490 isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) {
491 dns_acl_t *blackhole;
492 isc_netaddr_t netaddr;
493 int match;
494 isc_boolean_t drop = ISC_FALSE;
495 char netaddrstr[ISC_NETADDR_FORMATSIZE];
497 blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
498 if (blackhole != NULL) {
499 isc_netaddr_fromsockaddr(&netaddr, destaddr);
500 if (dns_acl_match(&netaddr, NULL, blackhole,
501 NULL, &match, NULL) == ISC_R_SUCCESS &&
502 match > 0)
503 drop = ISC_TRUE;
505 if (drop) {
506 isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
507 req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
509 return (drop);
512 static isc_result_t
513 create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
514 isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
516 isc_result_t result;
517 isc_socket_t *socket = NULL;
518 isc_sockaddr_t src;
519 unsigned int attrs;
520 isc_sockaddr_t bind_any;
522 result = isc_socket_create(requestmgr->socketmgr,
523 isc_sockaddr_pf(destaddr),
524 isc_sockettype_tcp, &socket);
525 if (result != ISC_R_SUCCESS)
526 return (result);
527 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
528 if (srcaddr == NULL) {
529 isc_sockaddr_anyofpf(&bind_any,
530 isc_sockaddr_pf(destaddr));
531 result = isc_socket_bind(socket, &bind_any, 0);
532 } else {
533 src = *srcaddr;
534 isc_sockaddr_setport(&src, 0);
535 result = isc_socket_bind(socket, &src, 0);
537 if (result != ISC_R_SUCCESS)
538 goto cleanup;
539 #endif
540 attrs = 0;
541 attrs |= DNS_DISPATCHATTR_TCP;
542 attrs |= DNS_DISPATCHATTR_PRIVATE;
543 if (isc_sockaddr_pf(destaddr) == AF_INET)
544 attrs |= DNS_DISPATCHATTR_IPV4;
545 else
546 attrs |= DNS_DISPATCHATTR_IPV6;
547 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
548 result = dns_dispatch_createtcp(requestmgr->dispatchmgr,
549 socket, requestmgr->taskmgr,
550 4096, 2, 1, 1, 3, attrs,
551 dispatchp);
552 cleanup:
553 isc_socket_detach(&socket);
554 return (result);
557 static isc_result_t
558 find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
559 isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
561 dns_dispatch_t *disp = NULL;
562 unsigned int attrs, attrmask;
564 if (srcaddr == NULL) {
565 switch (isc_sockaddr_pf(destaddr)) {
566 case PF_INET:
567 disp = requestmgr->dispatchv4;
568 break;
570 case PF_INET6:
571 disp = requestmgr->dispatchv6;
572 break;
574 default:
575 return (ISC_R_NOTIMPLEMENTED);
577 if (disp == NULL)
578 return (ISC_R_FAMILYNOSUPPORT);
579 dns_dispatch_attach(disp, dispatchp);
580 return (ISC_R_SUCCESS);
582 attrs = 0;
583 attrs |= DNS_DISPATCHATTR_UDP;
584 switch (isc_sockaddr_pf(srcaddr)) {
585 case PF_INET:
586 attrs |= DNS_DISPATCHATTR_IPV4;
587 break;
589 case PF_INET6:
590 attrs |= DNS_DISPATCHATTR_IPV6;
591 break;
593 default:
594 return (ISC_R_NOTIMPLEMENTED);
596 attrmask = 0;
597 attrmask |= DNS_DISPATCHATTR_UDP;
598 attrmask |= DNS_DISPATCHATTR_TCP;
599 attrmask |= DNS_DISPATCHATTR_IPV4;
600 attrmask |= DNS_DISPATCHATTR_IPV6;
601 return (dns_dispatch_getudp(requestmgr->dispatchmgr,
602 requestmgr->socketmgr,
603 requestmgr->taskmgr,
604 srcaddr, 4096,
605 1000, 32768, 16411, 16433,
606 attrs, attrmask,
607 dispatchp));
610 static isc_result_t
611 get_dispatch(isc_boolean_t tcp, dns_requestmgr_t *requestmgr,
612 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
613 dns_dispatch_t **dispatchp)
615 isc_result_t result;
616 if (tcp)
617 result = create_tcp_dispatch(requestmgr, srcaddr,
618 destaddr, dispatchp);
619 else
620 result = find_udp_dispatch(requestmgr, srcaddr,
621 destaddr, dispatchp);
622 return (result);
625 static isc_result_t
626 set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) {
627 isc_time_t expires;
628 isc_interval_t interval;
629 isc_result_t result;
630 isc_timertype_t timertype;
632 isc_interval_set(&interval, timeout, 0);
633 result = isc_time_nowplusinterval(&expires, &interval);
634 isc_interval_set(&interval, udpresend, 0);
636 timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once;
637 if (result == ISC_R_SUCCESS)
638 result = isc_timer_reset(timer, timertype, &expires,
639 &interval, ISC_FALSE);
640 return (result);
643 isc_result_t
644 dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
645 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
646 unsigned int options, unsigned int timeout,
647 isc_task_t *task, isc_taskaction_t action, void *arg,
648 dns_request_t **requestp)
650 return(dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
651 options, timeout, 0, 0, task, action,
652 arg, requestp));
655 isc_result_t
656 dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
657 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
658 unsigned int options, unsigned int timeout,
659 unsigned int udptimeout, isc_task_t *task,
660 isc_taskaction_t action, void *arg,
661 dns_request_t **requestp)
663 unsigned int udpretries = 0;
665 if (udptimeout != 0)
666 udpretries = timeout / udptimeout;
668 return (dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
669 options, timeout, udptimeout,
670 udpretries, task, action, arg,
671 requestp));
674 isc_result_t
675 dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
676 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
677 unsigned int options, unsigned int timeout,
678 unsigned int udptimeout, unsigned int udpretries,
679 isc_task_t *task, isc_taskaction_t action, void *arg,
680 dns_request_t **requestp)
682 dns_request_t *request = NULL;
683 isc_task_t *tclone = NULL;
684 isc_socket_t *socket = NULL;
685 isc_result_t result;
686 isc_mem_t *mctx;
687 dns_messageid_t id;
688 isc_boolean_t tcp = ISC_FALSE;
689 isc_region_t r;
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));
701 mctx = requestmgr->mctx;
703 req_log(ISC_LOG_DEBUG(3), "dns_request_createraw");
705 if (isblackholed(requestmgr->dispatchmgr, destaddr))
706 return (DNS_R_BLACKHOLED);
708 request = NULL;
709 result = new_request(mctx, &request);
710 if (result != ISC_R_SUCCESS)
711 return (result);
713 if (udptimeout == 0 && udpretries != 0) {
714 udptimeout = timeout / (udpretries + 1);
715 if (udptimeout == 0)
716 udptimeout = 1;
718 request->udpcount = udpretries;
721 * Create timer now. We will set it below once.
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;
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;
736 isc_task_attach(task, &tclone);
737 request->event->ev_sender = task;
738 request->event->request = request;
739 request->event->result = ISC_R_FAILURE;
741 isc_buffer_usedregion(msgbuf, &r);
742 if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
743 result = DNS_R_FORMERR;
744 goto cleanup;
747 if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512)
748 tcp = ISC_TRUE;
750 result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
751 &request->dispatch);
752 if (result != ISC_R_SUCCESS)
753 goto cleanup;
755 result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
756 req_response, request, &id,
757 &request->dispentry,
758 requestmgr->socketmgr);
759 if (result != ISC_R_SUCCESS)
760 goto cleanup;
762 socket = req_getsocket(request);
763 INSIST(socket != NULL);
765 result = isc_buffer_allocate(mctx, &request->query,
766 r.length + (tcp ? 2 : 0));
767 if (result != ISC_R_SUCCESS)
768 goto cleanup;
769 if (tcp)
770 isc_buffer_putuint16(request->query, (isc_uint16_t)r.length);
771 result = isc_buffer_copyregion(request->query, &r);
772 if (result != ISC_R_SUCCESS)
773 goto cleanup;
775 /* Add message ID. */
776 isc_buffer_usedregion(request->query, &r);
777 if (tcp)
778 isc_region_consume(&r, 2);
779 r.base[0] = (id>>8) & 0xff;
780 r.base[1] = id & 0xff;
782 LOCK(&requestmgr->lock);
783 if (requestmgr->exiting) {
784 UNLOCK(&requestmgr->lock);
785 result = ISC_R_SHUTTINGDOWN;
786 goto cleanup;
788 requestmgr_attach(requestmgr, &request->requestmgr);
789 request->hash = mgr_gethash(requestmgr);
790 ISC_LIST_APPEND(requestmgr->requests, request, link);
791 UNLOCK(&requestmgr->lock);
793 result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
794 if (result != ISC_R_SUCCESS)
795 goto unlink;
797 request->destaddr = *destaddr;
798 if (tcp) {
799 result = isc_socket_connect(socket, destaddr, task,
800 req_connected, request);
801 if (result != ISC_R_SUCCESS)
802 goto unlink;
803 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
804 } else {
805 result = req_send(request, task, destaddr);
806 if (result != ISC_R_SUCCESS)
807 goto unlink;
810 req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p",
811 request);
812 *requestp = request;
813 return (ISC_R_SUCCESS);
815 unlink:
816 LOCK(&requestmgr->lock);
817 ISC_LIST_UNLINK(requestmgr->requests, request, link);
818 UNLOCK(&requestmgr->lock);
820 cleanup:
821 if (tclone != NULL)
822 isc_task_detach(&tclone);
823 req_destroy(request);
824 req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
825 dns_result_totext(result));
826 return (result);
829 isc_result_t
830 dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
831 isc_sockaddr_t *address, unsigned int options,
832 dns_tsigkey_t *key,
833 unsigned int timeout, isc_task_t *task,
834 isc_taskaction_t action, void *arg,
835 dns_request_t **requestp)
837 return (dns_request_createvia3(requestmgr, message, NULL, address,
838 options, key, timeout, 0, 0, task,
839 action, arg, requestp));
842 isc_result_t
843 dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message,
844 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
845 unsigned int options, dns_tsigkey_t *key,
846 unsigned int timeout, isc_task_t *task,
847 isc_taskaction_t action, void *arg,
848 dns_request_t **requestp)
850 return(dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
851 options, key, timeout, 0, 0, task,
852 action, arg, requestp));
855 isc_result_t
856 dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message,
857 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
858 unsigned int options, dns_tsigkey_t *key,
859 unsigned int timeout, unsigned int udptimeout,
860 isc_task_t *task, isc_taskaction_t action, void *arg,
861 dns_request_t **requestp)
863 unsigned int udpretries = 0;
865 if (udptimeout != 0)
866 udpretries = timeout / udptimeout;
867 return (dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
868 options, key, timeout, udptimeout,
869 udpretries, task, action, arg,
870 requestp));
873 isc_result_t
874 dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
875 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
876 unsigned int options, dns_tsigkey_t *key,
877 unsigned int timeout, unsigned int udptimeout,
878 unsigned int udpretries, isc_task_t *task,
879 isc_taskaction_t action, void *arg,
880 dns_request_t **requestp)
882 dns_request_t *request = NULL;
883 isc_task_t *tclone = NULL;
884 isc_socket_t *socket = NULL;
885 isc_result_t result;
886 isc_mem_t *mctx;
887 dns_messageid_t id;
888 isc_boolean_t tcp;
889 isc_boolean_t setkey = ISC_TRUE;
891 REQUIRE(VALID_REQUESTMGR(requestmgr));
892 REQUIRE(message != NULL);
893 REQUIRE(destaddr != NULL);
894 REQUIRE(task != NULL);
895 REQUIRE(action != NULL);
896 REQUIRE(requestp != NULL && *requestp == NULL);
897 REQUIRE(timeout > 0);
898 if (srcaddr != NULL)
899 REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
901 mctx = requestmgr->mctx;
903 req_log(ISC_LOG_DEBUG(3), "dns_request_createvia");
905 if (isblackholed(requestmgr->dispatchmgr, destaddr))
906 return (DNS_R_BLACKHOLED);
908 request = NULL;
909 result = new_request(mctx, &request);
910 if (result != ISC_R_SUCCESS)
911 return (result);
913 if (udptimeout == 0 && udpretries != 0) {
914 udptimeout = timeout / (udpretries + 1);
915 if (udptimeout == 0)
916 udptimeout = 1;
918 request->udpcount = udpretries;
921 * Create timer now. We will set it below once.
923 result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
924 NULL, NULL, task, req_timeout, request,
925 &request->timer);
926 if (result != ISC_R_SUCCESS)
927 goto cleanup;
929 request->event = (dns_requestevent_t *)
930 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
931 action, arg, sizeof(dns_requestevent_t));
932 if (request->event == NULL) {
933 result = ISC_R_NOMEMORY;
934 goto cleanup;
936 isc_task_attach(task, &tclone);
937 request->event->ev_sender = task;
938 request->event->request = request;
939 request->event->result = ISC_R_FAILURE;
940 if (key != NULL)
941 dns_tsigkey_attach(key, &request->tsigkey);
943 use_tcp:
944 tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0);
945 result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
946 &request->dispatch);
947 if (result != ISC_R_SUCCESS)
948 goto cleanup;
950 result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
951 req_response, request, &id,
952 &request->dispentry,
953 requestmgr->socketmgr);
954 if (result != ISC_R_SUCCESS)
955 goto cleanup;
956 socket = req_getsocket(request);
957 INSIST(socket != NULL);
959 message->id = id;
960 if (setkey) {
961 result = dns_message_settsigkey(message, request->tsigkey);
962 if (result != ISC_R_SUCCESS)
963 goto cleanup;
965 result = req_render(message, &request->query, options, mctx);
966 if (result == DNS_R_USETCP &&
967 (options & DNS_REQUESTOPT_TCP) == 0) {
969 * Try again using TCP.
971 dns_message_renderreset(message);
972 dns_dispatch_removeresponse(&request->dispentry, NULL);
973 dns_dispatch_detach(&request->dispatch);
974 socket = NULL;
975 options |= DNS_REQUESTOPT_TCP;
976 setkey = ISC_FALSE;
977 goto use_tcp;
979 if (result != ISC_R_SUCCESS)
980 goto cleanup;
982 result = dns_message_getquerytsig(message, mctx, &request->tsig);
983 if (result != ISC_R_SUCCESS)
984 goto cleanup;
986 LOCK(&requestmgr->lock);
987 if (requestmgr->exiting) {
988 UNLOCK(&requestmgr->lock);
989 result = ISC_R_SHUTTINGDOWN;
990 goto cleanup;
992 requestmgr_attach(requestmgr, &request->requestmgr);
993 request->hash = mgr_gethash(requestmgr);
994 ISC_LIST_APPEND(requestmgr->requests, request, link);
995 UNLOCK(&requestmgr->lock);
997 result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
998 if (result != ISC_R_SUCCESS)
999 goto unlink;
1001 request->destaddr = *destaddr;
1002 if (tcp) {
1003 result = isc_socket_connect(socket, destaddr, task,
1004 req_connected, request);
1005 if (result != ISC_R_SUCCESS)
1006 goto unlink;
1007 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
1008 } else {
1009 result = req_send(request, task, destaddr);
1010 if (result != ISC_R_SUCCESS)
1011 goto unlink;
1014 req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p",
1015 request);
1016 *requestp = request;
1017 return (ISC_R_SUCCESS);
1019 unlink:
1020 LOCK(&requestmgr->lock);
1021 ISC_LIST_UNLINK(requestmgr->requests, request, link);
1022 UNLOCK(&requestmgr->lock);
1024 cleanup:
1025 if (tclone != NULL)
1026 isc_task_detach(&tclone);
1027 req_destroy(request);
1028 req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s",
1029 dns_result_totext(result));
1030 return (result);
1033 static isc_result_t
1034 req_render(dns_message_t *message, isc_buffer_t **bufferp,
1035 unsigned int options, isc_mem_t *mctx)
1037 isc_buffer_t *buf1 = NULL;
1038 isc_buffer_t *buf2 = NULL;
1039 isc_result_t result;
1040 isc_region_t r;
1041 isc_boolean_t tcp = ISC_FALSE;
1042 dns_compress_t cctx;
1043 isc_boolean_t cleanup_cctx = ISC_FALSE;
1045 REQUIRE(bufferp != NULL && *bufferp == NULL);
1047 req_log(ISC_LOG_DEBUG(3), "request_render");
1050 * Create buffer able to hold largest possible message.
1052 result = isc_buffer_allocate(mctx, &buf1, 65535);
1053 if (result != ISC_R_SUCCESS)
1054 return (result);
1056 result = dns_compress_init(&cctx, -1, mctx);
1057 if (result != ISC_R_SUCCESS)
1058 return (result);
1059 cleanup_cctx = ISC_TRUE;
1062 * Render message.
1064 result = dns_message_renderbegin(message, &cctx, buf1);
1065 if (result != ISC_R_SUCCESS)
1066 goto cleanup;
1067 result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
1068 if (result != ISC_R_SUCCESS)
1069 goto cleanup;
1070 result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
1071 if (result != ISC_R_SUCCESS)
1072 goto cleanup;
1073 result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
1074 if (result != ISC_R_SUCCESS)
1075 goto cleanup;
1076 result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
1077 if (result != ISC_R_SUCCESS)
1078 goto cleanup;
1079 result = dns_message_renderend(message);
1080 if (result != ISC_R_SUCCESS)
1081 goto cleanup;
1083 dns_compress_invalidate(&cctx);
1084 cleanup_cctx = ISC_FALSE;
1087 * Copy rendered message to exact sized buffer.
1089 isc_buffer_usedregion(buf1, &r);
1090 if ((options & DNS_REQUESTOPT_TCP) != 0) {
1091 tcp = ISC_TRUE;
1092 } else if (r.length > 512) {
1093 result = DNS_R_USETCP;
1094 goto cleanup;
1096 result = isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0));
1097 if (result != ISC_R_SUCCESS)
1098 goto cleanup;
1099 if (tcp)
1100 isc_buffer_putuint16(buf2, (isc_uint16_t)r.length);
1101 result = isc_buffer_copyregion(buf2, &r);
1102 if (result != ISC_R_SUCCESS)
1103 goto cleanup;
1106 * Cleanup and return.
1108 isc_buffer_free(&buf1);
1109 *bufferp = buf2;
1110 return (ISC_R_SUCCESS);
1112 cleanup:
1113 dns_message_renderreset(message);
1114 if (buf1 != NULL)
1115 isc_buffer_free(&buf1);
1116 if (buf2 != NULL)
1117 isc_buffer_free(&buf2);
1118 if (cleanup_cctx)
1119 dns_compress_invalidate(&cctx);
1120 return (result);
1125 * If this request is no longer waiting for events,
1126 * send the completion event. This will ultimately
1127 * cause the request to be destroyed.
1129 * Requires:
1130 * 'request' is locked by the caller.
1132 static void
1133 send_if_done(dns_request_t *request, isc_result_t result) {
1134 if (!DNS_REQUEST_CONNECTING(request) &&
1135 !DNS_REQUEST_SENDING(request) &&
1136 !request->canceling)
1137 req_sendevent(request, result);
1141 * Handle the control event.
1143 static void
1144 do_cancel(isc_task_t *task, isc_event_t *event) {
1145 dns_request_t *request = event->ev_arg;
1146 UNUSED(task);
1147 INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL);
1148 LOCK(&request->requestmgr->locks[request->hash]);
1149 request->canceling = ISC_FALSE;
1150 if (!DNS_REQUEST_CANCELED(request))
1151 req_cancel(request);
1152 send_if_done(request, ISC_R_CANCELED);
1153 UNLOCK(&request->requestmgr->locks[request->hash]);
1156 void
1157 dns_request_cancel(dns_request_t *request) {
1158 REQUIRE(VALID_REQUEST(request));
1160 req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request);
1162 REQUIRE(VALID_REQUEST(request));
1164 LOCK(&request->requestmgr->locks[request->hash]);
1165 if (!request->canceling && !DNS_REQUEST_CANCELED(request)) {
1166 isc_event_t *ev = &request->ctlevent;
1167 isc_task_send(request->event->ev_sender, &ev);
1168 request->canceling = ISC_TRUE;
1170 UNLOCK(&request->requestmgr->locks[request->hash]);
1173 isc_result_t
1174 dns_request_getresponse(dns_request_t *request, dns_message_t *message,
1175 unsigned int options)
1177 isc_result_t result;
1179 REQUIRE(VALID_REQUEST(request));
1180 REQUIRE(request->answer != NULL);
1182 req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p",
1183 request);
1185 result = dns_message_setquerytsig(message, request->tsig);
1186 if (result != ISC_R_SUCCESS)
1187 return (result);
1188 result = dns_message_settsigkey(message, request->tsigkey);
1189 if (result != ISC_R_SUCCESS)
1190 return (result);
1191 result = dns_message_parse(message, request->answer, options);
1192 if (result != ISC_R_SUCCESS)
1193 return (result);
1194 if (request->tsigkey != NULL)
1195 result = dns_tsig_verify(request->answer, message, NULL, NULL);
1196 return (result);
1199 isc_boolean_t
1200 dns_request_usedtcp(dns_request_t *request) {
1201 REQUIRE(VALID_REQUEST(request));
1203 return (ISC_TF((request->flags & DNS_REQUEST_F_TCP) != 0));
1206 void
1207 dns_request_destroy(dns_request_t **requestp) {
1208 dns_request_t *request;
1210 REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
1212 request = *requestp;
1214 req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request);
1216 LOCK(&request->requestmgr->lock);
1217 LOCK(&request->requestmgr->locks[request->hash]);
1218 ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
1219 INSIST(!DNS_REQUEST_CONNECTING(request));
1220 INSIST(!DNS_REQUEST_SENDING(request));
1221 UNLOCK(&request->requestmgr->locks[request->hash]);
1222 UNLOCK(&request->requestmgr->lock);
1225 * These should have been cleaned up by req_cancel() before
1226 * the completion event was sent.
1228 INSIST(!ISC_LINK_LINKED(request, link));
1229 INSIST(request->dispentry == NULL);
1230 INSIST(request->dispatch == NULL);
1231 INSIST(request->timer == NULL);
1233 req_destroy(request);
1235 *requestp = NULL;
1238 /***
1239 *** Private: request.
1240 ***/
1242 static isc_socket_t *
1243 req_getsocket(dns_request_t *request) {
1244 unsigned int dispattr;
1245 isc_socket_t *socket;
1247 dispattr = dns_dispatch_getattributes(request->dispatch);
1248 if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1249 INSIST(request->dispentry != NULL);
1250 socket = dns_dispatch_getentrysocket(request->dispentry);
1251 } else
1252 socket = dns_dispatch_getsocket(request->dispatch);
1254 return (socket);
1257 static void
1258 req_connected(isc_task_t *task, isc_event_t *event) {
1259 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1260 isc_result_t result;
1261 dns_request_t *request = event->ev_arg;
1263 REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
1264 REQUIRE(VALID_REQUEST(request));
1265 REQUIRE(DNS_REQUEST_CONNECTING(request));
1267 req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request);
1269 LOCK(&request->requestmgr->locks[request->hash]);
1270 request->flags &= ~DNS_REQUEST_F_CONNECTING;
1272 if (DNS_REQUEST_CANCELED(request)) {
1274 * Send delayed event.
1276 if (DNS_REQUEST_TIMEDOUT(request))
1277 send_if_done(request, ISC_R_TIMEDOUT);
1278 else
1279 send_if_done(request, ISC_R_CANCELED);
1280 } else {
1281 dns_dispatch_starttcp(request->dispatch);
1282 result = sevent->result;
1283 if (result == ISC_R_SUCCESS)
1284 result = req_send(request, task, NULL);
1286 if (result != ISC_R_SUCCESS) {
1287 req_cancel(request);
1288 send_if_done(request, ISC_R_CANCELED);
1291 UNLOCK(&request->requestmgr->locks[request->hash]);
1292 isc_event_free(&event);
1295 static void
1296 req_senddone(isc_task_t *task, isc_event_t *event) {
1297 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1298 dns_request_t *request = event->ev_arg;
1300 REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1301 REQUIRE(VALID_REQUEST(request));
1302 REQUIRE(DNS_REQUEST_SENDING(request));
1304 req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
1306 UNUSED(task);
1308 LOCK(&request->requestmgr->locks[request->hash]);
1309 request->flags &= ~DNS_REQUEST_F_SENDING;
1311 if (DNS_REQUEST_CANCELED(request)) {
1313 * Send delayed event.
1315 if (DNS_REQUEST_TIMEDOUT(request))
1316 send_if_done(request, ISC_R_TIMEDOUT);
1317 else
1318 send_if_done(request, ISC_R_CANCELED);
1319 } else if (sevent->result != ISC_R_SUCCESS) {
1320 req_cancel(request);
1321 send_if_done(request, ISC_R_CANCELED);
1323 UNLOCK(&request->requestmgr->locks[request->hash]);
1325 isc_event_free(&event);
1328 static void
1329 req_response(isc_task_t *task, isc_event_t *event) {
1330 isc_result_t result;
1331 dns_request_t *request = event->ev_arg;
1332 dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
1333 isc_region_t r;
1335 REQUIRE(VALID_REQUEST(request));
1336 REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
1338 UNUSED(task);
1340 req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
1341 dns_result_totext(devent->result));
1343 LOCK(&request->requestmgr->locks[request->hash]);
1344 result = devent->result;
1345 if (result != ISC_R_SUCCESS)
1346 goto done;
1349 * Copy buffer to request.
1351 isc_buffer_usedregion(&devent->buffer, &r);
1352 result = isc_buffer_allocate(request->mctx, &request->answer,
1353 r.length);
1354 if (result != ISC_R_SUCCESS)
1355 goto done;
1356 result = isc_buffer_copyregion(request->answer, &r);
1357 if (result != ISC_R_SUCCESS)
1358 isc_buffer_free(&request->answer);
1359 done:
1361 * Cleanup.
1363 dns_dispatch_removeresponse(&request->dispentry, &devent);
1364 req_cancel(request);
1366 * Send completion event.
1368 send_if_done(request, result);
1369 UNLOCK(&request->requestmgr->locks[request->hash]);
1372 static void
1373 req_timeout(isc_task_t *task, isc_event_t *event) {
1374 dns_request_t *request = event->ev_arg;
1375 isc_result_t result;
1377 REQUIRE(VALID_REQUEST(request));
1379 req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
1381 UNUSED(task);
1382 LOCK(&request->requestmgr->locks[request->hash]);
1383 if (event->ev_type == ISC_TIMEREVENT_TICK &&
1384 request->udpcount-- != 0) {
1385 if (! DNS_REQUEST_SENDING(request)) {
1386 result = req_send(request, task, &request->destaddr);
1387 if (result != ISC_R_SUCCESS) {
1388 req_cancel(request);
1389 send_if_done(request, result);
1392 } else {
1393 request->flags |= DNS_REQUEST_F_TIMEDOUT;
1394 req_cancel(request);
1395 send_if_done(request, ISC_R_TIMEDOUT);
1397 UNLOCK(&request->requestmgr->locks[request->hash]);
1398 isc_event_free(&event);
1401 static void
1402 req_sendevent(dns_request_t *request, isc_result_t result) {
1403 isc_task_t *task;
1405 REQUIRE(VALID_REQUEST(request));
1407 req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request);
1410 * Lock held by caller.
1412 task = request->event->ev_sender;
1413 request->event->ev_sender = request;
1414 request->event->result = result;
1415 isc_task_sendanddetach(&task, (isc_event_t **)&request->event);
1418 static void
1419 req_destroy(dns_request_t *request) {
1420 isc_mem_t *mctx;
1422 REQUIRE(VALID_REQUEST(request));
1424 req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request);
1426 request->magic = 0;
1427 if (request->query != NULL)
1428 isc_buffer_free(&request->query);
1429 if (request->answer != NULL)
1430 isc_buffer_free(&request->answer);
1431 if (request->event != NULL)
1432 isc_event_free((isc_event_t **)&request->event);
1433 if (request->dispentry != NULL)
1434 dns_dispatch_removeresponse(&request->dispentry, NULL);
1435 if (request->dispatch != NULL)
1436 dns_dispatch_detach(&request->dispatch);
1437 if (request->timer != NULL)
1438 isc_timer_detach(&request->timer);
1439 if (request->tsig != NULL)
1440 isc_buffer_free(&request->tsig);
1441 if (request->tsigkey != NULL)
1442 dns_tsigkey_detach(&request->tsigkey);
1443 if (request->requestmgr != NULL)
1444 requestmgr_detach(&request->requestmgr);
1445 mctx = request->mctx;
1446 isc_mem_put(mctx, request, sizeof(*request));
1447 isc_mem_detach(&mctx);
1451 * Stop the current request. Must be called from the request's task.
1453 static void
1454 req_cancel(dns_request_t *request) {
1455 isc_socket_t *socket;
1456 unsigned int dispattr;
1458 REQUIRE(VALID_REQUEST(request));
1460 req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request);
1463 * Lock held by caller.
1465 request->flags |= DNS_REQUEST_F_CANCELED;
1467 if (request->timer != NULL)
1468 isc_timer_detach(&request->timer);
1469 dispattr = dns_dispatch_getattributes(request->dispatch);
1470 socket = NULL;
1471 if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) {
1472 if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1473 if (request->dispentry != NULL) {
1474 socket = dns_dispatch_getentrysocket(
1475 request->dispentry);
1477 } else
1478 socket = dns_dispatch_getsocket(request->dispatch);
1479 if (DNS_REQUEST_CONNECTING(request) && socket != NULL)
1480 isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
1481 if (DNS_REQUEST_SENDING(request) && socket != NULL)
1482 isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
1484 if (request->dispentry != NULL)
1485 dns_dispatch_removeresponse(&request->dispentry, NULL);
1486 dns_dispatch_detach(&request->dispatch);
1489 static void
1490 req_log(int level, const char *fmt, ...) {
1491 va_list ap;
1493 va_start(ap, fmt);
1494 isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1495 DNS_LOGMODULE_REQUEST, level, fmt, ap);
1496 va_end(ap);