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