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