Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / dns / request.c
blob8e14d5e5597d1486f0e8d52830cdb823b180c6f7
1 /* $NetBSD: request.c,v 1.9 2015/07/08 17:28:59 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2015 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 */
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;
94 isc_dscp_t dscp;
97 #define DNS_REQUEST_F_CONNECTING 0x0001
98 #define DNS_REQUEST_F_SENDING 0x0002
99 #define DNS_REQUEST_F_CANCELED 0x0004 /*%< ctlevent received, or otherwise
100 synchronously canceled */
101 #define DNS_REQUEST_F_TIMEDOUT 0x0008 /*%< canceled due to a timeout */
102 #define DNS_REQUEST_F_TCP 0x0010 /*%< This request used TCP */
103 #define DNS_REQUEST_CANCELED(r) \
104 (((r)->flags & DNS_REQUEST_F_CANCELED) != 0)
105 #define DNS_REQUEST_CONNECTING(r) \
106 (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
107 #define DNS_REQUEST_SENDING(r) \
108 (((r)->flags & DNS_REQUEST_F_SENDING) != 0)
109 #define DNS_REQUEST_TIMEDOUT(r) \
110 (((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0)
113 /***
114 *** Forward
115 ***/
117 static void mgr_destroy(dns_requestmgr_t *requestmgr);
118 static void mgr_shutdown(dns_requestmgr_t *requestmgr);
119 static unsigned int mgr_gethash(dns_requestmgr_t *requestmgr);
120 static void send_shutdown_events(dns_requestmgr_t *requestmgr);
122 static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer,
123 unsigned int options, isc_mem_t *mctx);
124 static void req_senddone(isc_task_t *task, isc_event_t *event);
125 static void req_response(isc_task_t *task, isc_event_t *event);
126 static void req_timeout(isc_task_t *task, isc_event_t *event);
127 static isc_socket_t * req_getsocket(dns_request_t *request);
128 static void req_connected(isc_task_t *task, isc_event_t *event);
129 static void req_sendevent(dns_request_t *request, isc_result_t result);
130 static void req_cancel(dns_request_t *request);
131 static void req_destroy(dns_request_t *request);
132 static void req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
133 static void do_cancel(isc_task_t *task, isc_event_t *event);
135 /***
136 *** Public
137 ***/
139 isc_result_t
140 dns_requestmgr_create(isc_mem_t *mctx,
141 isc_timermgr_t *timermgr,
142 isc_socketmgr_t *socketmgr,
143 isc_taskmgr_t *taskmgr,
144 dns_dispatchmgr_t *dispatchmgr,
145 dns_dispatch_t *dispatchv4,
146 dns_dispatch_t *dispatchv6,
147 dns_requestmgr_t **requestmgrp)
149 dns_requestmgr_t *requestmgr;
150 isc_socket_t *socket;
151 isc_result_t result;
152 int i;
153 unsigned int dispattr;
155 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
157 REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
158 REQUIRE(timermgr != NULL);
159 REQUIRE(socketmgr != NULL);
160 REQUIRE(taskmgr != NULL);
161 REQUIRE(dispatchmgr != NULL);
162 UNUSED(socket);
163 if (dispatchv4 != NULL) {
164 dispattr = dns_dispatch_getattributes(dispatchv4);
165 REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
167 if (dispatchv6 != NULL) {
168 dispattr = dns_dispatch_getattributes(dispatchv6);
169 REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
172 requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
173 if (requestmgr == NULL)
174 return (ISC_R_NOMEMORY);
176 result = isc_mutex_init(&requestmgr->lock);
177 if (result != ISC_R_SUCCESS) {
178 isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
179 return (result);
181 for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
182 result = isc_mutex_init(&requestmgr->locks[i]);
183 if (result != ISC_R_SUCCESS) {
184 while (--i >= 0)
185 DESTROYLOCK(&requestmgr->locks[i]);
186 DESTROYLOCK(&requestmgr->lock);
187 isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
188 return (result);
191 requestmgr->timermgr = timermgr;
192 requestmgr->socketmgr = socketmgr;
193 requestmgr->taskmgr = taskmgr;
194 requestmgr->dispatchmgr = dispatchmgr;
195 requestmgr->dispatchv4 = NULL;
196 if (dispatchv4 != NULL)
197 dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
198 requestmgr->dispatchv6 = NULL;
199 if (dispatchv6 != NULL)
200 dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
201 requestmgr->mctx = NULL;
202 isc_mem_attach(mctx, &requestmgr->mctx);
203 requestmgr->eref = 1; /* implicit attach */
204 requestmgr->iref = 0;
205 ISC_LIST_INIT(requestmgr->whenshutdown);
206 ISC_LIST_INIT(requestmgr->requests);
207 requestmgr->exiting = ISC_FALSE;
208 requestmgr->hash = 0;
209 requestmgr->magic = REQUESTMGR_MAGIC;
211 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
213 *requestmgrp = requestmgr;
214 return (ISC_R_SUCCESS);
217 void
218 dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
219 isc_event_t **eventp)
221 isc_task_t *clone;
222 isc_event_t *event;
224 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_whenshutdown");
226 REQUIRE(VALID_REQUESTMGR(requestmgr));
227 REQUIRE(eventp != NULL);
229 event = *eventp;
230 *eventp = NULL;
232 LOCK(&requestmgr->lock);
234 if (requestmgr->exiting) {
236 * We're already shutdown. Send the event.
238 event->ev_sender = requestmgr;
239 isc_task_send(task, &event);
240 } else {
241 clone = NULL;
242 isc_task_attach(task, &clone);
243 event->ev_sender = clone;
244 ISC_LIST_APPEND(requestmgr->whenshutdown, event, ev_link);
246 UNLOCK(&requestmgr->lock);
249 void
250 dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
252 REQUIRE(VALID_REQUESTMGR(requestmgr));
254 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr);
256 LOCK(&requestmgr->lock);
257 mgr_shutdown(requestmgr);
258 UNLOCK(&requestmgr->lock);
261 static void
262 mgr_shutdown(dns_requestmgr_t *requestmgr) {
263 dns_request_t *request;
266 * Caller holds lock.
268 if (!requestmgr->exiting) {
269 requestmgr->exiting = ISC_TRUE;
270 for (request = ISC_LIST_HEAD(requestmgr->requests);
271 request != NULL;
272 request = ISC_LIST_NEXT(request, link)) {
273 dns_request_cancel(request);
275 if (requestmgr->iref == 0) {
276 INSIST(ISC_LIST_EMPTY(requestmgr->requests));
277 send_shutdown_events(requestmgr);
282 static void
283 requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
286 * Locked by caller.
289 REQUIRE(VALID_REQUESTMGR(source));
290 REQUIRE(targetp != NULL && *targetp == NULL);
292 REQUIRE(!source->exiting);
294 source->iref++;
295 *targetp = source;
297 req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d",
298 source, source->eref, source->iref);
301 static void
302 requestmgr_detach(dns_requestmgr_t **requestmgrp) {
303 dns_requestmgr_t *requestmgr;
304 isc_boolean_t need_destroy = ISC_FALSE;
306 REQUIRE(requestmgrp != NULL);
307 requestmgr = *requestmgrp;
308 REQUIRE(VALID_REQUESTMGR(requestmgr));
310 *requestmgrp = NULL;
311 LOCK(&requestmgr->lock);
312 INSIST(requestmgr->iref > 0);
313 requestmgr->iref--;
315 req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d",
316 requestmgr, requestmgr->eref, requestmgr->iref);
318 if (requestmgr->iref == 0 && requestmgr->exiting) {
319 INSIST(ISC_LIST_HEAD(requestmgr->requests) == NULL);
320 send_shutdown_events(requestmgr);
321 if (requestmgr->eref == 0)
322 need_destroy = ISC_TRUE;
324 UNLOCK(&requestmgr->lock);
326 if (need_destroy)
327 mgr_destroy(requestmgr);
330 void
331 dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
333 REQUIRE(VALID_REQUESTMGR(source));
334 REQUIRE(targetp != NULL && *targetp == NULL);
335 REQUIRE(!source->exiting);
337 LOCK(&source->lock);
338 source->eref++;
339 *targetp = source;
340 UNLOCK(&source->lock);
342 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d",
343 source, source->eref, source->iref);
346 void
347 dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) {
348 dns_requestmgr_t *requestmgr;
349 isc_boolean_t need_destroy = ISC_FALSE;
351 REQUIRE(requestmgrp != NULL);
352 requestmgr = *requestmgrp;
353 REQUIRE(VALID_REQUESTMGR(requestmgr));
355 LOCK(&requestmgr->lock);
356 INSIST(requestmgr->eref > 0);
357 requestmgr->eref--;
359 req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d",
360 requestmgr, requestmgr->eref, requestmgr->iref);
362 if (requestmgr->eref == 0 && requestmgr->iref == 0) {
363 INSIST(requestmgr->exiting &&
364 ISC_LIST_HEAD(requestmgr->requests) == NULL);
365 need_destroy = ISC_TRUE;
367 UNLOCK(&requestmgr->lock);
369 if (need_destroy)
370 mgr_destroy(requestmgr);
372 *requestmgrp = NULL;
375 static void
376 send_shutdown_events(dns_requestmgr_t *requestmgr) {
377 isc_event_t *event, *next_event;
378 isc_task_t *etask;
380 req_log(ISC_LOG_DEBUG(3), "send_shutdown_events: %p", requestmgr);
383 * Caller must be holding the manager lock.
385 for (event = ISC_LIST_HEAD(requestmgr->whenshutdown);
386 event != NULL;
387 event = next_event) {
388 next_event = ISC_LIST_NEXT(event, ev_link);
389 ISC_LIST_UNLINK(requestmgr->whenshutdown, event, ev_link);
390 etask = event->ev_sender;
391 event->ev_sender = requestmgr;
392 isc_task_sendanddetach(&etask, &event);
396 static void
397 mgr_destroy(dns_requestmgr_t *requestmgr) {
398 int i;
399 isc_mem_t *mctx;
401 req_log(ISC_LOG_DEBUG(3), "mgr_destroy");
403 REQUIRE(requestmgr->eref == 0);
404 REQUIRE(requestmgr->iref == 0);
406 DESTROYLOCK(&requestmgr->lock);
407 for (i = 0; i < DNS_REQUEST_NLOCKS; i++)
408 DESTROYLOCK(&requestmgr->locks[i]);
409 if (requestmgr->dispatchv4 != NULL)
410 dns_dispatch_detach(&requestmgr->dispatchv4);
411 if (requestmgr->dispatchv6 != NULL)
412 dns_dispatch_detach(&requestmgr->dispatchv6);
413 requestmgr->magic = 0;
414 mctx = requestmgr->mctx;
415 isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
416 isc_mem_detach(&mctx);
419 static unsigned int
420 mgr_gethash(dns_requestmgr_t *requestmgr) {
421 req_log(ISC_LOG_DEBUG(3), "mgr_gethash");
423 * Locked by caller.
425 requestmgr->hash++;
426 return (requestmgr->hash % DNS_REQUEST_NLOCKS);
429 static inline isc_result_t
430 req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) {
431 isc_region_t r;
432 isc_socket_t *socket;
433 isc_socketevent_t *sendevent;
434 isc_result_t result;
436 req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
438 REQUIRE(VALID_REQUEST(request));
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 sendevent = isc_socket_socketevent(request->mctx, socket,
447 ISC_SOCKEVENT_SENDDONE,
448 req_senddone, request);
449 if (sendevent == NULL)
450 return (ISC_R_NOMEMORY);
451 if (request->dscp == -1) {
452 sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP;
453 sendevent->dscp = 0;
454 } else {
455 sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP;
456 sendevent->dscp = request->dscp;
459 result = isc_socket_sendto2(socket, &r, task, address, NULL,
460 sendevent, 0);
461 if (result == ISC_R_SUCCESS)
462 request->flags |= DNS_REQUEST_F_SENDING;
463 return (result);
466 static isc_result_t
467 new_request(isc_mem_t *mctx, dns_request_t **requestp)
469 dns_request_t *request;
471 request = isc_mem_get(mctx, sizeof(*request));
472 if (request == NULL)
473 return (ISC_R_NOMEMORY);
476 * Zero structure.
478 request->magic = 0;
479 request->mctx = NULL;
480 request->flags = 0;
481 ISC_LINK_INIT(request, link);
482 request->query = NULL;
483 request->answer = NULL;
484 request->event = NULL;
485 request->dispatch = NULL;
486 request->dispentry = NULL;
487 request->timer = NULL;
488 request->requestmgr = NULL;
489 request->tsig = NULL;
490 request->tsigkey = NULL;
491 request->dscp = -1;
492 ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL,
493 DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL,
494 NULL, NULL);
495 request->canceling = ISC_FALSE;
496 request->udpcount = 0;
498 isc_mem_attach(mctx, &request->mctx);
500 request->magic = REQUEST_MAGIC;
501 *requestp = request;
502 return (ISC_R_SUCCESS);
506 static isc_boolean_t
507 isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) {
508 dns_acl_t *blackhole;
509 isc_netaddr_t netaddr;
510 int match;
511 isc_boolean_t drop = ISC_FALSE;
512 char netaddrstr[ISC_NETADDR_FORMATSIZE];
514 blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
515 if (blackhole != NULL) {
516 isc_netaddr_fromsockaddr(&netaddr, destaddr);
517 if (dns_acl_match(&netaddr, NULL, blackhole,
518 NULL, &match, NULL) == ISC_R_SUCCESS &&
519 match > 0)
520 drop = ISC_TRUE;
522 if (drop) {
523 isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
524 req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
526 return (drop);
529 static isc_result_t
530 create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
531 isc_sockaddr_t *destaddr, isc_dscp_t dscp,
532 dns_dispatch_t **dispatchp)
534 isc_result_t result;
535 isc_socket_t *socket = NULL;
536 isc_sockaddr_t src;
537 unsigned int attrs;
538 isc_sockaddr_t bind_any;
540 result = isc_socket_create(requestmgr->socketmgr,
541 isc_sockaddr_pf(destaddr),
542 isc_sockettype_tcp, &socket);
543 if (result != ISC_R_SUCCESS)
544 return (result);
545 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
546 if (srcaddr == NULL) {
547 isc_sockaddr_anyofpf(&bind_any,
548 isc_sockaddr_pf(destaddr));
549 result = isc_socket_bind(socket, &bind_any, 0);
550 } else {
551 src = *srcaddr;
552 isc_sockaddr_setport(&src, 0);
553 result = isc_socket_bind(socket, &src, 0);
555 if (result != ISC_R_SUCCESS)
556 goto cleanup;
557 #endif
559 attrs = 0;
560 attrs |= DNS_DISPATCHATTR_TCP;
561 attrs |= DNS_DISPATCHATTR_PRIVATE;
562 if (isc_sockaddr_pf(destaddr) == AF_INET)
563 attrs |= DNS_DISPATCHATTR_IPV4;
564 else
565 attrs |= DNS_DISPATCHATTR_IPV6;
566 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
568 isc_socket_dscp(socket, dscp);
569 result = dns_dispatch_createtcp(requestmgr->dispatchmgr,
570 socket, requestmgr->taskmgr,
571 4096, 2, 1, 1, 3, attrs,
572 dispatchp);
573 cleanup:
574 isc_socket_detach(&socket);
575 return (result);
578 static isc_result_t
579 find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
580 isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
582 dns_dispatch_t *disp = NULL;
583 unsigned int attrs, attrmask;
585 if (srcaddr == NULL) {
586 switch (isc_sockaddr_pf(destaddr)) {
587 case PF_INET:
588 disp = requestmgr->dispatchv4;
589 break;
591 case PF_INET6:
592 disp = requestmgr->dispatchv6;
593 break;
595 default:
596 return (ISC_R_NOTIMPLEMENTED);
598 if (disp == NULL)
599 return (ISC_R_FAMILYNOSUPPORT);
600 dns_dispatch_attach(disp, dispatchp);
601 return (ISC_R_SUCCESS);
603 attrs = 0;
604 attrs |= DNS_DISPATCHATTR_UDP;
605 switch (isc_sockaddr_pf(srcaddr)) {
606 case PF_INET:
607 attrs |= DNS_DISPATCHATTR_IPV4;
608 break;
610 case PF_INET6:
611 attrs |= DNS_DISPATCHATTR_IPV6;
612 break;
614 default:
615 return (ISC_R_NOTIMPLEMENTED);
617 attrmask = 0;
618 attrmask |= DNS_DISPATCHATTR_UDP;
619 attrmask |= DNS_DISPATCHATTR_TCP;
620 attrmask |= DNS_DISPATCHATTR_IPV4;
621 attrmask |= DNS_DISPATCHATTR_IPV6;
622 return (dns_dispatch_getudp(requestmgr->dispatchmgr,
623 requestmgr->socketmgr,
624 requestmgr->taskmgr,
625 srcaddr, 4096,
626 32768, 32768, 16411, 16433,
627 attrs, attrmask,
628 dispatchp));
631 static isc_result_t
632 get_dispatch(isc_boolean_t tcp, dns_requestmgr_t *requestmgr,
633 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
634 isc_dscp_t dscp, dns_dispatch_t **dispatchp)
636 isc_result_t result;
637 if (tcp)
638 result = create_tcp_dispatch(requestmgr, srcaddr,
639 destaddr, dscp, dispatchp);
640 else
641 result = find_udp_dispatch(requestmgr, srcaddr,
642 destaddr, dispatchp);
643 return (result);
646 static isc_result_t
647 set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) {
648 isc_time_t expires;
649 isc_interval_t interval;
650 isc_result_t result;
651 isc_timertype_t timertype;
653 isc_interval_set(&interval, timeout, 0);
654 result = isc_time_nowplusinterval(&expires, &interval);
655 isc_interval_set(&interval, udpresend, 0);
657 timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once;
658 if (result == ISC_R_SUCCESS)
659 result = isc_timer_reset(timer, timertype, &expires,
660 &interval, ISC_FALSE);
661 return (result);
664 isc_result_t
665 dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
666 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
667 unsigned int options, unsigned int timeout,
668 isc_task_t *task, isc_taskaction_t action, void *arg,
669 dns_request_t **requestp)
671 return(dns_request_createraw4(requestmgr, msgbuf, srcaddr, destaddr,
672 -1, options, timeout, 0, 0, task, action,
673 arg, requestp));
676 isc_result_t
677 dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
678 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
679 unsigned int options, unsigned int timeout,
680 unsigned int udptimeout, isc_task_t *task,
681 isc_taskaction_t action, void *arg,
682 dns_request_t **requestp)
684 unsigned int udpretries = 0;
686 if (udptimeout != 0)
687 udpretries = timeout / udptimeout;
689 return (dns_request_createraw4(requestmgr, msgbuf, srcaddr, destaddr,
690 -1, options, timeout, udptimeout,
691 udpretries, task, action, arg,
692 requestp));
695 isc_result_t
696 dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
697 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
698 unsigned int options, unsigned int timeout,
699 unsigned int udptimeout, unsigned int udpretries,
700 isc_task_t *task, isc_taskaction_t action, void *arg,
701 dns_request_t **requestp)
703 return (dns_request_createraw4(requestmgr, msgbuf, srcaddr, destaddr,
704 -1, options, timeout, udptimeout,
705 udpretries, task, action, arg,
706 requestp));
709 isc_result_t
710 dns_request_createraw4(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
711 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
712 isc_dscp_t dscp, unsigned int options,
713 unsigned int timeout, unsigned int udptimeout,
714 unsigned int udpretries, isc_task_t *task,
715 isc_taskaction_t action, void *arg,
716 dns_request_t **requestp)
718 dns_request_t *request = NULL;
719 isc_task_t *tclone = NULL;
720 isc_socket_t *socket = NULL;
721 isc_result_t result;
722 isc_mem_t *mctx;
723 dns_messageid_t id;
724 isc_boolean_t tcp = ISC_FALSE;
725 isc_region_t r;
726 unsigned int dispopt = 0;
728 REQUIRE(VALID_REQUESTMGR(requestmgr));
729 REQUIRE(msgbuf != NULL);
730 REQUIRE(destaddr != NULL);
731 REQUIRE(task != NULL);
732 REQUIRE(action != NULL);
733 REQUIRE(requestp != NULL && *requestp == NULL);
734 REQUIRE(timeout > 0);
735 if (srcaddr != NULL)
736 REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
738 mctx = requestmgr->mctx;
740 req_log(ISC_LOG_DEBUG(3), "dns_request_createraw");
742 if (isblackholed(requestmgr->dispatchmgr, destaddr))
743 return (DNS_R_BLACKHOLED);
745 request = NULL;
746 result = new_request(mctx, &request);
747 if (result != ISC_R_SUCCESS)
748 return (result);
750 if (udptimeout == 0 && udpretries != 0) {
751 udptimeout = timeout / (udpretries + 1);
752 if (udptimeout == 0)
753 udptimeout = 1;
755 request->udpcount = udpretries;
756 request->dscp = dscp;
759 * Create timer now. We will set it below once.
761 result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
762 NULL, NULL, task, req_timeout, request,
763 &request->timer);
764 if (result != ISC_R_SUCCESS)
765 goto cleanup;
767 request->event = (dns_requestevent_t *)
768 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
769 action, arg, sizeof(dns_requestevent_t));
770 if (request->event == NULL) {
771 result = ISC_R_NOMEMORY;
772 goto cleanup;
774 isc_task_attach(task, &tclone);
775 request->event->ev_sender = task;
776 request->event->request = request;
777 request->event->result = ISC_R_FAILURE;
779 isc_buffer_usedregion(msgbuf, &r);
780 if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
781 result = DNS_R_FORMERR;
782 goto cleanup;
785 if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512)
786 tcp = ISC_TRUE;
788 result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, dscp,
789 &request->dispatch);
790 if (result != ISC_R_SUCCESS)
791 goto cleanup;
793 if ((options & DNS_REQUESTOPT_FIXEDID) != 0) {
794 id = (r.base[0] << 8) | r.base[1];
795 dispopt |= DNS_DISPATCHOPT_FIXEDID;
798 result = dns_dispatch_addresponse3(request->dispatch, dispopt,
799 destaddr, task, req_response,
800 request, &id, &request->dispentry,
801 requestmgr->socketmgr);
802 if (result != ISC_R_SUCCESS)
803 goto cleanup;
805 socket = req_getsocket(request);
806 INSIST(socket != NULL);
808 result = isc_buffer_allocate(mctx, &request->query,
809 r.length + (tcp ? 2 : 0));
810 if (result != ISC_R_SUCCESS)
811 goto cleanup;
812 if (tcp)
813 isc_buffer_putuint16(request->query, (isc_uint16_t)r.length);
814 result = isc_buffer_copyregion(request->query, &r);
815 if (result != ISC_R_SUCCESS)
816 goto cleanup;
818 /* Add message ID. */
819 isc_buffer_usedregion(request->query, &r);
820 if (tcp)
821 isc_region_consume(&r, 2);
822 r.base[0] = (id>>8) & 0xff;
823 r.base[1] = id & 0xff;
825 LOCK(&requestmgr->lock);
826 if (requestmgr->exiting) {
827 UNLOCK(&requestmgr->lock);
828 result = ISC_R_SHUTTINGDOWN;
829 goto cleanup;
831 requestmgr_attach(requestmgr, &request->requestmgr);
832 request->hash = mgr_gethash(requestmgr);
833 ISC_LIST_APPEND(requestmgr->requests, request, link);
834 UNLOCK(&requestmgr->lock);
836 result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
837 if (result != ISC_R_SUCCESS)
838 goto unlink;
840 request->destaddr = *destaddr;
841 if (tcp) {
842 result = isc_socket_connect(socket, destaddr, task,
843 req_connected, request);
844 if (result != ISC_R_SUCCESS)
845 goto unlink;
846 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
847 } else {
848 result = req_send(request, task, destaddr);
849 if (result != ISC_R_SUCCESS)
850 goto unlink;
853 req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p",
854 request);
855 *requestp = request;
856 return (ISC_R_SUCCESS);
858 unlink:
859 LOCK(&requestmgr->lock);
860 ISC_LIST_UNLINK(requestmgr->requests, request, link);
861 UNLOCK(&requestmgr->lock);
863 cleanup:
864 if (tclone != NULL)
865 isc_task_detach(&tclone);
866 req_destroy(request);
867 req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
868 dns_result_totext(result));
869 return (result);
872 isc_result_t
873 dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
874 isc_sockaddr_t *address, unsigned int options,
875 dns_tsigkey_t *key,
876 unsigned int timeout, isc_task_t *task,
877 isc_taskaction_t action, void *arg,
878 dns_request_t **requestp)
880 return (dns_request_createvia4(requestmgr, message, NULL, address,
881 -1, options, key, timeout, 0, 0, task,
882 action, arg, requestp));
885 isc_result_t
886 dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message,
887 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
888 unsigned int options, dns_tsigkey_t *key,
889 unsigned int timeout, isc_task_t *task,
890 isc_taskaction_t action, void *arg,
891 dns_request_t **requestp)
893 return(dns_request_createvia4(requestmgr, message, srcaddr, destaddr,
894 -1, options, key, timeout, 0, 0, task,
895 action, arg, requestp));
898 isc_result_t
899 dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message,
900 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
901 unsigned int options, dns_tsigkey_t *key,
902 unsigned int timeout, unsigned int udptimeout,
903 isc_task_t *task, isc_taskaction_t action, void *arg,
904 dns_request_t **requestp)
906 unsigned int udpretries = 0;
908 if (udptimeout != 0)
909 udpretries = timeout / udptimeout;
910 return (dns_request_createvia4(requestmgr, message, srcaddr, destaddr,
911 -1, options, key, timeout, udptimeout,
912 udpretries, task, action, arg,
913 requestp));
916 isc_result_t
917 dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
918 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
919 unsigned int options, dns_tsigkey_t *key,
920 unsigned int timeout, unsigned int udptimeout,
921 unsigned int udpretries, isc_task_t *task,
922 isc_taskaction_t action, void *arg,
923 dns_request_t **requestp)
925 return (dns_request_createvia4(requestmgr, message, srcaddr, destaddr,
926 -1, options, key, timeout, udptimeout,
927 udpretries, task, action, arg,
928 requestp));
931 isc_result_t
932 dns_request_createvia4(dns_requestmgr_t *requestmgr, dns_message_t *message,
933 isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
934 isc_dscp_t dscp, unsigned int options,
935 dns_tsigkey_t *key, unsigned int timeout,
936 unsigned int udptimeout, unsigned int udpretries,
937 isc_task_t *task, isc_taskaction_t action, void *arg,
938 dns_request_t **requestp)
940 dns_request_t *request = NULL;
941 isc_task_t *tclone = NULL;
942 isc_socket_t *socket = NULL;
943 isc_result_t result;
944 isc_mem_t *mctx;
945 dns_messageid_t id;
946 isc_boolean_t tcp;
947 isc_boolean_t setkey = ISC_TRUE;
949 REQUIRE(VALID_REQUESTMGR(requestmgr));
950 REQUIRE(message != NULL);
951 REQUIRE(destaddr != NULL);
952 REQUIRE(task != NULL);
953 REQUIRE(action != NULL);
954 REQUIRE(requestp != NULL && *requestp == NULL);
955 REQUIRE(timeout > 0);
957 mctx = requestmgr->mctx;
959 req_log(ISC_LOG_DEBUG(3), "dns_request_createvia");
961 if (srcaddr != NULL &&
962 isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr))
963 return (ISC_R_FAMILYMISMATCH);
965 if (isblackholed(requestmgr->dispatchmgr, destaddr))
966 return (DNS_R_BLACKHOLED);
968 request = NULL;
969 result = new_request(mctx, &request);
970 if (result != ISC_R_SUCCESS)
971 return (result);
973 if (udptimeout == 0 && udpretries != 0) {
974 udptimeout = timeout / (udpretries + 1);
975 if (udptimeout == 0)
976 udptimeout = 1;
978 request->udpcount = udpretries;
979 request->dscp = dscp;
982 * Create timer now. We will set it below once.
984 result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
985 NULL, NULL, task, req_timeout, request,
986 &request->timer);
987 if (result != ISC_R_SUCCESS)
988 goto cleanup;
990 request->event = (dns_requestevent_t *)
991 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
992 action, arg, sizeof(dns_requestevent_t));
993 if (request->event == NULL) {
994 result = ISC_R_NOMEMORY;
995 goto cleanup;
997 isc_task_attach(task, &tclone);
998 request->event->ev_sender = task;
999 request->event->request = request;
1000 request->event->result = ISC_R_FAILURE;
1001 if (key != NULL)
1002 dns_tsigkey_attach(key, &request->tsigkey);
1004 use_tcp:
1005 tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0);
1006 result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, dscp,
1007 &request->dispatch);
1008 if (result != ISC_R_SUCCESS)
1009 goto cleanup;
1011 result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
1012 req_response, request, &id,
1013 &request->dispentry,
1014 requestmgr->socketmgr);
1015 if (result != ISC_R_SUCCESS)
1016 goto cleanup;
1017 socket = req_getsocket(request);
1018 INSIST(socket != NULL);
1020 message->id = id;
1021 if (setkey) {
1022 result = dns_message_settsigkey(message, request->tsigkey);
1023 if (result != ISC_R_SUCCESS)
1024 goto cleanup;
1026 result = req_render(message, &request->query, options, mctx);
1027 if (result == DNS_R_USETCP &&
1028 (options & DNS_REQUESTOPT_TCP) == 0) {
1030 * Try again using TCP.
1032 dns_message_renderreset(message);
1033 dns_dispatch_removeresponse(&request->dispentry, NULL);
1034 dns_dispatch_detach(&request->dispatch);
1035 socket = NULL;
1036 options |= DNS_REQUESTOPT_TCP;
1037 setkey = ISC_FALSE;
1038 goto use_tcp;
1040 if (result != ISC_R_SUCCESS)
1041 goto cleanup;
1043 result = dns_message_getquerytsig(message, mctx, &request->tsig);
1044 if (result != ISC_R_SUCCESS)
1045 goto cleanup;
1047 LOCK(&requestmgr->lock);
1048 if (requestmgr->exiting) {
1049 UNLOCK(&requestmgr->lock);
1050 result = ISC_R_SHUTTINGDOWN;
1051 goto cleanup;
1053 requestmgr_attach(requestmgr, &request->requestmgr);
1054 request->hash = mgr_gethash(requestmgr);
1055 ISC_LIST_APPEND(requestmgr->requests, request, link);
1056 UNLOCK(&requestmgr->lock);
1058 result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
1059 if (result != ISC_R_SUCCESS)
1060 goto unlink;
1062 request->destaddr = *destaddr;
1063 if (tcp) {
1064 result = isc_socket_connect(socket, destaddr, task,
1065 req_connected, request);
1066 if (result != ISC_R_SUCCESS)
1067 goto unlink;
1068 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
1069 } else {
1070 result = req_send(request, task, destaddr);
1071 if (result != ISC_R_SUCCESS)
1072 goto unlink;
1075 req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p",
1076 request);
1077 *requestp = request;
1078 return (ISC_R_SUCCESS);
1080 unlink:
1081 LOCK(&requestmgr->lock);
1082 ISC_LIST_UNLINK(requestmgr->requests, request, link);
1083 UNLOCK(&requestmgr->lock);
1085 cleanup:
1086 if (tclone != NULL)
1087 isc_task_detach(&tclone);
1088 req_destroy(request);
1089 req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s",
1090 dns_result_totext(result));
1091 return (result);
1094 static isc_result_t
1095 req_render(dns_message_t *message, isc_buffer_t **bufferp,
1096 unsigned int options, isc_mem_t *mctx)
1098 isc_buffer_t *buf1 = NULL;
1099 isc_buffer_t *buf2 = NULL;
1100 isc_result_t result;
1101 isc_region_t r;
1102 isc_boolean_t tcp = ISC_FALSE;
1103 dns_compress_t cctx;
1104 isc_boolean_t cleanup_cctx = ISC_FALSE;
1106 REQUIRE(bufferp != NULL && *bufferp == NULL);
1108 req_log(ISC_LOG_DEBUG(3), "request_render");
1111 * Create buffer able to hold largest possible message.
1113 result = isc_buffer_allocate(mctx, &buf1, 65535);
1114 if (result != ISC_R_SUCCESS)
1115 return (result);
1117 result = dns_compress_init(&cctx, -1, mctx);
1118 if (result != ISC_R_SUCCESS)
1119 return (result);
1120 cleanup_cctx = ISC_TRUE;
1122 if ((options & DNS_REQUESTOPT_CASE) != 0)
1123 dns_compress_setsensitive(&cctx, ISC_TRUE);
1126 * Render message.
1128 result = dns_message_renderbegin(message, &cctx, buf1);
1129 if (result != ISC_R_SUCCESS)
1130 goto cleanup;
1131 result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
1132 if (result != ISC_R_SUCCESS)
1133 goto cleanup;
1134 result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
1135 if (result != ISC_R_SUCCESS)
1136 goto cleanup;
1137 result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
1138 if (result != ISC_R_SUCCESS)
1139 goto cleanup;
1140 result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
1141 if (result != ISC_R_SUCCESS)
1142 goto cleanup;
1143 result = dns_message_renderend(message);
1144 if (result != ISC_R_SUCCESS)
1145 goto cleanup;
1147 dns_compress_invalidate(&cctx);
1148 cleanup_cctx = ISC_FALSE;
1151 * Copy rendered message to exact sized buffer.
1153 isc_buffer_usedregion(buf1, &r);
1154 if ((options & DNS_REQUESTOPT_TCP) != 0) {
1155 tcp = ISC_TRUE;
1156 } else if (r.length > 512) {
1157 result = DNS_R_USETCP;
1158 goto cleanup;
1160 result = isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0));
1161 if (result != ISC_R_SUCCESS)
1162 goto cleanup;
1163 if (tcp)
1164 isc_buffer_putuint16(buf2, (isc_uint16_t)r.length);
1165 result = isc_buffer_copyregion(buf2, &r);
1166 if (result != ISC_R_SUCCESS)
1167 goto cleanup;
1170 * Cleanup and return.
1172 isc_buffer_free(&buf1);
1173 *bufferp = buf2;
1174 return (ISC_R_SUCCESS);
1176 cleanup:
1177 dns_message_renderreset(message);
1178 if (buf1 != NULL)
1179 isc_buffer_free(&buf1);
1180 if (buf2 != NULL)
1181 isc_buffer_free(&buf2);
1182 if (cleanup_cctx)
1183 dns_compress_invalidate(&cctx);
1184 return (result);
1189 * If this request is no longer waiting for events,
1190 * send the completion event. This will ultimately
1191 * cause the request to be destroyed.
1193 * Requires:
1194 * 'request' is locked by the caller.
1196 static void
1197 send_if_done(dns_request_t *request, isc_result_t result) {
1198 if (request->event != NULL && !request->canceling)
1199 req_sendevent(request, result);
1203 * Handle the control event.
1205 static void
1206 do_cancel(isc_task_t *task, isc_event_t *event) {
1207 dns_request_t *request = event->ev_arg;
1208 UNUSED(task);
1209 INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL);
1210 LOCK(&request->requestmgr->locks[request->hash]);
1211 request->canceling = ISC_FALSE;
1212 if (!DNS_REQUEST_CANCELED(request))
1213 req_cancel(request);
1214 send_if_done(request, ISC_R_CANCELED);
1215 UNLOCK(&request->requestmgr->locks[request->hash]);
1218 void
1219 dns_request_cancel(dns_request_t *request) {
1220 REQUIRE(VALID_REQUEST(request));
1222 req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request);
1224 REQUIRE(VALID_REQUEST(request));
1226 LOCK(&request->requestmgr->locks[request->hash]);
1227 if (!request->canceling && !DNS_REQUEST_CANCELED(request)) {
1228 isc_event_t *ev = &request->ctlevent;
1229 isc_task_send(request->event->ev_sender, &ev);
1230 request->canceling = ISC_TRUE;
1232 UNLOCK(&request->requestmgr->locks[request->hash]);
1235 isc_result_t
1236 dns_request_getresponse(dns_request_t *request, dns_message_t *message,
1237 unsigned int options)
1239 isc_result_t result;
1241 REQUIRE(VALID_REQUEST(request));
1242 REQUIRE(request->answer != NULL);
1244 req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p",
1245 request);
1247 result = dns_message_setquerytsig(message, request->tsig);
1248 if (result != ISC_R_SUCCESS)
1249 return (result);
1250 result = dns_message_settsigkey(message, request->tsigkey);
1251 if (result != ISC_R_SUCCESS)
1252 return (result);
1253 result = dns_message_parse(message, request->answer, options);
1254 if (result != ISC_R_SUCCESS)
1255 return (result);
1256 if (request->tsigkey != NULL)
1257 result = dns_tsig_verify(request->answer, message, NULL, NULL);
1258 return (result);
1261 isc_boolean_t
1262 dns_request_usedtcp(dns_request_t *request) {
1263 REQUIRE(VALID_REQUEST(request));
1265 return (ISC_TF((request->flags & DNS_REQUEST_F_TCP) != 0));
1268 void
1269 dns_request_destroy(dns_request_t **requestp) {
1270 dns_request_t *request;
1272 REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
1274 request = *requestp;
1276 req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request);
1278 LOCK(&request->requestmgr->lock);
1279 LOCK(&request->requestmgr->locks[request->hash]);
1280 ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
1281 INSIST(!DNS_REQUEST_CONNECTING(request));
1282 INSIST(!DNS_REQUEST_SENDING(request));
1283 UNLOCK(&request->requestmgr->locks[request->hash]);
1284 UNLOCK(&request->requestmgr->lock);
1287 * These should have been cleaned up by req_cancel() before
1288 * the completion event was sent.
1290 INSIST(!ISC_LINK_LINKED(request, link));
1291 INSIST(request->dispentry == NULL);
1292 INSIST(request->dispatch == NULL);
1293 INSIST(request->timer == NULL);
1295 req_destroy(request);
1297 *requestp = NULL;
1300 /***
1301 *** Private: request.
1302 ***/
1304 static isc_socket_t *
1305 req_getsocket(dns_request_t *request) {
1306 unsigned int dispattr;
1307 isc_socket_t *socket;
1309 dispattr = dns_dispatch_getattributes(request->dispatch);
1310 if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1311 INSIST(request->dispentry != NULL);
1312 socket = dns_dispatch_getentrysocket(request->dispentry);
1313 } else
1314 socket = dns_dispatch_getsocket(request->dispatch);
1316 return (socket);
1319 static void
1320 req_connected(isc_task_t *task, isc_event_t *event) {
1321 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1322 isc_result_t result;
1323 dns_request_t *request = event->ev_arg;
1325 REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
1326 REQUIRE(VALID_REQUEST(request));
1327 REQUIRE(DNS_REQUEST_CONNECTING(request));
1329 req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request);
1331 LOCK(&request->requestmgr->locks[request->hash]);
1332 request->flags &= ~DNS_REQUEST_F_CONNECTING;
1334 if (DNS_REQUEST_CANCELED(request)) {
1336 * Send delayed event.
1338 if (DNS_REQUEST_TIMEDOUT(request))
1339 send_if_done(request, ISC_R_TIMEDOUT);
1340 else
1341 send_if_done(request, ISC_R_CANCELED);
1342 } else {
1343 dns_dispatch_starttcp(request->dispatch);
1344 result = sevent->result;
1345 if (result == ISC_R_SUCCESS)
1346 result = req_send(request, task, NULL);
1348 if (result != ISC_R_SUCCESS) {
1349 req_cancel(request);
1350 send_if_done(request, ISC_R_CANCELED);
1353 UNLOCK(&request->requestmgr->locks[request->hash]);
1354 isc_event_free(&event);
1357 static void
1358 req_senddone(isc_task_t *task, isc_event_t *event) {
1359 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1360 dns_request_t *request = event->ev_arg;
1362 REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1363 REQUIRE(VALID_REQUEST(request));
1364 REQUIRE(DNS_REQUEST_SENDING(request));
1366 req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
1368 UNUSED(task);
1370 LOCK(&request->requestmgr->locks[request->hash]);
1371 request->flags &= ~DNS_REQUEST_F_SENDING;
1373 if (DNS_REQUEST_CANCELED(request)) {
1375 * Send delayed event.
1377 if (DNS_REQUEST_TIMEDOUT(request))
1378 send_if_done(request, ISC_R_TIMEDOUT);
1379 else
1380 send_if_done(request, ISC_R_CANCELED);
1381 } else if (sevent->result != ISC_R_SUCCESS) {
1382 req_cancel(request);
1383 send_if_done(request, ISC_R_CANCELED);
1385 UNLOCK(&request->requestmgr->locks[request->hash]);
1387 isc_event_free(&event);
1390 static void
1391 req_response(isc_task_t *task, isc_event_t *event) {
1392 isc_result_t result;
1393 dns_request_t *request = event->ev_arg;
1394 dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
1395 isc_region_t r;
1397 REQUIRE(VALID_REQUEST(request));
1398 REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
1400 UNUSED(task);
1402 req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
1403 dns_result_totext(devent->result));
1405 LOCK(&request->requestmgr->locks[request->hash]);
1406 result = devent->result;
1407 if (result != ISC_R_SUCCESS)
1408 goto done;
1411 * Copy buffer to request.
1413 isc_buffer_usedregion(&devent->buffer, &r);
1414 result = isc_buffer_allocate(request->mctx, &request->answer,
1415 r.length);
1416 if (result != ISC_R_SUCCESS)
1417 goto done;
1418 result = isc_buffer_copyregion(request->answer, &r);
1419 if (result != ISC_R_SUCCESS)
1420 isc_buffer_free(&request->answer);
1421 done:
1423 * Cleanup.
1425 dns_dispatch_removeresponse(&request->dispentry, &devent);
1426 req_cancel(request);
1428 * Send completion event.
1430 send_if_done(request, result);
1431 UNLOCK(&request->requestmgr->locks[request->hash]);
1434 static void
1435 req_timeout(isc_task_t *task, isc_event_t *event) {
1436 dns_request_t *request = event->ev_arg;
1437 isc_result_t result;
1439 REQUIRE(VALID_REQUEST(request));
1441 req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
1443 UNUSED(task);
1444 LOCK(&request->requestmgr->locks[request->hash]);
1445 if (event->ev_type == ISC_TIMEREVENT_TICK &&
1446 request->udpcount-- != 0) {
1447 if (! DNS_REQUEST_SENDING(request)) {
1448 result = req_send(request, task, &request->destaddr);
1449 if (result != ISC_R_SUCCESS) {
1450 req_cancel(request);
1451 send_if_done(request, result);
1454 } else {
1455 request->flags |= DNS_REQUEST_F_TIMEDOUT;
1456 req_cancel(request);
1457 send_if_done(request, ISC_R_TIMEDOUT);
1459 UNLOCK(&request->requestmgr->locks[request->hash]);
1460 isc_event_free(&event);
1463 static void
1464 req_sendevent(dns_request_t *request, isc_result_t result) {
1465 isc_task_t *task;
1467 REQUIRE(VALID_REQUEST(request));
1469 req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request);
1472 * Lock held by caller.
1474 task = request->event->ev_sender;
1475 request->event->ev_sender = request;
1476 request->event->result = result;
1477 isc_task_sendanddetach(&task, (isc_event_t **)(void *)&request->event);
1480 static void
1481 req_destroy(dns_request_t *request) {
1482 isc_mem_t *mctx;
1484 REQUIRE(VALID_REQUEST(request));
1486 req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request);
1488 request->magic = 0;
1489 if (request->query != NULL)
1490 isc_buffer_free(&request->query);
1491 if (request->answer != NULL)
1492 isc_buffer_free(&request->answer);
1493 if (request->event != NULL)
1494 isc_event_free((isc_event_t **)(void *)&request->event);
1495 if (request->dispentry != NULL)
1496 dns_dispatch_removeresponse(&request->dispentry, NULL);
1497 if (request->dispatch != NULL)
1498 dns_dispatch_detach(&request->dispatch);
1499 if (request->timer != NULL)
1500 isc_timer_detach(&request->timer);
1501 if (request->tsig != NULL)
1502 isc_buffer_free(&request->tsig);
1503 if (request->tsigkey != NULL)
1504 dns_tsigkey_detach(&request->tsigkey);
1505 if (request->requestmgr != NULL)
1506 requestmgr_detach(&request->requestmgr);
1507 mctx = request->mctx;
1508 isc_mem_put(mctx, request, sizeof(*request));
1509 isc_mem_detach(&mctx);
1513 * Stop the current request. Must be called from the request's task.
1515 static void
1516 req_cancel(dns_request_t *request) {
1517 isc_socket_t *socket;
1518 unsigned int dispattr;
1520 REQUIRE(VALID_REQUEST(request));
1522 req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request);
1525 * Lock held by caller.
1527 request->flags |= DNS_REQUEST_F_CANCELED;
1529 if (request->timer != NULL)
1530 isc_timer_detach(&request->timer);
1531 dispattr = dns_dispatch_getattributes(request->dispatch);
1532 socket = NULL;
1533 if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) {
1534 if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1535 if (request->dispentry != NULL) {
1536 socket = dns_dispatch_getentrysocket(
1537 request->dispentry);
1539 } else
1540 socket = dns_dispatch_getsocket(request->dispatch);
1541 if (DNS_REQUEST_CONNECTING(request) && socket != NULL)
1542 isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
1543 if (DNS_REQUEST_SENDING(request) && socket != NULL)
1544 isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
1546 if (request->dispentry != NULL)
1547 dns_dispatch_removeresponse(&request->dispentry, NULL);
1548 dns_dispatch_detach(&request->dispatch);
1551 static void
1552 req_log(int level, const char *fmt, ...) {
1553 va_list ap;
1555 va_start(ap, fmt);
1556 isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1557 DNS_LOGMODULE_REQUEST, level, fmt, ap);
1558 va_end(ap);