1/*
2 * Copyright (C) 2004-2012  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	if (srcaddr != NULL)
898		REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
899
900	mctx = requestmgr->mctx;
901
902	req_log(ISC_LOG_DEBUG(3), "dns_request_createvia");
903
904	if (isblackholed(requestmgr->dispatchmgr, destaddr))
905		return (DNS_R_BLACKHOLED);
906
907	request = NULL;
908	result = new_request(mctx, &request);
909	if (result != ISC_R_SUCCESS)
910		return (result);
911
912	if (udptimeout == 0 && udpretries != 0) {
913		udptimeout = timeout / (udpretries + 1);
914		if (udptimeout == 0)
915			udptimeout = 1;
916	}
917	request->udpcount = udpretries;
918
919	/*
920	 * Create timer now.  We will set it below once.
921	 */
922	result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
923				  NULL, NULL, task, req_timeout, request,
924				  &request->timer);
925	if (result != ISC_R_SUCCESS)
926		goto cleanup;
927
928	request->event = (dns_requestevent_t *)
929		isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
930				   action, arg, sizeof(dns_requestevent_t));
931	if (request->event == NULL) {
932		result = ISC_R_NOMEMORY;
933		goto cleanup;
934	}
935	isc_task_attach(task, &tclone);
936	request->event->ev_sender = task;
937	request->event->request = request;
938	request->event->result = ISC_R_FAILURE;
939	if (key != NULL)
940		dns_tsigkey_attach(key, &request->tsigkey);
941
942 use_tcp:
943	tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0);
944	result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
945			      &request->dispatch);
946	if (result != ISC_R_SUCCESS)
947		goto cleanup;
948
949	result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
950					   req_response, request, &id,
951					   &request->dispentry,
952					   requestmgr->socketmgr);
953	if (result != ISC_R_SUCCESS)
954		goto cleanup;
955	socket = req_getsocket(request);
956	INSIST(socket != NULL);
957
958	message->id = id;
959	if (setkey) {
960		result = dns_message_settsigkey(message, request->tsigkey);
961		if (result != ISC_R_SUCCESS)
962			goto cleanup;
963	}
964	result = req_render(message, &request->query, options, mctx);
965	if (result == DNS_R_USETCP &&
966	    (options & DNS_REQUESTOPT_TCP) == 0) {
967		/*
968		 * Try again using TCP.
969		 */
970		dns_message_renderreset(message);
971		dns_dispatch_removeresponse(&request->dispentry, NULL);
972		dns_dispatch_detach(&request->dispatch);
973		socket = NULL;
974		options |= DNS_REQUESTOPT_TCP;
975		setkey = ISC_FALSE;
976		goto use_tcp;
977	}
978	if (result != ISC_R_SUCCESS)
979		goto cleanup;
980
981	result = dns_message_getquerytsig(message, mctx, &request->tsig);
982	if (result != ISC_R_SUCCESS)
983		goto cleanup;
984
985	LOCK(&requestmgr->lock);
986	if (requestmgr->exiting) {
987		UNLOCK(&requestmgr->lock);
988		result = ISC_R_SHUTTINGDOWN;
989		goto cleanup;
990	}
991	requestmgr_attach(requestmgr, &request->requestmgr);
992	request->hash = mgr_gethash(requestmgr);
993	ISC_LIST_APPEND(requestmgr->requests, request, link);
994	UNLOCK(&requestmgr->lock);
995
996	result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
997	if (result != ISC_R_SUCCESS)
998		goto unlink;
999
1000	request->destaddr = *destaddr;
1001	if (tcp) {
1002		result = isc_socket_connect(socket, destaddr, task,
1003					    req_connected, request);
1004		if (result != ISC_R_SUCCESS)
1005			goto unlink;
1006		request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
1007	} else {
1008		result = req_send(request, task, destaddr);
1009		if (result != ISC_R_SUCCESS)
1010			goto unlink;
1011	}
1012
1013	req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p",
1014		request);
1015	*requestp = request;
1016	return (ISC_R_SUCCESS);
1017
1018 unlink:
1019	LOCK(&requestmgr->lock);
1020	ISC_LIST_UNLINK(requestmgr->requests, request, link);
1021	UNLOCK(&requestmgr->lock);
1022
1023 cleanup:
1024	if (tclone != NULL)
1025		isc_task_detach(&tclone);
1026	req_destroy(request);
1027	req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s",
1028		dns_result_totext(result));
1029	return (result);
1030}
1031
1032static isc_result_t
1033req_render(dns_message_t *message, isc_buffer_t **bufferp,
1034	   unsigned int options, isc_mem_t *mctx)
1035{
1036	isc_buffer_t *buf1 = NULL;
1037	isc_buffer_t *buf2 = NULL;
1038	isc_result_t result;
1039	isc_region_t r;
1040	isc_boolean_t tcp = ISC_FALSE;
1041	dns_compress_t cctx;
1042	isc_boolean_t cleanup_cctx = ISC_FALSE;
1043
1044	REQUIRE(bufferp != NULL && *bufferp == NULL);
1045
1046	req_log(ISC_LOG_DEBUG(3), "request_render");
1047
1048	/*
1049	 * Create buffer able to hold largest possible message.
1050	 */
1051	result = isc_buffer_allocate(mctx, &buf1, 65535);
1052	if (result != ISC_R_SUCCESS)
1053		return (result);
1054
1055	result = dns_compress_init(&cctx, -1, mctx);
1056	if (result != ISC_R_SUCCESS)
1057		return (result);
1058	cleanup_cctx = ISC_TRUE;
1059
1060	if ((options & DNS_REQUESTOPT_CASE) != 0)
1061		dns_compress_setsensitive(&cctx, ISC_TRUE);
1062
1063	/*
1064	 * Render message.
1065	 */
1066	result = dns_message_renderbegin(message, &cctx, buf1);
1067	if (result != ISC_R_SUCCESS)
1068		goto cleanup;
1069	result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
1070	if (result != ISC_R_SUCCESS)
1071		goto cleanup;
1072	result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
1073	if (result != ISC_R_SUCCESS)
1074		goto cleanup;
1075	result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
1076	if (result != ISC_R_SUCCESS)
1077		goto cleanup;
1078	result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
1079	if (result != ISC_R_SUCCESS)
1080		goto cleanup;
1081	result = dns_message_renderend(message);
1082	if (result != ISC_R_SUCCESS)
1083		goto cleanup;
1084
1085	dns_compress_invalidate(&cctx);
1086	cleanup_cctx = ISC_FALSE;
1087
1088	/*
1089	 * Copy rendered message to exact sized buffer.
1090	 */
1091	isc_buffer_usedregion(buf1, &r);
1092	if ((options & DNS_REQUESTOPT_TCP) != 0) {
1093		tcp = ISC_TRUE;
1094	} else if (r.length > 512) {
1095		result = DNS_R_USETCP;
1096		goto cleanup;
1097	}
1098	result = isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0));
1099	if (result != ISC_R_SUCCESS)
1100		goto cleanup;
1101	if (tcp)
1102		isc_buffer_putuint16(buf2, (isc_uint16_t)r.length);
1103	result = isc_buffer_copyregion(buf2, &r);
1104	if (result != ISC_R_SUCCESS)
1105		goto cleanup;
1106
1107	/*
1108	 * Cleanup and return.
1109	 */
1110	isc_buffer_free(&buf1);
1111	*bufferp = buf2;
1112	return (ISC_R_SUCCESS);
1113
1114 cleanup:
1115	dns_message_renderreset(message);
1116	if (buf1 != NULL)
1117		isc_buffer_free(&buf1);
1118	if (buf2 != NULL)
1119		isc_buffer_free(&buf2);
1120	if (cleanup_cctx)
1121		dns_compress_invalidate(&cctx);
1122	return (result);
1123}
1124
1125
1126/*
1127 * If this request is no longer waiting for events,
1128 * send the completion event.  This will ultimately
1129 * cause the request to be destroyed.
1130 *
1131 * Requires:
1132 *	'request' is locked by the caller.
1133 */
1134static void
1135send_if_done(dns_request_t *request, isc_result_t result) {
1136	if (request->event != NULL && !request->canceling)
1137		req_sendevent(request, result);
1138}
1139
1140/*
1141 * Handle the control event.
1142 */
1143static void
1144do_cancel(isc_task_t *task, isc_event_t *event) {
1145	dns_request_t *request = event->ev_arg;
1146	UNUSED(task);
1147	INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL);
1148	LOCK(&request->requestmgr->locks[request->hash]);
1149	request->canceling = ISC_FALSE;
1150	if (!DNS_REQUEST_CANCELED(request))
1151		req_cancel(request);
1152	send_if_done(request, ISC_R_CANCELED);
1153	UNLOCK(&request->requestmgr->locks[request->hash]);
1154}
1155
1156void
1157dns_request_cancel(dns_request_t *request) {
1158	REQUIRE(VALID_REQUEST(request));
1159
1160	req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request);
1161
1162	REQUIRE(VALID_REQUEST(request));
1163
1164	LOCK(&request->requestmgr->locks[request->hash]);
1165	if (!request->canceling && !DNS_REQUEST_CANCELED(request)) {
1166		isc_event_t *ev =  &request->ctlevent;
1167		isc_task_send(request->event->ev_sender, &ev);
1168		request->canceling = ISC_TRUE;
1169	}
1170	UNLOCK(&request->requestmgr->locks[request->hash]);
1171}
1172
1173isc_result_t
1174dns_request_getresponse(dns_request_t *request, dns_message_t *message,
1175			unsigned int options)
1176{
1177	isc_result_t result;
1178
1179	REQUIRE(VALID_REQUEST(request));
1180	REQUIRE(request->answer != NULL);
1181
1182	req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p",
1183		request);
1184
1185	result = dns_message_setquerytsig(message, request->tsig);
1186	if (result != ISC_R_SUCCESS)
1187		return (result);
1188	result = dns_message_settsigkey(message, request->tsigkey);
1189	if (result != ISC_R_SUCCESS)
1190		return (result);
1191	result = dns_message_parse(message, request->answer, options);
1192	if (result != ISC_R_SUCCESS)
1193		return (result);
1194	if (request->tsigkey != NULL)
1195		result = dns_tsig_verify(request->answer, message, NULL, NULL);
1196	return (result);
1197}
1198
1199isc_boolean_t
1200dns_request_usedtcp(dns_request_t *request) {
1201	REQUIRE(VALID_REQUEST(request));
1202
1203	return (ISC_TF((request->flags & DNS_REQUEST_F_TCP) != 0));
1204}
1205
1206void
1207dns_request_destroy(dns_request_t **requestp) {
1208	dns_request_t *request;
1209
1210	REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
1211
1212	request = *requestp;
1213
1214	req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request);
1215
1216	LOCK(&request->requestmgr->lock);
1217	LOCK(&request->requestmgr->locks[request->hash]);
1218	ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
1219	INSIST(!DNS_REQUEST_CONNECTING(request));
1220	INSIST(!DNS_REQUEST_SENDING(request));
1221	UNLOCK(&request->requestmgr->locks[request->hash]);
1222	UNLOCK(&request->requestmgr->lock);
1223
1224	/*
1225	 * These should have been cleaned up by req_cancel() before
1226	 * the completion event was sent.
1227	 */
1228	INSIST(!ISC_LINK_LINKED(request, link));
1229	INSIST(request->dispentry == NULL);
1230	INSIST(request->dispatch == NULL);
1231	INSIST(request->timer == NULL);
1232
1233	req_destroy(request);
1234
1235	*requestp = NULL;
1236}
1237
1238/***
1239 *** Private: request.
1240 ***/
1241
1242static isc_socket_t *
1243req_getsocket(dns_request_t *request) {
1244	unsigned int dispattr;
1245	isc_socket_t *socket;
1246
1247	dispattr = dns_dispatch_getattributes(request->dispatch);
1248	if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1249		INSIST(request->dispentry != NULL);
1250		socket = dns_dispatch_getentrysocket(request->dispentry);
1251	} else
1252		socket = dns_dispatch_getsocket(request->dispatch);
1253
1254	return (socket);
1255}
1256
1257static void
1258req_connected(isc_task_t *task, isc_event_t *event) {
1259	isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1260	isc_result_t result;
1261	dns_request_t *request = event->ev_arg;
1262
1263	REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
1264	REQUIRE(VALID_REQUEST(request));
1265	REQUIRE(DNS_REQUEST_CONNECTING(request));
1266
1267	req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request);
1268
1269	LOCK(&request->requestmgr->locks[request->hash]);
1270	request->flags &= ~DNS_REQUEST_F_CONNECTING;
1271
1272	if (DNS_REQUEST_CANCELED(request)) {
1273		/*
1274		 * Send delayed event.
1275		 */
1276		if (DNS_REQUEST_TIMEDOUT(request))
1277			send_if_done(request, ISC_R_TIMEDOUT);
1278		else
1279			send_if_done(request, ISC_R_CANCELED);
1280	} else {
1281		dns_dispatch_starttcp(request->dispatch);
1282		result = sevent->result;
1283		if (result == ISC_R_SUCCESS)
1284			result = req_send(request, task, NULL);
1285
1286		if (result != ISC_R_SUCCESS) {
1287			req_cancel(request);
1288			send_if_done(request, ISC_R_CANCELED);
1289		}
1290	}
1291	UNLOCK(&request->requestmgr->locks[request->hash]);
1292	isc_event_free(&event);
1293}
1294
1295static void
1296req_senddone(isc_task_t *task, isc_event_t *event) {
1297	isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1298	dns_request_t *request = event->ev_arg;
1299
1300	REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1301	REQUIRE(VALID_REQUEST(request));
1302	REQUIRE(DNS_REQUEST_SENDING(request));
1303
1304	req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
1305
1306	UNUSED(task);
1307
1308	LOCK(&request->requestmgr->locks[request->hash]);
1309	request->flags &= ~DNS_REQUEST_F_SENDING;
1310
1311	if (DNS_REQUEST_CANCELED(request)) {
1312		/*
1313		 * Send delayed event.
1314		 */
1315		if (DNS_REQUEST_TIMEDOUT(request))
1316			send_if_done(request, ISC_R_TIMEDOUT);
1317		else
1318			send_if_done(request, ISC_R_CANCELED);
1319	} else if (sevent->result != ISC_R_SUCCESS) {
1320		req_cancel(request);
1321		send_if_done(request, ISC_R_CANCELED);
1322	}
1323	UNLOCK(&request->requestmgr->locks[request->hash]);
1324
1325	isc_event_free(&event);
1326}
1327
1328static void
1329req_response(isc_task_t *task, isc_event_t *event) {
1330	isc_result_t result;
1331	dns_request_t *request = event->ev_arg;
1332	dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
1333	isc_region_t r;
1334
1335	REQUIRE(VALID_REQUEST(request));
1336	REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
1337
1338	UNUSED(task);
1339
1340	req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
1341		dns_result_totext(devent->result));
1342
1343	LOCK(&request->requestmgr->locks[request->hash]);
1344	result = devent->result;
1345	if (result != ISC_R_SUCCESS)
1346		goto done;
1347
1348	/*
1349	 * Copy buffer to request.
1350	 */
1351	isc_buffer_usedregion(&devent->buffer, &r);
1352	result = isc_buffer_allocate(request->mctx, &request->answer,
1353				     r.length);
1354	if (result != ISC_R_SUCCESS)
1355		goto done;
1356	result = isc_buffer_copyregion(request->answer, &r);
1357	if (result != ISC_R_SUCCESS)
1358		isc_buffer_free(&request->answer);
1359 done:
1360	/*
1361	 * Cleanup.
1362	 */
1363	dns_dispatch_removeresponse(&request->dispentry, &devent);
1364	req_cancel(request);
1365	/*
1366	 * Send completion event.
1367	 */
1368	send_if_done(request, result);
1369	UNLOCK(&request->requestmgr->locks[request->hash]);
1370}
1371
1372static void
1373req_timeout(isc_task_t *task, isc_event_t *event) {
1374	dns_request_t *request = event->ev_arg;
1375	isc_result_t result;
1376
1377	REQUIRE(VALID_REQUEST(request));
1378
1379	req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
1380
1381	UNUSED(task);
1382	LOCK(&request->requestmgr->locks[request->hash]);
1383	if (event->ev_type == ISC_TIMEREVENT_TICK &&
1384	    request->udpcount-- != 0) {
1385		if (! DNS_REQUEST_SENDING(request)) {
1386			result = req_send(request, task, &request->destaddr);
1387			if (result != ISC_R_SUCCESS) {
1388				req_cancel(request);
1389				send_if_done(request, result);
1390			}
1391		}
1392	} else {
1393		request->flags |= DNS_REQUEST_F_TIMEDOUT;
1394		req_cancel(request);
1395		send_if_done(request, ISC_R_TIMEDOUT);
1396	}
1397	UNLOCK(&request->requestmgr->locks[request->hash]);
1398	isc_event_free(&event);
1399}
1400
1401static void
1402req_sendevent(dns_request_t *request, isc_result_t result) {
1403	isc_task_t *task;
1404
1405	REQUIRE(VALID_REQUEST(request));
1406
1407	req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request);
1408
1409	/*
1410	 * Lock held by caller.
1411	 */
1412	task = request->event->ev_sender;
1413	request->event->ev_sender = request;
1414	request->event->result = result;
1415	isc_task_sendanddetach(&task, (isc_event_t **)&request->event);
1416}
1417
1418static void
1419req_destroy(dns_request_t *request) {
1420	isc_mem_t *mctx;
1421
1422	REQUIRE(VALID_REQUEST(request));
1423
1424	req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request);
1425
1426	request->magic = 0;
1427	if (request->query != NULL)
1428		isc_buffer_free(&request->query);
1429	if (request->answer != NULL)
1430		isc_buffer_free(&request->answer);
1431	if (request->event != NULL)
1432		isc_event_free((isc_event_t **)&request->event);
1433	if (request->dispentry != NULL)
1434		dns_dispatch_removeresponse(&request->dispentry, NULL);
1435	if (request->dispatch != NULL)
1436		dns_dispatch_detach(&request->dispatch);
1437	if (request->timer != NULL)
1438		isc_timer_detach(&request->timer);
1439	if (request->tsig != NULL)
1440		isc_buffer_free(&request->tsig);
1441	if (request->tsigkey != NULL)
1442		dns_tsigkey_detach(&request->tsigkey);
1443	if (request->requestmgr != NULL)
1444		requestmgr_detach(&request->requestmgr);
1445	mctx = request->mctx;
1446	isc_mem_put(mctx, request, sizeof(*request));
1447	isc_mem_detach(&mctx);
1448}
1449
1450/*
1451 * Stop the current request.  Must be called from the request's task.
1452 */
1453static void
1454req_cancel(dns_request_t *request) {
1455	isc_socket_t *socket;
1456	unsigned int dispattr;
1457
1458	REQUIRE(VALID_REQUEST(request));
1459
1460	req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request);
1461
1462	/*
1463	 * Lock held by caller.
1464	 */
1465	request->flags |= DNS_REQUEST_F_CANCELED;
1466
1467	if (request->timer != NULL)
1468		isc_timer_detach(&request->timer);
1469	dispattr = dns_dispatch_getattributes(request->dispatch);
1470	socket = NULL;
1471	if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) {
1472		if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1473			if (request->dispentry != NULL) {
1474				socket = dns_dispatch_getentrysocket(
1475					request->dispentry);
1476			}
1477		} else
1478			socket = dns_dispatch_getsocket(request->dispatch);
1479		if (DNS_REQUEST_CONNECTING(request) && socket != NULL)
1480			isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
1481		if (DNS_REQUEST_SENDING(request) && socket != NULL)
1482			isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
1483	}
1484	if (request->dispentry != NULL)
1485		dns_dispatch_removeresponse(&request->dispentry, NULL);
1486	dns_dispatch_detach(&request->dispatch);
1487}
1488
1489static void
1490req_log(int level, const char *fmt, ...) {
1491	va_list ap;
1492
1493	va_start(ap, fmt);
1494	isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1495		       DNS_LOGMODULE_REQUEST, level, fmt, ap);
1496	va_end(ap);
1497}
1498