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