PageRenderTime 99ms CodeModel.GetById 14ms app.highlight 74ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/dns/request.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1497 lines | 1170 code | 214 blank | 113 comment | 323 complexity | fd33bdb912225c7c7f16ecd2731003ef MD5 | raw file
   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}