Home | History | Annotate | Line # | Download | only in dns
      1  1.1  christos /*	$NetBSD: dispatch.c,v 1.1 2024/02/18 20:57:31 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 #include <stdlib.h>
     21  1.1  christos #include <sys/types.h>
     22  1.1  christos #include <unistd.h>
     23  1.1  christos 
     24  1.1  christos #include <isc/mem.h>
     25  1.1  christos #include <isc/mutex.h>
     26  1.1  christos #include <isc/portset.h>
     27  1.1  christos #include <isc/print.h>
     28  1.1  christos #include <isc/random.h>
     29  1.1  christos #include <isc/socket.h>
     30  1.1  christos #include <isc/stats.h>
     31  1.1  christos #include <isc/string.h>
     32  1.1  christos #include <isc/task.h>
     33  1.1  christos #include <isc/time.h>
     34  1.1  christos #include <isc/util.h>
     35  1.1  christos 
     36  1.1  christos #include <dns/acl.h>
     37  1.1  christos #include <dns/dispatch.h>
     38  1.1  christos #include <dns/events.h>
     39  1.1  christos #include <dns/log.h>
     40  1.1  christos #include <dns/message.h>
     41  1.1  christos #include <dns/portlist.h>
     42  1.1  christos #include <dns/stats.h>
     43  1.1  christos #include <dns/tcpmsg.h>
     44  1.1  christos #include <dns/types.h>
     45  1.1  christos 
     46  1.1  christos typedef ISC_LIST(dns_dispentry_t) dns_displist_t;
     47  1.1  christos 
     48  1.1  christos typedef struct dispsocket dispsocket_t;
     49  1.1  christos typedef ISC_LIST(dispsocket_t) dispsocketlist_t;
     50  1.1  christos 
     51  1.1  christos typedef struct dispportentry dispportentry_t;
     52  1.1  christos typedef ISC_LIST(dispportentry_t) dispportlist_t;
     53  1.1  christos 
     54  1.1  christos typedef struct dns_qid {
     55  1.1  christos 	unsigned int magic;
     56  1.1  christos 	unsigned int qid_nbuckets;  /*%< hash table size */
     57  1.1  christos 	unsigned int qid_increment; /*%< id increment on collision */
     58  1.1  christos 	isc_mutex_t lock;
     59  1.1  christos 	dns_displist_t *qid_table;    /*%< the table itself */
     60  1.1  christos 	dispsocketlist_t *sock_table; /*%< socket table */
     61  1.1  christos } dns_qid_t;
     62  1.1  christos 
     63  1.1  christos struct dns_dispatchmgr {
     64  1.1  christos 	/* Unlocked. */
     65  1.1  christos 	unsigned int magic;
     66  1.1  christos 	isc_mem_t *mctx;
     67  1.1  christos 	dns_acl_t *blackhole;
     68  1.1  christos 	dns_portlist_t *portlist;
     69  1.1  christos 	isc_stats_t *stats;
     70  1.1  christos 
     71  1.1  christos 	/* Locked by "lock". */
     72  1.1  christos 	isc_mutex_t lock;
     73  1.1  christos 	unsigned int state;
     74  1.1  christos 	ISC_LIST(dns_dispatch_t) list;
     75  1.1  christos 
     76  1.1  christos 	/* locked by buffer_lock */
     77  1.1  christos 	dns_qid_t *qid;
     78  1.1  christos 	isc_mutex_t buffer_lock;
     79  1.1  christos 	unsigned int buffers;	 /*%< allocated buffers */
     80  1.1  christos 	unsigned int buffersize; /*%< size of each buffer */
     81  1.1  christos 	unsigned int maxbuffers; /*%< max buffers */
     82  1.1  christos 
     83  1.1  christos 	isc_refcount_t irefs;
     84  1.1  christos 
     85  1.1  christos 	/*%
     86  1.1  christos 	 * Locked by qid->lock if qid exists; otherwise, can be used without
     87  1.1  christos 	 * being locked.
     88  1.1  christos 	 * Memory footprint considerations: this is a simple implementation of
     89  1.1  christos 	 * available ports, i.e., an ordered array of the actual port numbers.
     90  1.1  christos 	 * This will require about 256KB of memory in the worst case (128KB for
     91  1.1  christos 	 * each of IPv4 and IPv6).  We could reduce it by representing it as a
     92  1.1  christos 	 * more sophisticated way such as a list (or array) of ranges that are
     93  1.1  christos 	 * searched to identify a specific port.  Our decision here is the saved
     94  1.1  christos 	 * memory isn't worth the implementation complexity, considering the
     95  1.1  christos 	 * fact that the whole BIND9 process (which is mainly named) already
     96  1.1  christos 	 * requires a pretty large memory footprint.  We may, however, have to
     97  1.1  christos 	 * revisit the decision when we want to use it as a separate module for
     98  1.1  christos 	 * an environment where memory requirement is severer.
     99  1.1  christos 	 */
    100  1.1  christos 	in_port_t *v4ports;    /*%< available ports for IPv4 */
    101  1.1  christos 	unsigned int nv4ports; /*%< # of available ports for IPv4 */
    102  1.1  christos 	in_port_t *v6ports;    /*%< available ports for IPv4 */
    103  1.1  christos 	unsigned int nv6ports; /*%< # of available ports for IPv4 */
    104  1.1  christos };
    105  1.1  christos 
    106  1.1  christos #define MGR_SHUTTINGDOWN       0x00000001U
    107  1.1  christos #define MGR_IS_SHUTTINGDOWN(l) (((l)->state & MGR_SHUTTINGDOWN) != 0)
    108  1.1  christos 
    109  1.1  christos #define IS_PRIVATE(d) (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0)
    110  1.1  christos 
    111  1.1  christos struct dns_dispentry {
    112  1.1  christos 	unsigned int magic;
    113  1.1  christos 	dns_dispatch_t *disp;
    114  1.1  christos 	dns_messageid_t id;
    115  1.1  christos 	in_port_t port;
    116  1.1  christos 	unsigned int bucket;
    117  1.1  christos 	isc_sockaddr_t host;
    118  1.1  christos 	isc_task_t *task;
    119  1.1  christos 	isc_taskaction_t action;
    120  1.1  christos 	void *arg;
    121  1.1  christos 	bool item_out;
    122  1.1  christos 	dispsocket_t *dispsocket;
    123  1.1  christos 	ISC_LIST(dns_dispatchevent_t) items;
    124  1.1  christos 	ISC_LINK(dns_dispentry_t) link;
    125  1.1  christos };
    126  1.1  christos 
    127  1.1  christos /*%
    128  1.1  christos  * Maximum number of dispatch sockets that can be pooled for reuse.  The
    129  1.1  christos  * appropriate value may vary, but experiments have shown a busy caching server
    130  1.1  christos  * may need more than 1000 sockets concurrently opened.  The maximum allowable
    131  1.1  christos  * number of dispatch sockets (per manager) will be set to the double of this
    132  1.1  christos  * value.
    133  1.1  christos  */
    134  1.1  christos #ifndef DNS_DISPATCH_POOLSOCKS
    135  1.1  christos #define DNS_DISPATCH_POOLSOCKS 2048
    136  1.1  christos #endif /* ifndef DNS_DISPATCH_POOLSOCKS */
    137  1.1  christos 
    138  1.1  christos /*%
    139  1.1  christos  * Quota to control the number of dispatch sockets.  If a dispatch has more
    140  1.1  christos  * than the quota of sockets, new queries will purge oldest ones, so that
    141  1.1  christos  * a massive number of outstanding queries won't prevent subsequent queries
    142  1.1  christos  * (especially if the older ones take longer time and result in timeout).
    143  1.1  christos  */
    144  1.1  christos #ifndef DNS_DISPATCH_SOCKSQUOTA
    145  1.1  christos #define DNS_DISPATCH_SOCKSQUOTA 3072
    146  1.1  christos #endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */
    147  1.1  christos 
    148  1.1  christos struct dispsocket {
    149  1.1  christos 	unsigned int magic;
    150  1.1  christos 	isc_socket_t *socket;
    151  1.1  christos 	dns_dispatch_t *disp;
    152  1.1  christos 	isc_sockaddr_t host;
    153  1.1  christos 	in_port_t localport; /* XXX: should be removed later */
    154  1.1  christos 	dispportentry_t *portentry;
    155  1.1  christos 	dns_dispentry_t *resp;
    156  1.1  christos 	isc_task_t *task;
    157  1.1  christos 	ISC_LINK(dispsocket_t) link;
    158  1.1  christos 	unsigned int bucket;
    159  1.1  christos 	ISC_LINK(dispsocket_t) blink;
    160  1.1  christos };
    161  1.1  christos 
    162  1.1  christos /*%
    163  1.1  christos  * A port table entry.  We remember every port we first open in a table with a
    164  1.1  christos  * reference counter so that we can 'reuse' the same port (with different
    165  1.1  christos  * destination addresses) using the SO_REUSEADDR socket option.
    166  1.1  christos  */
    167  1.1  christos struct dispportentry {
    168  1.1  christos 	in_port_t port;
    169  1.1  christos 	isc_refcount_t refs;
    170  1.1  christos 	ISC_LINK(struct dispportentry) link;
    171  1.1  christos };
    172  1.1  christos 
    173  1.1  christos #ifndef DNS_DISPATCH_PORTTABLESIZE
    174  1.1  christos #define DNS_DISPATCH_PORTTABLESIZE 1024
    175  1.1  christos #endif /* ifndef DNS_DISPATCH_PORTTABLESIZE */
    176  1.1  christos 
    177  1.1  christos #define INVALID_BUCKET (0xffffdead)
    178  1.1  christos 
    179  1.1  christos /*%
    180  1.1  christos  * Number of tasks for each dispatch that use separate sockets for different
    181  1.1  christos  * transactions.  This must be a power of 2 as it will divide 32 bit numbers
    182  1.1  christos  * to get an uniformly random tasks selection.  See get_dispsocket().
    183  1.1  christos  */
    184  1.1  christos #define MAX_INTERNAL_TASKS 64
    185  1.1  christos 
    186  1.1  christos struct dns_dispatch {
    187  1.1  christos 	/* Unlocked. */
    188  1.1  christos 	unsigned int magic;	/*%< magic */
    189  1.1  christos 	dns_dispatchmgr_t *mgr; /*%< dispatch manager */
    190  1.1  christos 	int ntasks;
    191  1.1  christos 	/*%
    192  1.1  christos 	 * internal task buckets.  We use multiple tasks to distribute various
    193  1.1  christos 	 * socket events well when using separate dispatch sockets.  We use the
    194  1.1  christos 	 * 1st task (task[0]) for internal control events.
    195  1.1  christos 	 */
    196  1.1  christos 	isc_task_t *task[MAX_INTERNAL_TASKS];
    197  1.1  christos 	isc_socket_t *socket;	  /*%< isc socket attached to */
    198  1.1  christos 	isc_sockaddr_t local;	  /*%< local address */
    199  1.1  christos 	in_port_t localport;	  /*%< local UDP port */
    200  1.1  christos 	isc_sockaddr_t peer;	  /*%< peer address (TCP) */
    201  1.1  christos 	isc_dscp_t dscp;	  /*%< "listen-on" DSCP value */
    202  1.1  christos 	unsigned int maxrequests; /*%< max requests */
    203  1.1  christos 	isc_event_t *ctlevent;
    204  1.1  christos 
    205  1.1  christos 	isc_mem_t *sepool; /*%< pool for socket events */
    206  1.1  christos 
    207  1.1  christos 	/*% Locked by mgr->lock. */
    208  1.1  christos 	ISC_LINK(dns_dispatch_t) link;
    209  1.1  christos 
    210  1.1  christos 	/* Locked by "lock". */
    211  1.1  christos 	isc_mutex_t lock; /*%< locks all below */
    212  1.1  christos 	isc_sockettype_t socktype;
    213  1.1  christos 	unsigned int attributes;
    214  1.1  christos 	unsigned int refcount;		  /*%< number of users */
    215  1.1  christos 	dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */
    216  1.1  christos 	unsigned int shutting_down : 1, shutdown_out : 1, connected : 1,
    217  1.1  christos 		tcpmsg_valid : 1, recv_pending : 1; /*%< is a
    218  1.1  christos 						     * recv()
    219  1.1  christos 						     * pending?
    220  1.1  christos 						     * */
    221  1.1  christos 	isc_result_t shutdown_why;
    222  1.1  christos 	ISC_LIST(dispsocket_t) activesockets;
    223  1.1  christos 	ISC_LIST(dispsocket_t) inactivesockets;
    224  1.1  christos 	unsigned int nsockets;
    225  1.1  christos 	unsigned int requests;	 /*%< how many requests we have */
    226  1.1  christos 	unsigned int tcpbuffers; /*%< allocated buffers */
    227  1.1  christos 	dns_tcpmsg_t tcpmsg;	 /*%< for tcp streams */
    228  1.1  christos 	dns_qid_t *qid;
    229  1.1  christos 	dispportlist_t *port_table; /*%< hold ports 'owned' by us */
    230  1.1  christos };
    231  1.1  christos 
    232  1.1  christos #define QID_MAGIC    ISC_MAGIC('Q', 'i', 'd', ' ')
    233  1.1  christos #define VALID_QID(e) ISC_MAGIC_VALID((e), QID_MAGIC)
    234  1.1  christos 
    235  1.1  christos #define RESPONSE_MAGIC	  ISC_MAGIC('D', 'r', 's', 'p')
    236  1.1  christos #define VALID_RESPONSE(e) ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
    237  1.1  christos 
    238  1.1  christos #define DISPSOCK_MAGIC	  ISC_MAGIC('D', 's', 'o', 'c')
    239  1.1  christos #define VALID_DISPSOCK(e) ISC_MAGIC_VALID((e), DISPSOCK_MAGIC)
    240  1.1  christos 
    241  1.1  christos #define DISPATCH_MAGIC	  ISC_MAGIC('D', 'i', 's', 'p')
    242  1.1  christos #define VALID_DISPATCH(e) ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
    243  1.1  christos 
    244  1.1  christos #define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r')
    245  1.1  christos #define VALID_DISPATCHMGR(e)  ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC)
    246  1.1  christos 
    247  1.1  christos #define DNS_QID(disp)                                          \
    248  1.1  christos 	((disp)->socktype == isc_sockettype_tcp) ? (disp)->qid \
    249  1.1  christos 						 : (disp)->mgr->qid
    250  1.1  christos 
    251  1.1  christos /*%
    252  1.1  christos  * Locking a query port buffer is a bit tricky.  We access the buffer without
    253  1.1  christos  * locking until qid is created.  Technically, there is a possibility of race
    254  1.1  christos  * between the creation of qid and access to the port buffer; in practice,
    255  1.1  christos  * however, this should be safe because qid isn't created until the first
    256  1.1  christos  * dispatch is created and there should be no contending situation until then.
    257  1.1  christos  */
    258  1.1  christos #define PORTBUFLOCK(mgr)        \
    259  1.1  christos 	if ((mgr)->qid != NULL) \
    260  1.1  christos 	LOCK(&((mgr)->qid->lock))
    261  1.1  christos #define PORTBUFUNLOCK(mgr)      \
    262  1.1  christos 	if ((mgr)->qid != NULL) \
    263  1.1  christos 	UNLOCK((&(mgr)->qid->lock))
    264  1.1  christos 
    265  1.1  christos /*
    266  1.1  christos  * Statics.
    267  1.1  christos  */
    268  1.1  christos static dns_dispentry_t *
    269  1.1  christos entry_search(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t,
    270  1.1  christos 	     unsigned int);
    271  1.1  christos static bool
    272  1.1  christos destroy_disp_ok(dns_dispatch_t *);
    273  1.1  christos static void
    274  1.1  christos destroy_disp(isc_task_t *task, isc_event_t *event);
    275  1.1  christos static void
    276  1.1  christos destroy_dispsocket(dns_dispatch_t *, dispsocket_t **);
    277  1.1  christos static void
    278  1.1  christos deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *);
    279  1.1  christos static void
    280  1.1  christos udp_exrecv(isc_task_t *, isc_event_t *);
    281  1.1  christos static void
    282  1.1  christos udp_shrecv(isc_task_t *, isc_event_t *);
    283  1.1  christos static void
    284  1.1  christos udp_recv(isc_event_t *, dns_dispatch_t *, dispsocket_t *);
    285  1.1  christos static void
    286  1.1  christos tcp_recv(isc_task_t *, isc_event_t *);
    287  1.1  christos static isc_result_t
    288  1.1  christos startrecv(dns_dispatch_t *, dispsocket_t *);
    289  1.1  christos static uint32_t
    290  1.1  christos dns_hash(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t);
    291  1.1  christos static void
    292  1.1  christos free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
    293  1.1  christos static void *
    294  1.1  christos allocate_udp_buffer(dns_dispatch_t *disp);
    295  1.1  christos static void
    296  1.1  christos free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
    297  1.1  christos static dns_dispatchevent_t *
    298  1.1  christos allocate_devent(dns_dispatch_t *disp);
    299  1.1  christos static void
    300  1.1  christos do_cancel(dns_dispatch_t *disp);
    301  1.1  christos static dns_dispentry_t *
    302  1.1  christos linear_first(dns_qid_t *disp);
    303  1.1  christos static dns_dispentry_t *
    304  1.1  christos linear_next(dns_qid_t *disp, dns_dispentry_t *resp);
    305  1.1  christos static void
    306  1.1  christos dispatch_free(dns_dispatch_t **dispp);
    307  1.1  christos static isc_result_t
    308  1.1  christos get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp,
    309  1.1  christos 	      isc_socketmgr_t *sockmgr, const isc_sockaddr_t *localaddr,
    310  1.1  christos 	      isc_socket_t **sockp, isc_socket_t *dup_socket, bool duponly);
    311  1.1  christos static isc_result_t
    312  1.1  christos dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
    313  1.1  christos 		   isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr,
    314  1.1  christos 		   unsigned int maxrequests, unsigned int attributes,
    315  1.1  christos 		   dns_dispatch_t **dispp, isc_socket_t *dup_socket);
    316  1.1  christos static bool
    317  1.1  christos destroy_mgr_ok(dns_dispatchmgr_t *mgr);
    318  1.1  christos static void
    319  1.1  christos destroy_mgr(dns_dispatchmgr_t **mgrp);
    320  1.1  christos static isc_result_t
    321  1.1  christos qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
    322  1.1  christos 	     unsigned int increment, dns_qid_t **qidp, bool needaddrtable);
    323  1.1  christos static void
    324  1.1  christos qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
    325  1.1  christos static isc_result_t
    326  1.1  christos open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local,
    327  1.1  christos 	    unsigned int options, isc_socket_t **sockp,
    328  1.1  christos 	    isc_socket_t *dup_socket, bool duponly);
    329  1.1  christos static bool
    330  1.1  christos portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
    331  1.1  christos 	      isc_sockaddr_t *sockaddrp);
    332  1.1  christos 
    333  1.1  christos #define LVL(x) ISC_LOG_DEBUG(x)
    334  1.1  christos 
    335  1.1  christos static void
    336  1.1  christos mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...)
    337  1.1  christos 	ISC_FORMAT_PRINTF(3, 4);
    338  1.1  christos 
    339  1.1  christos static void
    340  1.1  christos mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) {
    341  1.1  christos 	char msgbuf[2048];
    342  1.1  christos 	va_list ap;
    343  1.1  christos 
    344  1.1  christos 	if (!isc_log_wouldlog(dns_lctx, level)) {
    345  1.1  christos 		return;
    346  1.1  christos 	}
    347  1.1  christos 
    348  1.1  christos 	va_start(ap, fmt);
    349  1.1  christos 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
    350  1.1  christos 	va_end(ap);
    351  1.1  christos 
    352  1.1  christos 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
    353  1.1  christos 		      DNS_LOGMODULE_DISPATCH, level, "dispatchmgr %p: %s", mgr,
    354  1.1  christos 		      msgbuf);
    355  1.1  christos }
    356  1.1  christos 
    357  1.1  christos static void
    358  1.1  christos inc_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
    359  1.1  christos 	if (mgr->stats != NULL) {
    360  1.1  christos 		isc_stats_increment(mgr->stats, counter);
    361  1.1  christos 	}
    362  1.1  christos }
    363  1.1  christos 
    364  1.1  christos static void
    365  1.1  christos dec_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
    366  1.1  christos 	if (mgr->stats != NULL) {
    367  1.1  christos 		isc_stats_decrement(mgr->stats, counter);
    368  1.1  christos 	}
    369  1.1  christos }
    370  1.1  christos 
    371  1.1  christos static void
    372  1.1  christos dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...)
    373  1.1  christos 	ISC_FORMAT_PRINTF(3, 4);
    374  1.1  christos 
    375  1.1  christos static void
    376  1.1  christos dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) {
    377  1.1  christos 	char msgbuf[2048];
    378  1.1  christos 	va_list ap;
    379  1.1  christos 
    380  1.1  christos 	if (!isc_log_wouldlog(dns_lctx, level)) {
    381  1.1  christos 		return;
    382  1.1  christos 	}
    383  1.1  christos 
    384  1.1  christos 	va_start(ap, fmt);
    385  1.1  christos 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
    386  1.1  christos 	va_end(ap);
    387  1.1  christos 
    388  1.1  christos 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
    389  1.1  christos 		      DNS_LOGMODULE_DISPATCH, level, "dispatch %p: %s", disp,
    390  1.1  christos 		      msgbuf);
    391  1.1  christos }
    392  1.1  christos 
    393  1.1  christos static void
    394  1.1  christos request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level,
    395  1.1  christos 	    const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
    396  1.1  christos 
    397  1.1  christos static void
    398  1.1  christos request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level,
    399  1.1  christos 	    const char *fmt, ...) {
    400  1.1  christos 	char msgbuf[2048];
    401  1.1  christos 	char peerbuf[256];
    402  1.1  christos 	va_list ap;
    403  1.1  christos 
    404  1.1  christos 	if (!isc_log_wouldlog(dns_lctx, level)) {
    405  1.1  christos 		return;
    406  1.1  christos 	}
    407  1.1  christos 
    408  1.1  christos 	va_start(ap, fmt);
    409  1.1  christos 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
    410  1.1  christos 	va_end(ap);
    411  1.1  christos 
    412  1.1  christos 	if (VALID_RESPONSE(resp)) {
    413  1.1  christos 		isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf));
    414  1.1  christos 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
    415  1.1  christos 			      DNS_LOGMODULE_DISPATCH, level,
    416  1.1  christos 			      "dispatch %p response %p %s: %s", disp, resp,
    417  1.1  christos 			      peerbuf, msgbuf);
    418  1.1  christos 	} else {
    419  1.1  christos 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
    420  1.1  christos 			      DNS_LOGMODULE_DISPATCH, level,
    421  1.1  christos 			      "dispatch %p req/resp %p: %s", disp, resp,
    422  1.1  christos 			      msgbuf);
    423  1.1  christos 	}
    424  1.1  christos }
    425  1.1  christos 
    426  1.1  christos /*
    427  1.1  christos  * Return a hash of the destination and message id.
    428  1.1  christos  */
    429  1.1  christos static uint32_t
    430  1.1  christos dns_hash(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id,
    431  1.1  christos 	 in_port_t port) {
    432  1.1  christos 	uint32_t ret;
    433  1.1  christos 
    434  1.1  christos 	ret = isc_sockaddr_hash(dest, true);
    435  1.1  christos 	ret ^= ((uint32_t)id << 16) | port;
    436  1.1  christos 	ret %= qid->qid_nbuckets;
    437  1.1  christos 
    438  1.1  christos 	INSIST(ret < qid->qid_nbuckets);
    439  1.1  christos 
    440  1.1  christos 	return (ret);
    441  1.1  christos }
    442  1.1  christos 
    443  1.1  christos /*
    444  1.1  christos  * Find the first entry in 'qid'.  Returns NULL if there are no entries.
    445  1.1  christos  */
    446  1.1  christos static dns_dispentry_t *
    447  1.1  christos linear_first(dns_qid_t *qid) {
    448  1.1  christos 	dns_dispentry_t *ret;
    449  1.1  christos 	unsigned int bucket;
    450  1.1  christos 
    451  1.1  christos 	bucket = 0;
    452  1.1  christos 
    453  1.1  christos 	while (bucket < qid->qid_nbuckets) {
    454  1.1  christos 		ret = ISC_LIST_HEAD(qid->qid_table[bucket]);
    455  1.1  christos 		if (ret != NULL) {
    456  1.1  christos 			return (ret);
    457  1.1  christos 		}
    458  1.1  christos 		bucket++;
    459  1.1  christos 	}
    460  1.1  christos 
    461  1.1  christos 	return (NULL);
    462  1.1  christos }
    463  1.1  christos 
    464  1.1  christos /*
    465  1.1  christos  * Find the next entry after 'resp' in 'qid'.  Return NULL if there are
    466  1.1  christos  * no more entries.
    467  1.1  christos  */
    468  1.1  christos static dns_dispentry_t *
    469  1.1  christos linear_next(dns_qid_t *qid, dns_dispentry_t *resp) {
    470  1.1  christos 	dns_dispentry_t *ret;
    471  1.1  christos 	unsigned int bucket;
    472  1.1  christos 
    473  1.1  christos 	ret = ISC_LIST_NEXT(resp, link);
    474  1.1  christos 	if (ret != NULL) {
    475  1.1  christos 		return (ret);
    476  1.1  christos 	}
    477  1.1  christos 
    478  1.1  christos 	bucket = resp->bucket;
    479  1.1  christos 	bucket++;
    480  1.1  christos 	while (bucket < qid->qid_nbuckets) {
    481  1.1  christos 		ret = ISC_LIST_HEAD(qid->qid_table[bucket]);
    482  1.1  christos 		if (ret != NULL) {
    483  1.1  christos 			return (ret);
    484  1.1  christos 		}
    485  1.1  christos 		bucket++;
    486  1.1  christos 	}
    487  1.1  christos 
    488  1.1  christos 	return (NULL);
    489  1.1  christos }
    490  1.1  christos 
    491  1.1  christos /*
    492  1.1  christos  * The dispatch must be locked.
    493  1.1  christos  */
    494  1.1  christos static bool
    495  1.1  christos destroy_disp_ok(dns_dispatch_t *disp) {
    496  1.1  christos 	if (disp->refcount != 0) {
    497  1.1  christos 		return (false);
    498  1.1  christos 	}
    499  1.1  christos 
    500  1.1  christos 	if (disp->recv_pending != 0) {
    501  1.1  christos 		return (false);
    502  1.1  christos 	}
    503  1.1  christos 
    504  1.1  christos 	if (!ISC_LIST_EMPTY(disp->activesockets)) {
    505  1.1  christos 		return (false);
    506  1.1  christos 	}
    507  1.1  christos 
    508  1.1  christos 	if (disp->shutting_down == 0) {
    509  1.1  christos 		return (false);
    510  1.1  christos 	}
    511  1.1  christos 
    512  1.1  christos 	return (true);
    513  1.1  christos }
    514  1.1  christos 
    515  1.1  christos /*
    516  1.1  christos  * Called when refcount reaches 0 (and safe to destroy).
    517  1.1  christos  *
    518  1.1  christos  * The dispatcher must be locked.
    519  1.1  christos  * The manager must not be locked.
    520  1.1  christos  */
    521  1.1  christos static void
    522  1.1  christos destroy_disp(isc_task_t *task, isc_event_t *event) {
    523  1.1  christos 	dns_dispatch_t *disp;
    524  1.1  christos 	dns_dispatchmgr_t *mgr;
    525  1.1  christos 	bool killmgr;
    526  1.1  christos 	dispsocket_t *dispsocket;
    527  1.1  christos 	int i;
    528  1.1  christos 
    529  1.1  christos 	INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL);
    530  1.1  christos 
    531  1.1  christos 	UNUSED(task);
    532  1.1  christos 
    533  1.1  christos 	disp = event->ev_arg;
    534  1.1  christos 	mgr = disp->mgr;
    535  1.1  christos 
    536  1.1  christos 	LOCK(&mgr->lock);
    537  1.1  christos 	ISC_LIST_UNLINK(mgr->list, disp, link);
    538  1.1  christos 
    539  1.1  christos 	dispatch_log(disp, LVL(90),
    540  1.1  christos 		     "shutting down; detaching from sock %p, task %p",
    541  1.1  christos 		     disp->socket, disp->task[0]); /* XXXX */
    542  1.1  christos 
    543  1.1  christos 	if (disp->sepool != NULL) {
    544  1.1  christos 		isc_mem_destroy(&disp->sepool);
    545  1.1  christos 	}
    546  1.1  christos 
    547  1.1  christos 	if (disp->socket != NULL) {
    548  1.1  christos 		isc_socket_detach(&disp->socket);
    549  1.1  christos 	}
    550  1.1  christos 	while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) {
    551  1.1  christos 		ISC_LIST_UNLINK(disp->inactivesockets, dispsocket, link);
    552  1.1  christos 		destroy_dispsocket(disp, &dispsocket);
    553  1.1  christos 	}
    554  1.1  christos 	for (i = 0; i < disp->ntasks; i++) {
    555  1.1  christos 		isc_task_detach(&disp->task[i]);
    556  1.1  christos 	}
    557  1.1  christos 	isc_event_free(&event);
    558  1.1  christos 
    559  1.1  christos 	dispatch_free(&disp);
    560  1.1  christos 
    561  1.1  christos 	killmgr = destroy_mgr_ok(mgr);
    562  1.1  christos 	UNLOCK(&mgr->lock);
    563  1.1  christos 	if (killmgr) {
    564  1.1  christos 		destroy_mgr(&mgr);
    565  1.1  christos 	}
    566  1.1  christos }
    567  1.1  christos 
    568  1.1  christos /*%
    569  1.1  christos  * Manipulate port table per dispatch: find an entry for a given port number,
    570  1.1  christos  * create a new entry, and decrement a given entry with possible clean-up.
    571  1.1  christos  */
    572  1.1  christos static dispportentry_t *
    573  1.1  christos port_search(dns_dispatch_t *disp, in_port_t port) {
    574  1.1  christos 	dispportentry_t *portentry;
    575  1.1  christos 
    576  1.1  christos 	REQUIRE(disp->port_table != NULL);
    577  1.1  christos 
    578  1.1  christos 	portentry = ISC_LIST_HEAD(
    579  1.1  christos 		disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE]);
    580  1.1  christos 	while (portentry != NULL) {
    581  1.1  christos 		if (portentry->port == port) {
    582  1.1  christos 			return (portentry);
    583  1.1  christos 		}
    584  1.1  christos 		portentry = ISC_LIST_NEXT(portentry, link);
    585  1.1  christos 	}
    586  1.1  christos 
    587  1.1  christos 	return (NULL);
    588  1.1  christos }
    589  1.1  christos 
    590  1.1  christos static dispportentry_t *
    591  1.1  christos new_portentry(dns_dispatch_t *disp, in_port_t port) {
    592  1.1  christos 	dispportentry_t *portentry;
    593  1.1  christos 	dns_qid_t *qid;
    594  1.1  christos 
    595  1.1  christos 	REQUIRE(disp->port_table != NULL);
    596  1.1  christos 
    597  1.1  christos 	portentry = isc_mem_get(disp->mgr->mctx, sizeof(*portentry));
    598  1.1  christos 
    599  1.1  christos 	portentry->port = port;
    600  1.1  christos 	isc_refcount_init(&portentry->refs, 1);
    601  1.1  christos 	ISC_LINK_INIT(portentry, link);
    602  1.1  christos 	qid = DNS_QID(disp);
    603  1.1  christos 	LOCK(&qid->lock);
    604  1.1  christos 	ISC_LIST_APPEND(disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE],
    605  1.1  christos 			portentry, link);
    606  1.1  christos 	UNLOCK(&qid->lock);
    607  1.1  christos 
    608  1.1  christos 	return (portentry);
    609  1.1  christos }
    610  1.1  christos 
    611  1.1  christos /*%
    612  1.1  christos  * The caller must hold the qid->lock.
    613  1.1  christos  */
    614  1.1  christos static void
    615  1.1  christos deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) {
    616  1.1  christos 	dispportentry_t *portentry = *portentryp;
    617  1.1  christos 	*portentryp = NULL;
    618  1.1  christos 
    619  1.1  christos 	REQUIRE(disp->port_table != NULL);
    620  1.1  christos 	REQUIRE(portentry != NULL);
    621  1.1  christos 
    622  1.1  christos 	if (isc_refcount_decrement(&portentry->refs) == 1) {
    623  1.1  christos 		ISC_LIST_UNLINK(disp->port_table[portentry->port %
    624  1.1  christos 						 DNS_DISPATCH_PORTTABLESIZE],
    625  1.1  christos 				portentry, link);
    626  1.1  christos 		isc_mem_put(disp->mgr->mctx, portentry, sizeof(*portentry));
    627  1.1  christos 	}
    628  1.1  christos }
    629  1.1  christos 
    630  1.1  christos /*%
    631  1.1  christos  * Find a dispsocket for socket address 'dest', and port number 'port'.
    632  1.1  christos  * Return NULL if no such entry exists.  Requires qid->lock to be held.
    633  1.1  christos  */
    634  1.1  christos static dispsocket_t *
    635  1.1  christos socket_search(dns_qid_t *qid, const isc_sockaddr_t *dest, in_port_t port,
    636  1.1  christos 	      unsigned int bucket) {
    637  1.1  christos 	dispsocket_t *dispsock;
    638  1.1  christos 
    639  1.1  christos 	REQUIRE(VALID_QID(qid));
    640  1.1  christos 	REQUIRE(bucket < qid->qid_nbuckets);
    641  1.1  christos 
    642  1.1  christos 	dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]);
    643  1.1  christos 
    644  1.1  christos 	while (dispsock != NULL) {
    645  1.1  christos 		if (dispsock->portentry != NULL &&
    646  1.1  christos 		    dispsock->portentry->port == port &&
    647  1.1  christos 		    isc_sockaddr_equal(dest, &dispsock->host))
    648  1.1  christos 		{
    649  1.1  christos 			return (dispsock);
    650  1.1  christos 		}
    651  1.1  christos 		dispsock = ISC_LIST_NEXT(dispsock, blink);
    652  1.1  christos 	}
    653  1.1  christos 
    654  1.1  christos 	return (NULL);
    655  1.1  christos }
    656  1.1  christos 
    657  1.1  christos /*%
    658  1.1  christos  * Make a new socket for a single dispatch with a random port number.
    659  1.1  christos  * The caller must hold the disp->lock
    660  1.1  christos  */
    661  1.1  christos static isc_result_t
    662  1.1  christos get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest,
    663  1.1  christos 	       isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp,
    664  1.1  christos 	       in_port_t *portp) {
    665  1.1  christos 	int i;
    666  1.1  christos 	dns_dispatchmgr_t *mgr = disp->mgr;
    667  1.1  christos 	isc_socket_t *sock = NULL;
    668  1.1  christos 	isc_result_t result = ISC_R_FAILURE;
    669  1.1  christos 	in_port_t port;
    670  1.1  christos 	isc_sockaddr_t localaddr;
    671  1.1  christos 	unsigned int bucket = 0;
    672  1.1  christos 	dispsocket_t *dispsock;
    673  1.1  christos 	unsigned int nports;
    674  1.1  christos 	in_port_t *ports;
    675  1.1  christos 	isc_socket_options_t bindoptions;
    676  1.1  christos 	dispportentry_t *portentry = NULL;
    677  1.1  christos 	dns_qid_t *qid;
    678  1.1  christos 
    679  1.1  christos 	if (isc_sockaddr_pf(&disp->local) == AF_INET) {
    680  1.1  christos 		nports = disp->mgr->nv4ports;
    681  1.1  christos 		ports = disp->mgr->v4ports;
    682  1.1  christos 	} else {
    683  1.1  christos 		nports = disp->mgr->nv6ports;
    684  1.1  christos 		ports = disp->mgr->v6ports;
    685  1.1  christos 	}
    686  1.1  christos 	if (nports == 0) {
    687  1.1  christos 		return (ISC_R_ADDRNOTAVAIL);
    688  1.1  christos 	}
    689  1.1  christos 
    690  1.1  christos 	dispsock = ISC_LIST_HEAD(disp->inactivesockets);
    691  1.1  christos 	if (dispsock != NULL) {
    692  1.1  christos 		ISC_LIST_UNLINK(disp->inactivesockets, dispsock, link);
    693  1.1  christos 		sock = dispsock->socket;
    694  1.1  christos 		dispsock->socket = NULL;
    695  1.1  christos 	} else {
    696  1.1  christos 		dispsock = isc_mem_get(mgr->mctx, sizeof(*dispsock));
    697  1.1  christos 
    698  1.1  christos 		disp->nsockets++;
    699  1.1  christos 		dispsock->socket = NULL;
    700  1.1  christos 		dispsock->disp = disp;
    701  1.1  christos 		dispsock->resp = NULL;
    702  1.1  christos 		dispsock->portentry = NULL;
    703  1.1  christos 		dispsock->task = NULL;
    704  1.1  christos 		isc_task_attach(disp->task[isc_random_uniform(disp->ntasks)],
    705  1.1  christos 				&dispsock->task);
    706  1.1  christos 		ISC_LINK_INIT(dispsock, link);
    707  1.1  christos 		ISC_LINK_INIT(dispsock, blink);
    708  1.1  christos 		dispsock->magic = DISPSOCK_MAGIC;
    709  1.1  christos 	}
    710  1.1  christos 
    711  1.1  christos 	/*
    712  1.1  christos 	 * Pick up a random UDP port and open a new socket with it.  Avoid
    713  1.1  christos 	 * choosing ports that share the same destination because it will be
    714  1.1  christos 	 * very likely to fail in bind(2) or connect(2).
    715  1.1  christos 	 */
    716  1.1  christos 	localaddr = disp->local;
    717  1.1  christos 	qid = DNS_QID(disp);
    718  1.1  christos 
    719  1.1  christos 	for (i = 0; i < 64; i++) {
    720  1.1  christos 		port = ports[isc_random_uniform(nports)];
    721  1.1  christos 		isc_sockaddr_setport(&localaddr, port);
    722  1.1  christos 
    723  1.1  christos 		LOCK(&qid->lock);
    724  1.1  christos 		bucket = dns_hash(qid, dest, 0, port);
    725  1.1  christos 		if (socket_search(qid, dest, port, bucket) != NULL) {
    726  1.1  christos 			UNLOCK(&qid->lock);
    727  1.1  christos 			continue;
    728  1.1  christos 		}
    729  1.1  christos 		UNLOCK(&qid->lock);
    730  1.1  christos 		bindoptions = 0;
    731  1.1  christos 		portentry = port_search(disp, port);
    732  1.1  christos 
    733  1.1  christos 		if (portentry != NULL) {
    734  1.1  christos 			bindoptions |= ISC_SOCKET_REUSEADDRESS;
    735  1.1  christos 		}
    736  1.1  christos 		result = open_socket(sockmgr, &localaddr, bindoptions, &sock,
    737  1.1  christos 				     NULL, false);
    738  1.1  christos 		if (result == ISC_R_SUCCESS) {
    739  1.1  christos 			if (portentry == NULL) {
    740  1.1  christos 				portentry = new_portentry(disp, port);
    741  1.1  christos 				if (portentry == NULL) {
    742  1.1  christos 					result = ISC_R_NOMEMORY;
    743  1.1  christos 					break;
    744  1.1  christos 				}
    745  1.1  christos 			} else {
    746  1.1  christos 				isc_refcount_increment(&portentry->refs);
    747  1.1  christos 			}
    748  1.1  christos 			break;
    749  1.1  christos 		} else if (result == ISC_R_NOPERM) {
    750  1.1  christos 			char buf[ISC_SOCKADDR_FORMATSIZE];
    751  1.1  christos 			isc_sockaddr_format(&localaddr, buf, sizeof(buf));
    752  1.1  christos 			dispatch_log(disp, ISC_LOG_WARNING,
    753  1.1  christos 				     "open_socket(%s) -> %s: continuing", buf,
    754  1.1  christos 				     isc_result_totext(result));
    755  1.1  christos 		} else if (result != ISC_R_ADDRINUSE) {
    756  1.1  christos 			break;
    757  1.1  christos 		}
    758  1.1  christos 	}
    759  1.1  christos 
    760  1.1  christos 	if (result == ISC_R_SUCCESS) {
    761  1.1  christos 		dispsock->socket = sock;
    762  1.1  christos 		dispsock->host = *dest;
    763  1.1  christos 		dispsock->bucket = bucket;
    764  1.1  christos 		LOCK(&qid->lock);
    765  1.1  christos 		dispsock->portentry = portentry;
    766  1.1  christos 		ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink);
    767  1.1  christos 		UNLOCK(&qid->lock);
    768  1.1  christos 		*dispsockp = dispsock;
    769  1.1  christos 		*portp = port;
    770  1.1  christos 	} else {
    771  1.1  christos 		/*
    772  1.1  christos 		 * We could keep it in the inactive list, but since this should
    773  1.1  christos 		 * be an exceptional case and might be resource shortage, we'd
    774  1.1  christos 		 * rather destroy it.
    775  1.1  christos 		 */
    776  1.1  christos 		if (sock != NULL) {
    777  1.1  christos 			isc_socket_detach(&sock);
    778  1.1  christos 		}
    779  1.1  christos 		destroy_dispsocket(disp, &dispsock);
    780  1.1  christos 	}
    781  1.1  christos 
    782  1.1  christos 	return (result);
    783  1.1  christos }
    784  1.1  christos 
    785  1.1  christos /*%
    786  1.1  christos  * Destroy a dedicated dispatch socket.
    787  1.1  christos  */
    788  1.1  christos static void
    789  1.1  christos destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) {
    790  1.1  christos 	dispsocket_t *dispsock;
    791  1.1  christos 	dns_qid_t *qid = DNS_QID(disp);
    792  1.1  christos 
    793  1.1  christos 	/*
    794  1.1  christos 	 * The dispatch must be locked.
    795  1.1  christos 	 */
    796  1.1  christos 
    797  1.1  christos 	REQUIRE(dispsockp != NULL && *dispsockp != NULL);
    798  1.1  christos 	dispsock = *dispsockp;
    799  1.1  christos 	*dispsockp = NULL;
    800  1.1  christos 	REQUIRE(!ISC_LINK_LINKED(dispsock, link));
    801  1.1  christos 
    802  1.1  christos 	disp->nsockets--;
    803  1.1  christos 	dispsock->magic = 0;
    804  1.1  christos 	if (dispsock->portentry != NULL) {
    805  1.1  christos 		/* socket_search() tests and dereferences portentry. */
    806  1.1  christos 		LOCK(&qid->lock);
    807  1.1  christos 		deref_portentry(disp, &dispsock->portentry);
    808  1.1  christos 		UNLOCK(&qid->lock);
    809  1.1  christos 	}
    810  1.1  christos 	if (dispsock->socket != NULL) {
    811  1.1  christos 		isc_socket_detach(&dispsock->socket);
    812  1.1  christos 	}
    813  1.1  christos 	if (ISC_LINK_LINKED(dispsock, blink)) {
    814  1.1  christos 		LOCK(&qid->lock);
    815  1.1  christos 		ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
    816  1.1  christos 				blink);
    817  1.1  christos 		UNLOCK(&qid->lock);
    818  1.1  christos 	}
    819  1.1  christos 	if (dispsock->task != NULL) {
    820  1.1  christos 		isc_task_detach(&dispsock->task);
    821  1.1  christos 	}
    822  1.1  christos 	isc_mem_put(disp->mgr->mctx, dispsock, sizeof(*dispsock));
    823  1.1  christos }
    824  1.1  christos 
    825  1.1  christos /*%
    826  1.1  christos  * Deactivate a dedicated dispatch socket.  Move it to the inactive list for
    827  1.1  christos  * future reuse unless the total number of sockets are exceeding the maximum.
    828  1.1  christos  */
    829  1.1  christos static void
    830  1.1  christos deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) {
    831  1.1  christos 	isc_result_t result;
    832  1.1  christos 	dns_qid_t *qid = DNS_QID(disp);
    833  1.1  christos 
    834  1.1  christos 	/*
    835  1.1  christos 	 * The dispatch must be locked.
    836  1.1  christos 	 */
    837  1.1  christos 	ISC_LIST_UNLINK(disp->activesockets, dispsock, link);
    838  1.1  christos 	if (dispsock->resp != NULL) {
    839  1.1  christos 		INSIST(dispsock->resp->dispsocket == dispsock);
    840  1.1  christos 		dispsock->resp->dispsocket = NULL;
    841  1.1  christos 	}
    842  1.1  christos 
    843  1.1  christos 	INSIST(dispsock->portentry != NULL);
    844  1.1  christos 	/* socket_search() tests and dereferences portentry. */
    845  1.1  christos 	LOCK(&qid->lock);
    846  1.1  christos 	deref_portentry(disp, &dispsock->portentry);
    847  1.1  christos 	UNLOCK(&qid->lock);
    848  1.1  christos 
    849  1.1  christos 	if (disp->nsockets > DNS_DISPATCH_POOLSOCKS) {
    850  1.1  christos 		destroy_dispsocket(disp, &dispsock);
    851  1.1  christos 	} else {
    852  1.1  christos 		result = isc_socket_close(dispsock->socket);
    853  1.1  christos 
    854  1.1  christos 		LOCK(&qid->lock);
    855  1.1  christos 		ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
    856  1.1  christos 				blink);
    857  1.1  christos 		UNLOCK(&qid->lock);
    858  1.1  christos 
    859  1.1  christos 		if (result == ISC_R_SUCCESS) {
    860  1.1  christos 			ISC_LIST_APPEND(disp->inactivesockets, dispsock, link);
    861  1.1  christos 		} else {
    862  1.1  christos 			/*
    863  1.1  christos 			 * If the underlying system does not allow this
    864  1.1  christos 			 * optimization, destroy this temporary structure (and
    865  1.1  christos 			 * create a new one for a new transaction).
    866  1.1  christos 			 */
    867  1.1  christos 			INSIST(result == ISC_R_NOTIMPLEMENTED);
    868  1.1  christos 			destroy_dispsocket(disp, &dispsock);
    869  1.1  christos 		}
    870  1.1  christos 	}
    871  1.1  christos }
    872  1.1  christos 
    873  1.1  christos /*
    874  1.1  christos  * Find an entry for query ID 'id', socket address 'dest', and port number
    875  1.1  christos  * 'port'.
    876  1.1  christos  * Return NULL if no such entry exists.
    877  1.1  christos  */
    878  1.1  christos static dns_dispentry_t *
    879  1.1  christos entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id,
    880  1.1  christos 	     in_port_t port, unsigned int bucket) {
    881  1.1  christos 	dns_dispentry_t *res;
    882  1.1  christos 
    883  1.1  christos 	REQUIRE(VALID_QID(qid));
    884  1.1  christos 	REQUIRE(bucket < qid->qid_nbuckets);
    885  1.1  christos 
    886  1.1  christos 	res = ISC_LIST_HEAD(qid->qid_table[bucket]);
    887  1.1  christos 
    888  1.1  christos 	while (res != NULL) {
    889  1.1  christos 		if (res->id == id && isc_sockaddr_equal(dest, &res->host) &&
    890  1.1  christos 		    res->port == port)
    891  1.1  christos 		{
    892  1.1  christos 			return (res);
    893  1.1  christos 		}
    894  1.1  christos 		res = ISC_LIST_NEXT(res, link);
    895  1.1  christos 	}
    896  1.1  christos 
    897  1.1  christos 	return (NULL);
    898  1.1  christos }
    899  1.1  christos 
    900  1.1  christos static void
    901  1.1  christos free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
    902  1.1  christos 	unsigned int buffersize;
    903  1.1  christos 	INSIST(buf != NULL && len != 0);
    904  1.1  christos 
    905  1.1  christos 	switch (disp->socktype) {
    906  1.1  christos 	case isc_sockettype_tcp:
    907  1.1  christos 		INSIST(disp->tcpbuffers > 0);
    908  1.1  christos 		disp->tcpbuffers--;
    909  1.1  christos 		isc_mem_put(disp->mgr->mctx, buf, len);
    910  1.1  christos 		break;
    911  1.1  christos 	case isc_sockettype_udp:
    912  1.1  christos 		LOCK(&disp->mgr->buffer_lock);
    913  1.1  christos 		INSIST(disp->mgr->buffers > 0);
    914  1.1  christos 		INSIST(len == disp->mgr->buffersize);
    915  1.1  christos 		disp->mgr->buffers--;
    916  1.1  christos 		buffersize = disp->mgr->buffersize;
    917  1.1  christos 		UNLOCK(&disp->mgr->buffer_lock);
    918  1.1  christos 		isc_mem_put(disp->mgr->mctx, buf, buffersize);
    919  1.1  christos 		break;
    920  1.1  christos 	default:
    921  1.1  christos 		UNREACHABLE();
    922  1.1  christos 	}
    923  1.1  christos }
    924  1.1  christos 
    925  1.1  christos static void *
    926  1.1  christos allocate_udp_buffer(dns_dispatch_t *disp) {
    927  1.1  christos 	unsigned int buffersize;
    928  1.1  christos 
    929  1.1  christos 	LOCK(&disp->mgr->buffer_lock);
    930  1.1  christos 	if (disp->mgr->buffers >= disp->mgr->maxbuffers) {
    931  1.1  christos 		UNLOCK(&disp->mgr->buffer_lock);
    932  1.1  christos 		return (NULL);
    933  1.1  christos 	}
    934  1.1  christos 	buffersize = disp->mgr->buffersize;
    935  1.1  christos 	disp->mgr->buffers++;
    936  1.1  christos 	UNLOCK(&disp->mgr->buffer_lock);
    937  1.1  christos 
    938  1.1  christos 	return (isc_mem_get(disp->mgr->mctx, buffersize));
    939  1.1  christos }
    940  1.1  christos 
    941  1.1  christos static void
    942  1.1  christos free_sevent(isc_event_t *ev) {
    943  1.1  christos 	isc_mem_t *pool = ev->ev_destroy_arg;
    944  1.1  christos 	isc_socketevent_t *sev = (isc_socketevent_t *)ev;
    945  1.1  christos 	isc_mem_put(pool, sev, sizeof(*sev));
    946  1.1  christos }
    947  1.1  christos 
    948  1.1  christos static isc_socketevent_t *
    949  1.1  christos allocate_sevent(dns_dispatch_t *disp, isc_socket_t *sock, isc_eventtype_t type,
    950  1.1  christos 		isc_taskaction_t action, const void *arg) {
    951  1.1  christos 	isc_socketevent_t *ev;
    952  1.1  christos 	void *deconst_arg;
    953  1.1  christos 
    954  1.1  christos 	ev = isc_mem_get(disp->sepool, sizeof(*ev));
    955  1.1  christos 	DE_CONST(arg, deconst_arg);
    956  1.1  christos 	ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, type, action, deconst_arg,
    957  1.1  christos 		       sock, free_sevent, disp->sepool);
    958  1.1  christos 	ev->result = ISC_R_UNSET;
    959  1.1  christos 	ISC_LINK_INIT(ev, ev_link);
    960  1.1  christos 	ev->region.base = NULL;
    961  1.1  christos 	ev->n = 0;
    962  1.1  christos 	ev->offset = 0;
    963  1.1  christos 	ev->attributes = 0;
    964  1.1  christos 
    965  1.1  christos 	return (ev);
    966  1.1  christos }
    967  1.1  christos 
    968  1.1  christos static void
    969  1.1  christos free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
    970  1.1  christos 	if (disp->failsafe_ev == ev) {
    971  1.1  christos 		INSIST(disp->shutdown_out == 1);
    972  1.1  christos 		disp->shutdown_out = 0;
    973  1.1  christos 
    974  1.1  christos 		return;
    975  1.1  christos 	}
    976  1.1  christos 
    977  1.1  christos 	isc_refcount_decrement(&disp->mgr->irefs);
    978  1.1  christos 	isc_mem_put(disp->mgr->mctx, ev, sizeof(*ev));
    979  1.1  christos }
    980  1.1  christos 
    981  1.1  christos static dns_dispatchevent_t *
    982  1.1  christos allocate_devent(dns_dispatch_t *disp) {
    983  1.1  christos 	dns_dispatchevent_t *ev;
    984  1.1  christos 
    985  1.1  christos 	ev = isc_mem_get(disp->mgr->mctx, sizeof(*ev));
    986  1.1  christos 	isc_refcount_increment0(&disp->mgr->irefs);
    987  1.1  christos 	ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0, NULL, NULL, NULL, NULL,
    988  1.1  christos 		       NULL);
    989  1.1  christos 
    990  1.1  christos 	return (ev);
    991  1.1  christos }
    992  1.1  christos 
    993  1.1  christos static void
    994  1.1  christos udp_exrecv(isc_task_t *task, isc_event_t *ev) {
    995  1.1  christos 	dispsocket_t *dispsock = ev->ev_arg;
    996  1.1  christos 
    997  1.1  christos 	UNUSED(task);
    998  1.1  christos 
    999  1.1  christos 	REQUIRE(VALID_DISPSOCK(dispsock));
   1000  1.1  christos 	udp_recv(ev, dispsock->disp, dispsock);
   1001  1.1  christos }
   1002  1.1  christos 
   1003  1.1  christos static void
   1004  1.1  christos udp_shrecv(isc_task_t *task, isc_event_t *ev) {
   1005  1.1  christos 	dns_dispatch_t *disp = ev->ev_arg;
   1006  1.1  christos 
   1007  1.1  christos 	UNUSED(task);
   1008  1.1  christos 
   1009  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   1010  1.1  christos 	udp_recv(ev, disp, NULL);
   1011  1.1  christos }
   1012  1.1  christos 
   1013  1.1  christos /*
   1014  1.1  christos  * General flow:
   1015  1.1  christos  *
   1016  1.1  christos  * If I/O result == CANCELED or error, free the buffer.
   1017  1.1  christos  *
   1018  1.1  christos  * If query, free the buffer, restart.
   1019  1.1  christos  *
   1020  1.1  christos  * If response:
   1021  1.1  christos  *	Allocate event, fill in details.
   1022  1.1  christos  *		If cannot allocate, free buffer, restart.
   1023  1.1  christos  *	find target.  If not found, free buffer, restart.
   1024  1.1  christos  *	if event queue is not empty, queue.  else, send.
   1025  1.1  christos  *	restart.
   1026  1.1  christos  */
   1027  1.1  christos static void
   1028  1.1  christos udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) {
   1029  1.1  christos 	isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
   1030  1.1  christos 	dns_messageid_t id;
   1031  1.1  christos 	isc_result_t dres;
   1032  1.1  christos 	isc_buffer_t source;
   1033  1.1  christos 	unsigned int flags;
   1034  1.1  christos 	dns_dispentry_t *resp = NULL;
   1035  1.1  christos 	dns_dispatchevent_t *rev;
   1036  1.1  christos 	unsigned int bucket;
   1037  1.1  christos 	bool killit;
   1038  1.1  christos 	bool queue_response;
   1039  1.1  christos 	dns_dispatchmgr_t *mgr;
   1040  1.1  christos 	dns_qid_t *qid;
   1041  1.1  christos 	isc_netaddr_t netaddr;
   1042  1.1  christos 	int match;
   1043  1.1  christos 	int result;
   1044  1.1  christos 	bool qidlocked = false;
   1045  1.1  christos 
   1046  1.1  christos 	LOCK(&disp->lock);
   1047  1.1  christos 
   1048  1.1  christos 	mgr = disp->mgr;
   1049  1.1  christos 	qid = mgr->qid;
   1050  1.1  christos 
   1051  1.1  christos 	LOCK(&disp->mgr->buffer_lock);
   1052  1.1  christos 	dispatch_log(disp, LVL(90),
   1053  1.1  christos 		     "got packet: requests %d, buffers %d, recvs %d",
   1054  1.1  christos 		     disp->requests, disp->mgr->buffers, disp->recv_pending);
   1055  1.1  christos 	UNLOCK(&disp->mgr->buffer_lock);
   1056  1.1  christos 
   1057  1.1  christos 	if (dispsock == NULL && ev->ev_type == ISC_SOCKEVENT_RECVDONE) {
   1058  1.1  christos 		/*
   1059  1.1  christos 		 * Unless the receive event was imported from a listening
   1060  1.1  christos 		 * interface, in which case the event type is
   1061  1.1  christos 		 * DNS_EVENT_IMPORTRECVDONE, receive operation must be pending.
   1062  1.1  christos 		 */
   1063  1.1  christos 		INSIST(disp->recv_pending != 0);
   1064  1.1  christos 		disp->recv_pending = 0;
   1065  1.1  christos 	}
   1066  1.1  christos 
   1067  1.1  christos 	if (dispsock != NULL &&
   1068  1.1  christos 	    (ev->result == ISC_R_CANCELED || dispsock->resp == NULL))
   1069  1.1  christos 	{
   1070  1.1  christos 		/*
   1071  1.1  christos 		 * dispsock->resp can be NULL if this transaction was canceled
   1072  1.1  christos 		 * just after receiving a response.  Since this socket is
   1073  1.1  christos 		 * exclusively used and there should be at most one receive
   1074  1.1  christos 		 * event the canceled event should have been no effect.  So
   1075  1.1  christos 		 * we can (and should) deactivate the socket right now.
   1076  1.1  christos 		 */
   1077  1.1  christos 		deactivate_dispsocket(disp, dispsock);
   1078  1.1  christos 		dispsock = NULL;
   1079  1.1  christos 	}
   1080  1.1  christos 
   1081  1.1  christos 	if (disp->shutting_down) {
   1082  1.1  christos 		/*
   1083  1.1  christos 		 * This dispatcher is shutting down.
   1084  1.1  christos 		 */
   1085  1.1  christos 		free_buffer(disp, ev->region.base, ev->region.length);
   1086  1.1  christos 
   1087  1.1  christos 		isc_event_free(&ev_in);
   1088  1.1  christos 		ev = NULL;
   1089  1.1  christos 
   1090  1.1  christos 		killit = destroy_disp_ok(disp);
   1091  1.1  christos 		UNLOCK(&disp->lock);
   1092  1.1  christos 		if (killit) {
   1093  1.1  christos 			isc_task_send(disp->task[0], &disp->ctlevent);
   1094  1.1  christos 		}
   1095  1.1  christos 
   1096  1.1  christos 		return;
   1097  1.1  christos 	}
   1098  1.1  christos 
   1099  1.1  christos 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
   1100  1.1  christos 		if (dispsock != NULL) {
   1101  1.1  christos 			resp = dispsock->resp;
   1102  1.1  christos 			id = resp->id;
   1103  1.1  christos 			if (ev->result != ISC_R_SUCCESS) {
   1104  1.1  christos 				/*
   1105  1.1  christos 				 * This is most likely a network error on a
   1106  1.1  christos 				 * connected socket.  It makes no sense to
   1107  1.1  christos 				 * check the address or parse the packet, but it
   1108  1.1  christos 				 * will help to return the error to the caller.
   1109  1.1  christos 				 */
   1110  1.1  christos 				goto sendresponse;
   1111  1.1  christos 			}
   1112  1.1  christos 		} else {
   1113  1.1  christos 			free_buffer(disp, ev->region.base, ev->region.length);
   1114  1.1  christos 
   1115  1.1  christos 			isc_event_free(&ev_in);
   1116  1.1  christos 			UNLOCK(&disp->lock);
   1117  1.1  christos 			return;
   1118  1.1  christos 		}
   1119  1.1  christos 	} else if (ev->result != ISC_R_SUCCESS) {
   1120  1.1  christos 		free_buffer(disp, ev->region.base, ev->region.length);
   1121  1.1  christos 
   1122  1.1  christos 		if (ev->result != ISC_R_CANCELED) {
   1123  1.1  christos 			dispatch_log(disp, ISC_LOG_ERROR,
   1124  1.1  christos 				     "odd socket result in udp_recv(): %s",
   1125  1.1  christos 				     isc_result_totext(ev->result));
   1126  1.1  christos 		}
   1127  1.1  christos 
   1128  1.1  christos 		isc_event_free(&ev_in);
   1129  1.1  christos 		UNLOCK(&disp->lock);
   1130  1.1  christos 		return;
   1131  1.1  christos 	}
   1132  1.1  christos 
   1133  1.1  christos 	/*
   1134  1.1  christos 	 * If this is from a blackholed address, drop it.
   1135  1.1  christos 	 */
   1136  1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &ev->address);
   1137  1.1  christos 	if (disp->mgr->blackhole != NULL &&
   1138  1.1  christos 	    dns_acl_match(&netaddr, NULL, disp->mgr->blackhole, NULL, &match,
   1139  1.1  christos 			  NULL) == ISC_R_SUCCESS &&
   1140  1.1  christos 	    match > 0)
   1141  1.1  christos 	{
   1142  1.1  christos 		if (isc_log_wouldlog(dns_lctx, LVL(10))) {
   1143  1.1  christos 			char netaddrstr[ISC_NETADDR_FORMATSIZE];
   1144  1.1  christos 			isc_netaddr_format(&netaddr, netaddrstr,
   1145  1.1  christos 					   sizeof(netaddrstr));
   1146  1.1  christos 			dispatch_log(disp, LVL(10), "blackholed packet from %s",
   1147  1.1  christos 				     netaddrstr);
   1148  1.1  christos 		}
   1149  1.1  christos 		free_buffer(disp, ev->region.base, ev->region.length);
   1150  1.1  christos 		goto restart;
   1151  1.1  christos 	}
   1152  1.1  christos 
   1153  1.1  christos 	/*
   1154  1.1  christos 	 * Peek into the buffer to see what we can see.
   1155  1.1  christos 	 */
   1156  1.1  christos 	isc_buffer_init(&source, ev->region.base, ev->region.length);
   1157  1.1  christos 	isc_buffer_add(&source, ev->n);
   1158  1.1  christos 	dres = dns_message_peekheader(&source, &id, &flags);
   1159  1.1  christos 	if (dres != ISC_R_SUCCESS) {
   1160  1.1  christos 		free_buffer(disp, ev->region.base, ev->region.length);
   1161  1.1  christos 		dispatch_log(disp, LVL(10), "got garbage packet");
   1162  1.1  christos 		goto restart;
   1163  1.1  christos 	}
   1164  1.1  christos 
   1165  1.1  christos 	dispatch_log(disp, LVL(92),
   1166  1.1  christos 		     "got valid DNS message header, /QR %c, id %u",
   1167  1.1  christos 		     (((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0'), id);
   1168  1.1  christos 
   1169  1.1  christos 	/*
   1170  1.1  christos 	 * Look at flags.  If query, drop it. If response,
   1171  1.1  christos 	 * look to see where it goes.
   1172  1.1  christos 	 */
   1173  1.1  christos 	if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
   1174  1.1  christos 		/* query */
   1175  1.1  christos 		free_buffer(disp, ev->region.base, ev->region.length);
   1176  1.1  christos 		goto restart;
   1177  1.1  christos 	}
   1178  1.1  christos 
   1179  1.1  christos 	/*
   1180  1.1  christos 	 * Search for the corresponding response.  If we are using an exclusive
   1181  1.1  christos 	 * socket, we've already identified it and we can skip the search; but
   1182  1.1  christos 	 * the ID and the address must match the expected ones.
   1183  1.1  christos 	 */
   1184  1.1  christos 	if (resp == NULL) {
   1185  1.1  christos 		bucket = dns_hash(qid, &ev->address, id, disp->localport);
   1186  1.1  christos 		LOCK(&qid->lock);
   1187  1.1  christos 		qidlocked = true;
   1188  1.1  christos 		resp = entry_search(qid, &ev->address, id, disp->localport,
   1189  1.1  christos 				    bucket);
   1190  1.1  christos 		dispatch_log(disp, LVL(90),
   1191  1.1  christos 			     "search for response in bucket %d: %s", bucket,
   1192  1.1  christos 			     (resp == NULL ? "not found" : "found"));
   1193  1.1  christos 
   1194  1.1  christos 	} else if (resp->id != id ||
   1195  1.1  christos 		   !isc_sockaddr_equal(&ev->address, &resp->host))
   1196  1.1  christos 	{
   1197  1.1  christos 		dispatch_log(disp, LVL(90),
   1198  1.1  christos 			     "response to an exclusive socket doesn't match");
   1199  1.1  christos 		inc_stats(mgr, dns_resstatscounter_mismatch);
   1200  1.1  christos 		free_buffer(disp, ev->region.base, ev->region.length);
   1201  1.1  christos 		goto unlock;
   1202  1.1  christos 	}
   1203  1.1  christos 
   1204  1.1  christos 	if (resp == NULL) {
   1205  1.1  christos 		inc_stats(mgr, dns_resstatscounter_mismatch);
   1206  1.1  christos 		free_buffer(disp, ev->region.base, ev->region.length);
   1207  1.1  christos 		goto unlock;
   1208  1.1  christos 	}
   1209  1.1  christos 
   1210  1.1  christos 	/*
   1211  1.1  christos 	 * Now that we have the original dispatch the query was sent
   1212  1.1  christos 	 * from check that the address and port the response was
   1213  1.1  christos 	 * sent to make sense.
   1214  1.1  christos 	 */
   1215  1.1  christos 	if (disp != resp->disp) {
   1216  1.1  christos 		isc_sockaddr_t a1;
   1217  1.1  christos 		isc_sockaddr_t a2;
   1218  1.1  christos 
   1219  1.1  christos 		/*
   1220  1.1  christos 		 * Check that the socket types and ports match.
   1221  1.1  christos 		 */
   1222  1.1  christos 		if (disp->socktype != resp->disp->socktype ||
   1223  1.1  christos 		    isc_sockaddr_getport(&disp->local) !=
   1224  1.1  christos 			    isc_sockaddr_getport(&resp->disp->local))
   1225  1.1  christos 		{
   1226  1.1  christos 			free_buffer(disp, ev->region.base, ev->region.length);
   1227  1.1  christos 			goto unlock;
   1228  1.1  christos 		}
   1229  1.1  christos 
   1230  1.1  christos 		/*
   1231  1.1  christos 		 * If each dispatch is bound to a different address
   1232  1.1  christos 		 * then fail.
   1233  1.1  christos 		 *
   1234  1.1  christos 		 * Note under Linux a packet can be sent out via IPv4 socket
   1235  1.1  christos 		 * and the response be received via a IPv6 socket.
   1236  1.1  christos 		 *
   1237  1.1  christos 		 * Requests sent out via IPv6 should always come back in
   1238  1.1  christos 		 * via IPv6.
   1239  1.1  christos 		 */
   1240  1.1  christos 		if (isc_sockaddr_pf(&resp->disp->local) == PF_INET6 &&
   1241  1.1  christos 		    isc_sockaddr_pf(&disp->local) != PF_INET6)
   1242  1.1  christos 		{
   1243  1.1  christos 			free_buffer(disp, ev->region.base, ev->region.length);
   1244  1.1  christos 			goto unlock;
   1245  1.1  christos 		}
   1246  1.1  christos 		isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local));
   1247  1.1  christos 		isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local));
   1248  1.1  christos 		if (!isc_sockaddr_eqaddr(&disp->local, &resp->disp->local) &&
   1249  1.1  christos 		    !isc_sockaddr_eqaddr(&a1, &resp->disp->local) &&
   1250  1.1  christos 		    !isc_sockaddr_eqaddr(&a2, &disp->local))
   1251  1.1  christos 		{
   1252  1.1  christos 			free_buffer(disp, ev->region.base, ev->region.length);
   1253  1.1  christos 			goto unlock;
   1254  1.1  christos 		}
   1255  1.1  christos 	}
   1256  1.1  christos 
   1257  1.1  christos sendresponse:
   1258  1.1  christos 	queue_response = resp->item_out;
   1259  1.1  christos 	rev = allocate_devent(resp->disp);
   1260  1.1  christos 	if (rev == NULL) {
   1261  1.1  christos 		free_buffer(disp, ev->region.base, ev->region.length);
   1262  1.1  christos 		goto unlock;
   1263  1.1  christos 	}
   1264  1.1  christos 
   1265  1.1  christos 	/*
   1266  1.1  christos 	 * At this point, rev contains the event we want to fill in, and
   1267  1.1  christos 	 * resp contains the information on the place to send it to.
   1268  1.1  christos 	 * Send the event off.
   1269  1.1  christos 	 */
   1270  1.1  christos 	isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length);
   1271  1.1  christos 	isc_buffer_add(&rev->buffer, ev->n);
   1272  1.1  christos 	rev->result = ev->result;
   1273  1.1  christos 	rev->id = id;
   1274  1.1  christos 	rev->addr = ev->address;
   1275  1.1  christos 	rev->pktinfo = ev->pktinfo;
   1276  1.1  christos 	rev->attributes = ev->attributes;
   1277  1.1  christos 	if (queue_response) {
   1278  1.1  christos 		ISC_LIST_APPEND(resp->items, rev, ev_link);
   1279  1.1  christos 	} else {
   1280  1.1  christos 		ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH,
   1281  1.1  christos 			       resp->action, resp->arg, resp, NULL, NULL);
   1282  1.1  christos 		request_log(disp, resp, LVL(90),
   1283  1.1  christos 			    "[a] Sent event %p buffer %p len %d to task %p",
   1284  1.1  christos 			    rev, rev->buffer.base, rev->buffer.length,
   1285  1.1  christos 			    resp->task);
   1286  1.1  christos 		resp->item_out = true;
   1287  1.1  christos 		isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
   1288  1.1  christos 	}
   1289  1.1  christos unlock:
   1290  1.1  christos 	if (qidlocked) {
   1291  1.1  christos 		UNLOCK(&qid->lock);
   1292  1.1  christos 	}
   1293  1.1  christos 
   1294  1.1  christos 	/*
   1295  1.1  christos 	 * Restart recv() to get the next packet.
   1296  1.1  christos 	 */
   1297  1.1  christos restart:
   1298  1.1  christos 	result = startrecv(disp, dispsock);
   1299  1.1  christos 	if (result != ISC_R_SUCCESS && dispsock != NULL) {
   1300  1.1  christos 		/*
   1301  1.1  christos 		 * XXX: wired. There seems to be no recovery process other than
   1302  1.1  christos 		 * deactivate this socket anyway (since we cannot start
   1303  1.1  christos 		 * receiving, we won't be able to receive a cancel event
   1304  1.1  christos 		 * from the user).
   1305  1.1  christos 		 */
   1306  1.1  christos 		deactivate_dispsocket(disp, dispsock);
   1307  1.1  christos 	}
   1308  1.1  christos 	isc_event_free(&ev_in);
   1309  1.1  christos 	UNLOCK(&disp->lock);
   1310  1.1  christos }
   1311  1.1  christos 
   1312  1.1  christos /*
   1313  1.1  christos  * General flow:
   1314  1.1  christos  *
   1315  1.1  christos  * If I/O result == CANCELED, EOF, or error, notify everyone as the
   1316  1.1  christos  * various queues drain.
   1317  1.1  christos  *
   1318  1.1  christos  * If query, restart.
   1319  1.1  christos  *
   1320  1.1  christos  * If response:
   1321  1.1  christos  *	Allocate event, fill in details.
   1322  1.1  christos  *		If cannot allocate, restart.
   1323  1.1  christos  *	find target.  If not found, restart.
   1324  1.1  christos  *	if event queue is not empty, queue.  else, send.
   1325  1.1  christos  *	restart.
   1326  1.1  christos  */
   1327  1.1  christos static void
   1328  1.1  christos tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
   1329  1.1  christos 	dns_dispatch_t *disp = ev_in->ev_arg;
   1330  1.1  christos 	dns_tcpmsg_t *tcpmsg = &disp->tcpmsg;
   1331  1.1  christos 	dns_messageid_t id;
   1332  1.1  christos 	isc_result_t dres;
   1333  1.1  christos 	unsigned int flags;
   1334  1.1  christos 	dns_dispentry_t *resp;
   1335  1.1  christos 	dns_dispatchevent_t *rev;
   1336  1.1  christos 	unsigned int bucket;
   1337  1.1  christos 	bool killit;
   1338  1.1  christos 	bool queue_response;
   1339  1.1  christos 	dns_qid_t *qid;
   1340  1.1  christos 	int level;
   1341  1.1  christos 	char buf[ISC_SOCKADDR_FORMATSIZE];
   1342  1.1  christos 
   1343  1.1  christos 	UNUSED(task);
   1344  1.1  christos 
   1345  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   1346  1.1  christos 
   1347  1.1  christos 	qid = disp->qid;
   1348  1.1  christos 
   1349  1.1  christos 	LOCK(&disp->lock);
   1350  1.1  christos 
   1351  1.1  christos 	dispatch_log(disp, LVL(90),
   1352  1.1  christos 		     "got TCP packet: requests %d, buffers %d, recvs %d",
   1353  1.1  christos 		     disp->requests, disp->tcpbuffers, disp->recv_pending);
   1354  1.1  christos 
   1355  1.1  christos 	INSIST(disp->recv_pending != 0);
   1356  1.1  christos 	disp->recv_pending = 0;
   1357  1.1  christos 
   1358  1.1  christos 	if (disp->refcount == 0) {
   1359  1.1  christos 		/*
   1360  1.1  christos 		 * This dispatcher is shutting down.  Force cancellation.
   1361  1.1  christos 		 */
   1362  1.1  christos 		tcpmsg->result = ISC_R_CANCELED;
   1363  1.1  christos 	}
   1364  1.1  christos 
   1365  1.1  christos 	if (tcpmsg->result != ISC_R_SUCCESS) {
   1366  1.1  christos 		switch (tcpmsg->result) {
   1367  1.1  christos 		case ISC_R_CANCELED:
   1368  1.1  christos 			break;
   1369  1.1  christos 
   1370  1.1  christos 		case ISC_R_EOF:
   1371  1.1  christos 			dispatch_log(disp, LVL(90), "shutting down on EOF");
   1372  1.1  christos 			do_cancel(disp);
   1373  1.1  christos 			break;
   1374  1.1  christos 
   1375  1.1  christos 		case ISC_R_CONNECTIONRESET:
   1376  1.1  christos 			level = ISC_LOG_INFO;
   1377  1.1  christos 			goto logit;
   1378  1.1  christos 
   1379  1.1  christos 		default:
   1380  1.1  christos 			level = ISC_LOG_ERROR;
   1381  1.1  christos 		logit:
   1382  1.1  christos 			isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf));
   1383  1.1  christos 			dispatch_log(disp, level,
   1384  1.1  christos 				     "shutting down due to TCP "
   1385  1.1  christos 				     "receive error: %s: %s",
   1386  1.1  christos 				     buf, isc_result_totext(tcpmsg->result));
   1387  1.1  christos 			do_cancel(disp);
   1388  1.1  christos 			break;
   1389  1.1  christos 		}
   1390  1.1  christos 
   1391  1.1  christos 		/*
   1392  1.1  christos 		 * The event is statically allocated in the tcpmsg
   1393  1.1  christos 		 * structure, and destroy_disp() frees the tcpmsg, so we must
   1394  1.1  christos 		 * free the event *before* calling destroy_disp().
   1395  1.1  christos 		 */
   1396  1.1  christos 		isc_event_free(&ev_in);
   1397  1.1  christos 
   1398  1.1  christos 		disp->shutting_down = 1;
   1399  1.1  christos 		disp->shutdown_why = tcpmsg->result;
   1400  1.1  christos 
   1401  1.1  christos 		/*
   1402  1.1  christos 		 * If the recv() was canceled pass the word on.
   1403  1.1  christos 		 */
   1404  1.1  christos 		killit = destroy_disp_ok(disp);
   1405  1.1  christos 		UNLOCK(&disp->lock);
   1406  1.1  christos 		if (killit) {
   1407  1.1  christos 			isc_task_send(disp->task[0], &disp->ctlevent);
   1408  1.1  christos 		}
   1409  1.1  christos 		return;
   1410  1.1  christos 	}
   1411  1.1  christos 
   1412  1.1  christos 	dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p",
   1413  1.1  christos 		     tcpmsg->result, tcpmsg->buffer.length,
   1414  1.1  christos 		     tcpmsg->buffer.base);
   1415  1.1  christos 
   1416  1.1  christos 	/*
   1417  1.1  christos 	 * Peek into the buffer to see what we can see.
   1418  1.1  christos 	 */
   1419  1.1  christos 	dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags);
   1420  1.1  christos 	if (dres != ISC_R_SUCCESS) {
   1421  1.1  christos 		dispatch_log(disp, LVL(10), "got garbage packet");
   1422  1.1  christos 		goto restart;
   1423  1.1  christos 	}
   1424  1.1  christos 
   1425  1.1  christos 	dispatch_log(disp, LVL(92),
   1426  1.1  christos 		     "got valid DNS message header, /QR %c, id %u",
   1427  1.1  christos 		     (((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0'), id);
   1428  1.1  christos 
   1429  1.1  christos 	/*
   1430  1.1  christos 	 * Allocate an event to send to the query or response client, and
   1431  1.1  christos 	 * allocate a new buffer for our use.
   1432  1.1  christos 	 */
   1433  1.1  christos 
   1434  1.1  christos 	/*
   1435  1.1  christos 	 * Look at flags.  If query, drop it. If response,
   1436  1.1  christos 	 * look to see where it goes.
   1437  1.1  christos 	 */
   1438  1.1  christos 	if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
   1439  1.1  christos 		/*
   1440  1.1  christos 		 * Query.
   1441  1.1  christos 		 */
   1442  1.1  christos 		goto restart;
   1443  1.1  christos 	}
   1444  1.1  christos 
   1445  1.1  christos 	/*
   1446  1.1  christos 	 * Response.
   1447  1.1  christos 	 */
   1448  1.1  christos 	bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport);
   1449  1.1  christos 	LOCK(&qid->lock);
   1450  1.1  christos 	resp = entry_search(qid, &tcpmsg->address, id, disp->localport, bucket);
   1451  1.1  christos 	dispatch_log(disp, LVL(90), "search for response in bucket %d: %s",
   1452  1.1  christos 		     bucket, (resp == NULL ? "not found" : "found"));
   1453  1.1  christos 
   1454  1.1  christos 	if (resp == NULL) {
   1455  1.1  christos 		goto unlock;
   1456  1.1  christos 	}
   1457  1.1  christos 	queue_response = resp->item_out;
   1458  1.1  christos 	rev = allocate_devent(disp);
   1459  1.1  christos 	if (rev == NULL) {
   1460  1.1  christos 		goto unlock;
   1461  1.1  christos 	}
   1462  1.1  christos 
   1463  1.1  christos 	/*
   1464  1.1  christos 	 * At this point, rev contains the event we want to fill in, and
   1465  1.1  christos 	 * resp contains the information on the place to send it to.
   1466  1.1  christos 	 * Send the event off.
   1467  1.1  christos 	 */
   1468  1.1  christos 	dns_tcpmsg_keepbuffer(tcpmsg, &rev->buffer);
   1469  1.1  christos 	disp->tcpbuffers++;
   1470  1.1  christos 	rev->result = ISC_R_SUCCESS;
   1471  1.1  christos 	rev->id = id;
   1472  1.1  christos 	rev->addr = tcpmsg->address;
   1473  1.1  christos 	if (queue_response) {
   1474  1.1  christos 		ISC_LIST_APPEND(resp->items, rev, ev_link);
   1475  1.1  christos 	} else {
   1476  1.1  christos 		ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH,
   1477  1.1  christos 			       resp->action, resp->arg, resp, NULL, NULL);
   1478  1.1  christos 		request_log(disp, resp, LVL(90),
   1479  1.1  christos 			    "[b] Sent event %p buffer %p len %d to task %p",
   1480  1.1  christos 			    rev, rev->buffer.base, rev->buffer.length,
   1481  1.1  christos 			    resp->task);
   1482  1.1  christos 		resp->item_out = true;
   1483  1.1  christos 		isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
   1484  1.1  christos 	}
   1485  1.1  christos unlock:
   1486  1.1  christos 	UNLOCK(&qid->lock);
   1487  1.1  christos 
   1488  1.1  christos 	/*
   1489  1.1  christos 	 * Restart recv() to get the next packet.
   1490  1.1  christos 	 */
   1491  1.1  christos restart:
   1492  1.1  christos 	(void)startrecv(disp, NULL);
   1493  1.1  christos 
   1494  1.1  christos 	isc_event_free(&ev_in);
   1495  1.1  christos 	UNLOCK(&disp->lock);
   1496  1.1  christos }
   1497  1.1  christos 
   1498  1.1  christos /*
   1499  1.1  christos  * disp must be locked.
   1500  1.1  christos  */
   1501  1.1  christos static isc_result_t
   1502  1.1  christos startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) {
   1503  1.1  christos 	isc_result_t res;
   1504  1.1  christos 	isc_region_t region;
   1505  1.1  christos 	isc_socket_t *sock;
   1506  1.1  christos 
   1507  1.1  christos 	if (disp->shutting_down == 1) {
   1508  1.1  christos 		return (ISC_R_SUCCESS);
   1509  1.1  christos 	}
   1510  1.1  christos 
   1511  1.1  christos 	if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) {
   1512  1.1  christos 		return (ISC_R_SUCCESS);
   1513  1.1  christos 	}
   1514  1.1  christos 
   1515  1.1  christos 	if (disp->recv_pending != 0 && dispsock == NULL) {
   1516  1.1  christos 		return (ISC_R_SUCCESS);
   1517  1.1  christos 	}
   1518  1.1  christos 
   1519  1.1  christos 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
   1520  1.1  christos 	    dispsock == NULL)
   1521  1.1  christos 	{
   1522  1.1  christos 		return (ISC_R_SUCCESS);
   1523  1.1  christos 	}
   1524  1.1  christos 
   1525  1.1  christos 	if (dispsock != NULL) {
   1526  1.1  christos 		sock = dispsock->socket;
   1527  1.1  christos 	} else {
   1528  1.1  christos 		sock = disp->socket;
   1529  1.1  christos 	}
   1530  1.1  christos 	INSIST(sock != NULL);
   1531  1.1  christos 
   1532  1.1  christos 	switch (disp->socktype) {
   1533  1.1  christos 	/*
   1534  1.1  christos 	 * UDP reads are always maximal.
   1535  1.1  christos 	 */
   1536  1.1  christos 	case isc_sockettype_udp:
   1537  1.1  christos 		region.length = disp->mgr->buffersize;
   1538  1.1  christos 		region.base = allocate_udp_buffer(disp);
   1539  1.1  christos 		if (region.base == NULL) {
   1540  1.1  christos 			return (ISC_R_NOMEMORY);
   1541  1.1  christos 		}
   1542  1.1  christos 		if (dispsock != NULL) {
   1543  1.1  christos 			isc_task_t *dt = dispsock->task;
   1544  1.1  christos 			isc_socketevent_t *sev = allocate_sevent(
   1545  1.1  christos 				disp, sock, ISC_SOCKEVENT_RECVDONE, udp_exrecv,
   1546  1.1  christos 				dispsock);
   1547  1.1  christos 			if (sev == NULL) {
   1548  1.1  christos 				free_buffer(disp, region.base, region.length);
   1549  1.1  christos 				return (ISC_R_NOMEMORY);
   1550  1.1  christos 			}
   1551  1.1  christos 
   1552  1.1  christos 			res = isc_socket_recv2(sock, &region, 1, dt, sev, 0);
   1553  1.1  christos 			if (res != ISC_R_SUCCESS) {
   1554  1.1  christos 				free_buffer(disp, region.base, region.length);
   1555  1.1  christos 				return (res);
   1556  1.1  christos 			}
   1557  1.1  christos 		} else {
   1558  1.1  christos 			isc_task_t *dt = disp->task[0];
   1559  1.1  christos 			isc_socketevent_t *sev = allocate_sevent(
   1560  1.1  christos 				disp, sock, ISC_SOCKEVENT_RECVDONE, udp_shrecv,
   1561  1.1  christos 				disp);
   1562  1.1  christos 			if (sev == NULL) {
   1563  1.1  christos 				free_buffer(disp, region.base, region.length);
   1564  1.1  christos 				return (ISC_R_NOMEMORY);
   1565  1.1  christos 			}
   1566  1.1  christos 
   1567  1.1  christos 			res = isc_socket_recv2(sock, &region, 1, dt, sev, 0);
   1568  1.1  christos 			if (res != ISC_R_SUCCESS) {
   1569  1.1  christos 				free_buffer(disp, region.base, region.length);
   1570  1.1  christos 				disp->shutdown_why = res;
   1571  1.1  christos 				disp->shutting_down = 1;
   1572  1.1  christos 				do_cancel(disp);
   1573  1.1  christos 				return (ISC_R_SUCCESS); /* recover by cancel */
   1574  1.1  christos 			}
   1575  1.1  christos 			INSIST(disp->recv_pending == 0);
   1576  1.1  christos 			disp->recv_pending = 1;
   1577  1.1  christos 		}
   1578  1.1  christos 		break;
   1579  1.1  christos 
   1580  1.1  christos 	case isc_sockettype_tcp:
   1581  1.1  christos 		res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task[0],
   1582  1.1  christos 					     tcp_recv, disp);
   1583  1.1  christos 		if (res != ISC_R_SUCCESS) {
   1584  1.1  christos 			disp->shutdown_why = res;
   1585  1.1  christos 			disp->shutting_down = 1;
   1586  1.1  christos 			do_cancel(disp);
   1587  1.1  christos 			return (ISC_R_SUCCESS); /* recover by cancel */
   1588  1.1  christos 		}
   1589  1.1  christos 		INSIST(disp->recv_pending == 0);
   1590  1.1  christos 		disp->recv_pending = 1;
   1591  1.1  christos 		break;
   1592  1.1  christos 	default:
   1593  1.1  christos 		UNREACHABLE();
   1594  1.1  christos 	}
   1595  1.1  christos 
   1596  1.1  christos 	return (ISC_R_SUCCESS);
   1597  1.1  christos }
   1598  1.1  christos 
   1599  1.1  christos /*
   1600  1.1  christos  * Mgr must be locked when calling this function.
   1601  1.1  christos  */
   1602  1.1  christos static bool
   1603  1.1  christos destroy_mgr_ok(dns_dispatchmgr_t *mgr) {
   1604  1.1  christos 	mgr_log(mgr, LVL(90),
   1605  1.1  christos 		"destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, ",
   1606  1.1  christos 		MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list));
   1607  1.1  christos 	if (!MGR_IS_SHUTTINGDOWN(mgr)) {
   1608  1.1  christos 		return (false);
   1609  1.1  christos 	}
   1610  1.1  christos 	if (!ISC_LIST_EMPTY(mgr->list)) {
   1611  1.1  christos 		return (false);
   1612  1.1  christos 	}
   1613  1.1  christos 	if (isc_refcount_current(&mgr->irefs) != 0) {
   1614  1.1  christos 		return (false);
   1615  1.1  christos 	}
   1616  1.1  christos 
   1617  1.1  christos 	return (true);
   1618  1.1  christos }
   1619  1.1  christos 
   1620  1.1  christos /*
   1621  1.1  christos  * Mgr must be unlocked when calling this function.
   1622  1.1  christos  */
   1623  1.1  christos static void
   1624  1.1  christos destroy_mgr(dns_dispatchmgr_t **mgrp) {
   1625  1.1  christos 	dns_dispatchmgr_t *mgr;
   1626  1.1  christos 
   1627  1.1  christos 	mgr = *mgrp;
   1628  1.1  christos 	*mgrp = NULL;
   1629  1.1  christos 
   1630  1.1  christos 	mgr->magic = 0;
   1631  1.1  christos 	isc_mutex_destroy(&mgr->lock);
   1632  1.1  christos 	mgr->state = 0;
   1633  1.1  christos 
   1634  1.1  christos 	if (mgr->qid != NULL) {
   1635  1.1  christos 		qid_destroy(mgr->mctx, &mgr->qid);
   1636  1.1  christos 	}
   1637  1.1  christos 
   1638  1.1  christos 	isc_mutex_destroy(&mgr->buffer_lock);
   1639  1.1  christos 
   1640  1.1  christos 	if (mgr->blackhole != NULL) {
   1641  1.1  christos 		dns_acl_detach(&mgr->blackhole);
   1642  1.1  christos 	}
   1643  1.1  christos 
   1644  1.1  christos 	if (mgr->stats != NULL) {
   1645  1.1  christos 		isc_stats_detach(&mgr->stats);
   1646  1.1  christos 	}
   1647  1.1  christos 
   1648  1.1  christos 	if (mgr->v4ports != NULL) {
   1649  1.1  christos 		isc_mem_put(mgr->mctx, mgr->v4ports,
   1650  1.1  christos 			    mgr->nv4ports * sizeof(in_port_t));
   1651  1.1  christos 	}
   1652  1.1  christos 	if (mgr->v6ports != NULL) {
   1653  1.1  christos 		isc_mem_put(mgr->mctx, mgr->v6ports,
   1654  1.1  christos 			    mgr->nv6ports * sizeof(in_port_t));
   1655  1.1  christos 	}
   1656  1.1  christos 	isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t));
   1657  1.1  christos }
   1658  1.1  christos 
   1659  1.1  christos static isc_result_t
   1660  1.1  christos open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local,
   1661  1.1  christos 	    unsigned int options, isc_socket_t **sockp,
   1662  1.1  christos 	    isc_socket_t *dup_socket, bool duponly) {
   1663  1.1  christos 	isc_socket_t *sock;
   1664  1.1  christos 	isc_result_t result;
   1665  1.1  christos 
   1666  1.1  christos 	sock = *sockp;
   1667  1.1  christos 	if (sock != NULL) {
   1668  1.1  christos 		result = isc_socket_open(sock);
   1669  1.1  christos 		if (result != ISC_R_SUCCESS) {
   1670  1.1  christos 			return (result);
   1671  1.1  christos 		}
   1672  1.1  christos 	} else if (dup_socket != NULL &&
   1673  1.1  christos 		   (!isc_socket_hasreuseport() || duponly))
   1674  1.1  christos 	{
   1675  1.1  christos 		result = isc_socket_dup(dup_socket, &sock);
   1676  1.1  christos 		if (result != ISC_R_SUCCESS) {
   1677  1.1  christos 			return (result);
   1678  1.1  christos 		}
   1679  1.1  christos 
   1680  1.1  christos 		isc_socket_setname(sock, "dispatcher", NULL);
   1681  1.1  christos 		*sockp = sock;
   1682  1.1  christos 		return (ISC_R_SUCCESS);
   1683  1.1  christos 	} else {
   1684  1.1  christos 		result = isc_socket_create(mgr, isc_sockaddr_pf(local),
   1685  1.1  christos 					   isc_sockettype_udp, &sock);
   1686  1.1  christos 		if (result != ISC_R_SUCCESS) {
   1687  1.1  christos 			return (result);
   1688  1.1  christos 		}
   1689  1.1  christos 	}
   1690  1.1  christos 
   1691  1.1  christos 	isc_socket_setname(sock, "dispatcher", NULL);
   1692  1.1  christos 
   1693  1.1  christos #ifndef ISC_ALLOW_MAPPED
   1694  1.1  christos 	isc_socket_ipv6only(sock, true);
   1695  1.1  christos #endif /* ifndef ISC_ALLOW_MAPPED */
   1696  1.1  christos 	result = isc_socket_bind(sock, local, options);
   1697  1.1  christos 	if (result != ISC_R_SUCCESS) {
   1698  1.1  christos 		if (*sockp == NULL) {
   1699  1.1  christos 			isc_socket_detach(&sock);
   1700  1.1  christos 		} else {
   1701  1.1  christos 			isc_socket_close(sock);
   1702  1.1  christos 		}
   1703  1.1  christos 		return (result);
   1704  1.1  christos 	}
   1705  1.1  christos 
   1706  1.1  christos 	*sockp = sock;
   1707  1.1  christos 	return (ISC_R_SUCCESS);
   1708  1.1  christos }
   1709  1.1  christos 
   1710  1.1  christos /*%
   1711  1.1  christos  * Create a temporary port list to set the initial default set of dispatch
   1712  1.1  christos  * ports: [1024, 65535].  This is almost meaningless as the application will
   1713  1.1  christos  * normally set the ports explicitly, but is provided to fill some minor corner
   1714  1.1  christos  * cases.
   1715  1.1  christos  */
   1716  1.1  christos static isc_result_t
   1717  1.1  christos create_default_portset(isc_mem_t *mctx, isc_portset_t **portsetp) {
   1718  1.1  christos 	isc_result_t result;
   1719  1.1  christos 
   1720  1.1  christos 	result = isc_portset_create(mctx, portsetp);
   1721  1.1  christos 	if (result != ISC_R_SUCCESS) {
   1722  1.1  christos 		return (result);
   1723  1.1  christos 	}
   1724  1.1  christos 	isc_portset_addrange(*portsetp, 1024, 65535);
   1725  1.1  christos 
   1726  1.1  christos 	return (ISC_R_SUCCESS);
   1727  1.1  christos }
   1728  1.1  christos 
   1729  1.1  christos /*
   1730  1.1  christos  * Publics.
   1731  1.1  christos  */
   1732  1.1  christos 
   1733  1.1  christos isc_result_t
   1734  1.1  christos dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) {
   1735  1.1  christos 	dns_dispatchmgr_t *mgr;
   1736  1.1  christos 	isc_result_t result;
   1737  1.1  christos 	isc_portset_t *v4portset = NULL;
   1738  1.1  christos 	isc_portset_t *v6portset = NULL;
   1739  1.1  christos 
   1740  1.1  christos 	REQUIRE(mctx != NULL);
   1741  1.1  christos 	REQUIRE(mgrp != NULL && *mgrp == NULL);
   1742  1.1  christos 
   1743  1.1  christos 	mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
   1744  1.1  christos 	*mgr = (dns_dispatchmgr_t){ 0 };
   1745  1.1  christos 
   1746  1.1  christos 	isc_mem_attach(mctx, &mgr->mctx);
   1747  1.1  christos 
   1748  1.1  christos 	isc_mutex_init(&mgr->lock);
   1749  1.1  christos 	isc_mutex_init(&mgr->buffer_lock);
   1750  1.1  christos 
   1751  1.1  christos 	isc_refcount_init(&mgr->irefs, 0);
   1752  1.1  christos 
   1753  1.1  christos 	ISC_LIST_INIT(mgr->list);
   1754  1.1  christos 
   1755  1.1  christos 	mgr->magic = DNS_DISPATCHMGR_MAGIC;
   1756  1.1  christos 
   1757  1.1  christos 	result = create_default_portset(mctx, &v4portset);
   1758  1.1  christos 	if (result == ISC_R_SUCCESS) {
   1759  1.1  christos 		result = create_default_portset(mctx, &v6portset);
   1760  1.1  christos 		if (result == ISC_R_SUCCESS) {
   1761  1.1  christos 			result = dns_dispatchmgr_setavailports(mgr, v4portset,
   1762  1.1  christos 							       v6portset);
   1763  1.1  christos 		}
   1764  1.1  christos 	}
   1765  1.1  christos 	if (v4portset != NULL) {
   1766  1.1  christos 		isc_portset_destroy(mctx, &v4portset);
   1767  1.1  christos 	}
   1768  1.1  christos 	if (v6portset != NULL) {
   1769  1.1  christos 		isc_portset_destroy(mctx, &v6portset);
   1770  1.1  christos 	}
   1771  1.1  christos 	if (result != ISC_R_SUCCESS) {
   1772  1.1  christos 		goto kill_dpool;
   1773  1.1  christos 	}
   1774  1.1  christos 
   1775  1.1  christos 	*mgrp = mgr;
   1776  1.1  christos 	return (ISC_R_SUCCESS);
   1777  1.1  christos 
   1778  1.1  christos kill_dpool:
   1779  1.1  christos 	isc_mutex_destroy(&mgr->buffer_lock);
   1780  1.1  christos 	isc_mutex_destroy(&mgr->lock);
   1781  1.1  christos 	isc_mem_putanddetach(&mctx, mgr, sizeof(dns_dispatchmgr_t));
   1782  1.1  christos 
   1783  1.1  christos 	return (result);
   1784  1.1  christos }
   1785  1.1  christos 
   1786  1.1  christos void
   1787  1.1  christos dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) {
   1788  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   1789  1.1  christos 	if (mgr->blackhole != NULL) {
   1790  1.1  christos 		dns_acl_detach(&mgr->blackhole);
   1791  1.1  christos 	}
   1792  1.1  christos 	dns_acl_attach(blackhole, &mgr->blackhole);
   1793  1.1  christos }
   1794  1.1  christos 
   1795  1.1  christos dns_acl_t *
   1796  1.1  christos dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) {
   1797  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   1798  1.1  christos 	return (mgr->blackhole);
   1799  1.1  christos }
   1800  1.1  christos 
   1801  1.1  christos void
   1802  1.1  christos dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr,
   1803  1.1  christos 				 dns_portlist_t *portlist) {
   1804  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   1805  1.1  christos 	UNUSED(portlist);
   1806  1.1  christos 
   1807  1.1  christos 	/* This function is deprecated: use dns_dispatchmgr_setavailports(). */
   1808  1.1  christos 	return;
   1809  1.1  christos }
   1810  1.1  christos 
   1811  1.1  christos dns_portlist_t *
   1812  1.1  christos dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) {
   1813  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   1814  1.1  christos 	return (NULL); /* this function is deprecated */
   1815  1.1  christos }
   1816  1.1  christos 
   1817  1.1  christos isc_result_t
   1818  1.1  christos dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
   1819  1.1  christos 			      isc_portset_t *v6portset) {
   1820  1.1  christos 	in_port_t *v4ports, *v6ports, p;
   1821  1.1  christos 	unsigned int nv4ports, nv6ports, i4, i6;
   1822  1.1  christos 
   1823  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   1824  1.1  christos 
   1825  1.1  christos 	nv4ports = isc_portset_nports(v4portset);
   1826  1.1  christos 	nv6ports = isc_portset_nports(v6portset);
   1827  1.1  christos 
   1828  1.1  christos 	v4ports = NULL;
   1829  1.1  christos 	if (nv4ports != 0) {
   1830  1.1  christos 		v4ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv4ports);
   1831  1.1  christos 	}
   1832  1.1  christos 	v6ports = NULL;
   1833  1.1  christos 	if (nv6ports != 0) {
   1834  1.1  christos 		v6ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv6ports);
   1835  1.1  christos 	}
   1836  1.1  christos 
   1837  1.1  christos 	p = 0;
   1838  1.1  christos 	i4 = 0;
   1839  1.1  christos 	i6 = 0;
   1840  1.1  christos 	do {
   1841  1.1  christos 		if (isc_portset_isset(v4portset, p)) {
   1842  1.1  christos 			INSIST(i4 < nv4ports);
   1843  1.1  christos 			v4ports[i4++] = p;
   1844  1.1  christos 		}
   1845  1.1  christos 		if (isc_portset_isset(v6portset, p)) {
   1846  1.1  christos 			INSIST(i6 < nv6ports);
   1847  1.1  christos 			v6ports[i6++] = p;
   1848  1.1  christos 		}
   1849  1.1  christos 	} while (p++ < 65535);
   1850  1.1  christos 	INSIST(i4 == nv4ports && i6 == nv6ports);
   1851  1.1  christos 
   1852  1.1  christos 	PORTBUFLOCK(mgr);
   1853  1.1  christos 	if (mgr->v4ports != NULL) {
   1854  1.1  christos 		isc_mem_put(mgr->mctx, mgr->v4ports,
   1855  1.1  christos 			    mgr->nv4ports * sizeof(in_port_t));
   1856  1.1  christos 	}
   1857  1.1  christos 	mgr->v4ports = v4ports;
   1858  1.1  christos 	mgr->nv4ports = nv4ports;
   1859  1.1  christos 
   1860  1.1  christos 	if (mgr->v6ports != NULL) {
   1861  1.1  christos 		isc_mem_put(mgr->mctx, mgr->v6ports,
   1862  1.1  christos 			    mgr->nv6ports * sizeof(in_port_t));
   1863  1.1  christos 	}
   1864  1.1  christos 	mgr->v6ports = v6ports;
   1865  1.1  christos 	mgr->nv6ports = nv6ports;
   1866  1.1  christos 	PORTBUFUNLOCK(mgr);
   1867  1.1  christos 
   1868  1.1  christos 	return (ISC_R_SUCCESS);
   1869  1.1  christos }
   1870  1.1  christos 
   1871  1.1  christos static isc_result_t
   1872  1.1  christos dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, unsigned int buffersize,
   1873  1.1  christos 		       unsigned int maxbuffers, unsigned int maxrequests,
   1874  1.1  christos 		       unsigned int buckets, unsigned int increment) {
   1875  1.1  christos 	isc_result_t result;
   1876  1.1  christos 
   1877  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   1878  1.1  christos 	REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
   1879  1.1  christos 	REQUIRE(maxbuffers > 0);
   1880  1.1  christos 	REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */
   1881  1.1  christos 	REQUIRE(increment > buckets);
   1882  1.1  christos 	UNUSED(maxrequests);
   1883  1.1  christos 
   1884  1.1  christos 	/*
   1885  1.1  christos 	 * Keep some number of items around.  This should be a config
   1886  1.1  christos 	 * option.  For now, keep 8, but later keep at least two even
   1887  1.1  christos 	 * if the caller wants less.  This allows us to ensure certain
   1888  1.1  christos 	 * things, like an event can be "freed" and the next allocation
   1889  1.1  christos 	 * will always succeed.
   1890  1.1  christos 	 *
   1891  1.1  christos 	 * Note that if limits are placed on anything here, we use one
   1892  1.1  christos 	 * event internally, so the actual limit should be "wanted + 1."
   1893  1.1  christos 	 *
   1894  1.1  christos 	 * XXXMLG
   1895  1.1  christos 	 */
   1896  1.1  christos 
   1897  1.1  christos 	if (maxbuffers < 8) {
   1898  1.1  christos 		maxbuffers = 8;
   1899  1.1  christos 	}
   1900  1.1  christos 
   1901  1.1  christos 	LOCK(&mgr->buffer_lock);
   1902  1.1  christos 
   1903  1.1  christos 	if (maxbuffers > mgr->maxbuffers) {
   1904  1.1  christos 		mgr->maxbuffers = maxbuffers;
   1905  1.1  christos 	}
   1906  1.1  christos 
   1907  1.1  christos 	/* Create or adjust socket pool */
   1908  1.1  christos 	if (mgr->qid != NULL) {
   1909  1.1  christos 		UNLOCK(&mgr->buffer_lock);
   1910  1.1  christos 		return (ISC_R_SUCCESS);
   1911  1.1  christos 	}
   1912  1.1  christos 
   1913  1.1  christos 	result = qid_allocate(mgr, buckets, increment, &mgr->qid, true);
   1914  1.1  christos 	if (result != ISC_R_SUCCESS) {
   1915  1.1  christos 		goto cleanup;
   1916  1.1  christos 	}
   1917  1.1  christos 
   1918  1.1  christos 	mgr->buffersize = buffersize;
   1919  1.1  christos 	mgr->maxbuffers = maxbuffers;
   1920  1.1  christos 	UNLOCK(&mgr->buffer_lock);
   1921  1.1  christos 	return (ISC_R_SUCCESS);
   1922  1.1  christos 
   1923  1.1  christos cleanup:
   1924  1.1  christos 	UNLOCK(&mgr->buffer_lock);
   1925  1.1  christos 	return (result);
   1926  1.1  christos }
   1927  1.1  christos 
   1928  1.1  christos void
   1929  1.1  christos dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) {
   1930  1.1  christos 	dns_dispatchmgr_t *mgr;
   1931  1.1  christos 	bool killit;
   1932  1.1  christos 
   1933  1.1  christos 	REQUIRE(mgrp != NULL);
   1934  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(*mgrp));
   1935  1.1  christos 
   1936  1.1  christos 	mgr = *mgrp;
   1937  1.1  christos 	*mgrp = NULL;
   1938  1.1  christos 
   1939  1.1  christos 	LOCK(&mgr->lock);
   1940  1.1  christos 	mgr->state |= MGR_SHUTTINGDOWN;
   1941  1.1  christos 	killit = destroy_mgr_ok(mgr);
   1942  1.1  christos 	UNLOCK(&mgr->lock);
   1943  1.1  christos 
   1944  1.1  christos 	mgr_log(mgr, LVL(90), "destroy: killit=%d", killit);
   1945  1.1  christos 
   1946  1.1  christos 	if (killit) {
   1947  1.1  christos 		destroy_mgr(&mgr);
   1948  1.1  christos 	}
   1949  1.1  christos }
   1950  1.1  christos 
   1951  1.1  christos void
   1952  1.1  christos dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) {
   1953  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   1954  1.1  christos 	REQUIRE(ISC_LIST_EMPTY(mgr->list));
   1955  1.1  christos 	REQUIRE(mgr->stats == NULL);
   1956  1.1  christos 
   1957  1.1  christos 	isc_stats_attach(stats, &mgr->stats);
   1958  1.1  christos }
   1959  1.1  christos 
   1960  1.1  christos static int
   1961  1.1  christos port_cmp(const void *key, const void *ent) {
   1962  1.1  christos 	in_port_t p1 = *(const in_port_t *)key;
   1963  1.1  christos 	in_port_t p2 = *(const in_port_t *)ent;
   1964  1.1  christos 
   1965  1.1  christos 	if (p1 < p2) {
   1966  1.1  christos 		return (-1);
   1967  1.1  christos 	} else if (p1 == p2) {
   1968  1.1  christos 		return (0);
   1969  1.1  christos 	} else {
   1970  1.1  christos 		return (1);
   1971  1.1  christos 	}
   1972  1.1  christos }
   1973  1.1  christos 
   1974  1.1  christos static bool
   1975  1.1  christos portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
   1976  1.1  christos 	      isc_sockaddr_t *sockaddrp) {
   1977  1.1  christos 	isc_sockaddr_t sockaddr;
   1978  1.1  christos 	isc_result_t result;
   1979  1.1  christos 	in_port_t *ports, port;
   1980  1.1  christos 	unsigned int nports;
   1981  1.1  christos 	bool available = false;
   1982  1.1  christos 
   1983  1.1  christos 	REQUIRE(sock != NULL || sockaddrp != NULL);
   1984  1.1  christos 
   1985  1.1  christos 	PORTBUFLOCK(mgr);
   1986  1.1  christos 	if (sock != NULL) {
   1987  1.1  christos 		sockaddrp = &sockaddr;
   1988  1.1  christos 		result = isc_socket_getsockname(sock, sockaddrp);
   1989  1.1  christos 		if (result != ISC_R_SUCCESS) {
   1990  1.1  christos 			goto unlock;
   1991  1.1  christos 		}
   1992  1.1  christos 	}
   1993  1.1  christos 
   1994  1.1  christos 	if (isc_sockaddr_pf(sockaddrp) == AF_INET) {
   1995  1.1  christos 		ports = mgr->v4ports;
   1996  1.1  christos 		nports = mgr->nv4ports;
   1997  1.1  christos 	} else {
   1998  1.1  christos 		ports = mgr->v6ports;
   1999  1.1  christos 		nports = mgr->nv6ports;
   2000  1.1  christos 	}
   2001  1.1  christos 	if (ports == NULL) {
   2002  1.1  christos 		goto unlock;
   2003  1.1  christos 	}
   2004  1.1  christos 
   2005  1.1  christos 	port = isc_sockaddr_getport(sockaddrp);
   2006  1.1  christos 	if (bsearch(&port, ports, nports, sizeof(in_port_t), port_cmp) != NULL)
   2007  1.1  christos 	{
   2008  1.1  christos 		available = true;
   2009  1.1  christos 	}
   2010  1.1  christos 
   2011  1.1  christos unlock:
   2012  1.1  christos 	PORTBUFUNLOCK(mgr);
   2013  1.1  christos 	return (available);
   2014  1.1  christos }
   2015  1.1  christos 
   2016  1.1  christos #define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))
   2017  1.1  christos 
   2018  1.1  christos static bool
   2019  1.1  christos local_addr_match(dns_dispatch_t *disp, const isc_sockaddr_t *addr) {
   2020  1.1  christos 	isc_sockaddr_t sockaddr;
   2021  1.1  christos 	isc_result_t result;
   2022  1.1  christos 
   2023  1.1  christos 	REQUIRE(disp->socket != NULL);
   2024  1.1  christos 
   2025  1.1  christos 	if (addr == NULL) {
   2026  1.1  christos 		return (true);
   2027  1.1  christos 	}
   2028  1.1  christos 
   2029  1.1  christos 	/*
   2030  1.1  christos 	 * Don't match wildcard ports unless the port is available in the
   2031  1.1  christos 	 * current configuration.
   2032  1.1  christos 	 */
   2033  1.1  christos 	if (isc_sockaddr_getport(addr) == 0 &&
   2034  1.1  christos 	    isc_sockaddr_getport(&disp->local) == 0 &&
   2035  1.1  christos 	    !portavailable(disp->mgr, disp->socket, NULL))
   2036  1.1  christos 	{
   2037  1.1  christos 		return (false);
   2038  1.1  christos 	}
   2039  1.1  christos 
   2040  1.1  christos 	/*
   2041  1.1  christos 	 * Check if we match the binding <address,port>.
   2042  1.1  christos 	 * Wildcard ports match/fail here.
   2043  1.1  christos 	 */
   2044  1.1  christos 	if (isc_sockaddr_equal(&disp->local, addr)) {
   2045  1.1  christos 		return (true);
   2046  1.1  christos 	}
   2047  1.1  christos 	if (isc_sockaddr_getport(addr) == 0) {
   2048  1.1  christos 		return (false);
   2049  1.1  christos 	}
   2050  1.1  christos 
   2051  1.1  christos 	/*
   2052  1.1  christos 	 * Check if we match a bound wildcard port <address,port>.
   2053  1.1  christos 	 */
   2054  1.1  christos 	if (!isc_sockaddr_eqaddr(&disp->local, addr)) {
   2055  1.1  christos 		return (false);
   2056  1.1  christos 	}
   2057  1.1  christos 	result = isc_socket_getsockname(disp->socket, &sockaddr);
   2058  1.1  christos 	if (result != ISC_R_SUCCESS) {
   2059  1.1  christos 		return (false);
   2060  1.1  christos 	}
   2061  1.1  christos 
   2062  1.1  christos 	return (isc_sockaddr_equal(&sockaddr, addr));
   2063  1.1  christos }
   2064  1.1  christos 
   2065  1.1  christos /*
   2066  1.1  christos  * Requires mgr be locked.
   2067  1.1  christos  *
   2068  1.1  christos  * No dispatcher can be locked by this thread when calling this function.
   2069  1.1  christos  *
   2070  1.1  christos  *
   2071  1.1  christos  * NOTE:
   2072  1.1  christos  *	If a matching dispatcher is found, it is locked after this function
   2073  1.1  christos  *	returns, and must be unlocked by the caller.
   2074  1.1  christos  */
   2075  1.1  christos static isc_result_t
   2076  1.1  christos dispatch_find(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *local,
   2077  1.1  christos 	      unsigned int attributes, unsigned int mask,
   2078  1.1  christos 	      dns_dispatch_t **dispp) {
   2079  1.1  christos 	dns_dispatch_t *disp;
   2080  1.1  christos 	isc_result_t result;
   2081  1.1  christos 
   2082  1.1  christos 	/*
   2083  1.1  christos 	 * Make certain that we will not match a private or exclusive dispatch.
   2084  1.1  christos 	 */
   2085  1.1  christos 	attributes &= ~(DNS_DISPATCHATTR_PRIVATE | DNS_DISPATCHATTR_EXCLUSIVE);
   2086  1.1  christos 	mask |= (DNS_DISPATCHATTR_PRIVATE | DNS_DISPATCHATTR_EXCLUSIVE);
   2087  1.1  christos 
   2088  1.1  christos 	disp = ISC_LIST_HEAD(mgr->list);
   2089  1.1  christos 	while (disp != NULL) {
   2090  1.1  christos 		LOCK(&disp->lock);
   2091  1.1  christos 		if ((disp->shutting_down == 0) &&
   2092  1.1  christos 		    ATTRMATCH(disp->attributes, attributes, mask) &&
   2093  1.1  christos 		    local_addr_match(disp, local))
   2094  1.1  christos 		{
   2095  1.1  christos 			break;
   2096  1.1  christos 		}
   2097  1.1  christos 		UNLOCK(&disp->lock);
   2098  1.1  christos 		disp = ISC_LIST_NEXT(disp, link);
   2099  1.1  christos 	}
   2100  1.1  christos 
   2101  1.1  christos 	if (disp == NULL) {
   2102  1.1  christos 		result = ISC_R_NOTFOUND;
   2103  1.1  christos 		goto out;
   2104  1.1  christos 	}
   2105  1.1  christos 
   2106  1.1  christos 	*dispp = disp;
   2107  1.1  christos 	result = ISC_R_SUCCESS;
   2108  1.1  christos out:
   2109  1.1  christos 
   2110  1.1  christos 	return (result);
   2111  1.1  christos }
   2112  1.1  christos 
   2113  1.1  christos static isc_result_t
   2114  1.1  christos qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
   2115  1.1  christos 	     unsigned int increment, dns_qid_t **qidp, bool needsocktable) {
   2116  1.1  christos 	dns_qid_t *qid;
   2117  1.1  christos 	unsigned int i;
   2118  1.1  christos 
   2119  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   2120  1.1  christos 	REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */
   2121  1.1  christos 	REQUIRE(increment > buckets);
   2122  1.1  christos 	REQUIRE(qidp != NULL && *qidp == NULL);
   2123  1.1  christos 
   2124  1.1  christos 	qid = isc_mem_get(mgr->mctx, sizeof(*qid));
   2125  1.1  christos 
   2126  1.1  christos 	qid->qid_table = isc_mem_get(mgr->mctx,
   2127  1.1  christos 				     buckets * sizeof(dns_displist_t));
   2128  1.1  christos 
   2129  1.1  christos 	qid->sock_table = NULL;
   2130  1.1  christos 	if (needsocktable) {
   2131  1.1  christos 		qid->sock_table = isc_mem_get(
   2132  1.1  christos 			mgr->mctx, buckets * sizeof(dispsocketlist_t));
   2133  1.1  christos 	}
   2134  1.1  christos 
   2135  1.1  christos 	isc_mutex_init(&qid->lock);
   2136  1.1  christos 
   2137  1.1  christos 	for (i = 0; i < buckets; i++) {
   2138  1.1  christos 		ISC_LIST_INIT(qid->qid_table[i]);
   2139  1.1  christos 		if (qid->sock_table != NULL) {
   2140  1.1  christos 			ISC_LIST_INIT(qid->sock_table[i]);
   2141  1.1  christos 		}
   2142  1.1  christos 	}
   2143  1.1  christos 
   2144  1.1  christos 	qid->qid_nbuckets = buckets;
   2145  1.1  christos 	qid->qid_increment = increment;
   2146  1.1  christos 	qid->magic = QID_MAGIC;
   2147  1.1  christos 	*qidp = qid;
   2148  1.1  christos 	return (ISC_R_SUCCESS);
   2149  1.1  christos }
   2150  1.1  christos 
   2151  1.1  christos static void
   2152  1.1  christos qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
   2153  1.1  christos 	dns_qid_t *qid;
   2154  1.1  christos 
   2155  1.1  christos 	REQUIRE(qidp != NULL);
   2156  1.1  christos 	qid = *qidp;
   2157  1.1  christos 	*qidp = NULL;
   2158  1.1  christos 
   2159  1.1  christos 	REQUIRE(VALID_QID(qid));
   2160  1.1  christos 
   2161  1.1  christos 	qid->magic = 0;
   2162  1.1  christos 	isc_mem_put(mctx, qid->qid_table,
   2163  1.1  christos 		    qid->qid_nbuckets * sizeof(dns_displist_t));
   2164  1.1  christos 	if (qid->sock_table != NULL) {
   2165  1.1  christos 		isc_mem_put(mctx, qid->sock_table,
   2166  1.1  christos 			    qid->qid_nbuckets * sizeof(dispsocketlist_t));
   2167  1.1  christos 	}
   2168  1.1  christos 	isc_mutex_destroy(&qid->lock);
   2169  1.1  christos 	isc_mem_put(mctx, qid, sizeof(*qid));
   2170  1.1  christos }
   2171  1.1  christos 
   2172  1.1  christos /*
   2173  1.1  christos  * Allocate and set important limits.
   2174  1.1  christos  */
   2175  1.1  christos static isc_result_t
   2176  1.1  christos dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests,
   2177  1.1  christos 		  dns_dispatch_t **dispp) {
   2178  1.1  christos 	dns_dispatch_t *disp;
   2179  1.1  christos 	isc_result_t result;
   2180  1.1  christos 
   2181  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   2182  1.1  christos 	REQUIRE(dispp != NULL && *dispp == NULL);
   2183  1.1  christos 
   2184  1.1  christos 	/*
   2185  1.1  christos 	 * Set up the dispatcher, mostly.  Don't bother setting some of
   2186  1.1  christos 	 * the options that are controlled by tcp vs. udp, etc.
   2187  1.1  christos 	 */
   2188  1.1  christos 
   2189  1.1  christos 	disp = isc_mem_get(mgr->mctx, sizeof(*disp));
   2190  1.1  christos 	isc_refcount_increment0(&mgr->irefs);
   2191  1.1  christos 
   2192  1.1  christos 	disp->magic = 0;
   2193  1.1  christos 	disp->mgr = mgr;
   2194  1.1  christos 	disp->maxrequests = maxrequests;
   2195  1.1  christos 	disp->attributes = 0;
   2196  1.1  christos 	ISC_LINK_INIT(disp, link);
   2197  1.1  christos 	disp->refcount = 1;
   2198  1.1  christos 	disp->recv_pending = 0;
   2199  1.1  christos 	memset(&disp->local, 0, sizeof(disp->local));
   2200  1.1  christos 	memset(&disp->peer, 0, sizeof(disp->peer));
   2201  1.1  christos 	disp->localport = 0;
   2202  1.1  christos 	disp->shutting_down = 0;
   2203  1.1  christos 	disp->shutdown_out = 0;
   2204  1.1  christos 	disp->connected = 0;
   2205  1.1  christos 	disp->tcpmsg_valid = 0;
   2206  1.1  christos 	disp->shutdown_why = ISC_R_UNEXPECTED;
   2207  1.1  christos 	disp->requests = 0;
   2208  1.1  christos 	disp->tcpbuffers = 0;
   2209  1.1  christos 	disp->qid = NULL;
   2210  1.1  christos 	ISC_LIST_INIT(disp->activesockets);
   2211  1.1  christos 	ISC_LIST_INIT(disp->inactivesockets);
   2212  1.1  christos 	disp->nsockets = 0;
   2213  1.1  christos 	disp->port_table = NULL;
   2214  1.1  christos 	disp->dscp = -1;
   2215  1.1  christos 
   2216  1.1  christos 	isc_mutex_init(&disp->lock);
   2217  1.1  christos 
   2218  1.1  christos 	disp->failsafe_ev = allocate_devent(disp);
   2219  1.1  christos 	if (disp->failsafe_ev == NULL) {
   2220  1.1  christos 		result = ISC_R_NOMEMORY;
   2221  1.1  christos 		goto kill_lock;
   2222  1.1  christos 	}
   2223  1.1  christos 
   2224  1.1  christos 	disp->magic = DISPATCH_MAGIC;
   2225  1.1  christos 
   2226  1.1  christos 	*dispp = disp;
   2227  1.1  christos 	return (ISC_R_SUCCESS);
   2228  1.1  christos 
   2229  1.1  christos 	/*
   2230  1.1  christos 	 * error returns
   2231  1.1  christos 	 */
   2232  1.1  christos kill_lock:
   2233  1.1  christos 	isc_mutex_destroy(&disp->lock);
   2234  1.1  christos 	isc_refcount_decrement(&mgr->irefs);
   2235  1.1  christos 	isc_mem_put(mgr->mctx, disp, sizeof(*disp));
   2236  1.1  christos 
   2237  1.1  christos 	return (result);
   2238  1.1  christos }
   2239  1.1  christos 
   2240  1.1  christos /*
   2241  1.1  christos  * MUST be unlocked, and not used by anything.
   2242  1.1  christos  */
   2243  1.1  christos static void
   2244  1.1  christos dispatch_free(dns_dispatch_t **dispp) {
   2245  1.1  christos 	dns_dispatch_t *disp;
   2246  1.1  christos 	dns_dispatchmgr_t *mgr;
   2247  1.1  christos 
   2248  1.1  christos 	REQUIRE(VALID_DISPATCH(*dispp));
   2249  1.1  christos 	disp = *dispp;
   2250  1.1  christos 	*dispp = NULL;
   2251  1.1  christos 
   2252  1.1  christos 	mgr = disp->mgr;
   2253  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   2254  1.1  christos 
   2255  1.1  christos 	if (disp->tcpmsg_valid) {
   2256  1.1  christos 		dns_tcpmsg_invalidate(&disp->tcpmsg);
   2257  1.1  christos 		disp->tcpmsg_valid = 0;
   2258  1.1  christos 	}
   2259  1.1  christos 
   2260  1.1  christos 	INSIST(disp->tcpbuffers == 0);
   2261  1.1  christos 	INSIST(disp->requests == 0);
   2262  1.1  christos 	INSIST(disp->recv_pending == 0);
   2263  1.1  christos 	INSIST(ISC_LIST_EMPTY(disp->activesockets));
   2264  1.1  christos 	INSIST(ISC_LIST_EMPTY(disp->inactivesockets));
   2265  1.1  christos 
   2266  1.1  christos 	isc_refcount_decrement(&mgr->irefs);
   2267  1.1  christos 	isc_mem_put(mgr->mctx, disp->failsafe_ev, sizeof(*disp->failsafe_ev));
   2268  1.1  christos 	disp->failsafe_ev = NULL;
   2269  1.1  christos 
   2270  1.1  christos 	if (disp->qid != NULL) {
   2271  1.1  christos 		qid_destroy(mgr->mctx, &disp->qid);
   2272  1.1  christos 	}
   2273  1.1  christos 
   2274  1.1  christos 	if (disp->port_table != NULL) {
   2275  1.1  christos 		for (int i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) {
   2276  1.1  christos 			INSIST(ISC_LIST_EMPTY(disp->port_table[i]));
   2277  1.1  christos 		}
   2278  1.1  christos 		isc_mem_put(mgr->mctx, disp->port_table,
   2279  1.1  christos 			    sizeof(disp->port_table[0]) *
   2280  1.1  christos 				    DNS_DISPATCH_PORTTABLESIZE);
   2281  1.1  christos 	}
   2282  1.1  christos 
   2283  1.1  christos 	disp->mgr = NULL;
   2284  1.1  christos 	isc_mutex_destroy(&disp->lock);
   2285  1.1  christos 	disp->magic = 0;
   2286  1.1  christos 	isc_refcount_decrement(&mgr->irefs);
   2287  1.1  christos 	isc_mem_put(mgr->mctx, disp, sizeof(*disp));
   2288  1.1  christos }
   2289  1.1  christos 
   2290  1.1  christos isc_result_t
   2291  1.1  christos dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
   2292  1.1  christos 		       isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr,
   2293  1.1  christos 		       const isc_sockaddr_t *destaddr, unsigned int buffersize,
   2294  1.1  christos 		       unsigned int maxbuffers, unsigned int maxrequests,
   2295  1.1  christos 		       unsigned int buckets, unsigned int increment,
   2296  1.1  christos 		       unsigned int attributes, dns_dispatch_t **dispp) {
   2297  1.1  christos 	isc_result_t result;
   2298  1.1  christos 	dns_dispatch_t *disp;
   2299  1.1  christos 
   2300  1.1  christos 	UNUSED(maxbuffers);
   2301  1.1  christos 	UNUSED(buffersize);
   2302  1.1  christos 
   2303  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   2304  1.1  christos 	REQUIRE(isc_socket_gettype(sock) == isc_sockettype_tcp);
   2305  1.1  christos 	REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0);
   2306  1.1  christos 	REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0);
   2307  1.1  christos 
   2308  1.1  christos 	if (destaddr == NULL) {
   2309  1.1  christos 		attributes |= DNS_DISPATCHATTR_PRIVATE; /* XXXMLG */
   2310  1.1  christos 	}
   2311  1.1  christos 
   2312  1.1  christos 	LOCK(&mgr->lock);
   2313  1.1  christos 
   2314  1.1  christos 	/*
   2315  1.1  christos 	 * dispatch_allocate() checks mgr for us.
   2316  1.1  christos 	 * qid_allocate() checks buckets and increment for us.
   2317  1.1  christos 	 */
   2318  1.1  christos 	disp = NULL;
   2319  1.1  christos 	result = dispatch_allocate(mgr, maxrequests, &disp);
   2320  1.1  christos 	if (result != ISC_R_SUCCESS) {
   2321  1.1  christos 		UNLOCK(&mgr->lock);
   2322  1.1  christos 		return (result);
   2323  1.1  christos 	}
   2324  1.1  christos 
   2325  1.1  christos 	result = qid_allocate(mgr, buckets, increment, &disp->qid, false);
   2326  1.1  christos 	if (result != ISC_R_SUCCESS) {
   2327  1.1  christos 		goto deallocate_dispatch;
   2328  1.1  christos 	}
   2329  1.1  christos 
   2330  1.1  christos 	disp->socktype = isc_sockettype_tcp;
   2331  1.1  christos 	disp->socket = NULL;
   2332  1.1  christos 	isc_socket_attach(sock, &disp->socket);
   2333  1.1  christos 
   2334  1.1  christos 	disp->sepool = NULL;
   2335  1.1  christos 
   2336  1.1  christos 	disp->ntasks = 1;
   2337  1.1  christos 	disp->task[0] = NULL;
   2338  1.1  christos 	result = isc_task_create(taskmgr, 50, &disp->task[0]);
   2339  1.1  christos 	if (result != ISC_R_SUCCESS) {
   2340  1.1  christos 		goto kill_socket;
   2341  1.1  christos 	}
   2342  1.1  christos 
   2343  1.1  christos 	disp->ctlevent =
   2344  1.1  christos 		isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL,
   2345  1.1  christos 				   destroy_disp, disp, sizeof(isc_event_t));
   2346  1.1  christos 
   2347  1.1  christos 	isc_task_setname(disp->task[0], "tcpdispatch", disp);
   2348  1.1  christos 
   2349  1.1  christos 	dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg);
   2350  1.1  christos 	disp->tcpmsg_valid = 1;
   2351  1.1  christos 
   2352  1.1  christos 	disp->attributes = attributes;
   2353  1.1  christos 
   2354  1.1  christos 	if (localaddr == NULL) {
   2355  1.1  christos 		if (destaddr != NULL) {
   2356  1.1  christos 			switch (isc_sockaddr_pf(destaddr)) {
   2357  1.1  christos 			case AF_INET:
   2358  1.1  christos 				isc_sockaddr_any(&disp->local);
   2359  1.1  christos 				break;
   2360  1.1  christos 			case AF_INET6:
   2361  1.1  christos 				isc_sockaddr_any6(&disp->local);
   2362  1.1  christos 				break;
   2363  1.1  christos 			}
   2364  1.1  christos 		}
   2365  1.1  christos 	} else {
   2366  1.1  christos 		disp->local = *localaddr;
   2367  1.1  christos 	}
   2368  1.1  christos 
   2369  1.1  christos 	if (destaddr != NULL) {
   2370  1.1  christos 		disp->peer = *destaddr;
   2371  1.1  christos 	}
   2372  1.1  christos 
   2373  1.1  christos 	/*
   2374  1.1  christos 	 * Append it to the dispatcher list.
   2375  1.1  christos 	 */
   2376  1.1  christos 	ISC_LIST_APPEND(mgr->list, disp, link);
   2377  1.1  christos 	UNLOCK(&mgr->lock);
   2378  1.1  christos 
   2379  1.1  christos 	mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp);
   2380  1.1  christos 	dispatch_log(disp, LVL(90), "created task %p", disp->task[0]);
   2381  1.1  christos 	*dispp = disp;
   2382  1.1  christos 
   2383  1.1  christos 	return (ISC_R_SUCCESS);
   2384  1.1  christos 
   2385  1.1  christos kill_socket:
   2386  1.1  christos 	isc_socket_detach(&disp->socket);
   2387  1.1  christos deallocate_dispatch:
   2388  1.1  christos 	dispatch_free(&disp);
   2389  1.1  christos 
   2390  1.1  christos 	UNLOCK(&mgr->lock);
   2391  1.1  christos 
   2392  1.1  christos 	return (result);
   2393  1.1  christos }
   2394  1.1  christos 
   2395  1.1  christos isc_result_t
   2396  1.1  christos dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
   2397  1.1  christos 		    const isc_sockaddr_t *localaddr, bool *connected,
   2398  1.1  christos 		    dns_dispatch_t **dispp) {
   2399  1.1  christos 	dns_dispatch_t *disp;
   2400  1.1  christos 	isc_result_t result;
   2401  1.1  christos 	isc_sockaddr_t peeraddr;
   2402  1.1  christos 	isc_sockaddr_t sockname;
   2403  1.1  christos 	unsigned int attributes, mask;
   2404  1.1  christos 	bool match = false;
   2405  1.1  christos 
   2406  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   2407  1.1  christos 	REQUIRE(destaddr != NULL);
   2408  1.1  christos 	REQUIRE(dispp != NULL && *dispp == NULL);
   2409  1.1  christos 
   2410  1.1  christos 	/* First pass  */
   2411  1.1  christos 	attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED;
   2412  1.1  christos 	mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE |
   2413  1.1  christos 	       DNS_DISPATCHATTR_EXCLUSIVE | DNS_DISPATCHATTR_CONNECTED;
   2414  1.1  christos 
   2415  1.1  christos 	LOCK(&mgr->lock);
   2416  1.1  christos 	disp = ISC_LIST_HEAD(mgr->list);
   2417  1.1  christos 	while (disp != NULL && !match) {
   2418  1.1  christos 		LOCK(&disp->lock);
   2419  1.1  christos 		if ((disp->shutting_down == 0) &&
   2420  1.1  christos 		    ATTRMATCH(disp->attributes, attributes, mask) &&
   2421  1.1  christos 		    (localaddr == NULL ||
   2422  1.1  christos 		     isc_sockaddr_eqaddr(localaddr, &disp->local)))
   2423  1.1  christos 		{
   2424  1.1  christos 			result = isc_socket_getsockname(disp->socket,
   2425  1.1  christos 							&sockname);
   2426  1.1  christos 			if (result == ISC_R_SUCCESS) {
   2427  1.1  christos 				result = isc_socket_getpeername(disp->socket,
   2428  1.1  christos 								&peeraddr);
   2429  1.1  christos 			}
   2430  1.1  christos 			if (result == ISC_R_SUCCESS &&
   2431  1.1  christos 			    isc_sockaddr_equal(destaddr, &peeraddr) &&
   2432  1.1  christos 			    (localaddr == NULL ||
   2433  1.1  christos 			     isc_sockaddr_eqaddr(localaddr, &sockname)))
   2434  1.1  christos 			{
   2435  1.1  christos 				/* attach */
   2436  1.1  christos 				disp->refcount++;
   2437  1.1  christos 				*dispp = disp;
   2438  1.1  christos 				match = true;
   2439  1.1  christos 				if (connected != NULL) {
   2440  1.1  christos 					*connected = true;
   2441  1.1  christos 				}
   2442  1.1  christos 			}
   2443  1.1  christos 		}
   2444  1.1  christos 		UNLOCK(&disp->lock);
   2445  1.1  christos 		disp = ISC_LIST_NEXT(disp, link);
   2446  1.1  christos 	}
   2447  1.1  christos 	if (match || connected == NULL) {
   2448  1.1  christos 		UNLOCK(&mgr->lock);
   2449  1.1  christos 		return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND);
   2450  1.1  christos 	}
   2451  1.1  christos 
   2452  1.1  christos 	/* Second pass, only if connected != NULL */
   2453  1.1  christos 	attributes = DNS_DISPATCHATTR_TCP;
   2454  1.1  christos 
   2455  1.1  christos 	disp = ISC_LIST_HEAD(mgr->list);
   2456  1.1  christos 	while (disp != NULL && !match) {
   2457  1.1  christos 		LOCK(&disp->lock);
   2458  1.1  christos 		if ((disp->shutting_down == 0) &&
   2459  1.1  christos 		    ATTRMATCH(disp->attributes, attributes, mask) &&
   2460  1.1  christos 		    (localaddr == NULL ||
   2461  1.1  christos 		     isc_sockaddr_eqaddr(localaddr, &disp->local)) &&
   2462  1.1  christos 		    isc_sockaddr_equal(destaddr, &disp->peer))
   2463  1.1  christos 		{
   2464  1.1  christos 			/* attach */
   2465  1.1  christos 			disp->refcount++;
   2466  1.1  christos 			*dispp = disp;
   2467  1.1  christos 			match = true;
   2468  1.1  christos 		}
   2469  1.1  christos 		UNLOCK(&disp->lock);
   2470  1.1  christos 		disp = ISC_LIST_NEXT(disp, link);
   2471  1.1  christos 	}
   2472  1.1  christos 	UNLOCK(&mgr->lock);
   2473  1.1  christos 	return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND);
   2474  1.1  christos }
   2475  1.1  christos 
   2476  1.1  christos isc_result_t
   2477  1.1  christos dns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
   2478  1.1  christos 			isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr,
   2479  1.1  christos 			unsigned int buffersize, unsigned int maxbuffers,
   2480  1.1  christos 			unsigned int maxrequests, unsigned int buckets,
   2481  1.1  christos 			unsigned int increment, unsigned int attributes,
   2482  1.1  christos 			unsigned int mask, dns_dispatch_t **dispp,
   2483  1.1  christos 			dns_dispatch_t *dup_dispatch) {
   2484  1.1  christos 	isc_result_t result;
   2485  1.1  christos 	dns_dispatch_t *disp = NULL;
   2486  1.1  christos 
   2487  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   2488  1.1  christos 	REQUIRE(sockmgr != NULL);
   2489  1.1  christos 	REQUIRE(localaddr != NULL);
   2490  1.1  christos 	REQUIRE(taskmgr != NULL);
   2491  1.1  christos 	REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
   2492  1.1  christos 	REQUIRE(maxbuffers > 0);
   2493  1.1  christos 	REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */
   2494  1.1  christos 	REQUIRE(increment > buckets);
   2495  1.1  christos 	REQUIRE(dispp != NULL && *dispp == NULL);
   2496  1.1  christos 	REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0);
   2497  1.1  christos 
   2498  1.1  christos 	result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers,
   2499  1.1  christos 					maxrequests, buckets, increment);
   2500  1.1  christos 	if (result != ISC_R_SUCCESS) {
   2501  1.1  christos 		return (result);
   2502  1.1  christos 	}
   2503  1.1  christos 
   2504  1.1  christos 	LOCK(&mgr->lock);
   2505  1.1  christos 
   2506  1.1  christos 	if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
   2507  1.1  christos 		REQUIRE(isc_sockaddr_getport(localaddr) == 0);
   2508  1.1  christos 		goto createudp;
   2509  1.1  christos 	}
   2510  1.1  christos 
   2511  1.1  christos 	/*
   2512  1.1  christos 	 * See if we have a dispatcher that matches.
   2513  1.1  christos 	 */
   2514  1.1  christos 	if (dup_dispatch == NULL) {
   2515  1.1  christos 		result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
   2516  1.1  christos 		if (result == ISC_R_SUCCESS) {
   2517  1.1  christos 			disp->refcount++;
   2518  1.1  christos 
   2519  1.1  christos 			if (disp->maxrequests < maxrequests) {
   2520  1.1  christos 				disp->maxrequests = maxrequests;
   2521  1.1  christos 			}
   2522  1.1  christos 
   2523  1.1  christos 			if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) ==
   2524  1.1  christos 				    0 &&
   2525  1.1  christos 			    (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
   2526  1.1  christos 			{
   2527  1.1  christos 				disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
   2528  1.1  christos 				if (disp->recv_pending != 0) {
   2529  1.1  christos 					isc_socket_cancel(disp->socket,
   2530  1.1  christos 							  disp->task[0],
   2531  1.1  christos 							  ISC_SOCKCANCEL_RECV);
   2532  1.1  christos 				}
   2533  1.1  christos 			}
   2534  1.1  christos 
   2535  1.1  christos 			UNLOCK(&disp->lock);
   2536  1.1  christos 			UNLOCK(&mgr->lock);
   2537  1.1  christos 
   2538  1.1  christos 			*dispp = disp;
   2539  1.1  christos 
   2540  1.1  christos 			return (ISC_R_SUCCESS);
   2541  1.1  christos 		}
   2542  1.1  christos 	}
   2543  1.1  christos 
   2544  1.1  christos createudp:
   2545  1.1  christos 	/*
   2546  1.1  christos 	 * Nope, create one.
   2547  1.1  christos 	 */
   2548  1.1  christos 	result = dispatch_createudp(
   2549  1.1  christos 		mgr, sockmgr, taskmgr, localaddr, maxrequests, attributes,
   2550  1.1  christos 		&disp, dup_dispatch == NULL ? NULL : dup_dispatch->socket);
   2551  1.1  christos 
   2552  1.1  christos 	if (result != ISC_R_SUCCESS) {
   2553  1.1  christos 		UNLOCK(&mgr->lock);
   2554  1.1  christos 		return (result);
   2555  1.1  christos 	}
   2556  1.1  christos 
   2557  1.1  christos 	UNLOCK(&mgr->lock);
   2558  1.1  christos 	*dispp = disp;
   2559  1.1  christos 
   2560  1.1  christos 	return (ISC_R_SUCCESS);
   2561  1.1  christos }
   2562  1.1  christos 
   2563  1.1  christos isc_result_t
   2564  1.1  christos dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
   2565  1.1  christos 		    isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr,
   2566  1.1  christos 		    unsigned int buffersize, unsigned int maxbuffers,
   2567  1.1  christos 		    unsigned int maxrequests, unsigned int buckets,
   2568  1.1  christos 		    unsigned int increment, unsigned int attributes,
   2569  1.1  christos 		    unsigned int mask, dns_dispatch_t **dispp) {
   2570  1.1  christos 	return (dns_dispatch_getudp_dup(mgr, sockmgr, taskmgr, localaddr,
   2571  1.1  christos 					buffersize, maxbuffers, maxrequests,
   2572  1.1  christos 					buckets, increment, attributes, mask,
   2573  1.1  christos 					dispp, NULL));
   2574  1.1  christos }
   2575  1.1  christos 
   2576  1.1  christos /*
   2577  1.1  christos  * mgr should be locked.
   2578  1.1  christos  */
   2579  1.1  christos 
   2580  1.1  christos #ifndef DNS_DISPATCH_HELD
   2581  1.1  christos #define DNS_DISPATCH_HELD 20U
   2582  1.1  christos #endif /* ifndef DNS_DISPATCH_HELD */
   2583  1.1  christos 
   2584  1.1  christos static isc_result_t
   2585  1.1  christos get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp,
   2586  1.1  christos 	      isc_socketmgr_t *sockmgr, const isc_sockaddr_t *localaddr,
   2587  1.1  christos 	      isc_socket_t **sockp, isc_socket_t *dup_socket, bool duponly) {
   2588  1.1  christos 	unsigned int i, j;
   2589  1.1  christos 	isc_socket_t *held[DNS_DISPATCH_HELD];
   2590  1.1  christos 	isc_sockaddr_t localaddr_bound;
   2591  1.1  christos 	isc_socket_t *sock = NULL;
   2592  1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   2593  1.1  christos 	bool anyport;
   2594  1.1  christos 
   2595  1.1  christos 	INSIST(sockp != NULL && *sockp == NULL);
   2596  1.1  christos 
   2597  1.1  christos 	localaddr_bound = *localaddr;
   2598  1.1  christos 	anyport = (isc_sockaddr_getport(localaddr) == 0);
   2599  1.1  christos 
   2600  1.1  christos 	if (anyport) {
   2601  1.1  christos 		unsigned int nports;
   2602  1.1  christos 		in_port_t *ports;
   2603  1.1  christos 
   2604  1.1  christos 		/*
   2605  1.1  christos 		 * If no port is specified, we first try to pick up a random
   2606  1.1  christos 		 * port by ourselves.
   2607  1.1  christos 		 */
   2608  1.1  christos 		if (isc_sockaddr_pf(localaddr) == AF_INET) {
   2609  1.1  christos 			nports = disp->mgr->nv4ports;
   2610  1.1  christos 			ports = disp->mgr->v4ports;
   2611  1.1  christos 		} else {
   2612  1.1  christos 			nports = disp->mgr->nv6ports;
   2613  1.1  christos 			ports = disp->mgr->v6ports;
   2614  1.1  christos 		}
   2615  1.1  christos 		if (nports == 0) {
   2616  1.1  christos 			return (ISC_R_ADDRNOTAVAIL);
   2617  1.1  christos 		}
   2618  1.1  christos 
   2619  1.1  christos 		for (i = 0; i < 1024; i++) {
   2620  1.1  christos 			in_port_t prt;
   2621  1.1  christos 
   2622  1.1  christos 			prt = ports[isc_random_uniform(nports)];
   2623  1.1  christos 			isc_sockaddr_setport(&localaddr_bound, prt);
   2624  1.1  christos 			result = open_socket(sockmgr, &localaddr_bound, 0,
   2625  1.1  christos 					     &sock, NULL, false);
   2626  1.1  christos 			/*
   2627  1.1  christos 			 * Continue if the port chosen is already in use
   2628  1.1  christos 			 * or the OS has reserved it.
   2629  1.1  christos 			 */
   2630  1.1  christos 			if (result == ISC_R_NOPERM || result == ISC_R_ADDRINUSE)
   2631  1.1  christos 			{
   2632  1.1  christos 				continue;
   2633  1.1  christos 			}
   2634  1.1  christos 			disp->localport = prt;
   2635  1.1  christos 			*sockp = sock;
   2636  1.1  christos 			return (result);
   2637  1.1  christos 		}
   2638  1.1  christos 
   2639  1.1  christos 		/*
   2640  1.1  christos 		 * If this fails 1024 times, we then ask the kernel for
   2641  1.1  christos 		 * choosing one.
   2642  1.1  christos 		 */
   2643  1.1  christos 	} else {
   2644  1.1  christos 		/* Allow to reuse address for non-random ports. */
   2645  1.1  christos 		result = open_socket(sockmgr, localaddr,
   2646  1.1  christos 				     ISC_SOCKET_REUSEADDRESS, &sock, dup_socket,
   2647  1.1  christos 				     duponly);
   2648  1.1  christos 
   2649  1.1  christos 		if (result == ISC_R_SUCCESS) {
   2650  1.1  christos 			*sockp = sock;
   2651  1.1  christos 		}
   2652  1.1  christos 
   2653  1.1  christos 		return (result);
   2654  1.1  christos 	}
   2655  1.1  christos 
   2656  1.1  christos 	memset(held, 0, sizeof(held));
   2657  1.1  christos 	i = 0;
   2658  1.1  christos 
   2659  1.1  christos 	for (j = 0; j < 0xffffU; j++) {
   2660  1.1  christos 		result = open_socket(sockmgr, localaddr, 0, &sock, NULL, false);
   2661  1.1  christos 		if (result != ISC_R_SUCCESS) {
   2662  1.1  christos 			goto end;
   2663  1.1  christos 		} else if (portavailable(mgr, sock, NULL)) {
   2664  1.1  christos 			break;
   2665  1.1  christos 		}
   2666  1.1  christos 		if (held[i] != NULL) {
   2667  1.1  christos 			isc_socket_detach(&held[i]);
   2668  1.1  christos 		}
   2669  1.1  christos 		held[i++] = sock;
   2670  1.1  christos 		sock = NULL;
   2671  1.1  christos 		if (i == DNS_DISPATCH_HELD) {
   2672  1.1  christos 			i = 0;
   2673  1.1  christos 		}
   2674  1.1  christos 	}
   2675  1.1  christos 	if (j == 0xffffU) {
   2676  1.1  christos 		mgr_log(mgr, ISC_LOG_ERROR,
   2677  1.1  christos 			"avoid-v%s-udp-ports: unable to allocate "
   2678  1.1  christos 			"an available port",
   2679  1.1  christos 			isc_sockaddr_pf(localaddr) == AF_INET ? "4" : "6");
   2680  1.1  christos 		result = ISC_R_FAILURE;
   2681  1.1  christos 		goto end;
   2682  1.1  christos 	}
   2683  1.1  christos 	*sockp = sock;
   2684  1.1  christos 
   2685  1.1  christos end:
   2686  1.1  christos 	for (i = 0; i < DNS_DISPATCH_HELD; i++) {
   2687  1.1  christos 		if (held[i] != NULL) {
   2688  1.1  christos 			isc_socket_detach(&held[i]);
   2689  1.1  christos 		}
   2690  1.1  christos 	}
   2691  1.1  christos 
   2692  1.1  christos 	return (result);
   2693  1.1  christos }
   2694  1.1  christos 
   2695  1.1  christos static isc_result_t
   2696  1.1  christos dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
   2697  1.1  christos 		   isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr,
   2698  1.1  christos 		   unsigned int maxrequests, unsigned int attributes,
   2699  1.1  christos 		   dns_dispatch_t **dispp, isc_socket_t *dup_socket) {
   2700  1.1  christos 	isc_result_t result;
   2701  1.1  christos 	dns_dispatch_t *disp;
   2702  1.1  christos 	isc_socket_t *sock = NULL;
   2703  1.1  christos 	int i = 0;
   2704  1.1  christos 	bool duponly = ((attributes & DNS_DISPATCHATTR_CANREUSE) == 0);
   2705  1.1  christos 
   2706  1.1  christos 	/* This is an attribute needed only at creation time */
   2707  1.1  christos 	attributes &= ~DNS_DISPATCHATTR_CANREUSE;
   2708  1.1  christos 	/*
   2709  1.1  christos 	 * dispatch_allocate() checks mgr for us.
   2710  1.1  christos 	 */
   2711  1.1  christos 	disp = NULL;
   2712  1.1  christos 	result = dispatch_allocate(mgr, maxrequests, &disp);
   2713  1.1  christos 	if (result != ISC_R_SUCCESS) {
   2714  1.1  christos 		return (result);
   2715  1.1  christos 	}
   2716  1.1  christos 
   2717  1.1  christos 	disp->socktype = isc_sockettype_udp;
   2718  1.1  christos 
   2719  1.1  christos 	if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) {
   2720  1.1  christos 		result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock,
   2721  1.1  christos 				       dup_socket, duponly);
   2722  1.1  christos 		if (result != ISC_R_SUCCESS) {
   2723  1.1  christos 			goto deallocate_dispatch;
   2724  1.1  christos 		}
   2725  1.1  christos 
   2726  1.1  christos 		if (isc_log_wouldlog(dns_lctx, 90)) {
   2727  1.1  christos 			char addrbuf[ISC_SOCKADDR_FORMATSIZE];
   2728  1.1  christos 
   2729  1.1  christos 			isc_sockaddr_format(localaddr, addrbuf,
   2730  1.1  christos 					    ISC_SOCKADDR_FORMATSIZE);
   2731  1.1  christos 			mgr_log(mgr, LVL(90),
   2732  1.1  christos 				"dns_dispatch_createudp: Created"
   2733  1.1  christos 				" UDP dispatch for %s with socket fd %d",
   2734  1.1  christos 				addrbuf, isc_socket_getfd(sock));
   2735  1.1  christos 		}
   2736  1.1  christos 	} else {
   2737  1.1  christos 		isc_sockaddr_t sa_any;
   2738  1.1  christos 
   2739  1.1  christos 		/*
   2740  1.1  christos 		 * For dispatches using exclusive sockets with a specific
   2741  1.1  christos 		 * source address, we only check if the specified address is
   2742  1.1  christos 		 * available on the system.  Query sockets will be created later
   2743  1.1  christos 		 * on demand.
   2744  1.1  christos 		 */
   2745  1.1  christos 		isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr));
   2746  1.1  christos 		if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) {
   2747  1.1  christos 			result = open_socket(sockmgr, localaddr, 0, &sock, NULL,
   2748  1.1  christos 					     false);
   2749  1.1  christos 			if (sock != NULL) {
   2750  1.1  christos 				isc_socket_detach(&sock);
   2751  1.1  christos 			}
   2752  1.1  christos 			if (result != ISC_R_SUCCESS) {
   2753  1.1  christos 				goto deallocate_dispatch;
   2754  1.1  christos 			}
   2755  1.1  christos 		}
   2756  1.1  christos 
   2757  1.1  christos 		disp->port_table = isc_mem_get(
   2758  1.1  christos 			mgr->mctx, sizeof(disp->port_table[0]) *
   2759  1.1  christos 					   DNS_DISPATCH_PORTTABLESIZE);
   2760  1.1  christos 		for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) {
   2761  1.1  christos 			ISC_LIST_INIT(disp->port_table[i]);
   2762  1.1  christos 		}
   2763  1.1  christos 	}
   2764  1.1  christos 	disp->socket = sock;
   2765  1.1  christos 	disp->local = *localaddr;
   2766  1.1  christos 
   2767  1.1  christos 	if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
   2768  1.1  christos 		disp->ntasks = MAX_INTERNAL_TASKS;
   2769  1.1  christos 	} else {
   2770  1.1  christos 		disp->ntasks = 1;
   2771  1.1  christos 	}
   2772  1.1  christos 	for (i = 0; i < disp->ntasks; i++) {
   2773  1.1  christos 		disp->task[i] = NULL;
   2774  1.1  christos 		result = isc_task_create(taskmgr, 0, &disp->task[i]);
   2775  1.1  christos 		if (result != ISC_R_SUCCESS) {
   2776  1.1  christos 			while (--i >= 0) {
   2777  1.1  christos 				isc_task_shutdown(disp->task[i]);
   2778  1.1  christos 				isc_task_detach(&disp->task[i]);
   2779  1.1  christos 			}
   2780  1.1  christos 			goto kill_socket;
   2781  1.1  christos 		}
   2782  1.1  christos 		isc_task_setname(disp->task[i], "udpdispatch", disp);
   2783  1.1  christos 	}
   2784  1.1  christos 
   2785  1.1  christos 	disp->ctlevent =
   2786  1.1  christos 		isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL,
   2787  1.1  christos 				   destroy_disp, disp, sizeof(isc_event_t));
   2788  1.1  christos 
   2789  1.1  christos 	disp->sepool = NULL;
   2790  1.1  christos 	isc_mem_create(&disp->sepool);
   2791  1.1  christos 	isc_mem_setname(disp->sepool, "disp_sepool", NULL);
   2792  1.1  christos 
   2793  1.1  christos 	attributes &= ~DNS_DISPATCHATTR_TCP;
   2794  1.1  christos 	attributes |= DNS_DISPATCHATTR_UDP;
   2795  1.1  christos 	disp->attributes = attributes;
   2796  1.1  christos 
   2797  1.1  christos 	/*
   2798  1.1  christos 	 * Append it to the dispatcher list.
   2799  1.1  christos 	 */
   2800  1.1  christos 	ISC_LIST_APPEND(mgr->list, disp, link);
   2801  1.1  christos 
   2802  1.1  christos 	mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp);
   2803  1.1  christos 	dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); /* XXX */
   2804  1.1  christos 	if (disp->socket != NULL) {
   2805  1.1  christos 		dispatch_log(disp, LVL(90), "created socket %p", disp->socket);
   2806  1.1  christos 	}
   2807  1.1  christos 
   2808  1.1  christos 	*dispp = disp;
   2809  1.1  christos 
   2810  1.1  christos 	return (result);
   2811  1.1  christos 
   2812  1.1  christos 	/*
   2813  1.1  christos 	 * Error returns.
   2814  1.1  christos 	 */
   2815  1.1  christos kill_socket:
   2816  1.1  christos 	if (disp->socket != NULL) {
   2817  1.1  christos 		isc_socket_detach(&disp->socket);
   2818  1.1  christos 	}
   2819  1.1  christos deallocate_dispatch:
   2820  1.1  christos 	dispatch_free(&disp);
   2821  1.1  christos 
   2822  1.1  christos 	return (result);
   2823  1.1  christos }
   2824  1.1  christos 
   2825  1.1  christos void
   2826  1.1  christos dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) {
   2827  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   2828  1.1  christos 	REQUIRE(dispp != NULL && *dispp == NULL);
   2829  1.1  christos 
   2830  1.1  christos 	LOCK(&disp->lock);
   2831  1.1  christos 	disp->refcount++;
   2832  1.1  christos 	UNLOCK(&disp->lock);
   2833  1.1  christos 
   2834  1.1  christos 	*dispp = disp;
   2835  1.1  christos }
   2836  1.1  christos 
   2837  1.1  christos /*
   2838  1.1  christos  * It is important to lock the manager while we are deleting the dispatch,
   2839  1.1  christos  * since dns_dispatch_getudp will call dispatch_find, which returns to
   2840  1.1  christos  * the caller a dispatch but does not attach to it until later.  _getudp
   2841  1.1  christos  * locks the manager, however, so locking it here will keep us from attaching
   2842  1.1  christos  * to a dispatcher that is in the process of going away.
   2843  1.1  christos  */
   2844  1.1  christos void
   2845  1.1  christos dns_dispatch_detach(dns_dispatch_t **dispp) {
   2846  1.1  christos 	dns_dispatch_t *disp;
   2847  1.1  christos 	dispsocket_t *dispsock;
   2848  1.1  christos 	bool killit;
   2849  1.1  christos 
   2850  1.1  christos 	REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp));
   2851  1.1  christos 
   2852  1.1  christos 	disp = *dispp;
   2853  1.1  christos 	*dispp = NULL;
   2854  1.1  christos 
   2855  1.1  christos 	LOCK(&disp->lock);
   2856  1.1  christos 
   2857  1.1  christos 	INSIST(disp->refcount > 0);
   2858  1.1  christos 	disp->refcount--;
   2859  1.1  christos 	if (disp->refcount == 0) {
   2860  1.1  christos 		if (disp->recv_pending > 0) {
   2861  1.1  christos 			isc_socket_cancel(disp->socket, disp->task[0],
   2862  1.1  christos 					  ISC_SOCKCANCEL_RECV);
   2863  1.1  christos 		}
   2864  1.1  christos 		for (dispsock = ISC_LIST_HEAD(disp->activesockets);
   2865  1.1  christos 		     dispsock != NULL; dispsock = ISC_LIST_NEXT(dispsock, link))
   2866  1.1  christos 		{
   2867  1.1  christos 			isc_socket_cancel(dispsock->socket, dispsock->task,
   2868  1.1  christos 					  ISC_SOCKCANCEL_RECV);
   2869  1.1  christos 		}
   2870  1.1  christos 		disp->shutting_down = 1;
   2871  1.1  christos 	}
   2872  1.1  christos 
   2873  1.1  christos 	dispatch_log(disp, LVL(90), "detach: refcount %d", disp->refcount);
   2874  1.1  christos 
   2875  1.1  christos 	killit = destroy_disp_ok(disp);
   2876  1.1  christos 	UNLOCK(&disp->lock);
   2877  1.1  christos 	if (killit) {
   2878  1.1  christos 		isc_task_send(disp->task[0], &disp->ctlevent);
   2879  1.1  christos 	}
   2880  1.1  christos }
   2881  1.1  christos 
   2882  1.1  christos isc_result_t
   2883  1.1  christos dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options,
   2884  1.1  christos 			 const isc_sockaddr_t *dest, isc_task_t *task,
   2885  1.1  christos 			 isc_taskaction_t action, void *arg,
   2886  1.1  christos 			 dns_messageid_t *idp, dns_dispentry_t **resp,
   2887  1.1  christos 			 isc_socketmgr_t *sockmgr) {
   2888  1.1  christos 	dns_dispentry_t *res;
   2889  1.1  christos 	unsigned int bucket;
   2890  1.1  christos 	in_port_t localport = 0;
   2891  1.1  christos 	dns_messageid_t id;
   2892  1.1  christos 	int i;
   2893  1.1  christos 	bool ok;
   2894  1.1  christos 	dns_qid_t *qid;
   2895  1.1  christos 	dispsocket_t *dispsocket = NULL;
   2896  1.1  christos 	isc_result_t result;
   2897  1.1  christos 
   2898  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   2899  1.1  christos 	REQUIRE(task != NULL);
   2900  1.1  christos 	REQUIRE(dest != NULL);
   2901  1.1  christos 	REQUIRE(resp != NULL && *resp == NULL);
   2902  1.1  christos 	REQUIRE(idp != NULL);
   2903  1.1  christos 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
   2904  1.1  christos 		REQUIRE(sockmgr != NULL);
   2905  1.1  christos 	}
   2906  1.1  christos 
   2907  1.1  christos 	LOCK(&disp->lock);
   2908  1.1  christos 
   2909  1.1  christos 	if (disp->shutting_down == 1) {
   2910  1.1  christos 		UNLOCK(&disp->lock);
   2911  1.1  christos 		return (ISC_R_SHUTTINGDOWN);
   2912  1.1  christos 	}
   2913  1.1  christos 
   2914  1.1  christos 	if (disp->requests >= disp->maxrequests) {
   2915  1.1  christos 		UNLOCK(&disp->lock);
   2916  1.1  christos 		return (ISC_R_QUOTA);
   2917  1.1  christos 	}
   2918  1.1  christos 
   2919  1.1  christos 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
   2920  1.1  christos 	    disp->nsockets > DNS_DISPATCH_SOCKSQUOTA)
   2921  1.1  christos 	{
   2922  1.1  christos 		dispsocket_t *oldestsocket;
   2923  1.1  christos 		dns_dispentry_t *oldestresp;
   2924  1.1  christos 		dns_dispatchevent_t *rev;
   2925  1.1  christos 
   2926  1.1  christos 		/*
   2927  1.1  christos 		 * Kill oldest outstanding query if the number of sockets
   2928  1.1  christos 		 * exceeds the quota to keep the room for new queries.
   2929  1.1  christos 		 */
   2930  1.1  christos 		oldestsocket = ISC_LIST_HEAD(disp->activesockets);
   2931  1.1  christos 		oldestresp = oldestsocket->resp;
   2932  1.1  christos 		if (oldestresp != NULL && !oldestresp->item_out) {
   2933  1.1  christos 			rev = allocate_devent(oldestresp->disp);
   2934  1.1  christos 			if (rev != NULL) {
   2935  1.1  christos 				rev->buffer.base = NULL;
   2936  1.1  christos 				rev->result = ISC_R_CANCELED;
   2937  1.1  christos 				rev->id = oldestresp->id;
   2938  1.1  christos 				ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL,
   2939  1.1  christos 					       DNS_EVENT_DISPATCH,
   2940  1.1  christos 					       oldestresp->action,
   2941  1.1  christos 					       oldestresp->arg, oldestresp,
   2942  1.1  christos 					       NULL, NULL);
   2943  1.1  christos 				oldestresp->item_out = true;
   2944  1.1  christos 				isc_task_send(oldestresp->task,
   2945  1.1  christos 					      ISC_EVENT_PTR(&rev));
   2946  1.1  christos 				inc_stats(disp->mgr,
   2947  1.1  christos 					  dns_resstatscounter_dispabort);
   2948  1.1  christos 			}
   2949  1.1  christos 		}
   2950  1.1  christos 
   2951  1.1  christos 		/*
   2952  1.1  christos 		 * Move this entry to the tail so that it won't (easily) be
   2953  1.1  christos 		 * examined before actually being canceled.
   2954  1.1  christos 		 */
   2955  1.1  christos 		ISC_LIST_UNLINK(disp->activesockets, oldestsocket, link);
   2956  1.1  christos 		ISC_LIST_APPEND(disp->activesockets, oldestsocket, link);
   2957  1.1  christos 	}
   2958  1.1  christos 
   2959  1.1  christos 	qid = DNS_QID(disp);
   2960  1.1  christos 
   2961  1.1  christos 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
   2962  1.1  christos 		/*
   2963  1.1  christos 		 * Get a separate UDP socket with a random port number.
   2964  1.1  christos 		 */
   2965  1.1  christos 		result = get_dispsocket(disp, dest, sockmgr, &dispsocket,
   2966  1.1  christos 					&localport);
   2967  1.1  christos 		if (result != ISC_R_SUCCESS) {
   2968  1.1  christos 			UNLOCK(&disp->lock);
   2969  1.1  christos 			inc_stats(disp->mgr, dns_resstatscounter_dispsockfail);
   2970  1.1  christos 			return (result);
   2971  1.1  christos 		}
   2972  1.1  christos 	} else {
   2973  1.1  christos 		localport = disp->localport;
   2974  1.1  christos 	}
   2975  1.1  christos 
   2976  1.1  christos 	/*
   2977  1.1  christos 	 * Try somewhat hard to find an unique ID unless FIXEDID is set
   2978  1.1  christos 	 * in which case we use the id passed in via *idp.
   2979  1.1  christos 	 */
   2980  1.1  christos 	LOCK(&qid->lock);
   2981  1.1  christos 	if ((options & DNS_DISPATCHOPT_FIXEDID) != 0) {
   2982  1.1  christos 		id = *idp;
   2983  1.1  christos 	} else {
   2984  1.1  christos 		id = (dns_messageid_t)isc_random16();
   2985  1.1  christos 	}
   2986  1.1  christos 	ok = false;
   2987  1.1  christos 	i = 0;
   2988  1.1  christos 	do {
   2989  1.1  christos 		bucket = dns_hash(qid, dest, id, localport);
   2990  1.1  christos 		if (entry_search(qid, dest, id, localport, bucket) == NULL) {
   2991  1.1  christos 			ok = true;
   2992  1.1  christos 			break;
   2993  1.1  christos 		}
   2994  1.1  christos 		if ((disp->attributes & DNS_DISPATCHATTR_FIXEDID) != 0) {
   2995  1.1  christos 			break;
   2996  1.1  christos 		}
   2997  1.1  christos 		id += qid->qid_increment;
   2998  1.1  christos 		id &= 0x0000ffff;
   2999  1.1  christos 	} while (i++ < 64);
   3000  1.1  christos 	UNLOCK(&qid->lock);
   3001  1.1  christos 
   3002  1.1  christos 	if (!ok) {
   3003  1.1  christos 		UNLOCK(&disp->lock);
   3004  1.1  christos 		return (ISC_R_NOMORE);
   3005  1.1  christos 	}
   3006  1.1  christos 
   3007  1.1  christos 	res = isc_mem_get(disp->mgr->mctx, sizeof(*res));
   3008  1.1  christos 	isc_refcount_increment0(&disp->mgr->irefs);
   3009  1.1  christos 
   3010  1.1  christos 	disp->refcount++;
   3011  1.1  christos 	disp->requests++;
   3012  1.1  christos 	res->task = NULL;
   3013  1.1  christos 	isc_task_attach(task, &res->task);
   3014  1.1  christos 	res->disp = disp;
   3015  1.1  christos 	res->id = id;
   3016  1.1  christos 	res->port = localport;
   3017  1.1  christos 	res->bucket = bucket;
   3018  1.1  christos 	res->host = *dest;
   3019  1.1  christos 	res->action = action;
   3020  1.1  christos 	res->arg = arg;
   3021  1.1  christos 	res->dispsocket = dispsocket;
   3022  1.1  christos 	if (dispsocket != NULL) {
   3023  1.1  christos 		dispsocket->resp = res;
   3024  1.1  christos 	}
   3025  1.1  christos 	res->item_out = false;
   3026  1.1  christos 	ISC_LIST_INIT(res->items);
   3027  1.1  christos 	ISC_LINK_INIT(res, link);
   3028  1.1  christos 	res->magic = RESPONSE_MAGIC;
   3029  1.1  christos 
   3030  1.1  christos 	LOCK(&qid->lock);
   3031  1.1  christos 	ISC_LIST_APPEND(qid->qid_table[bucket], res, link);
   3032  1.1  christos 	UNLOCK(&qid->lock);
   3033  1.1  christos 
   3034  1.1  christos 	inc_stats(disp->mgr, (qid == disp->mgr->qid)
   3035  1.1  christos 				     ? dns_resstatscounter_disprequdp
   3036  1.1  christos 				     : dns_resstatscounter_dispreqtcp);
   3037  1.1  christos 
   3038  1.1  christos 	request_log(disp, res, LVL(90), "attached to task %p", res->task);
   3039  1.1  christos 
   3040  1.1  christos 	if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) ||
   3041  1.1  christos 	    ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0))
   3042  1.1  christos 	{
   3043  1.1  christos 		result = startrecv(disp, dispsocket);
   3044  1.1  christos 		if (result != ISC_R_SUCCESS) {
   3045  1.1  christos 			LOCK(&qid->lock);
   3046  1.1  christos 			ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
   3047  1.1  christos 			UNLOCK(&qid->lock);
   3048  1.1  christos 
   3049  1.1  christos 			if (dispsocket != NULL) {
   3050  1.1  christos 				destroy_dispsocket(disp, &dispsocket);
   3051  1.1  christos 			}
   3052  1.1  christos 
   3053  1.1  christos 			disp->refcount--;
   3054  1.1  christos 			disp->requests--;
   3055  1.1  christos 
   3056  1.1  christos 			dec_stats(disp->mgr,
   3057  1.1  christos 				  (qid == disp->mgr->qid)
   3058  1.1  christos 					  ? dns_resstatscounter_disprequdp
   3059  1.1  christos 					  : dns_resstatscounter_dispreqtcp);
   3060  1.1  christos 
   3061  1.1  christos 			UNLOCK(&disp->lock);
   3062  1.1  christos 			isc_task_detach(&res->task);
   3063  1.1  christos 			isc_refcount_decrement(&disp->mgr->irefs);
   3064  1.1  christos 			isc_mem_put(disp->mgr->mctx, res, sizeof(*res));
   3065  1.1  christos 			return (result);
   3066  1.1  christos 		}
   3067  1.1  christos 	}
   3068  1.1  christos 
   3069  1.1  christos 	if (dispsocket != NULL) {
   3070  1.1  christos 		ISC_LIST_APPEND(disp->activesockets, dispsocket, link);
   3071  1.1  christos 	}
   3072  1.1  christos 
   3073  1.1  christos 	UNLOCK(&disp->lock);
   3074  1.1  christos 
   3075  1.1  christos 	*idp = id;
   3076  1.1  christos 	*resp = res;
   3077  1.1  christos 
   3078  1.1  christos 	if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
   3079  1.1  christos 		INSIST(res->dispsocket != NULL);
   3080  1.1  christos 	}
   3081  1.1  christos 
   3082  1.1  christos 	return (ISC_R_SUCCESS);
   3083  1.1  christos }
   3084  1.1  christos 
   3085  1.1  christos void
   3086  1.1  christos dns_dispatch_starttcp(dns_dispatch_t *disp) {
   3087  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3088  1.1  christos 
   3089  1.1  christos 	dispatch_log(disp, LVL(90), "starttcp %p", disp->task[0]);
   3090  1.1  christos 
   3091  1.1  christos 	LOCK(&disp->lock);
   3092  1.1  christos 	if ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) == 0) {
   3093  1.1  christos 		disp->attributes |= DNS_DISPATCHATTR_CONNECTED;
   3094  1.1  christos 		(void)startrecv(disp, NULL);
   3095  1.1  christos 	}
   3096  1.1  christos 	UNLOCK(&disp->lock);
   3097  1.1  christos }
   3098  1.1  christos 
   3099  1.1  christos isc_result_t
   3100  1.1  christos dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) {
   3101  1.1  christos 	dns_dispatch_t *disp;
   3102  1.1  christos 	dns_dispatchevent_t *ev;
   3103  1.1  christos 
   3104  1.1  christos 	REQUIRE(VALID_RESPONSE(resp));
   3105  1.1  christos 	REQUIRE(sockevent != NULL && *sockevent != NULL);
   3106  1.1  christos 
   3107  1.1  christos 	disp = resp->disp;
   3108  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3109  1.1  christos 
   3110  1.1  christos 	ev = *sockevent;
   3111  1.1  christos 	*sockevent = NULL;
   3112  1.1  christos 
   3113  1.1  christos 	LOCK(&disp->lock);
   3114  1.1  christos 
   3115  1.1  christos 	REQUIRE(resp->item_out);
   3116  1.1  christos 	resp->item_out = false;
   3117  1.1  christos 
   3118  1.1  christos 	if (ev->buffer.base != NULL) {
   3119  1.1  christos 		free_buffer(disp, ev->buffer.base, ev->buffer.length);
   3120  1.1  christos 	}
   3121  1.1  christos 	free_devent(disp, ev);
   3122  1.1  christos 
   3123  1.1  christos 	if (disp->shutting_down == 1) {
   3124  1.1  christos 		UNLOCK(&disp->lock);
   3125  1.1  christos 		return (ISC_R_SHUTTINGDOWN);
   3126  1.1  christos 	}
   3127  1.1  christos 	ev = ISC_LIST_HEAD(resp->items);
   3128  1.1  christos 	if (ev != NULL) {
   3129  1.1  christos 		ISC_LIST_UNLINK(resp->items, ev, ev_link);
   3130  1.1  christos 		ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH,
   3131  1.1  christos 			       resp->action, resp->arg, resp, NULL, NULL);
   3132  1.1  christos 		request_log(disp, resp, LVL(90),
   3133  1.1  christos 			    "[c] Sent event %p buffer %p len %d to task %p", ev,
   3134  1.1  christos 			    ev->buffer.base, ev->buffer.length, resp->task);
   3135  1.1  christos 		resp->item_out = true;
   3136  1.1  christos 		isc_task_send(resp->task, ISC_EVENT_PTR(&ev));
   3137  1.1  christos 	}
   3138  1.1  christos 	UNLOCK(&disp->lock);
   3139  1.1  christos 	return (ISC_R_SUCCESS);
   3140  1.1  christos }
   3141  1.1  christos 
   3142  1.1  christos void
   3143  1.1  christos dns_dispatch_removeresponse(dns_dispentry_t **resp,
   3144  1.1  christos 			    dns_dispatchevent_t **sockevent) {
   3145  1.1  christos 	dns_dispatchmgr_t *mgr;
   3146  1.1  christos 	dns_dispatch_t *disp;
   3147  1.1  christos 	dns_dispentry_t *res;
   3148  1.1  christos 	dispsocket_t *dispsock;
   3149  1.1  christos 	dns_dispatchevent_t *ev;
   3150  1.1  christos 	unsigned int bucket;
   3151  1.1  christos 	bool killit;
   3152  1.1  christos 	unsigned int n;
   3153  1.1  christos 	isc_eventlist_t events;
   3154  1.1  christos 	dns_qid_t *qid;
   3155  1.1  christos 
   3156  1.1  christos 	REQUIRE(resp != NULL);
   3157  1.1  christos 	REQUIRE(VALID_RESPONSE(*resp));
   3158  1.1  christos 
   3159  1.1  christos 	res = *resp;
   3160  1.1  christos 	*resp = NULL;
   3161  1.1  christos 
   3162  1.1  christos 	disp = res->disp;
   3163  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3164  1.1  christos 	mgr = disp->mgr;
   3165  1.1  christos 	REQUIRE(VALID_DISPATCHMGR(mgr));
   3166  1.1  christos 
   3167  1.1  christos 	qid = DNS_QID(disp);
   3168  1.1  christos 
   3169  1.1  christos 	if (sockevent != NULL) {
   3170  1.1  christos 		REQUIRE(*sockevent != NULL);
   3171  1.1  christos 		ev = *sockevent;
   3172  1.1  christos 		*sockevent = NULL;
   3173  1.1  christos 	} else {
   3174  1.1  christos 		ev = NULL;
   3175  1.1  christos 	}
   3176  1.1  christos 
   3177  1.1  christos 	LOCK(&disp->lock);
   3178  1.1  christos 
   3179  1.1  christos 	INSIST(disp->requests > 0);
   3180  1.1  christos 	disp->requests--;
   3181  1.1  christos 	dec_stats(disp->mgr, (qid == disp->mgr->qid)
   3182  1.1  christos 				     ? dns_resstatscounter_disprequdp
   3183  1.1  christos 				     : dns_resstatscounter_dispreqtcp);
   3184  1.1  christos 	INSIST(disp->refcount > 0);
   3185  1.1  christos 	disp->refcount--;
   3186  1.1  christos 	if (disp->refcount == 0) {
   3187  1.1  christos 		if (disp->recv_pending > 0) {
   3188  1.1  christos 			isc_socket_cancel(disp->socket, disp->task[0],
   3189  1.1  christos 					  ISC_SOCKCANCEL_RECV);
   3190  1.1  christos 		}
   3191  1.1  christos 		for (dispsock = ISC_LIST_HEAD(disp->activesockets);
   3192  1.1  christos 		     dispsock != NULL; dispsock = ISC_LIST_NEXT(dispsock, link))
   3193  1.1  christos 		{
   3194  1.1  christos 			isc_socket_cancel(dispsock->socket, dispsock->task,
   3195  1.1  christos 					  ISC_SOCKCANCEL_RECV);
   3196  1.1  christos 		}
   3197  1.1  christos 		disp->shutting_down = 1;
   3198  1.1  christos 	}
   3199  1.1  christos 
   3200  1.1  christos 	bucket = res->bucket;
   3201  1.1  christos 
   3202  1.1  christos 	LOCK(&qid->lock);
   3203  1.1  christos 	ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
   3204  1.1  christos 	UNLOCK(&qid->lock);
   3205  1.1  christos 
   3206  1.1  christos 	if (ev == NULL && res->item_out) {
   3207  1.1  christos 		/*
   3208  1.1  christos 		 * We've posted our event, but the caller hasn't gotten it
   3209  1.1  christos 		 * yet.  Take it back.
   3210  1.1  christos 		 */
   3211  1.1  christos 		ISC_LIST_INIT(events);
   3212  1.1  christos 		n = isc_task_unsend(res->task, res, DNS_EVENT_DISPATCH, NULL,
   3213  1.1  christos 				    &events);
   3214  1.1  christos 		/*
   3215  1.1  christos 		 * We had better have gotten it back.
   3216  1.1  christos 		 */
   3217  1.1  christos 		INSIST(n == 1);
   3218  1.1  christos 		ev = (dns_dispatchevent_t *)ISC_LIST_HEAD(events);
   3219  1.1  christos 	}
   3220  1.1  christos 
   3221  1.1  christos 	if (ev != NULL) {
   3222  1.1  christos 		REQUIRE(res->item_out);
   3223  1.1  christos 		res->item_out = false;
   3224  1.1  christos 		if (ev->buffer.base != NULL) {
   3225  1.1  christos 			free_buffer(disp, ev->buffer.base, ev->buffer.length);
   3226  1.1  christos 		}
   3227  1.1  christos 		free_devent(disp, ev);
   3228  1.1  christos 	}
   3229  1.1  christos 
   3230  1.1  christos 	request_log(disp, res, LVL(90), "detaching from task %p", res->task);
   3231  1.1  christos 	isc_task_detach(&res->task);
   3232  1.1  christos 
   3233  1.1  christos 	if (res->dispsocket != NULL) {
   3234  1.1  christos 		isc_socket_cancel(res->dispsocket->socket,
   3235  1.1  christos 				  res->dispsocket->task, ISC_SOCKCANCEL_RECV);
   3236  1.1  christos 		res->dispsocket->resp = NULL;
   3237  1.1  christos 	}
   3238  1.1  christos 
   3239  1.1  christos 	/*
   3240  1.1  christos 	 * Free any buffered responses as well
   3241  1.1  christos 	 */
   3242  1.1  christos 	ev = ISC_LIST_HEAD(res->items);
   3243  1.1  christos 	while (ev != NULL) {
   3244  1.1  christos 		ISC_LIST_UNLINK(res->items, ev, ev_link);
   3245  1.1  christos 		if (ev->buffer.base != NULL) {
   3246  1.1  christos 			free_buffer(disp, ev->buffer.base, ev->buffer.length);
   3247  1.1  christos 		}
   3248  1.1  christos 		free_devent(disp, ev);
   3249  1.1  christos 		ev = ISC_LIST_HEAD(res->items);
   3250  1.1  christos 	}
   3251  1.1  christos 	res->magic = 0;
   3252  1.1  christos 	isc_refcount_decrement(&disp->mgr->irefs);
   3253  1.1  christos 	isc_mem_put(disp->mgr->mctx, res, sizeof(*res));
   3254  1.1  christos 	if (disp->shutting_down == 1) {
   3255  1.1  christos 		do_cancel(disp);
   3256  1.1  christos 	} else {
   3257  1.1  christos 		(void)startrecv(disp, NULL);
   3258  1.1  christos 	}
   3259  1.1  christos 
   3260  1.1  christos 	killit = destroy_disp_ok(disp);
   3261  1.1  christos 	UNLOCK(&disp->lock);
   3262  1.1  christos 	if (killit) {
   3263  1.1  christos 		isc_task_send(disp->task[0], &disp->ctlevent);
   3264  1.1  christos 	}
   3265  1.1  christos }
   3266  1.1  christos 
   3267  1.1  christos /*
   3268  1.1  christos  * disp must be locked.
   3269  1.1  christos  */
   3270  1.1  christos static void
   3271  1.1  christos do_cancel(dns_dispatch_t *disp) {
   3272  1.1  christos 	dns_dispatchevent_t *ev;
   3273  1.1  christos 	dns_dispentry_t *resp;
   3274  1.1  christos 	dns_qid_t *qid;
   3275  1.1  christos 
   3276  1.1  christos 	if (disp->shutdown_out == 1) {
   3277  1.1  christos 		return;
   3278  1.1  christos 	}
   3279  1.1  christos 
   3280  1.1  christos 	qid = DNS_QID(disp);
   3281  1.1  christos 
   3282  1.1  christos 	/*
   3283  1.1  christos 	 * Search for the first response handler without packets outstanding
   3284  1.1  christos 	 * unless a specific handler is given.
   3285  1.1  christos 	 */
   3286  1.1  christos 	LOCK(&qid->lock);
   3287  1.1  christos 	for (resp = linear_first(qid); resp != NULL && resp->item_out;
   3288  1.1  christos 	     /* Empty. */)
   3289  1.1  christos 	{
   3290  1.1  christos 		resp = linear_next(qid, resp);
   3291  1.1  christos 	}
   3292  1.1  christos 
   3293  1.1  christos 	/*
   3294  1.1  christos 	 * No one to send the cancel event to, so nothing to do.
   3295  1.1  christos 	 */
   3296  1.1  christos 	if (resp == NULL) {
   3297  1.1  christos 		goto unlock;
   3298  1.1  christos 	}
   3299  1.1  christos 
   3300  1.1  christos 	/*
   3301  1.1  christos 	 * Send the shutdown failsafe event to this resp.
   3302  1.1  christos 	 */
   3303  1.1  christos 	ev = disp->failsafe_ev;
   3304  1.1  christos 	ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH,
   3305  1.1  christos 		       resp->action, resp->arg, resp, NULL, NULL);
   3306  1.1  christos 	ev->result = disp->shutdown_why;
   3307  1.1  christos 	ev->buffer.base = NULL;
   3308  1.1  christos 	ev->buffer.length = 0;
   3309  1.1  christos 	disp->shutdown_out = 1;
   3310  1.1  christos 	request_log(disp, resp, LVL(10), "cancel: failsafe event %p -> task %p",
   3311  1.1  christos 		    ev, resp->task);
   3312  1.1  christos 	resp->item_out = true;
   3313  1.1  christos 	isc_task_send(resp->task, ISC_EVENT_PTR(&ev));
   3314  1.1  christos unlock:
   3315  1.1  christos 	UNLOCK(&qid->lock);
   3316  1.1  christos }
   3317  1.1  christos 
   3318  1.1  christos isc_socket_t *
   3319  1.1  christos dns_dispatch_getsocket(dns_dispatch_t *disp) {
   3320  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3321  1.1  christos 
   3322  1.1  christos 	return (disp->socket);
   3323  1.1  christos }
   3324  1.1  christos 
   3325  1.1  christos isc_socket_t *
   3326  1.1  christos dns_dispatch_getentrysocket(dns_dispentry_t *resp) {
   3327  1.1  christos 	REQUIRE(VALID_RESPONSE(resp));
   3328  1.1  christos 
   3329  1.1  christos 	if (resp->dispsocket != NULL) {
   3330  1.1  christos 		return (resp->dispsocket->socket);
   3331  1.1  christos 	} else {
   3332  1.1  christos 		return (NULL);
   3333  1.1  christos 	}
   3334  1.1  christos }
   3335  1.1  christos 
   3336  1.1  christos isc_result_t
   3337  1.1  christos dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) {
   3338  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3339  1.1  christos 	REQUIRE(addrp != NULL);
   3340  1.1  christos 
   3341  1.1  christos 	if (disp->socktype == isc_sockettype_udp) {
   3342  1.1  christos 		*addrp = disp->local;
   3343  1.1  christos 		return (ISC_R_SUCCESS);
   3344  1.1  christos 	}
   3345  1.1  christos 	return (ISC_R_NOTIMPLEMENTED);
   3346  1.1  christos }
   3347  1.1  christos 
   3348  1.1  christos void
   3349  1.1  christos dns_dispatch_cancel(dns_dispatch_t *disp) {
   3350  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3351  1.1  christos 
   3352  1.1  christos 	LOCK(&disp->lock);
   3353  1.1  christos 
   3354  1.1  christos 	if (disp->shutting_down == 1) {
   3355  1.1  christos 		UNLOCK(&disp->lock);
   3356  1.1  christos 		return;
   3357  1.1  christos 	}
   3358  1.1  christos 
   3359  1.1  christos 	disp->shutdown_why = ISC_R_CANCELED;
   3360  1.1  christos 	disp->shutting_down = 1;
   3361  1.1  christos 	do_cancel(disp);
   3362  1.1  christos 
   3363  1.1  christos 	UNLOCK(&disp->lock);
   3364  1.1  christos 
   3365  1.1  christos 	return;
   3366  1.1  christos }
   3367  1.1  christos 
   3368  1.1  christos unsigned int
   3369  1.1  christos dns_dispatch_getattributes(dns_dispatch_t *disp) {
   3370  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3371  1.1  christos 
   3372  1.1  christos 	/*
   3373  1.1  christos 	 * We don't bother locking disp here; it's the caller's responsibility
   3374  1.1  christos 	 * to use only non volatile flags.
   3375  1.1  christos 	 */
   3376  1.1  christos 	return (disp->attributes);
   3377  1.1  christos }
   3378  1.1  christos 
   3379  1.1  christos void
   3380  1.1  christos dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes,
   3381  1.1  christos 			      unsigned int mask) {
   3382  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3383  1.1  christos 	/* Exclusive attribute can only be set on creation */
   3384  1.1  christos 	REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0);
   3385  1.1  christos 	/* Also, a dispatch with randomport specified cannot start listening */
   3386  1.1  christos 	REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0 ||
   3387  1.1  christos 		(attributes & DNS_DISPATCHATTR_NOLISTEN) == 0);
   3388  1.1  christos 
   3389  1.1  christos 	/* XXXMLG
   3390  1.1  christos 	 * Should check for valid attributes here!
   3391  1.1  christos 	 */
   3392  1.1  christos 
   3393  1.1  christos 	LOCK(&disp->lock);
   3394  1.1  christos 
   3395  1.1  christos 	if ((mask & DNS_DISPATCHATTR_NOLISTEN) != 0) {
   3396  1.1  christos 		if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 &&
   3397  1.1  christos 		    (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0)
   3398  1.1  christos 		{
   3399  1.1  christos 			disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN;
   3400  1.1  christos 			(void)startrecv(disp, NULL);
   3401  1.1  christos 		} else if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) ==
   3402  1.1  christos 				   0 &&
   3403  1.1  christos 			   (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
   3404  1.1  christos 		{
   3405  1.1  christos 			disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
   3406  1.1  christos 			if (disp->recv_pending != 0) {
   3407  1.1  christos 				isc_socket_cancel(disp->socket, disp->task[0],
   3408  1.1  christos 						  ISC_SOCKCANCEL_RECV);
   3409  1.1  christos 			}
   3410  1.1  christos 		}
   3411  1.1  christos 	}
   3412  1.1  christos 
   3413  1.1  christos 	disp->attributes &= ~mask;
   3414  1.1  christos 	disp->attributes |= (attributes & mask);
   3415  1.1  christos 	UNLOCK(&disp->lock);
   3416  1.1  christos }
   3417  1.1  christos 
   3418  1.1  christos void
   3419  1.1  christos dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) {
   3420  1.1  christos 	void *buf;
   3421  1.1  christos 	isc_socketevent_t *sevent, *newsevent;
   3422  1.1  christos 
   3423  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3424  1.1  christos 	REQUIRE(event != NULL);
   3425  1.1  christos 
   3426  1.1  christos 	if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) {
   3427  1.1  christos 		return;
   3428  1.1  christos 	}
   3429  1.1  christos 
   3430  1.1  christos 	sevent = (isc_socketevent_t *)event;
   3431  1.1  christos 	INSIST(sevent->n <= disp->mgr->buffersize);
   3432  1.1  christos 
   3433  1.1  christos 	newsevent = (isc_socketevent_t *)isc_event_allocate(
   3434  1.1  christos 		disp->mgr->mctx, NULL, DNS_EVENT_IMPORTRECVDONE, udp_shrecv,
   3435  1.1  christos 		disp, sizeof(isc_socketevent_t));
   3436  1.1  christos 
   3437  1.1  christos 	buf = allocate_udp_buffer(disp);
   3438  1.1  christos 	if (buf == NULL) {
   3439  1.1  christos 		isc_event_free(ISC_EVENT_PTR(&newsevent));
   3440  1.1  christos 		return;
   3441  1.1  christos 	}
   3442  1.1  christos 	memmove(buf, sevent->region.base, sevent->n);
   3443  1.1  christos 	newsevent->region.base = buf;
   3444  1.1  christos 	newsevent->region.length = disp->mgr->buffersize;
   3445  1.1  christos 	newsevent->n = sevent->n;
   3446  1.1  christos 	newsevent->result = sevent->result;
   3447  1.1  christos 	newsevent->address = sevent->address;
   3448  1.1  christos 	newsevent->timestamp = sevent->timestamp;
   3449  1.1  christos 	newsevent->pktinfo = sevent->pktinfo;
   3450  1.1  christos 	newsevent->attributes = sevent->attributes;
   3451  1.1  christos 
   3452  1.1  christos 	isc_task_send(disp->task[0], ISC_EVENT_PTR(&newsevent));
   3453  1.1  christos }
   3454  1.1  christos 
   3455  1.1  christos dns_dispatch_t *
   3456  1.1  christos dns_dispatchset_get(dns_dispatchset_t *dset) {
   3457  1.1  christos 	dns_dispatch_t *disp;
   3458  1.1  christos 
   3459  1.1  christos 	/* check that dispatch set is configured */
   3460  1.1  christos 	if (dset == NULL || dset->ndisp == 0) {
   3461  1.1  christos 		return (NULL);
   3462  1.1  christos 	}
   3463  1.1  christos 
   3464  1.1  christos 	LOCK(&dset->lock);
   3465  1.1  christos 	disp = dset->dispatches[dset->cur];
   3466  1.1  christos 	dset->cur++;
   3467  1.1  christos 	if (dset->cur == dset->ndisp) {
   3468  1.1  christos 		dset->cur = 0;
   3469  1.1  christos 	}
   3470  1.1  christos 	UNLOCK(&dset->lock);
   3471  1.1  christos 
   3472  1.1  christos 	return (disp);
   3473  1.1  christos }
   3474  1.1  christos 
   3475  1.1  christos isc_result_t
   3476  1.1  christos dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr,
   3477  1.1  christos 		       isc_taskmgr_t *taskmgr, dns_dispatch_t *source,
   3478  1.1  christos 		       dns_dispatchset_t **dsetp, int n) {
   3479  1.1  christos 	isc_result_t result;
   3480  1.1  christos 	dns_dispatchset_t *dset;
   3481  1.1  christos 	dns_dispatchmgr_t *mgr;
   3482  1.1  christos 	int i, j;
   3483  1.1  christos 
   3484  1.1  christos 	REQUIRE(VALID_DISPATCH(source));
   3485  1.1  christos 	REQUIRE((source->attributes & DNS_DISPATCHATTR_UDP) != 0);
   3486  1.1  christos 	REQUIRE(dsetp != NULL && *dsetp == NULL);
   3487  1.1  christos 
   3488  1.1  christos 	mgr = source->mgr;
   3489  1.1  christos 
   3490  1.1  christos 	dset = isc_mem_get(mctx, sizeof(dns_dispatchset_t));
   3491  1.1  christos 	memset(dset, 0, sizeof(*dset));
   3492  1.1  christos 
   3493  1.1  christos 	isc_mutex_init(&dset->lock);
   3494  1.1  christos 
   3495  1.1  christos 	dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n);
   3496  1.1  christos 
   3497  1.1  christos 	isc_mem_attach(mctx, &dset->mctx);
   3498  1.1  christos 	dset->ndisp = n;
   3499  1.1  christos 	dset->cur = 0;
   3500  1.1  christos 
   3501  1.1  christos 	dset->dispatches[0] = NULL;
   3502  1.1  christos 	dns_dispatch_attach(source, &dset->dispatches[0]);
   3503  1.1  christos 
   3504  1.1  christos 	LOCK(&mgr->lock);
   3505  1.1  christos 	for (i = 1; i < n; i++) {
   3506  1.1  christos 		dset->dispatches[i] = NULL;
   3507  1.1  christos 		result = dispatch_createudp(
   3508  1.1  christos 			mgr, sockmgr, taskmgr, &source->local,
   3509  1.1  christos 			source->maxrequests, source->attributes,
   3510  1.1  christos 			&dset->dispatches[i], source->socket);
   3511  1.1  christos 		if (result != ISC_R_SUCCESS) {
   3512  1.1  christos 			goto fail;
   3513  1.1  christos 		}
   3514  1.1  christos 	}
   3515  1.1  christos 
   3516  1.1  christos 	UNLOCK(&mgr->lock);
   3517  1.1  christos 	*dsetp = dset;
   3518  1.1  christos 
   3519  1.1  christos 	return (ISC_R_SUCCESS);
   3520  1.1  christos 
   3521  1.1  christos fail:
   3522  1.1  christos 	UNLOCK(&mgr->lock);
   3523  1.1  christos 
   3524  1.1  christos 	for (j = 0; j < i; j++) {
   3525  1.1  christos 		dns_dispatch_detach(&(dset->dispatches[j]));
   3526  1.1  christos 	}
   3527  1.1  christos 	isc_mem_put(mctx, dset->dispatches, sizeof(dns_dispatch_t *) * n);
   3528  1.1  christos 	if (dset->mctx == mctx) {
   3529  1.1  christos 		isc_mem_detach(&dset->mctx);
   3530  1.1  christos 	}
   3531  1.1  christos 
   3532  1.1  christos 	isc_mutex_destroy(&dset->lock);
   3533  1.1  christos 	isc_mem_put(mctx, dset, sizeof(dns_dispatchset_t));
   3534  1.1  christos 	return (result);
   3535  1.1  christos }
   3536  1.1  christos 
   3537  1.1  christos void
   3538  1.1  christos dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task) {
   3539  1.1  christos 	int i;
   3540  1.1  christos 
   3541  1.1  christos 	REQUIRE(dset != NULL);
   3542  1.1  christos 
   3543  1.1  christos 	for (i = 0; i < dset->ndisp; i++) {
   3544  1.1  christos 		isc_socket_t *sock;
   3545  1.1  christos 		sock = dns_dispatch_getsocket(dset->dispatches[i]);
   3546  1.1  christos 		isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
   3547  1.1  christos 	}
   3548  1.1  christos }
   3549  1.1  christos 
   3550  1.1  christos void
   3551  1.1  christos dns_dispatchset_destroy(dns_dispatchset_t **dsetp) {
   3552  1.1  christos 	dns_dispatchset_t *dset;
   3553  1.1  christos 	int i;
   3554  1.1  christos 
   3555  1.1  christos 	REQUIRE(dsetp != NULL && *dsetp != NULL);
   3556  1.1  christos 
   3557  1.1  christos 	dset = *dsetp;
   3558  1.1  christos 	*dsetp = NULL;
   3559  1.1  christos 	for (i = 0; i < dset->ndisp; i++) {
   3560  1.1  christos 		dns_dispatch_detach(&(dset->dispatches[i]));
   3561  1.1  christos 	}
   3562  1.1  christos 	isc_mem_put(dset->mctx, dset->dispatches,
   3563  1.1  christos 		    sizeof(dns_dispatch_t *) * dset->ndisp);
   3564  1.1  christos 	isc_mutex_destroy(&dset->lock);
   3565  1.1  christos 	isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t));
   3566  1.1  christos }
   3567  1.1  christos 
   3568  1.1  christos void
   3569  1.1  christos dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp) {
   3570  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3571  1.1  christos 	disp->dscp = dscp;
   3572  1.1  christos }
   3573  1.1  christos 
   3574  1.1  christos isc_dscp_t
   3575  1.1  christos dns_dispatch_getdscp(dns_dispatch_t *disp) {
   3576  1.1  christos 	REQUIRE(VALID_DISPATCH(disp));
   3577  1.1  christos 	return (disp->dscp);
   3578  1.1  christos }
   3579  1.1  christos 
   3580  1.1  christos #if 0
   3581  1.1  christos void
   3582  1.1  christos dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) {
   3583  1.1  christos 	dns_dispatch_t *disp;
   3584  1.1  christos 	char foo[1024];
   3585  1.1  christos 
   3586  1.1  christos 	disp = ISC_LIST_HEAD(mgr->list);
   3587  1.1  christos 	while (disp != NULL) {
   3588  1.1  christos 		isc_sockaddr_format(&disp->local, foo, sizeof(foo));
   3589  1.1  christos 		printf("\tdispatch %p, addr %s\n", disp, foo);
   3590  1.1  christos 		disp = ISC_LIST_NEXT(disp, link);
   3591  1.1  christos 	}
   3592  1.1  christos }
   3593  1.1  christos #endif /* if 0 */
   3594