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