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