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