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