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