1/*
2 * Copyright (C) 2004-2013  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2002  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id$ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <isc/magic.h>
25#include <isc/mem.h>
26#include <isc/task.h>
27#include <isc/timer.h>
28#include <isc/util.h>
29
30#include <dns/acl.h>
31#include <dns/compress.h>
32#include <dns/dispatch.h>
33#include <dns/events.h>
34#include <dns/log.h>
35#include <dns/message.h>
36#include <dns/rdata.h>
37#include <dns/rdatastruct.h>
38#include <dns/request.h>
39#include <dns/result.h>
40#include <dns/tsig.h>
41
42#define REQUESTMGR_MAGIC	ISC_MAGIC('R', 'q', 'u', 'M')
43#define VALID_REQUESTMGR(mgr)	ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC)
44
45#define REQUEST_MAGIC		ISC_MAGIC('R', 'q', 'u', '!')
46#define VALID_REQUEST(request)	ISC_MAGIC_VALID(request, REQUEST_MAGIC)
47
48typedef ISC_LIST(dns_request_t) dns_requestlist_t;
49
50#define DNS_REQUEST_NLOCKS 7
51
52struct dns_requestmgr {
53	unsigned int			magic;
54	isc_mutex_t			lock;
55	isc_mem_t		       *mctx;
56
57	/* locked */
58	isc_int32_t			eref;
59	isc_int32_t			iref;
60	isc_timermgr_t		       *timermgr;
61	isc_socketmgr_t		       *socketmgr;
62	isc_taskmgr_t		       *taskmgr;
63	dns_dispatchmgr_t	       *dispatchmgr;
64	dns_dispatch_t		       *dispatchv4;
65	dns_dispatch_t		       *dispatchv6;
66	isc_boolean_t			exiting;
67	isc_eventlist_t			whenshutdown;
68	unsigned int			hash;
69	isc_mutex_t			locks[DNS_REQUEST_NLOCKS];
70	dns_requestlist_t 		requests;
71};
72
73struct dns_request {
74	unsigned int			magic;
75	unsigned int			hash;
76	isc_mem_t		       *mctx;
77	isc_int32_t			flags;
78	ISC_LINK(dns_request_t) 	link;
79	isc_buffer_t		       *query;
80	isc_buffer_t		       *answer;
81	dns_requestevent_t	       *event;
82	dns_dispatch_t		       *dispatch;
83	dns_dispentry_t		       *dispentry;
84	isc_timer_t		       *timer;
85	dns_requestmgr_t	       *requestmgr;
86	isc_buffer_t		       *tsig;
87	dns_tsigkey_t		       *tsigkey;
88	isc_event_t			ctlevent;
89	isc_boolean_t			canceling; /* ctlevent outstanding */
90	isc_sockaddr_t			destaddr;
91	unsigned int			udpcount;
92};
93
94#define DNS_REQUEST_F_CONNECTING 0x0001
95#define DNS_REQUEST_F_SENDING 0x0002
96#define DNS_REQUEST_F_CANCELED 0x0004	/*%< ctlevent received, or otherwise
97					   synchronously canceled */
98#define DNS_REQUEST_F_TIMEDOUT 0x0008	/*%< canceled due to a timeout */
99#define DNS_REQUEST_F_TCP 0x0010	/*%< This request used TCP */
100#define DNS_REQUEST_CANCELED(r) \
101	(((r)->flags & DNS_REQUEST_F_CANCELED) != 0)
102#define DNS_REQUEST_CONNECTING(r) \
103	(((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
104#define DNS_REQUEST_SENDING(r) \
105	(((r)->flags & DNS_REQUEST_F_SENDING) != 0)
106#define DNS_REQUEST_TIMEDOUT(r) \
107	(((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0)
108
109
110/***
111 *** Forward
112 ***/
113
114static void mgr_destroy(dns_requestmgr_t *requestmgr);
115static void mgr_shutdown(dns_requestmgr_t *requestmgr);
116static unsigned int mgr_gethash(dns_requestmgr_t *requestmgr);
117static void send_shutdown_events(dns_requestmgr_t *requestmgr);
118
119static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer,
120			       unsigned int options, isc_mem_t *mctx);
121static void req_senddone(isc_task_t *task, isc_event_t *event);
122static void req_response(isc_task_t *task, isc_event_t *event);
123static void req_timeout(isc_task_t *task, isc_event_t *event);
124static isc_socket_t * req_getsocket(dns_request_t *request);
125static void req_connected(isc_task_t *task, isc_event_t *event);
126static void req_sendevent(dns_request_t *request, isc_result_t result);
127static void req_cancel(dns_request_t *request);
128static void req_destroy(dns_request_t *request);
129static void req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
130static void do_cancel(isc_task_t *task, isc_event_t *event);
131
132/***
133 *** Public
134 ***/
135
136isc_result_t
137dns_requestmgr_create(isc_mem_t *mctx,
138		      isc_timermgr_t *timermgr,
139		      isc_socketmgr_t *socketmgr,
140		      isc_taskmgr_t *taskmgr,
141		      dns_dispatchmgr_t *dispatchmgr,
142		      dns_dispatch_t *dispatchv4,
143		      dns_dispatch_t *dispatchv6,
144		      dns_requestmgr_t **requestmgrp)
145{
146	dns_requestmgr_t *requestmgr;
147	isc_socket_t *socket;
148	isc_result_t result;
149	int i;
150	unsigned int dispattr;
151
152	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
153
154	REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
155	REQUIRE(timermgr != NULL);
156	REQUIRE(socketmgr != NULL);
157	REQUIRE(taskmgr != NULL);
158	REQUIRE(dispatchmgr != NULL);
159	UNUSED(socket);
160	if (dispatchv4 != NULL) {
161		dispattr = dns_dispatch_getattributes(dispatchv4);
162		REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
163	}
164	if (dispatchv6 != NULL) {
165		dispattr = dns_dispatch_getattributes(dispatchv6);
166		REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
167	}
168
169	requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
170	if (requestmgr == NULL)
171		return (ISC_R_NOMEMORY);
172
173	result = isc_mutex_init(&requestmgr->lock);
174	if (result != ISC_R_SUCCESS) {
175		isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
176		return (result);
177	}
178	for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
179		result = isc_mutex_init(&requestmgr->locks[i]);
180		if (result != ISC_R_SUCCESS) {
181			while (--i >= 0)
182				DESTROYLOCK(&requestmgr->locks[i]);
183			DESTROYLOCK(&requestmgr->lock);
184			isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
185			return (result);
186		}
187	}
188	requestmgr->timermgr = timermgr;
189	requestmgr->socketmgr = socketmgr;
190	requestmgr->taskmgr = taskmgr;
191	requestmgr->dispatchmgr = dispatchmgr;
192	requestmgr->dispatchv4 = NULL;
193	if (dispatchv4 != NULL)
194		dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
195	requestmgr->dispatchv6 = NULL;
196	if (dispatchv6 != NULL)
197		dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
198	requestmgr->mctx = NULL;
199	isc_mem_attach(mctx, &requestmgr->mctx);
200	requestmgr->eref = 1;	/* implicit attach */
201	requestmgr->iref = 0;
202	ISC_LIST_INIT(requestmgr->whenshutdown);
203	ISC_LIST_INIT(requestmgr->requests);
204	requestmgr->exiting = ISC_FALSE;
205	requestmgr->hash = 0;
206	requestmgr->magic = REQUESTMGR_MAGIC;
207
208	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
209
210	*requestmgrp = requestmgr;
211	return (ISC_R_SUCCESS);
212}
213
214void
215dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
216			    isc_event_t **eventp)
217{
218	isc_task_t *clone;
219	isc_event_t *event;
220
221	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_whenshutdown");
222
223	REQUIRE(VALID_REQUESTMGR(requestmgr));
224	REQUIRE(eventp != NULL);
225
226	event = *eventp;
227	*eventp = NULL;
228
229	LOCK(&requestmgr->lock);
230
231	if (requestmgr->exiting) {
232		/*
233		 * We're already shutdown.  Send the event.
234		 */
235		event->ev_sender = requestmgr;
236		isc_task_send(task, &event);
237	} else {
238		clone = NULL;
239		isc_task_attach(task, &clone);
240		event->ev_sender = clone;
241		ISC_LIST_APPEND(requestmgr->whenshutdown, event, ev_link);
242	}
243	UNLOCK(&requestmgr->lock);
244}
245
246void
247dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
248
249	REQUIRE(VALID_REQUESTMGR(requestmgr));
250
251	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr);
252
253	LOCK(&requestmgr->lock);
254	mgr_shutdown(requestmgr);
255	UNLOCK(&requestmgr->lock);
256}
257
258static void
259mgr_shutdown(dns_requestmgr_t *requestmgr) {
260	dns_request_t *request;
261
262	/*
263	 * Caller holds lock.
264	 */
265	if (!requestmgr->exiting) {
266		requestmgr->exiting = ISC_TRUE;
267		for (request = ISC_LIST_HEAD(requestmgr->requests);
268		     request != NULL;
269		     request = ISC_LIST_NEXT(request, link)) {
270			dns_request_cancel(request);
271		}
272		if (requestmgr->iref == 0) {
273			INSIST(ISC_LIST_EMPTY(requestmgr->requests));
274			send_shutdown_events(requestmgr);
275		}
276	}
277}
278
279static void
280requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
281
282	/*
283	 * Locked by caller.
284	 */
285
286	REQUIRE(VALID_REQUESTMGR(source));
287	REQUIRE(targetp != NULL && *targetp == NULL);
288
289	REQUIRE(!source->exiting);
290
291	source->iref++;
292	*targetp = source;
293
294	req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d",
295		source, source->eref, source->iref);
296}
297
298static void
299requestmgr_detach(dns_requestmgr_t **requestmgrp) {
300	dns_requestmgr_t *requestmgr;
301	isc_boolean_t need_destroy = ISC_FALSE;
302
303	REQUIRE(requestmgrp != NULL);
304	requestmgr = *requestmgrp;
305	REQUIRE(VALID_REQUESTMGR(requestmgr));
306
307	*requestmgrp = NULL;
308	LOCK(&requestmgr->lock);
309	INSIST(requestmgr->iref > 0);
310	requestmgr->iref--;
311
312	req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d",
313		requestmgr, requestmgr->eref, requestmgr->iref);
314
315	if (requestmgr->iref == 0 && requestmgr->exiting) {
316		INSIST(ISC_LIST_HEAD(requestmgr->requests) == NULL);
317		send_shutdown_events(requestmgr);
318		if (requestmgr->eref == 0)
319			need_destroy = ISC_TRUE;
320	}
321	UNLOCK(&requestmgr->lock);
322
323	if (need_destroy)
324		mgr_destroy(requestmgr);
325}
326
327void
328dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
329
330	REQUIRE(VALID_REQUESTMGR(source));
331	REQUIRE(targetp != NULL && *targetp == NULL);
332	REQUIRE(!source->exiting);
333
334	LOCK(&source->lock);
335	source->eref++;
336	*targetp = source;
337	UNLOCK(&source->lock);
338
339	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d",
340		source, source->eref, source->iref);
341}
342
343void
344dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) {
345	dns_requestmgr_t *requestmgr;
346	isc_boolean_t need_destroy = ISC_FALSE;
347
348	REQUIRE(requestmgrp != NULL);
349	requestmgr = *requestmgrp;
350	REQUIRE(VALID_REQUESTMGR(requestmgr));
351
352	LOCK(&requestmgr->lock);
353	INSIST(requestmgr->eref > 0);
354	requestmgr->eref--;
355
356	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d",
357		requestmgr, requestmgr->eref, requestmgr->iref);
358
359	if (requestmgr->eref == 0 && requestmgr->iref == 0) {
360		INSIST(requestmgr->exiting &&
361		       ISC_LIST_HEAD(requestmgr->requests) == NULL);
362		need_destroy = ISC_TRUE;
363	}
364	UNLOCK(&requestmgr->lock);
365
366	if (need_destroy)
367		mgr_destroy(requestmgr);
368
369	*requestmgrp = NULL;
370}
371
372static void
373send_shutdown_events(dns_requestmgr_t *requestmgr) {
374	isc_event_t *event, *next_event;
375	isc_task_t *etask;
376
377	req_log(ISC_LOG_DEBUG(3), "send_shutdown_events: %p", requestmgr);
378
379	/*
380	 * Caller must be holding the manager lock.
381	 */
382	for (event = ISC_LIST_HEAD(requestmgr->whenshutdown);
383	     event != NULL;
384	     event = next_event) {
385		next_event = ISC_LIST_NEXT(event, ev_link);
386		ISC_LIST_UNLINK(requestmgr->whenshutdown, event, ev_link);
387		etask = event->ev_sender;
388		event->ev_sender = requestmgr;
389		isc_task_sendanddetach(&etask, &event);
390	}
391}
392
393static void
394mgr_destroy(dns_requestmgr_t *requestmgr) {
395	int i;
396	isc_mem_t *mctx;
397
398	req_log(ISC_LOG_DEBUG(3), "mgr_destroy");
399
400	REQUIRE(requestmgr->eref == 0);
401	REQUIRE(requestmgr->iref == 0);
402
403	DESTROYLOCK(&requestmgr->lock);
404	for (i = 0; i < DNS_REQUEST_NLOCKS; i++)
405		DESTROYLOCK(&requestmgr->locks[i]);
406	if (requestmgr->dispatchv4 != NULL)
407		dns_dispatch_detach(&requestmgr->dispatchv4);
408	if (requestmgr->dispatchv6 != NULL)
409		dns_dispatch_detach(&requestmgr->dispatchv6);
410	requestmgr->magic = 0;
411	mctx = requestmgr->mctx;
412	isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
413	isc_mem_detach(&mctx);
414}
415
416static unsigned int
417mgr_gethash(dns_requestmgr_t *requestmgr) {
418	req_log(ISC_LOG_DEBUG(3), "mgr_gethash");
419	/*
420	 * Locked by caller.
421	 */
422	requestmgr->hash++;
423	return (requestmgr->hash % DNS_REQUEST_NLOCKS);
424}
425
426static inline isc_result_t
427req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) {
428	isc_region_t r;
429	isc_socket_t *socket;
430	isc_result_t result;
431
432	req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
433
434	REQUIRE(VALID_REQUEST(request));
435	socket = req_getsocket(request);
436	isc_buffer_usedregion(request->query, &r);
437	/*
438	 * We could connect the socket when we are using an exclusive dispatch
439	 * as we do in resolver.c, but we prefer implementation simplicity
440	 * at this moment.
441	 */
442	result = isc_socket_sendto(socket, &r, task, req_senddone,
443				  request, address, NULL);
444	if (result == ISC_R_SUCCESS)
445		request->flags |= DNS_REQUEST_F_SENDING;
446	return (result);
447}
448
449static isc_result_t
450new_request(isc_mem_t *mctx, dns_request_t **requestp)
451{
452	dns_request_t *request;
453
454	request = isc_mem_get(mctx, sizeof(*request));
455	if (request == NULL)
456		return (ISC_R_NOMEMORY);
457
458	/*
459	 * Zero structure.
460	 */
461	request->magic = 0;
462	request->mctx = NULL;
463	request->flags = 0;
464	ISC_LINK_INIT(request, link);
465	request->query = NULL;
466	request->answer = NULL;
467	request->event = NULL;
468	request->dispatch = NULL;
469	request->dispentry = NULL;
470	request->timer = NULL;
471	request->requestmgr = NULL;
472	request->tsig = NULL;
473	request->tsigkey = NULL;
474	ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL,
475		       DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL,
476		       NULL, NULL);
477	request->canceling = ISC_FALSE;
478	request->udpcount = 0;
479
480	isc_mem_attach(mctx, &request->mctx);
481
482	request->magic = REQUEST_MAGIC;
483	*requestp = request;
484	return (ISC_R_SUCCESS);
485}
486
487
488static isc_boolean_t
489isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) {
490	dns_acl_t *blackhole;
491	isc_netaddr_t netaddr;
492	int match;
493	isc_boolean_t drop = ISC_FALSE;
494	char netaddrstr[ISC_NETADDR_FORMATSIZE];
495
496	blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
497	if (blackhole != NULL) {
498		isc_netaddr_fromsockaddr(&netaddr, destaddr);
499		if (dns_acl_match(&netaddr, NULL, blackhole,
500				  NULL, &match, NULL) == ISC_R_SUCCESS &&
501		    match > 0)
502			drop = ISC_TRUE;
503	}
504	if (drop) {
505		isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
506		req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
507	}
508	return (drop);
509}
510
511static isc_result_t
512create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
513		    isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
514{
515	isc_result_t result;
516	isc_socket_t *socket = NULL;
517	isc_sockaddr_t src;
518	unsigned int attrs;
519	isc_sockaddr_t bind_any;
520
521	result = isc_socket_create(requestmgr->socketmgr,
522				   isc_sockaddr_pf(destaddr),
523				   isc_sockettype_tcp, &socket);
524	if (result != ISC_R_SUCCESS)
525		return (result);
526#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
527	if (srcaddr == NULL) {
528		isc_sockaddr_anyofpf(&bind_any,
529				     isc_sockaddr_pf(destaddr));
530		result = isc_socket_bind(socket, &bind_any, 0);
531	} else {
532		src = *srcaddr;
533		isc_sockaddr_setport(&src, 0);
534		result = isc_socket_bind(socket, &src, 0);
535	}
536	if (result != ISC_R_SUCCESS)
537		goto cleanup;
538#endif
539	attrs = 0;
540	attrs |= DNS_DISPATCHATTR_TCP;
541	attrs |= DNS_DISPATCHATTR_PRIVATE;
542	if (isc_sockaddr_pf(destaddr) == AF_INET)
543		attrs |= DNS_DISPATCHATTR_IPV4;
544	else
545		attrs |= DNS_DISPATCHATTR_IPV6;
546	attrs |= DNS_DISPATCHATTR_MAKEQUERY;
547	result = dns_dispatch_createtcp(requestmgr->dispatchmgr,
548					socket, requestmgr->taskmgr,
549					4096, 2, 1, 1, 3, attrs,
550					dispatchp);
551cleanup:
552	isc_socket_detach(&socket);
553	return (result);
554}
555
556static isc_result_t
557find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
558		  isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
559{
560	dns_dispatch_t *disp = NULL;
561	unsigned int attrs, attrmask;
562
563	if (srcaddr == NULL) {
564		switch (isc_sockaddr_pf(destaddr)) {
565		case PF_INET:
566			disp = requestmgr->dispatchv4;
567			break;
568
569		case PF_INET6:
570			disp = requestmgr->dispatchv6;
571			break;
572
573		default:
574			return (ISC_R_NOTIMPLEMENTED);
575		}
576		if (disp == NULL)
577			return (ISC_R_FAMILYNOSUPPORT);
578		dns_dispatch_attach(disp, dispatchp);
579		return (ISC_R_SUCCESS);
580	}
581	attrs = 0;
582	attrs |= DNS_DISPATCHATTR_UDP;
583	switch (isc_sockaddr_pf(srcaddr)) {
584	case PF_INET:
585		attrs |= DNS_DISPATCHATTR_IPV4;
586		break;
587
588	case PF_INET6:
589		attrs |= DNS_DISPATCHATTR_IPV6;
590		break;
591
592	default:
593		return (ISC_R_NOTIMPLEMENTED);
594	}
595	attrmask = 0;
596	attrmask |= DNS_DISPATCHATTR_UDP;
597	attrmask |= DNS_DISPATCHATTR_TCP;
598	attrmask |= DNS_DISPATCHATTR_IPV4;
599	attrmask |= DNS_DISPATCHATTR_IPV6;
600	return (dns_dispatch_getudp(requestmgr->dispatchmgr,
601				    requestmgr->socketmgr,
602				    requestmgr->taskmgr,
603				    srcaddr, 4096,
604				    1000, 32768, 16411, 16433,
605				    attrs, attrmask,
606				    dispatchp));
607}
608
609static isc_result_t
610get_dispatch(isc_boolean_t tcp, dns_requestmgr_t *requestmgr,
611	     isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
612	     dns_dispatch_t **dispatchp)
613{
614	isc_result_t result;
615	if (tcp)
616		result = create_tcp_dispatch(requestmgr, srcaddr,
617					     destaddr, dispatchp);
618	else
619		result = find_udp_dispatch(requestmgr, srcaddr,
620					   destaddr, dispatchp);
621	return (result);
622}
623
624static isc_result_t
625set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) {
626	isc_time_t expires;
627	isc_interval_t interval;
628	isc_result_t result;
629	isc_timertype_t timertype;
630
631	isc_interval_set(&interval, timeout, 0);
632	result = isc_time_nowplusinterval(&expires, &interval);
633	isc_interval_set(&interval, udpresend, 0);
634
635	timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once;
636	if (result == ISC_R_SUCCESS)
637		result = isc_timer_reset(timer, timertype, &expires,
638					 &interval, ISC_FALSE);
639	return (result);
640}
641
642isc_result_t
643dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
644		      isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
645		      unsigned int options, unsigned int timeout,
646		      isc_task_t *task, isc_taskaction_t action, void *arg,
647		      dns_request_t **requestp)
648{
649	return(dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
650				      options, timeout, 0, 0, task, action,
651				      arg, requestp));
652}
653
654isc_result_t
655dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
656		       isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
657		       unsigned int options, unsigned int timeout,
658		       unsigned int udptimeout, isc_task_t *task,
659		       isc_taskaction_t action, void *arg,
660		       dns_request_t **requestp)
661{
662	unsigned int udpretries = 0;
663
664	if (udptimeout != 0)
665		udpretries = timeout / udptimeout;
666
667	return (dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
668				       options, timeout, udptimeout,
669				       udpretries, task, action, arg,
670				       requestp));
671}
672
673isc_result_t
674dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
675		       isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
676		       unsigned int options, unsigned int timeout,
677		       unsigned int udptimeout, unsigned int udpretries,
678		       isc_task_t *task, isc_taskaction_t action, void *arg,
679		       dns_request_t **requestp)
680{
681	dns_request_t *request = NULL;
682	isc_task_t *tclone = NULL;
683	isc_socket_t *socket = NULL;
684	isc_result_t result;
685	isc_mem_t *mctx;
686	dns_messageid_t	id;
687	isc_boolean_t tcp = ISC_FALSE;
688	isc_region_t r;
689
690	REQUIRE(VALID_REQUESTMGR(requestmgr));
691	REQUIRE(msgbuf != NULL);
692	REQUIRE(destaddr != NULL);
693	REQUIRE(task != NULL);
694	REQUIRE(action != NULL);
695	REQUIRE(requestp != NULL && *requestp == NULL);
696	REQUIRE(timeout > 0);
697	if (srcaddr != NULL)
698		REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
699
700	mctx = requestmgr->mctx;
701
702	req_log(ISC_LOG_DEBUG(3), "dns_request_createraw");
703
704	if (isblackholed(requestmgr->dispatchmgr, destaddr))
705		return (DNS_R_BLACKHOLED);
706
707	request = NULL;
708	result = new_request(mctx, &request);
709	if (result != ISC_R_SUCCESS)
710		return (result);
711
712	if (udptimeout == 0 && udpretries != 0) {
713		udptimeout = timeout / (udpretries + 1);
714		if (udptimeout == 0)
715			udptimeout = 1;
716	}
717	request->udpcount = udpretries;
718
719	/*
720	 * Create timer now.  We will set it below once.
721	 */
722	result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
723				  NULL, NULL, task, req_timeout, request,
724				  &request->timer);
725	if (result != ISC_R_SUCCESS)
726		goto cleanup;
727
728	request->event = (dns_requestevent_t *)
729		isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
730				   action, arg, sizeof(dns_requestevent_t));
731	if (request->event == NULL) {
732		result = ISC_R_NOMEMORY;
733		goto cleanup;
734	}
735	isc_task_attach(task, &tclone);
736	request->event->ev_sender = task;
737	request->event->request = request;
738	request->event->result = ISC_R_FAILURE;
739
740	isc_buffer_usedregion(msgbuf, &r);
741	if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
742		result = DNS_R_FORMERR;
743		goto cleanup;
744	}
745
746	if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512)
747		tcp = ISC_TRUE;
748
749	result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
750			      &request->dispatch);
751	if (result != ISC_R_SUCCESS)
752		goto cleanup;
753
754	result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
755					   req_response, request, &id,
756					   &request->dispentry,
757					   requestmgr->socketmgr);
758	if (result != ISC_R_SUCCESS)
759		goto cleanup;
760
761	socket = req_getsocket(request);
762	INSIST(socket != NULL);
763
764	result = isc_buffer_allocate(mctx, &request->query,
765				     r.length + (tcp ? 2 : 0));
766	if (result != ISC_R_SUCCESS)
767		goto cleanup;
768	if (tcp)
769		isc_buffer_putuint16(request->query, (isc_uint16_t)r.length);
770	result = isc_buffer_copyregion(request->query, &r);
771	if (result != ISC_R_SUCCESS)
772		goto cleanup;
773
774	/* Add message ID. */
775	isc_buffer_usedregion(request->query, &r);
776	if (tcp)
777		isc_region_consume(&r, 2);
778	r.base[0] = (id>>8) & 0xff;
779	r.base[1] = id & 0xff;
780
781	LOCK(&requestmgr->lock);
782	if (requestmgr->exiting) {
783		UNLOCK(&requestmgr->lock);
784		result = ISC_R_SHUTTINGDOWN;
785		goto cleanup;
786	}
787	requestmgr_attach(requestmgr, &request->requestmgr);
788	request->hash = mgr_gethash(requestmgr);
789	ISC_LIST_APPEND(requestmgr->requests, request, link);
790	UNLOCK(&requestmgr->lock);
791
792	result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
793	if (result != ISC_R_SUCCESS)
794		goto unlink;
795
796	request->destaddr = *destaddr;
797	if (tcp) {
798		result = isc_socket_connect(socket, destaddr, task,
799					    req_connected, request);
800		if (result != ISC_R_SUCCESS)
801			goto unlink;
802		request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
803	} else {
804		result = req_send(request, task, destaddr);
805		if (result != ISC_R_SUCCESS)
806			goto unlink;
807	}
808
809	req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p",
810		request);
811	*requestp = request;
812	return (ISC_R_SUCCESS);
813
814 unlink:
815	LOCK(&requestmgr->lock);
816	ISC_LIST_UNLINK(requestmgr->requests, request, link);
817	UNLOCK(&requestmgr->lock);
818
819 cleanup:
820	if (tclone != NULL)
821		isc_task_detach(&tclone);
822	req_destroy(request);
823	req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
824		dns_result_totext(result));
825	return (result);
826}
827
828isc_result_t
829dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
830		   isc_sockaddr_t *address, unsigned int options,
831		   dns_tsigkey_t *key,
832		   unsigned int timeout, isc_task_t *task,
833		   isc_taskaction_t action, void *arg,
834		   dns_request_t **requestp)
835{
836	return (dns_request_createvia3(requestmgr, message, NULL, address,
837				       options, key, timeout, 0, 0, task,
838				       action, arg, requestp));
839}
840
841isc_result_t
842dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message,
843		      isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
844		      unsigned int options, dns_tsigkey_t *key,
845		      unsigned int timeout, isc_task_t *task,
846		      isc_taskaction_t action, void *arg,
847		      dns_request_t **requestp)
848{
849	return(dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
850				      options, key, timeout, 0, 0, task,
851				      action, arg, requestp));
852}
853
854isc_result_t
855dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message,
856		       isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
857		       unsigned int options, dns_tsigkey_t *key,
858		       unsigned int timeout, unsigned int udptimeout,
859		       isc_task_t *task, isc_taskaction_t action, void *arg,
860		       dns_request_t **requestp)
861{
862	unsigned int udpretries = 0;
863
864	if (udptimeout != 0)
865		udpretries = timeout / udptimeout;
866	return (dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
867				       options, key, timeout, udptimeout,
868				       udpretries, task, action, arg,
869				       requestp));
870}
871
872isc_result_t
873dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
874		       isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
875		       unsigned int options, dns_tsigkey_t *key,
876		       unsigned int timeout, unsigned int udptimeout,
877		       unsigned int udpretries, isc_task_t *task,
878		       isc_taskaction_t action, void *arg,
879		       dns_request_t **requestp)
880{
881	dns_request_t *request = NULL;
882	isc_task_t *tclone = NULL;
883	isc_socket_t *socket = NULL;
884	isc_result_t result;
885	isc_mem_t *mctx;
886	dns_messageid_t	id;
887	isc_boolean_t tcp;
888	isc_boolean_t setkey = ISC_TRUE;
889
890	REQUIRE(VALID_REQUESTMGR(requestmgr));
891	REQUIRE(message != NULL);
892	REQUIRE(destaddr != NULL);
893	REQUIRE(task != NULL);
894	REQUIRE(action != NULL);
895	REQUIRE(requestp != NULL && *requestp == NULL);
896	REQUIRE(timeout > 0);
897
898	mctx = requestmgr->mctx;
899
900	req_log(ISC_LOG_DEBUG(3), "dns_request_createvia");
901
902	if (srcaddr != NULL &&
903	    isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr))
904		return (ISC_R_FAMILYMISMATCH);
905
906	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 **)&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 **)&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