xref: /minix3/external/bsd/bind/dist/lib/isc/win32/socket.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: socket.c,v 1.10 2015/07/08 17:29:00 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 2000-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 */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /* This code uses functions which are only available on Server 2003 and
23*00b67f09SDavid van Moolenbroek  * higher, and Windows XP and higher.
24*00b67f09SDavid van Moolenbroek  *
25*00b67f09SDavid van Moolenbroek  * This code is by nature multithreaded and takes advantage of various
26*00b67f09SDavid van Moolenbroek  * features to pass on information through the completion port for
27*00b67f09SDavid van Moolenbroek  * when I/O is completed.  All sends, receives, accepts, and connects are
28*00b67f09SDavid van Moolenbroek  * completed through the completion port.
29*00b67f09SDavid van Moolenbroek  *
30*00b67f09SDavid van Moolenbroek  * The number of Completion Port Worker threads used is the total number
31*00b67f09SDavid van Moolenbroek  * of CPU's + 1. This increases the likelihood that a Worker Thread is
32*00b67f09SDavid van Moolenbroek  * available for processing a completed request.
33*00b67f09SDavid van Moolenbroek  *
34*00b67f09SDavid van Moolenbroek  * XXXPDM 5 August, 2002
35*00b67f09SDavid van Moolenbroek  */
36*00b67f09SDavid van Moolenbroek 
37*00b67f09SDavid van Moolenbroek #define MAKE_EXTERNAL 1
38*00b67f09SDavid van Moolenbroek #include <config.h>
39*00b67f09SDavid van Moolenbroek 
40*00b67f09SDavid van Moolenbroek #include <sys/types.h>
41*00b67f09SDavid van Moolenbroek 
42*00b67f09SDavid van Moolenbroek #ifndef _WINSOCKAPI_
43*00b67f09SDavid van Moolenbroek #define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
44*00b67f09SDavid van Moolenbroek #endif
45*00b67f09SDavid van Moolenbroek 
46*00b67f09SDavid van Moolenbroek #include <errno.h>
47*00b67f09SDavid van Moolenbroek #include <stddef.h>
48*00b67f09SDavid van Moolenbroek #include <stdlib.h>
49*00b67f09SDavid van Moolenbroek #include <string.h>
50*00b67f09SDavid van Moolenbroek #include <unistd.h>
51*00b67f09SDavid van Moolenbroek #include <io.h>
52*00b67f09SDavid van Moolenbroek #include <fcntl.h>
53*00b67f09SDavid van Moolenbroek #include <process.h>
54*00b67f09SDavid van Moolenbroek 
55*00b67f09SDavid van Moolenbroek #include <isc/app.h>
56*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
57*00b67f09SDavid van Moolenbroek #include <isc/bufferlist.h>
58*00b67f09SDavid van Moolenbroek #include <isc/condition.h>
59*00b67f09SDavid van Moolenbroek #include <isc/list.h>
60*00b67f09SDavid van Moolenbroek #include <isc/log.h>
61*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
62*00b67f09SDavid van Moolenbroek #include <isc/msgs.h>
63*00b67f09SDavid van Moolenbroek #include <isc/mutex.h>
64*00b67f09SDavid van Moolenbroek #include <isc/net.h>
65*00b67f09SDavid van Moolenbroek #include <isc/once.h>
66*00b67f09SDavid van Moolenbroek #include <isc/os.h>
67*00b67f09SDavid van Moolenbroek #include <isc/platform.h>
68*00b67f09SDavid van Moolenbroek #include <isc/print.h>
69*00b67f09SDavid van Moolenbroek #include <isc/region.h>
70*00b67f09SDavid van Moolenbroek #include <isc/socket.h>
71*00b67f09SDavid van Moolenbroek #include <isc/stats.h>
72*00b67f09SDavid van Moolenbroek #include <isc/strerror.h>
73*00b67f09SDavid van Moolenbroek #include <isc/syslog.h>
74*00b67f09SDavid van Moolenbroek #include <isc/task.h>
75*00b67f09SDavid van Moolenbroek #include <isc/thread.h>
76*00b67f09SDavid van Moolenbroek #include <isc/util.h>
77*00b67f09SDavid van Moolenbroek #include <isc/win32os.h>
78*00b67f09SDavid van Moolenbroek 
79*00b67f09SDavid van Moolenbroek #include <mswsock.h>
80*00b67f09SDavid van Moolenbroek 
81*00b67f09SDavid van Moolenbroek #include "errno2result.h"
82*00b67f09SDavid van Moolenbroek 
83*00b67f09SDavid van Moolenbroek /*
84*00b67f09SDavid van Moolenbroek  * Set by the -T dscp option on the command line. If set to a value
85*00b67f09SDavid van Moolenbroek  * other than -1, we check to make sure DSCP values match it, and
86*00b67f09SDavid van Moolenbroek  * assert if not.
87*00b67f09SDavid van Moolenbroek  */
88*00b67f09SDavid van Moolenbroek int isc_dscp_check_value = -1;
89*00b67f09SDavid van Moolenbroek 
90*00b67f09SDavid van Moolenbroek /*
91*00b67f09SDavid van Moolenbroek  * How in the world can Microsoft exist with APIs like this?
92*00b67f09SDavid van Moolenbroek  * We can't actually call this directly, because it turns out
93*00b67f09SDavid van Moolenbroek  * no library exports this function.  Instead, we need to
94*00b67f09SDavid van Moolenbroek  * issue a runtime call to get the address.
95*00b67f09SDavid van Moolenbroek  */
96*00b67f09SDavid van Moolenbroek LPFN_CONNECTEX ISCConnectEx;
97*00b67f09SDavid van Moolenbroek LPFN_ACCEPTEX ISCAcceptEx;
98*00b67f09SDavid van Moolenbroek LPFN_GETACCEPTEXSOCKADDRS ISCGetAcceptExSockaddrs;
99*00b67f09SDavid van Moolenbroek 
100*00b67f09SDavid van Moolenbroek /*
101*00b67f09SDavid van Moolenbroek  * Run expensive internal consistency checks.
102*00b67f09SDavid van Moolenbroek  */
103*00b67f09SDavid van Moolenbroek #ifdef ISC_SOCKET_CONSISTENCY_CHECKS
104*00b67f09SDavid van Moolenbroek #define CONSISTENT(sock) consistent(sock)
105*00b67f09SDavid van Moolenbroek #else
106*00b67f09SDavid van Moolenbroek #define CONSISTENT(sock) do {} while (/*CONSTCOND*/0)
107*00b67f09SDavid van Moolenbroek #endif
108*00b67f09SDavid van Moolenbroek static void consistent(isc_socket_t *sock);
109*00b67f09SDavid van Moolenbroek 
110*00b67f09SDavid van Moolenbroek /*
111*00b67f09SDavid van Moolenbroek  * Define this macro to control the behavior of connection
112*00b67f09SDavid van Moolenbroek  * resets on UDP sockets.  See Microsoft KnowledgeBase Article Q263823
113*00b67f09SDavid van Moolenbroek  * for details.
114*00b67f09SDavid van Moolenbroek  * NOTE: This requires that Windows 2000 systems install Service Pack 2
115*00b67f09SDavid van Moolenbroek  * or later.
116*00b67f09SDavid van Moolenbroek  */
117*00b67f09SDavid van Moolenbroek #ifndef SIO_UDP_CONNRESET
118*00b67f09SDavid van Moolenbroek #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
119*00b67f09SDavid van Moolenbroek #endif
120*00b67f09SDavid van Moolenbroek 
121*00b67f09SDavid van Moolenbroek /*
122*00b67f09SDavid van Moolenbroek  * Some systems define the socket length argument as an int, some as size_t,
123*00b67f09SDavid van Moolenbroek  * some as socklen_t.  This is here so it can be easily changed if needed.
124*00b67f09SDavid van Moolenbroek  */
125*00b67f09SDavid van Moolenbroek #ifndef ISC_SOCKADDR_LEN_T
126*00b67f09SDavid van Moolenbroek #define ISC_SOCKADDR_LEN_T unsigned int
127*00b67f09SDavid van Moolenbroek #endif
128*00b67f09SDavid van Moolenbroek 
129*00b67f09SDavid van Moolenbroek /*
130*00b67f09SDavid van Moolenbroek  * Define what the possible "soft" errors can be.  These are non-fatal returns
131*00b67f09SDavid van Moolenbroek  * of various network related functions, like recv() and so on.
132*00b67f09SDavid van Moolenbroek  */
133*00b67f09SDavid van Moolenbroek #define SOFT_ERROR(e)	((e) == WSAEINTR || \
134*00b67f09SDavid van Moolenbroek 			 (e) == WSAEWOULDBLOCK || \
135*00b67f09SDavid van Moolenbroek 			 (e) == EWOULDBLOCK || \
136*00b67f09SDavid van Moolenbroek 			 (e) == EINTR || \
137*00b67f09SDavid van Moolenbroek 			 (e) == EAGAIN || \
138*00b67f09SDavid van Moolenbroek 			 (e) == 0)
139*00b67f09SDavid van Moolenbroek 
140*00b67f09SDavid van Moolenbroek /*
141*00b67f09SDavid van Moolenbroek  * Pending errors are not really errors and should be
142*00b67f09SDavid van Moolenbroek  * kept separate
143*00b67f09SDavid van Moolenbroek  */
144*00b67f09SDavid van Moolenbroek #define PENDING_ERROR(e) ((e) == WSA_IO_PENDING || (e) == 0)
145*00b67f09SDavid van Moolenbroek 
146*00b67f09SDavid van Moolenbroek #define DOIO_SUCCESS	  0       /* i/o ok, event sent */
147*00b67f09SDavid van Moolenbroek #define DOIO_SOFT	  1       /* i/o ok, soft error, no event sent */
148*00b67f09SDavid van Moolenbroek #define DOIO_HARD	  2       /* i/o error, event sent */
149*00b67f09SDavid van Moolenbroek #define DOIO_EOF	  3       /* EOF, no event sent */
150*00b67f09SDavid van Moolenbroek #define DOIO_PENDING	  4       /* status when i/o is in process */
151*00b67f09SDavid van Moolenbroek #define DOIO_NEEDMORE	  5       /* IO was processed, but we need more due to minimum */
152*00b67f09SDavid van Moolenbroek 
153*00b67f09SDavid van Moolenbroek #define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x)
154*00b67f09SDavid van Moolenbroek 
155*00b67f09SDavid van Moolenbroek /*
156*00b67f09SDavid van Moolenbroek  * DLVL(90)  --  Function entry/exit and other tracing.
157*00b67f09SDavid van Moolenbroek  * DLVL(70)  --  Socket "correctness" -- including returning of events, etc.
158*00b67f09SDavid van Moolenbroek  * DLVL(60)  --  Socket data send/receive
159*00b67f09SDavid van Moolenbroek  * DLVL(50)  --  Event tracing, including receiving/sending completion events.
160*00b67f09SDavid van Moolenbroek  * DLVL(20)  --  Socket creation/destruction.
161*00b67f09SDavid van Moolenbroek  */
162*00b67f09SDavid van Moolenbroek #define TRACE_LEVEL		90
163*00b67f09SDavid van Moolenbroek #define CORRECTNESS_LEVEL	70
164*00b67f09SDavid van Moolenbroek #define IOEVENT_LEVEL		60
165*00b67f09SDavid van Moolenbroek #define EVENT_LEVEL		50
166*00b67f09SDavid van Moolenbroek #define CREATION_LEVEL		20
167*00b67f09SDavid van Moolenbroek 
168*00b67f09SDavid van Moolenbroek #define TRACE		DLVL(TRACE_LEVEL)
169*00b67f09SDavid van Moolenbroek #define CORRECTNESS	DLVL(CORRECTNESS_LEVEL)
170*00b67f09SDavid van Moolenbroek #define IOEVENT		DLVL(IOEVENT_LEVEL)
171*00b67f09SDavid van Moolenbroek #define EVENT		DLVL(EVENT_LEVEL)
172*00b67f09SDavid van Moolenbroek #define CREATION	DLVL(CREATION_LEVEL)
173*00b67f09SDavid van Moolenbroek 
174*00b67f09SDavid van Moolenbroek typedef isc_event_t intev_t;
175*00b67f09SDavid van Moolenbroek 
176*00b67f09SDavid van Moolenbroek /*
177*00b67f09SDavid van Moolenbroek  * Socket State
178*00b67f09SDavid van Moolenbroek  */
179*00b67f09SDavid van Moolenbroek enum {
180*00b67f09SDavid van Moolenbroek   SOCK_INITIALIZED,	/* Socket Initialized */
181*00b67f09SDavid van Moolenbroek   SOCK_OPEN,		/* Socket opened but nothing yet to do */
182*00b67f09SDavid van Moolenbroek   SOCK_DATA,		/* Socket sending or receiving data */
183*00b67f09SDavid van Moolenbroek   SOCK_LISTEN,		/* TCP Socket listening for connects */
184*00b67f09SDavid van Moolenbroek   SOCK_ACCEPT,		/* TCP socket is waiting to accept */
185*00b67f09SDavid van Moolenbroek   SOCK_CONNECT,		/* TCP Socket connecting */
186*00b67f09SDavid van Moolenbroek   SOCK_CLOSED,		/* Socket has been closed */
187*00b67f09SDavid van Moolenbroek };
188*00b67f09SDavid van Moolenbroek 
189*00b67f09SDavid van Moolenbroek #define SOCKET_MAGIC		ISC_MAGIC('I', 'O', 'i', 'o')
190*00b67f09SDavid van Moolenbroek #define VALID_SOCKET(t)		ISC_MAGIC_VALID(t, SOCKET_MAGIC)
191*00b67f09SDavid van Moolenbroek 
192*00b67f09SDavid van Moolenbroek /*
193*00b67f09SDavid van Moolenbroek  * IPv6 control information.  If the socket is an IPv6 socket we want
194*00b67f09SDavid van Moolenbroek  * to collect the destination address and interface so the client can
195*00b67f09SDavid van Moolenbroek  * set them on outgoing packets.
196*00b67f09SDavid van Moolenbroek  */
197*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIPV6
198*00b67f09SDavid van Moolenbroek #ifndef USE_CMSG
199*00b67f09SDavid van Moolenbroek #define USE_CMSG	1
200*00b67f09SDavid van Moolenbroek #endif
201*00b67f09SDavid van Moolenbroek #endif
202*00b67f09SDavid van Moolenbroek 
203*00b67f09SDavid van Moolenbroek /*
204*00b67f09SDavid van Moolenbroek  * We really  don't want to try and use these control messages. Win32
205*00b67f09SDavid van Moolenbroek  * doesn't have this mechanism before XP.
206*00b67f09SDavid van Moolenbroek  */
207*00b67f09SDavid van Moolenbroek #undef USE_CMSG
208*00b67f09SDavid van Moolenbroek 
209*00b67f09SDavid van Moolenbroek /*
210*00b67f09SDavid van Moolenbroek  * Message header for recvmsg and sendmsg calls.
211*00b67f09SDavid van Moolenbroek  * Used value-result for recvmsg, value only for sendmsg.
212*00b67f09SDavid van Moolenbroek  */
213*00b67f09SDavid van Moolenbroek struct msghdr {
214*00b67f09SDavid van Moolenbroek 	SOCKADDR_STORAGE to_addr;	/* UDP send/recv address */
215*00b67f09SDavid van Moolenbroek 	int      to_addr_len;		/* length of the address */
216*00b67f09SDavid van Moolenbroek 	WSABUF  *msg_iov;		/* scatter/gather array */
217*00b67f09SDavid van Moolenbroek 	u_int   msg_iovlen;             /* # elements in msg_iov */
218*00b67f09SDavid van Moolenbroek 	void	*msg_control;           /* ancillary data, see below */
219*00b67f09SDavid van Moolenbroek 	u_int   msg_controllen;         /* ancillary data buffer len */
220*00b67f09SDavid van Moolenbroek 	u_int	msg_totallen;		/* total length of this message */
221*00b67f09SDavid van Moolenbroek } msghdr;
222*00b67f09SDavid van Moolenbroek 
223*00b67f09SDavid van Moolenbroek /*
224*00b67f09SDavid van Moolenbroek  * The size to raise the receive buffer to.
225*00b67f09SDavid van Moolenbroek  */
226*00b67f09SDavid van Moolenbroek #define RCVBUFSIZE (32*1024)
227*00b67f09SDavid van Moolenbroek 
228*00b67f09SDavid van Moolenbroek /*
229*00b67f09SDavid van Moolenbroek  * The number of times a send operation is repeated if the result
230*00b67f09SDavid van Moolenbroek  * is WSAEINTR.
231*00b67f09SDavid van Moolenbroek  */
232*00b67f09SDavid van Moolenbroek #define NRETRIES 10
233*00b67f09SDavid van Moolenbroek 
234*00b67f09SDavid van Moolenbroek struct isc_socket {
235*00b67f09SDavid van Moolenbroek 	/* Not locked. */
236*00b67f09SDavid van Moolenbroek 	unsigned int		magic;
237*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t	       *manager;
238*00b67f09SDavid van Moolenbroek 	isc_mutex_t		lock;
239*00b67f09SDavid van Moolenbroek 	isc_sockettype_t	type;
240*00b67f09SDavid van Moolenbroek 
241*00b67f09SDavid van Moolenbroek 	/* Pointers to scatter/gather buffers */
242*00b67f09SDavid van Moolenbroek 	WSABUF			iov[ISC_SOCKET_MAXSCATTERGATHER];
243*00b67f09SDavid van Moolenbroek 
244*00b67f09SDavid van Moolenbroek 	/* Locked by socket lock. */
245*00b67f09SDavid van Moolenbroek 	ISC_LINK(isc_socket_t)	link;
246*00b67f09SDavid van Moolenbroek 	unsigned int		references; /* EXTERNAL references */
247*00b67f09SDavid van Moolenbroek 	SOCKET			fd;	/* file handle */
248*00b67f09SDavid van Moolenbroek 	int			pf;	/* protocol family */
249*00b67f09SDavid van Moolenbroek 	char			name[16];
250*00b67f09SDavid van Moolenbroek 	void *			tag;
251*00b67f09SDavid van Moolenbroek 
252*00b67f09SDavid van Moolenbroek 	/*
253*00b67f09SDavid van Moolenbroek 	 * Each recv() call uses this buffer.  It is a per-socket receive
254*00b67f09SDavid van Moolenbroek 	 * buffer that allows us to decouple the system recv() from the
255*00b67f09SDavid van Moolenbroek 	 * recv_list done events.  This means the items on the recv_list
256*00b67f09SDavid van Moolenbroek 	 * can be removed without having to cancel pending system recv()
257*00b67f09SDavid van Moolenbroek 	 * calls.  It also allows us to read-ahead in some cases.
258*00b67f09SDavid van Moolenbroek 	 */
259*00b67f09SDavid van Moolenbroek 	struct {
260*00b67f09SDavid van Moolenbroek 		SOCKADDR_STORAGE	from_addr;	   // UDP send/recv address
261*00b67f09SDavid van Moolenbroek 		int		from_addr_len;	   // length of the address
262*00b67f09SDavid van Moolenbroek 		char		*base;		   // the base of the buffer
263*00b67f09SDavid van Moolenbroek 		char		*consume_position; // where to start copying data from next
264*00b67f09SDavid van Moolenbroek 		unsigned int	len;		   // the actual size of this buffer
265*00b67f09SDavid van Moolenbroek 		unsigned int	remaining;	   // the number of bytes remaining
266*00b67f09SDavid van Moolenbroek 	} recvbuf;
267*00b67f09SDavid van Moolenbroek 
268*00b67f09SDavid van Moolenbroek 	ISC_LIST(isc_socketevent_t)		send_list;
269*00b67f09SDavid van Moolenbroek 	ISC_LIST(isc_socketevent_t)		recv_list;
270*00b67f09SDavid van Moolenbroek 	ISC_LIST(isc_socket_newconnev_t)	accept_list;
271*00b67f09SDavid van Moolenbroek 	isc_socket_connev_t		       *connect_ev;
272*00b67f09SDavid van Moolenbroek 
273*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t		address;  /* remote address */
274*00b67f09SDavid van Moolenbroek 
275*00b67f09SDavid van Moolenbroek 	unsigned int		listener : 1,	/* listener socket */
276*00b67f09SDavid van Moolenbroek 				connected : 1,
277*00b67f09SDavid van Moolenbroek 				pending_connect : 1, /* connect pending */
278*00b67f09SDavid van Moolenbroek 				bound : 1,	/* bound to local addr */
279*00b67f09SDavid van Moolenbroek 				dupped : 1;     /* created by isc_socket_dup() */
280*00b67f09SDavid van Moolenbroek 	unsigned int		pending_iocp;	/* Should equal the counters below. Debug. */
281*00b67f09SDavid van Moolenbroek 	unsigned int		pending_recv;  /* Number of outstanding recv() calls. */
282*00b67f09SDavid van Moolenbroek 	unsigned int		pending_send;  /* Number of outstanding send() calls. */
283*00b67f09SDavid van Moolenbroek 	unsigned int		pending_accept; /* Number of outstanding accept() calls. */
284*00b67f09SDavid van Moolenbroek 	unsigned int		state; /* Socket state. Debugging and consistency checking. */
285*00b67f09SDavid van Moolenbroek 	int			state_lineno;  /* line which last touched state */
286*00b67f09SDavid van Moolenbroek };
287*00b67f09SDavid van Moolenbroek 
288*00b67f09SDavid van Moolenbroek #define _set_state(sock, _state) do { (sock)->state = (_state); (sock)->state_lineno = __LINE__; } while (/*CONSTCOND*/0)
289*00b67f09SDavid van Moolenbroek 
290*00b67f09SDavid van Moolenbroek /*
291*00b67f09SDavid van Moolenbroek  * Buffer structure
292*00b67f09SDavid van Moolenbroek  */
293*00b67f09SDavid van Moolenbroek typedef struct buflist buflist_t;
294*00b67f09SDavid van Moolenbroek 
295*00b67f09SDavid van Moolenbroek struct buflist {
296*00b67f09SDavid van Moolenbroek 	void			*buf;
297*00b67f09SDavid van Moolenbroek 	unsigned int		buflen;
298*00b67f09SDavid van Moolenbroek 	ISC_LINK(buflist_t)	link;
299*00b67f09SDavid van Moolenbroek };
300*00b67f09SDavid van Moolenbroek 
301*00b67f09SDavid van Moolenbroek /*
302*00b67f09SDavid van Moolenbroek  * I/O Completion ports Info structures
303*00b67f09SDavid van Moolenbroek  */
304*00b67f09SDavid van Moolenbroek 
305*00b67f09SDavid van Moolenbroek static HANDLE hHeapHandle = NULL;
306*00b67f09SDavid van Moolenbroek typedef struct IoCompletionInfo {
307*00b67f09SDavid van Moolenbroek 	OVERLAPPED		overlapped;
308*00b67f09SDavid van Moolenbroek 	isc_socketevent_t	*dev;  /* send()/recv() done event */
309*00b67f09SDavid van Moolenbroek 	isc_socket_connev_t	*cdev; /* connect() done event */
310*00b67f09SDavid van Moolenbroek 	isc_socket_newconnev_t	*adev; /* accept() done event */
311*00b67f09SDavid van Moolenbroek 	void			*acceptbuffer;
312*00b67f09SDavid van Moolenbroek 	DWORD			received_bytes;
313*00b67f09SDavid van Moolenbroek 	int			request_type;
314*00b67f09SDavid van Moolenbroek 	struct msghdr		messagehdr;
315*00b67f09SDavid van Moolenbroek 	ISC_LIST(buflist_t)	bufferlist;	/*%< list of buffers */
316*00b67f09SDavid van Moolenbroek } IoCompletionInfo;
317*00b67f09SDavid van Moolenbroek 
318*00b67f09SDavid van Moolenbroek /*
319*00b67f09SDavid van Moolenbroek  * Define a maximum number of I/O Completion Port worker threads
320*00b67f09SDavid van Moolenbroek  * to handle the load on the Completion Port. The actual number
321*00b67f09SDavid van Moolenbroek  * used is the number of CPU's + 1.
322*00b67f09SDavid van Moolenbroek  */
323*00b67f09SDavid van Moolenbroek #define MAX_IOCPTHREADS 20
324*00b67f09SDavid van Moolenbroek 
325*00b67f09SDavid van Moolenbroek #define SOCKET_MANAGER_MAGIC	ISC_MAGIC('I', 'O', 'm', 'g')
326*00b67f09SDavid van Moolenbroek #define VALID_MANAGER(m)	ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC)
327*00b67f09SDavid van Moolenbroek 
328*00b67f09SDavid van Moolenbroek struct isc_socketmgr {
329*00b67f09SDavid van Moolenbroek 	/* Not locked. */
330*00b67f09SDavid van Moolenbroek 	unsigned int			magic;
331*00b67f09SDavid van Moolenbroek 	isc_mem_t		       *mctx;
332*00b67f09SDavid van Moolenbroek 	isc_mutex_t			lock;
333*00b67f09SDavid van Moolenbroek 	isc_stats_t		       *stats;
334*00b67f09SDavid van Moolenbroek 
335*00b67f09SDavid van Moolenbroek 	/* Locked by manager lock. */
336*00b67f09SDavid van Moolenbroek 	ISC_LIST(isc_socket_t)		socklist;
337*00b67f09SDavid van Moolenbroek 	isc_boolean_t			bShutdown;
338*00b67f09SDavid van Moolenbroek 	isc_condition_t			shutdown_ok;
339*00b67f09SDavid van Moolenbroek 	HANDLE				hIoCompletionPort;
340*00b67f09SDavid van Moolenbroek 	int				maxIOCPThreads;
341*00b67f09SDavid van Moolenbroek 	HANDLE				hIOCPThreads[MAX_IOCPTHREADS];
342*00b67f09SDavid van Moolenbroek 	DWORD				dwIOCPThreadIds[MAX_IOCPTHREADS];
343*00b67f09SDavid van Moolenbroek 
344*00b67f09SDavid van Moolenbroek 	/*
345*00b67f09SDavid van Moolenbroek 	 * Debugging.
346*00b67f09SDavid van Moolenbroek 	 * Modified by InterlockedIncrement() and InterlockedDecrement()
347*00b67f09SDavid van Moolenbroek 	 */
348*00b67f09SDavid van Moolenbroek 	LONG				totalSockets;
349*00b67f09SDavid van Moolenbroek 	LONG				iocp_total;
350*00b67f09SDavid van Moolenbroek };
351*00b67f09SDavid van Moolenbroek 
352*00b67f09SDavid van Moolenbroek enum {
353*00b67f09SDavid van Moolenbroek 	SOCKET_RECV,
354*00b67f09SDavid van Moolenbroek 	SOCKET_SEND,
355*00b67f09SDavid van Moolenbroek 	SOCKET_ACCEPT,
356*00b67f09SDavid van Moolenbroek 	SOCKET_CONNECT
357*00b67f09SDavid van Moolenbroek };
358*00b67f09SDavid van Moolenbroek 
359*00b67f09SDavid van Moolenbroek /*
360*00b67f09SDavid van Moolenbroek  * send() and recv() iovec counts
361*00b67f09SDavid van Moolenbroek  */
362*00b67f09SDavid van Moolenbroek #define MAXSCATTERGATHER_SEND	(ISC_SOCKET_MAXSCATTERGATHER)
363*00b67f09SDavid van Moolenbroek #define MAXSCATTERGATHER_RECV	(ISC_SOCKET_MAXSCATTERGATHER)
364*00b67f09SDavid van Moolenbroek 
365*00b67f09SDavid van Moolenbroek static isc_result_t socket_create(isc_socketmgr_t *manager0, int pf,
366*00b67f09SDavid van Moolenbroek 				  isc_sockettype_t type,
367*00b67f09SDavid van Moolenbroek 				  isc_socket_t **socketp,
368*00b67f09SDavid van Moolenbroek 				  isc_socket_t *dup_socket);
369*00b67f09SDavid van Moolenbroek static isc_threadresult_t WINAPI SocketIoThread(LPVOID ThreadContext);
370*00b67f09SDavid van Moolenbroek static void maybe_free_socket(isc_socket_t **, int);
371*00b67f09SDavid van Moolenbroek static void free_socket(isc_socket_t **, int);
372*00b67f09SDavid van Moolenbroek static isc_boolean_t senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev);
373*00b67f09SDavid van Moolenbroek static isc_boolean_t acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev);
374*00b67f09SDavid van Moolenbroek static isc_boolean_t connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev);
375*00b67f09SDavid van Moolenbroek static void send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev);
376*00b67f09SDavid van Moolenbroek static void send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev);
377*00b67f09SDavid van Moolenbroek static void send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev);
378*00b67f09SDavid van Moolenbroek static void send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev);
379*00b67f09SDavid van Moolenbroek static void send_recvdone_abort(isc_socket_t *sock, isc_result_t result);
380*00b67f09SDavid van Moolenbroek static void queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev);
381*00b67f09SDavid van Moolenbroek static void queue_receive_request(isc_socket_t *sock);
382*00b67f09SDavid van Moolenbroek 
383*00b67f09SDavid van Moolenbroek /*
384*00b67f09SDavid van Moolenbroek  * This is used to dump the contents of the sock structure
385*00b67f09SDavid van Moolenbroek  * You should make sure that the sock is locked before
386*00b67f09SDavid van Moolenbroek  * dumping it. Since the code uses simple printf() statements
387*00b67f09SDavid van Moolenbroek  * it should only be used interactively.
388*00b67f09SDavid van Moolenbroek  */
389*00b67f09SDavid van Moolenbroek void
sock_dump(isc_socket_t * sock)390*00b67f09SDavid van Moolenbroek sock_dump(isc_socket_t *sock) {
391*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *ldev;
392*00b67f09SDavid van Moolenbroek 	isc_socket_newconnev_t *ndev;
393*00b67f09SDavid van Moolenbroek 
394*00b67f09SDavid van Moolenbroek #if 0
395*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t addr;
396*00b67f09SDavid van Moolenbroek 	char socktext[ISC_SOCKADDR_FORMATSIZE];
397*00b67f09SDavid van Moolenbroek 	isc_result_t result;
398*00b67f09SDavid van Moolenbroek 
399*00b67f09SDavid van Moolenbroek 	result = isc_socket_getpeername(sock, &addr);
400*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
401*00b67f09SDavid van Moolenbroek 		isc_sockaddr_format(&addr, socktext, sizeof(socktext));
402*00b67f09SDavid van Moolenbroek 		printf("Remote Socket: %s\n", socktext);
403*00b67f09SDavid van Moolenbroek 	}
404*00b67f09SDavid van Moolenbroek 	result = isc_socket_getsockname(sock, &addr);
405*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
406*00b67f09SDavid van Moolenbroek 		isc_sockaddr_format(&addr, socktext, sizeof(socktext));
407*00b67f09SDavid van Moolenbroek 		printf("This Socket: %s\n", socktext);
408*00b67f09SDavid van Moolenbroek 	}
409*00b67f09SDavid van Moolenbroek #endif
410*00b67f09SDavid van Moolenbroek 
411*00b67f09SDavid van Moolenbroek 	printf("\n\t\tSock Dump\n");
412*00b67f09SDavid van Moolenbroek 	printf("\t\tfd: %u\n", sock->fd);
413*00b67f09SDavid van Moolenbroek 	printf("\t\treferences: %d\n", sock->references);
414*00b67f09SDavid van Moolenbroek 	printf("\t\tpending_accept: %d\n", sock->pending_accept);
415*00b67f09SDavid van Moolenbroek 	printf("\t\tconnecting: %d\n", sock->pending_connect);
416*00b67f09SDavid van Moolenbroek 	printf("\t\tconnected: %d\n", sock->connected);
417*00b67f09SDavid van Moolenbroek 	printf("\t\tbound: %d\n", sock->bound);
418*00b67f09SDavid van Moolenbroek 	printf("\t\tpending_iocp: %d\n", sock->pending_iocp);
419*00b67f09SDavid van Moolenbroek 	printf("\t\tsocket type: %d\n", sock->type);
420*00b67f09SDavid van Moolenbroek 
421*00b67f09SDavid van Moolenbroek 	printf("\n\t\tSock Recv List\n");
422*00b67f09SDavid van Moolenbroek 	ldev = ISC_LIST_HEAD(sock->recv_list);
423*00b67f09SDavid van Moolenbroek 	while (ldev != NULL) {
424*00b67f09SDavid van Moolenbroek 		printf("\t\tdev: %p\n", ldev);
425*00b67f09SDavid van Moolenbroek 		ldev = ISC_LIST_NEXT(ldev, ev_link);
426*00b67f09SDavid van Moolenbroek 	}
427*00b67f09SDavid van Moolenbroek 
428*00b67f09SDavid van Moolenbroek 	printf("\n\t\tSock Send List\n");
429*00b67f09SDavid van Moolenbroek 	ldev = ISC_LIST_HEAD(sock->send_list);
430*00b67f09SDavid van Moolenbroek 	while (ldev != NULL) {
431*00b67f09SDavid van Moolenbroek 		printf("\t\tdev: %p\n", ldev);
432*00b67f09SDavid van Moolenbroek 		ldev = ISC_LIST_NEXT(ldev, ev_link);
433*00b67f09SDavid van Moolenbroek 	}
434*00b67f09SDavid van Moolenbroek 
435*00b67f09SDavid van Moolenbroek 	printf("\n\t\tSock Accept List\n");
436*00b67f09SDavid van Moolenbroek 	ndev = ISC_LIST_HEAD(sock->accept_list);
437*00b67f09SDavid van Moolenbroek 	while (ndev != NULL) {
438*00b67f09SDavid van Moolenbroek 		printf("\t\tdev: %p\n", ldev);
439*00b67f09SDavid van Moolenbroek 		ndev = ISC_LIST_NEXT(ndev, ev_link);
440*00b67f09SDavid van Moolenbroek 	}
441*00b67f09SDavid van Moolenbroek }
442*00b67f09SDavid van Moolenbroek 
443*00b67f09SDavid van Moolenbroek static void
444*00b67f09SDavid van Moolenbroek socket_log(int lineno, isc_socket_t *sock, isc_sockaddr_t *address,
445*00b67f09SDavid van Moolenbroek 	   isc_logcategory_t *category, isc_logmodule_t *module, int level,
446*00b67f09SDavid van Moolenbroek 	   isc_msgcat_t *msgcat, int msgset, int message,
447*00b67f09SDavid van Moolenbroek 	   const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10);
448*00b67f09SDavid van Moolenbroek 
449*00b67f09SDavid van Moolenbroek /*  This function will add an entry to the I/O completion port
450*00b67f09SDavid van Moolenbroek  *  that will signal the I/O thread to exit (gracefully)
451*00b67f09SDavid van Moolenbroek  */
452*00b67f09SDavid van Moolenbroek static void
signal_iocompletionport_exit(isc_socketmgr_t * manager)453*00b67f09SDavid van Moolenbroek signal_iocompletionport_exit(isc_socketmgr_t *manager) {
454*00b67f09SDavid van Moolenbroek 	int i;
455*00b67f09SDavid van Moolenbroek 	int errval;
456*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
457*00b67f09SDavid van Moolenbroek 
458*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
459*00b67f09SDavid van Moolenbroek 	for (i = 0; i < manager->maxIOCPThreads; i++) {
460*00b67f09SDavid van Moolenbroek 		if (!PostQueuedCompletionStatus(manager->hIoCompletionPort,
461*00b67f09SDavid van Moolenbroek 						0, 0, 0)) {
462*00b67f09SDavid van Moolenbroek 			errval = GetLastError();
463*00b67f09SDavid van Moolenbroek 			isc__strerror(errval, strbuf, sizeof(strbuf));
464*00b67f09SDavid van Moolenbroek 			FATAL_ERROR(__FILE__, __LINE__,
465*00b67f09SDavid van Moolenbroek 				isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
466*00b67f09SDavid van Moolenbroek 				ISC_MSG_FAILED,
467*00b67f09SDavid van Moolenbroek 				"Can't request service thread to exit: %s"),
468*00b67f09SDavid van Moolenbroek 				strbuf);
469*00b67f09SDavid van Moolenbroek 		}
470*00b67f09SDavid van Moolenbroek 	}
471*00b67f09SDavid van Moolenbroek }
472*00b67f09SDavid van Moolenbroek 
473*00b67f09SDavid van Moolenbroek /*
474*00b67f09SDavid van Moolenbroek  * Create the worker threads for the I/O Completion Port
475*00b67f09SDavid van Moolenbroek  */
476*00b67f09SDavid van Moolenbroek void
iocompletionport_createthreads(int total_threads,isc_socketmgr_t * manager)477*00b67f09SDavid van Moolenbroek iocompletionport_createthreads(int total_threads, isc_socketmgr_t *manager) {
478*00b67f09SDavid van Moolenbroek 	int errval;
479*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
480*00b67f09SDavid van Moolenbroek 	int i;
481*00b67f09SDavid van Moolenbroek 
482*00b67f09SDavid van Moolenbroek 	INSIST(total_threads > 0);
483*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
484*00b67f09SDavid van Moolenbroek 	/*
485*00b67f09SDavid van Moolenbroek 	 * We need at least one
486*00b67f09SDavid van Moolenbroek 	 */
487*00b67f09SDavid van Moolenbroek 	for (i = 0; i < total_threads; i++) {
488*00b67f09SDavid van Moolenbroek 		manager->hIOCPThreads[i] = CreateThread(NULL, 0, SocketIoThread,
489*00b67f09SDavid van Moolenbroek 						manager, 0,
490*00b67f09SDavid van Moolenbroek 						&manager->dwIOCPThreadIds[i]);
491*00b67f09SDavid van Moolenbroek 		if (manager->hIOCPThreads[i] == NULL) {
492*00b67f09SDavid van Moolenbroek 			errval = GetLastError();
493*00b67f09SDavid van Moolenbroek 			isc__strerror(errval, strbuf, sizeof(strbuf));
494*00b67f09SDavid van Moolenbroek 			FATAL_ERROR(__FILE__, __LINE__,
495*00b67f09SDavid van Moolenbroek 				isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
496*00b67f09SDavid van Moolenbroek 				ISC_MSG_FAILED,
497*00b67f09SDavid van Moolenbroek 				"Can't create IOCP thread: %s"),
498*00b67f09SDavid van Moolenbroek 				strbuf);
499*00b67f09SDavid van Moolenbroek 			exit(1);
500*00b67f09SDavid van Moolenbroek 		}
501*00b67f09SDavid van Moolenbroek 	}
502*00b67f09SDavid van Moolenbroek }
503*00b67f09SDavid van Moolenbroek 
504*00b67f09SDavid van Moolenbroek /*
505*00b67f09SDavid van Moolenbroek  *  Create/initialise the I/O completion port
506*00b67f09SDavid van Moolenbroek  */
507*00b67f09SDavid van Moolenbroek void
iocompletionport_init(isc_socketmgr_t * manager)508*00b67f09SDavid van Moolenbroek iocompletionport_init(isc_socketmgr_t *manager) {
509*00b67f09SDavid van Moolenbroek 	int errval;
510*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
511*00b67f09SDavid van Moolenbroek 
512*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
513*00b67f09SDavid van Moolenbroek 	/*
514*00b67f09SDavid van Moolenbroek 	 * Create a private heap to handle the socket overlapped structure
515*00b67f09SDavid van Moolenbroek 	 * The minimum number of structures is 10, there is no maximum
516*00b67f09SDavid van Moolenbroek 	 */
517*00b67f09SDavid van Moolenbroek 	hHeapHandle = HeapCreate(0, 10 * sizeof(IoCompletionInfo), 0);
518*00b67f09SDavid van Moolenbroek 	if (hHeapHandle == NULL) {
519*00b67f09SDavid van Moolenbroek 		errval = GetLastError();
520*00b67f09SDavid van Moolenbroek 		isc__strerror(errval, strbuf, sizeof(strbuf));
521*00b67f09SDavid van Moolenbroek 		FATAL_ERROR(__FILE__, __LINE__,
522*00b67f09SDavid van Moolenbroek 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
523*00b67f09SDavid van Moolenbroek 					   ISC_MSG_FAILED,
524*00b67f09SDavid van Moolenbroek 					   "HeapCreate() failed during "
525*00b67f09SDavid van Moolenbroek 					   "initialization: %s"),
526*00b67f09SDavid van Moolenbroek 			    strbuf);
527*00b67f09SDavid van Moolenbroek 		exit(1);
528*00b67f09SDavid van Moolenbroek 	}
529*00b67f09SDavid van Moolenbroek 
530*00b67f09SDavid van Moolenbroek 	manager->maxIOCPThreads = min(isc_os_ncpus() + 1, MAX_IOCPTHREADS);
531*00b67f09SDavid van Moolenbroek 
532*00b67f09SDavid van Moolenbroek 	/* Now Create the Completion Port */
533*00b67f09SDavid van Moolenbroek 	manager->hIoCompletionPort = CreateIoCompletionPort(
534*00b67f09SDavid van Moolenbroek 			INVALID_HANDLE_VALUE, NULL,
535*00b67f09SDavid van Moolenbroek 			0, manager->maxIOCPThreads);
536*00b67f09SDavid van Moolenbroek 	if (manager->hIoCompletionPort == NULL) {
537*00b67f09SDavid van Moolenbroek 		errval = GetLastError();
538*00b67f09SDavid van Moolenbroek 		isc__strerror(errval, strbuf, sizeof(strbuf));
539*00b67f09SDavid van Moolenbroek 		FATAL_ERROR(__FILE__, __LINE__,
540*00b67f09SDavid van Moolenbroek 				isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
541*00b67f09SDavid van Moolenbroek 				ISC_MSG_FAILED,
542*00b67f09SDavid van Moolenbroek 				"CreateIoCompletionPort() failed "
543*00b67f09SDavid van Moolenbroek 				"during initialization: %s"),
544*00b67f09SDavid van Moolenbroek 				strbuf);
545*00b67f09SDavid van Moolenbroek 		exit(1);
546*00b67f09SDavid van Moolenbroek 	}
547*00b67f09SDavid van Moolenbroek 
548*00b67f09SDavid van Moolenbroek 	/*
549*00b67f09SDavid van Moolenbroek 	 * Worker threads for servicing the I/O
550*00b67f09SDavid van Moolenbroek 	 */
551*00b67f09SDavid van Moolenbroek 	iocompletionport_createthreads(manager->maxIOCPThreads, manager);
552*00b67f09SDavid van Moolenbroek }
553*00b67f09SDavid van Moolenbroek 
554*00b67f09SDavid van Moolenbroek /*
555*00b67f09SDavid van Moolenbroek  * Associate a socket with an IO Completion Port.  This allows us to queue events for it
556*00b67f09SDavid van Moolenbroek  * and have our worker pool of threads process them.
557*00b67f09SDavid van Moolenbroek  */
558*00b67f09SDavid van Moolenbroek void
iocompletionport_update(isc_socket_t * sock)559*00b67f09SDavid van Moolenbroek iocompletionport_update(isc_socket_t *sock) {
560*00b67f09SDavid van Moolenbroek 	HANDLE hiocp;
561*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
562*00b67f09SDavid van Moolenbroek 
563*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
564*00b67f09SDavid van Moolenbroek 
565*00b67f09SDavid van Moolenbroek 	hiocp = CreateIoCompletionPort((HANDLE)sock->fd,
566*00b67f09SDavid van Moolenbroek 		sock->manager->hIoCompletionPort, (ULONG_PTR)sock, 0);
567*00b67f09SDavid van Moolenbroek 
568*00b67f09SDavid van Moolenbroek 	if (hiocp == NULL) {
569*00b67f09SDavid van Moolenbroek 		DWORD errval = GetLastError();
570*00b67f09SDavid van Moolenbroek 		isc__strerror(errval, strbuf, sizeof(strbuf));
571*00b67f09SDavid van Moolenbroek 		isc_log_iwrite(isc_lctx,
572*00b67f09SDavid van Moolenbroek 				ISC_LOGCATEGORY_GENERAL,
573*00b67f09SDavid van Moolenbroek 				ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
574*00b67f09SDavid van Moolenbroek 				isc_msgcat, ISC_MSGSET_SOCKET,
575*00b67f09SDavid van Moolenbroek 				ISC_MSG_TOOMANYHANDLES,
576*00b67f09SDavid van Moolenbroek 				"iocompletionport_update: failed to open"
577*00b67f09SDavid van Moolenbroek 				" io completion port: %s",
578*00b67f09SDavid van Moolenbroek 				strbuf);
579*00b67f09SDavid van Moolenbroek 
580*00b67f09SDavid van Moolenbroek 		/* XXXMLG temporary hack to make failures detected.
581*00b67f09SDavid van Moolenbroek 		 * This function should return errors to the caller, not
582*00b67f09SDavid van Moolenbroek 		 * exit here.
583*00b67f09SDavid van Moolenbroek 		 */
584*00b67f09SDavid van Moolenbroek 		FATAL_ERROR(__FILE__, __LINE__,
585*00b67f09SDavid van Moolenbroek 				isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
586*00b67f09SDavid van Moolenbroek 				ISC_MSG_FAILED,
587*00b67f09SDavid van Moolenbroek 				"CreateIoCompletionPort() failed "
588*00b67f09SDavid van Moolenbroek 				"during initialization: %s"),
589*00b67f09SDavid van Moolenbroek 				strbuf);
590*00b67f09SDavid van Moolenbroek 		exit(1);
591*00b67f09SDavid van Moolenbroek 	}
592*00b67f09SDavid van Moolenbroek 
593*00b67f09SDavid van Moolenbroek 	InterlockedIncrement(&sock->manager->iocp_total);
594*00b67f09SDavid van Moolenbroek }
595*00b67f09SDavid van Moolenbroek 
596*00b67f09SDavid van Moolenbroek /*
597*00b67f09SDavid van Moolenbroek  * Routine to cleanup and then close the socket.
598*00b67f09SDavid van Moolenbroek  * Only close the socket here if it is NOT associated
599*00b67f09SDavid van Moolenbroek  * with an event, otherwise the WSAWaitForMultipleEvents
600*00b67f09SDavid van Moolenbroek  * may fail due to the fact that the Wait should not
601*00b67f09SDavid van Moolenbroek  * be running while closing an event or a socket.
602*00b67f09SDavid van Moolenbroek  * The socket is locked before calling this function
603*00b67f09SDavid van Moolenbroek  */
604*00b67f09SDavid van Moolenbroek void
socket_close(isc_socket_t * sock)605*00b67f09SDavid van Moolenbroek socket_close(isc_socket_t *sock) {
606*00b67f09SDavid van Moolenbroek 
607*00b67f09SDavid van Moolenbroek 	REQUIRE(sock != NULL);
608*00b67f09SDavid van Moolenbroek 
609*00b67f09SDavid van Moolenbroek 	if (sock->fd != INVALID_SOCKET) {
610*00b67f09SDavid van Moolenbroek 		closesocket(sock->fd);
611*00b67f09SDavid van Moolenbroek 		sock->fd = INVALID_SOCKET;
612*00b67f09SDavid van Moolenbroek 		_set_state(sock, SOCK_CLOSED);
613*00b67f09SDavid van Moolenbroek 		InterlockedDecrement(&sock->manager->totalSockets);
614*00b67f09SDavid van Moolenbroek 	}
615*00b67f09SDavid van Moolenbroek }
616*00b67f09SDavid van Moolenbroek 
617*00b67f09SDavid van Moolenbroek static isc_once_t initialise_once = ISC_ONCE_INIT;
618*00b67f09SDavid van Moolenbroek static isc_boolean_t initialised = ISC_FALSE;
619*00b67f09SDavid van Moolenbroek 
620*00b67f09SDavid van Moolenbroek static void
initialise(void)621*00b67f09SDavid van Moolenbroek initialise(void) {
622*00b67f09SDavid van Moolenbroek 	WORD wVersionRequested;
623*00b67f09SDavid van Moolenbroek 	WSADATA wsaData;
624*00b67f09SDavid van Moolenbroek 	int err;
625*00b67f09SDavid van Moolenbroek 	SOCKET sock;
626*00b67f09SDavid van Moolenbroek 	GUID GUIDConnectEx = WSAID_CONNECTEX;
627*00b67f09SDavid van Moolenbroek 	GUID GUIDAcceptEx = WSAID_ACCEPTEX;
628*00b67f09SDavid van Moolenbroek 	GUID GUIDGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
629*00b67f09SDavid van Moolenbroek 	DWORD dwBytes;
630*00b67f09SDavid van Moolenbroek 
631*00b67f09SDavid van Moolenbroek 	/* Need Winsock 2.2 or better */
632*00b67f09SDavid van Moolenbroek 	wVersionRequested = MAKEWORD(2, 2);
633*00b67f09SDavid van Moolenbroek 
634*00b67f09SDavid van Moolenbroek 	err = WSAStartup(wVersionRequested, &wsaData);
635*00b67f09SDavid van Moolenbroek 	if (err != 0) {
636*00b67f09SDavid van Moolenbroek 		char strbuf[ISC_STRERRORSIZE];
637*00b67f09SDavid van Moolenbroek 		isc__strerror(err, strbuf, sizeof(strbuf));
638*00b67f09SDavid van Moolenbroek 		FATAL_ERROR(__FILE__, __LINE__, "WSAStartup() %s: %s",
639*00b67f09SDavid van Moolenbroek 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
640*00b67f09SDavid van Moolenbroek 					   ISC_MSG_FAILED, "failed"),
641*00b67f09SDavid van Moolenbroek 			    strbuf);
642*00b67f09SDavid van Moolenbroek 		exit(1);
643*00b67f09SDavid van Moolenbroek 	}
644*00b67f09SDavid van Moolenbroek 	/*
645*00b67f09SDavid van Moolenbroek 	 * The following APIs do not exist as functions in a library, but we must
646*00b67f09SDavid van Moolenbroek 	 * ask winsock for them.  They are "extensions" -- but why they cannot be
647*00b67f09SDavid van Moolenbroek 	 * actual functions is beyond me.  So, ask winsock for the pointers to the
648*00b67f09SDavid van Moolenbroek 	 * functions we need.
649*00b67f09SDavid van Moolenbroek 	 */
650*00b67f09SDavid van Moolenbroek 	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
651*00b67f09SDavid van Moolenbroek 	INSIST(sock != INVALID_SOCKET);
652*00b67f09SDavid van Moolenbroek 	err = WSAIoctl(sock,  SIO_GET_EXTENSION_FUNCTION_POINTER,
653*00b67f09SDavid van Moolenbroek 		 &GUIDConnectEx, sizeof(GUIDConnectEx),
654*00b67f09SDavid van Moolenbroek 		 &ISCConnectEx, sizeof(ISCConnectEx),
655*00b67f09SDavid van Moolenbroek 		 &dwBytes, NULL, NULL);
656*00b67f09SDavid van Moolenbroek 	INSIST(err == 0);
657*00b67f09SDavid van Moolenbroek 
658*00b67f09SDavid van Moolenbroek 	err = WSAIoctl(sock,  SIO_GET_EXTENSION_FUNCTION_POINTER,
659*00b67f09SDavid van Moolenbroek 		 &GUIDAcceptEx, sizeof(GUIDAcceptEx),
660*00b67f09SDavid van Moolenbroek 		 &ISCAcceptEx, sizeof(ISCAcceptEx),
661*00b67f09SDavid van Moolenbroek 		 &dwBytes, NULL, NULL);
662*00b67f09SDavid van Moolenbroek 	INSIST(err == 0);
663*00b67f09SDavid van Moolenbroek 
664*00b67f09SDavid van Moolenbroek 	err = WSAIoctl(sock,  SIO_GET_EXTENSION_FUNCTION_POINTER,
665*00b67f09SDavid van Moolenbroek 		 &GUIDGetAcceptExSockaddrs, sizeof(GUIDGetAcceptExSockaddrs),
666*00b67f09SDavid van Moolenbroek 		 &ISCGetAcceptExSockaddrs, sizeof(ISCGetAcceptExSockaddrs),
667*00b67f09SDavid van Moolenbroek 		 &dwBytes, NULL, NULL);
668*00b67f09SDavid van Moolenbroek 	INSIST(err == 0);
669*00b67f09SDavid van Moolenbroek 
670*00b67f09SDavid van Moolenbroek 	closesocket(sock);
671*00b67f09SDavid van Moolenbroek 
672*00b67f09SDavid van Moolenbroek 	initialised = ISC_TRUE;
673*00b67f09SDavid van Moolenbroek }
674*00b67f09SDavid van Moolenbroek 
675*00b67f09SDavid van Moolenbroek /*
676*00b67f09SDavid van Moolenbroek  * Initialize socket services
677*00b67f09SDavid van Moolenbroek  */
678*00b67f09SDavid van Moolenbroek void
InitSockets(void)679*00b67f09SDavid van Moolenbroek InitSockets(void) {
680*00b67f09SDavid van Moolenbroek 	RUNTIME_CHECK(isc_once_do(&initialise_once,
681*00b67f09SDavid van Moolenbroek 				  initialise) == ISC_R_SUCCESS);
682*00b67f09SDavid van Moolenbroek 	if (!initialised)
683*00b67f09SDavid van Moolenbroek 		exit(1);
684*00b67f09SDavid van Moolenbroek }
685*00b67f09SDavid van Moolenbroek 
686*00b67f09SDavid van Moolenbroek int
internal_sendmsg(isc_socket_t * sock,IoCompletionInfo * lpo,struct msghdr * messagehdr,int flags,int * Error)687*00b67f09SDavid van Moolenbroek internal_sendmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
688*00b67f09SDavid van Moolenbroek 		 struct msghdr *messagehdr, int flags, int *Error)
689*00b67f09SDavid van Moolenbroek {
690*00b67f09SDavid van Moolenbroek 	int Result;
691*00b67f09SDavid van Moolenbroek 	DWORD BytesSent;
692*00b67f09SDavid van Moolenbroek 	DWORD Flags = flags;
693*00b67f09SDavid van Moolenbroek 	int total_sent;
694*00b67f09SDavid van Moolenbroek 
695*00b67f09SDavid van Moolenbroek 	*Error = 0;
696*00b67f09SDavid van Moolenbroek 	Result = WSASendTo(sock->fd, messagehdr->msg_iov,
697*00b67f09SDavid van Moolenbroek 			   messagehdr->msg_iovlen, &BytesSent,
698*00b67f09SDavid van Moolenbroek 			   Flags, (SOCKADDR *)&messagehdr->to_addr,
699*00b67f09SDavid van Moolenbroek 			   messagehdr->to_addr_len, (LPWSAOVERLAPPED)lpo,
700*00b67f09SDavid van Moolenbroek 			   NULL);
701*00b67f09SDavid van Moolenbroek 
702*00b67f09SDavid van Moolenbroek 	total_sent = (int)BytesSent;
703*00b67f09SDavid van Moolenbroek 
704*00b67f09SDavid van Moolenbroek 	/* Check for errors.*/
705*00b67f09SDavid van Moolenbroek 	if (Result == SOCKET_ERROR) {
706*00b67f09SDavid van Moolenbroek 		*Error = WSAGetLastError();
707*00b67f09SDavid van Moolenbroek 
708*00b67f09SDavid van Moolenbroek 		switch (*Error) {
709*00b67f09SDavid van Moolenbroek 		case WSA_IO_INCOMPLETE:
710*00b67f09SDavid van Moolenbroek 		case WSA_WAIT_IO_COMPLETION:
711*00b67f09SDavid van Moolenbroek 		case WSA_IO_PENDING:
712*00b67f09SDavid van Moolenbroek 		case NO_ERROR:		/* Strange, but okay */
713*00b67f09SDavid van Moolenbroek 			sock->pending_iocp++;
714*00b67f09SDavid van Moolenbroek 			sock->pending_send++;
715*00b67f09SDavid van Moolenbroek 			break;
716*00b67f09SDavid van Moolenbroek 
717*00b67f09SDavid van Moolenbroek 		default:
718*00b67f09SDavid van Moolenbroek 			return (-1);
719*00b67f09SDavid van Moolenbroek 			break;
720*00b67f09SDavid van Moolenbroek 		}
721*00b67f09SDavid van Moolenbroek 	} else {
722*00b67f09SDavid van Moolenbroek 		sock->pending_iocp++;
723*00b67f09SDavid van Moolenbroek 		sock->pending_send++;
724*00b67f09SDavid van Moolenbroek 	}
725*00b67f09SDavid van Moolenbroek 
726*00b67f09SDavid van Moolenbroek 	if (lpo != NULL)
727*00b67f09SDavid van Moolenbroek 		return (0);
728*00b67f09SDavid van Moolenbroek 	else
729*00b67f09SDavid van Moolenbroek 		return (total_sent);
730*00b67f09SDavid van Moolenbroek }
731*00b67f09SDavid van Moolenbroek 
732*00b67f09SDavid van Moolenbroek static void
queue_receive_request(isc_socket_t * sock)733*00b67f09SDavid van Moolenbroek queue_receive_request(isc_socket_t *sock) {
734*00b67f09SDavid van Moolenbroek 	DWORD Flags = 0;
735*00b67f09SDavid van Moolenbroek 	DWORD NumBytes = 0;
736*00b67f09SDavid van Moolenbroek 	int Result;
737*00b67f09SDavid van Moolenbroek 	int Error;
738*00b67f09SDavid van Moolenbroek 	int need_retry;
739*00b67f09SDavid van Moolenbroek 	WSABUF iov[1];
740*00b67f09SDavid van Moolenbroek 	IoCompletionInfo *lpo = NULL;
741*00b67f09SDavid van Moolenbroek 	isc_result_t isc_result;
742*00b67f09SDavid van Moolenbroek 
743*00b67f09SDavid van Moolenbroek  retry:
744*00b67f09SDavid van Moolenbroek 	need_retry = ISC_FALSE;
745*00b67f09SDavid van Moolenbroek 
746*00b67f09SDavid van Moolenbroek 	/*
747*00b67f09SDavid van Moolenbroek 	 * If we already have a receive pending, do nothing.
748*00b67f09SDavid van Moolenbroek 	 */
749*00b67f09SDavid van Moolenbroek 	if (sock->pending_recv > 0) {
750*00b67f09SDavid van Moolenbroek 		if (lpo != NULL)
751*00b67f09SDavid van Moolenbroek 			HeapFree(hHeapHandle, 0, lpo);
752*00b67f09SDavid van Moolenbroek 		return;
753*00b67f09SDavid van Moolenbroek 	}
754*00b67f09SDavid van Moolenbroek 
755*00b67f09SDavid van Moolenbroek 	/*
756*00b67f09SDavid van Moolenbroek 	 * If no one is waiting, do nothing.
757*00b67f09SDavid van Moolenbroek 	 */
758*00b67f09SDavid van Moolenbroek 	if (ISC_LIST_EMPTY(sock->recv_list)) {
759*00b67f09SDavid van Moolenbroek 		if (lpo != NULL)
760*00b67f09SDavid van Moolenbroek 			HeapFree(hHeapHandle, 0, lpo);
761*00b67f09SDavid van Moolenbroek 		return;
762*00b67f09SDavid van Moolenbroek 	}
763*00b67f09SDavid van Moolenbroek 
764*00b67f09SDavid van Moolenbroek 	INSIST(sock->recvbuf.remaining == 0);
765*00b67f09SDavid van Moolenbroek 	INSIST(sock->fd != INVALID_SOCKET);
766*00b67f09SDavid van Moolenbroek 
767*00b67f09SDavid van Moolenbroek 	iov[0].len = sock->recvbuf.len;
768*00b67f09SDavid van Moolenbroek 	iov[0].buf = sock->recvbuf.base;
769*00b67f09SDavid van Moolenbroek 
770*00b67f09SDavid van Moolenbroek 	if (lpo == NULL) {
771*00b67f09SDavid van Moolenbroek 		lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
772*00b67f09SDavid van Moolenbroek 						    HEAP_ZERO_MEMORY,
773*00b67f09SDavid van Moolenbroek 						    sizeof(IoCompletionInfo));
774*00b67f09SDavid van Moolenbroek 		RUNTIME_CHECK(lpo != NULL);
775*00b67f09SDavid van Moolenbroek 	} else
776*00b67f09SDavid van Moolenbroek 		ZeroMemory(lpo, sizeof(IoCompletionInfo));
777*00b67f09SDavid van Moolenbroek 	lpo->request_type = SOCKET_RECV;
778*00b67f09SDavid van Moolenbroek 
779*00b67f09SDavid van Moolenbroek 	sock->recvbuf.from_addr_len = sizeof(sock->recvbuf.from_addr);
780*00b67f09SDavid van Moolenbroek 
781*00b67f09SDavid van Moolenbroek 	Error = 0;
782*00b67f09SDavid van Moolenbroek 	Result = WSARecvFrom((SOCKET)sock->fd, iov, 1,
783*00b67f09SDavid van Moolenbroek 			     &NumBytes, &Flags,
784*00b67f09SDavid van Moolenbroek 			     (SOCKADDR *)&sock->recvbuf.from_addr,
785*00b67f09SDavid van Moolenbroek 			     &sock->recvbuf.from_addr_len,
786*00b67f09SDavid van Moolenbroek 			     (LPWSAOVERLAPPED)lpo, NULL);
787*00b67f09SDavid van Moolenbroek 
788*00b67f09SDavid van Moolenbroek 	/* Check for errors. */
789*00b67f09SDavid van Moolenbroek 	if (Result == SOCKET_ERROR) {
790*00b67f09SDavid van Moolenbroek 		Error = WSAGetLastError();
791*00b67f09SDavid van Moolenbroek 
792*00b67f09SDavid van Moolenbroek 		switch (Error) {
793*00b67f09SDavid van Moolenbroek 		case WSA_IO_PENDING:
794*00b67f09SDavid van Moolenbroek 			sock->pending_iocp++;
795*00b67f09SDavid van Moolenbroek 			sock->pending_recv++;
796*00b67f09SDavid van Moolenbroek 			break;
797*00b67f09SDavid van Moolenbroek 
798*00b67f09SDavid van Moolenbroek 		/* direct error: no completion event */
799*00b67f09SDavid van Moolenbroek 		case ERROR_HOST_UNREACHABLE:
800*00b67f09SDavid van Moolenbroek 		case WSAENETRESET:
801*00b67f09SDavid van Moolenbroek 		case WSAECONNRESET:
802*00b67f09SDavid van Moolenbroek 			if (!sock->connected) {
803*00b67f09SDavid van Moolenbroek 				/* soft error */
804*00b67f09SDavid van Moolenbroek 				need_retry = ISC_TRUE;
805*00b67f09SDavid van Moolenbroek 				break;
806*00b67f09SDavid van Moolenbroek 			}
807*00b67f09SDavid van Moolenbroek 			/* FALLTHROUGH */
808*00b67f09SDavid van Moolenbroek 
809*00b67f09SDavid van Moolenbroek 		default:
810*00b67f09SDavid van Moolenbroek 			isc_result = isc__errno2result(Error);
811*00b67f09SDavid van Moolenbroek 			if (isc_result == ISC_R_UNEXPECTED)
812*00b67f09SDavid van Moolenbroek 				UNEXPECTED_ERROR(__FILE__, __LINE__,
813*00b67f09SDavid van Moolenbroek 					"WSARecvFrom: Windows error code: %d, isc result %d",
814*00b67f09SDavid van Moolenbroek 					Error, isc_result);
815*00b67f09SDavid van Moolenbroek 			send_recvdone_abort(sock, isc_result);
816*00b67f09SDavid van Moolenbroek 			HeapFree(hHeapHandle, 0, lpo);
817*00b67f09SDavid van Moolenbroek 			lpo = NULL;
818*00b67f09SDavid van Moolenbroek 			break;
819*00b67f09SDavid van Moolenbroek 		}
820*00b67f09SDavid van Moolenbroek 	} else {
821*00b67f09SDavid van Moolenbroek 		/*
822*00b67f09SDavid van Moolenbroek 		 * The recv() finished immediately, but we will still get
823*00b67f09SDavid van Moolenbroek 		 * a completion event.  Rather than duplicate code, let
824*00b67f09SDavid van Moolenbroek 		 * that thread handle sending the data along its way.
825*00b67f09SDavid van Moolenbroek 		 */
826*00b67f09SDavid van Moolenbroek 		sock->pending_iocp++;
827*00b67f09SDavid van Moolenbroek 		sock->pending_recv++;
828*00b67f09SDavid van Moolenbroek 	}
829*00b67f09SDavid van Moolenbroek 
830*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, IOEVENT,
831*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET,
832*00b67f09SDavid van Moolenbroek 		   ISC_MSG_DOIORECV,
833*00b67f09SDavid van Moolenbroek 		   "queue_io_request: fd %d result %d error %d",
834*00b67f09SDavid van Moolenbroek 		   sock->fd, Result, Error);
835*00b67f09SDavid van Moolenbroek 
836*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
837*00b67f09SDavid van Moolenbroek 
838*00b67f09SDavid van Moolenbroek 	if (need_retry)
839*00b67f09SDavid van Moolenbroek 		goto retry;
840*00b67f09SDavid van Moolenbroek }
841*00b67f09SDavid van Moolenbroek 
842*00b67f09SDavid van Moolenbroek static void
manager_log(isc_socketmgr_t * sockmgr,isc_logcategory_t * category,isc_logmodule_t * module,int level,const char * fmt,...)843*00b67f09SDavid van Moolenbroek manager_log(isc_socketmgr_t *sockmgr, isc_logcategory_t *category,
844*00b67f09SDavid van Moolenbroek 	    isc_logmodule_t *module, int level, const char *fmt, ...)
845*00b67f09SDavid van Moolenbroek {
846*00b67f09SDavid van Moolenbroek 	char msgbuf[2048];
847*00b67f09SDavid van Moolenbroek 	va_list ap;
848*00b67f09SDavid van Moolenbroek 
849*00b67f09SDavid van Moolenbroek 	if (!isc_log_wouldlog(isc_lctx, level))
850*00b67f09SDavid van Moolenbroek 		return;
851*00b67f09SDavid van Moolenbroek 
852*00b67f09SDavid van Moolenbroek 	va_start(ap, fmt);
853*00b67f09SDavid van Moolenbroek 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
854*00b67f09SDavid van Moolenbroek 	va_end(ap);
855*00b67f09SDavid van Moolenbroek 
856*00b67f09SDavid van Moolenbroek 	isc_log_write(isc_lctx, category, module, level,
857*00b67f09SDavid van Moolenbroek 		      "sockmgr %p: %s", sockmgr, msgbuf);
858*00b67f09SDavid van Moolenbroek }
859*00b67f09SDavid van Moolenbroek 
860*00b67f09SDavid van Moolenbroek static void
socket_log(int lineno,isc_socket_t * sock,isc_sockaddr_t * address,isc_logcategory_t * category,isc_logmodule_t * module,int level,isc_msgcat_t * msgcat,int msgset,int message,const char * fmt,...)861*00b67f09SDavid van Moolenbroek socket_log(int lineno, isc_socket_t *sock, isc_sockaddr_t *address,
862*00b67f09SDavid van Moolenbroek 	   isc_logcategory_t *category, isc_logmodule_t *module, int level,
863*00b67f09SDavid van Moolenbroek 	   isc_msgcat_t *msgcat, int msgset, int message,
864*00b67f09SDavid van Moolenbroek 	   const char *fmt, ...)
865*00b67f09SDavid van Moolenbroek {
866*00b67f09SDavid van Moolenbroek 	char msgbuf[2048];
867*00b67f09SDavid van Moolenbroek 	char peerbuf[256];
868*00b67f09SDavid van Moolenbroek 	va_list ap;
869*00b67f09SDavid van Moolenbroek 
870*00b67f09SDavid van Moolenbroek 
871*00b67f09SDavid van Moolenbroek 	if (!isc_log_wouldlog(isc_lctx, level))
872*00b67f09SDavid van Moolenbroek 		return;
873*00b67f09SDavid van Moolenbroek 
874*00b67f09SDavid van Moolenbroek 	va_start(ap, fmt);
875*00b67f09SDavid van Moolenbroek 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
876*00b67f09SDavid van Moolenbroek 	va_end(ap);
877*00b67f09SDavid van Moolenbroek 
878*00b67f09SDavid van Moolenbroek 	if (address == NULL) {
879*00b67f09SDavid van Moolenbroek 		isc_log_iwrite(isc_lctx, category, module, level,
880*00b67f09SDavid van Moolenbroek 			       msgcat, msgset, message,
881*00b67f09SDavid van Moolenbroek 			       "socket %p line %d: %s", sock, lineno, msgbuf);
882*00b67f09SDavid van Moolenbroek 	} else {
883*00b67f09SDavid van Moolenbroek 		isc_sockaddr_format(address, peerbuf, sizeof(peerbuf));
884*00b67f09SDavid van Moolenbroek 		isc_log_iwrite(isc_lctx, category, module, level,
885*00b67f09SDavid van Moolenbroek 			       msgcat, msgset, message,
886*00b67f09SDavid van Moolenbroek 				   "socket %p line %d peer %s: %s", sock, lineno,
887*00b67f09SDavid van Moolenbroek 				   peerbuf, msgbuf);
888*00b67f09SDavid van Moolenbroek 	}
889*00b67f09SDavid van Moolenbroek 
890*00b67f09SDavid van Moolenbroek }
891*00b67f09SDavid van Moolenbroek 
892*00b67f09SDavid van Moolenbroek /*
893*00b67f09SDavid van Moolenbroek  * Make an fd SOCKET non-blocking.
894*00b67f09SDavid van Moolenbroek  */
895*00b67f09SDavid van Moolenbroek static isc_result_t
make_nonblock(SOCKET fd)896*00b67f09SDavid van Moolenbroek make_nonblock(SOCKET fd) {
897*00b67f09SDavid van Moolenbroek 	int ret;
898*00b67f09SDavid van Moolenbroek 	unsigned long flags = 1;
899*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
900*00b67f09SDavid van Moolenbroek 
901*00b67f09SDavid van Moolenbroek 	/* Set the socket to non-blocking */
902*00b67f09SDavid van Moolenbroek 	ret = ioctlsocket(fd, FIONBIO, &flags);
903*00b67f09SDavid van Moolenbroek 
904*00b67f09SDavid van Moolenbroek 	if (ret == -1) {
905*00b67f09SDavid van Moolenbroek 		isc__strerror(errno, strbuf, sizeof(strbuf));
906*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
907*00b67f09SDavid van Moolenbroek 				 "ioctlsocket(%d, FIOBIO, %d): %s",
908*00b67f09SDavid van Moolenbroek 				 fd, flags, strbuf);
909*00b67f09SDavid van Moolenbroek 
910*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
911*00b67f09SDavid van Moolenbroek 	}
912*00b67f09SDavid van Moolenbroek 
913*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
914*00b67f09SDavid van Moolenbroek }
915*00b67f09SDavid van Moolenbroek 
916*00b67f09SDavid van Moolenbroek /*
917*00b67f09SDavid van Moolenbroek  * Windows 2000 systems incorrectly cause UDP sockets using WSARecvFrom
918*00b67f09SDavid van Moolenbroek  * to not work correctly, returning a WSACONNRESET error when a WSASendTo
919*00b67f09SDavid van Moolenbroek  * fails with an "ICMP port unreachable" response and preventing the
920*00b67f09SDavid van Moolenbroek  * socket from using the WSARecvFrom in subsequent operations.
921*00b67f09SDavid van Moolenbroek  * The function below fixes this, but requires that Windows 2000
922*00b67f09SDavid van Moolenbroek  * Service Pack 2 or later be installed on the system.  NT 4.0
923*00b67f09SDavid van Moolenbroek  * systems are not affected by this and work correctly.
924*00b67f09SDavid van Moolenbroek  * See Microsoft Knowledge Base Article Q263823 for details of this.
925*00b67f09SDavid van Moolenbroek  */
926*00b67f09SDavid van Moolenbroek isc_result_t
connection_reset_fix(SOCKET fd)927*00b67f09SDavid van Moolenbroek connection_reset_fix(SOCKET fd) {
928*00b67f09SDavid van Moolenbroek 	DWORD dwBytesReturned = 0;
929*00b67f09SDavid van Moolenbroek 	BOOL  bNewBehavior = FALSE;
930*00b67f09SDavid van Moolenbroek 	DWORD status;
931*00b67f09SDavid van Moolenbroek 
932*00b67f09SDavid van Moolenbroek 	if (isc_win32os_versioncheck(5, 0, 0, 0) < 0)
933*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS); /*  NT 4.0 has no problem */
934*00b67f09SDavid van Moolenbroek 
935*00b67f09SDavid van Moolenbroek 	/* disable bad behavior using IOCTL: SIO_UDP_CONNRESET */
936*00b67f09SDavid van Moolenbroek 	status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior,
937*00b67f09SDavid van Moolenbroek 			  sizeof(bNewBehavior), NULL, 0,
938*00b67f09SDavid van Moolenbroek 			  &dwBytesReturned, NULL, NULL);
939*00b67f09SDavid van Moolenbroek 	if (status != SOCKET_ERROR)
940*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
941*00b67f09SDavid van Moolenbroek 	else {
942*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
943*00b67f09SDavid van Moolenbroek 				 "WSAIoctl(SIO_UDP_CONNRESET, oldBehaviour) %s",
944*00b67f09SDavid van Moolenbroek 				 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
945*00b67f09SDavid van Moolenbroek 						ISC_MSG_FAILED, "failed"));
946*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
947*00b67f09SDavid van Moolenbroek 	}
948*00b67f09SDavid van Moolenbroek }
949*00b67f09SDavid van Moolenbroek 
950*00b67f09SDavid van Moolenbroek /*
951*00b67f09SDavid van Moolenbroek  * Construct an iov array and attach it to the msghdr passed in.  This is
952*00b67f09SDavid van Moolenbroek  * the SEND constructor, which will use the used region of the buffer
953*00b67f09SDavid van Moolenbroek  * (if using a buffer list) or will use the internal region (if a single
954*00b67f09SDavid van Moolenbroek  * buffer I/O is requested).
955*00b67f09SDavid van Moolenbroek  *
956*00b67f09SDavid van Moolenbroek  * Nothing can be NULL, and the done event must list at least one buffer
957*00b67f09SDavid van Moolenbroek  * on the buffer linked list for this function to be meaningful.
958*00b67f09SDavid van Moolenbroek  */
959*00b67f09SDavid van Moolenbroek static void
build_msghdr_send(isc_socket_t * sock,isc_socketevent_t * dev,struct msghdr * msg,char * cmsg,WSABUF * iov,IoCompletionInfo * lpo)960*00b67f09SDavid van Moolenbroek build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
961*00b67f09SDavid van Moolenbroek 		  struct msghdr *msg, char *cmsg, WSABUF *iov,
962*00b67f09SDavid van Moolenbroek 		  IoCompletionInfo  *lpo)
963*00b67f09SDavid van Moolenbroek {
964*00b67f09SDavid van Moolenbroek 	unsigned int iovcount;
965*00b67f09SDavid van Moolenbroek 	isc_buffer_t *buffer;
966*00b67f09SDavid van Moolenbroek 	buflist_t  *cpbuffer;
967*00b67f09SDavid van Moolenbroek 	isc_region_t used;
968*00b67f09SDavid van Moolenbroek 	size_t write_count;
969*00b67f09SDavid van Moolenbroek 	size_t skip_count;
970*00b67f09SDavid van Moolenbroek 
971*00b67f09SDavid van Moolenbroek 	memset(msg, 0, sizeof(*msg));
972*00b67f09SDavid van Moolenbroek 
973*00b67f09SDavid van Moolenbroek 	memmove(&msg->to_addr, &dev->address.type, dev->address.length);
974*00b67f09SDavid van Moolenbroek 	msg->to_addr_len = dev->address.length;
975*00b67f09SDavid van Moolenbroek 
976*00b67f09SDavid van Moolenbroek 	buffer = ISC_LIST_HEAD(dev->bufferlist);
977*00b67f09SDavid van Moolenbroek 	write_count = 0;
978*00b67f09SDavid van Moolenbroek 	iovcount = 0;
979*00b67f09SDavid van Moolenbroek 
980*00b67f09SDavid van Moolenbroek 	/*
981*00b67f09SDavid van Moolenbroek 	 * Single buffer I/O?  Skip what we've done so far in this region.
982*00b67f09SDavid van Moolenbroek 	 */
983*00b67f09SDavid van Moolenbroek 	if (buffer == NULL) {
984*00b67f09SDavid van Moolenbroek 		write_count = dev->region.length - dev->n;
985*00b67f09SDavid van Moolenbroek 		cpbuffer = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(buflist_t));
986*00b67f09SDavid van Moolenbroek 		RUNTIME_CHECK(cpbuffer != NULL);
987*00b67f09SDavid van Moolenbroek 		cpbuffer->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, write_count);
988*00b67f09SDavid van Moolenbroek 		RUNTIME_CHECK(cpbuffer->buf != NULL);
989*00b67f09SDavid van Moolenbroek 
990*00b67f09SDavid van Moolenbroek 		socket_log(__LINE__, sock, NULL, TRACE,
991*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
992*00b67f09SDavid van Moolenbroek 		   "alloc_buffer %p %d %p %d", cpbuffer, sizeof(buflist_t),
993*00b67f09SDavid van Moolenbroek 		   cpbuffer->buf, write_count);
994*00b67f09SDavid van Moolenbroek 
995*00b67f09SDavid van Moolenbroek 		memmove(cpbuffer->buf,(dev->region.base + dev->n), write_count);
996*00b67f09SDavid van Moolenbroek 		cpbuffer->buflen = (unsigned int)write_count;
997*00b67f09SDavid van Moolenbroek 		ISC_LIST_ENQUEUE(lpo->bufferlist, cpbuffer, link);
998*00b67f09SDavid van Moolenbroek 		iov[0].buf = cpbuffer->buf;
999*00b67f09SDavid van Moolenbroek 		iov[0].len = (u_long)write_count;
1000*00b67f09SDavid van Moolenbroek 		iovcount = 1;
1001*00b67f09SDavid van Moolenbroek 
1002*00b67f09SDavid van Moolenbroek 		goto config;
1003*00b67f09SDavid van Moolenbroek 	}
1004*00b67f09SDavid van Moolenbroek 
1005*00b67f09SDavid van Moolenbroek 	/*
1006*00b67f09SDavid van Moolenbroek 	 * Multibuffer I/O.
1007*00b67f09SDavid van Moolenbroek 	 * Skip the data in the buffer list that we have already written.
1008*00b67f09SDavid van Moolenbroek 	 */
1009*00b67f09SDavid van Moolenbroek 	skip_count = dev->n;
1010*00b67f09SDavid van Moolenbroek 	while (buffer != NULL) {
1011*00b67f09SDavid van Moolenbroek 		REQUIRE(ISC_BUFFER_VALID(buffer));
1012*00b67f09SDavid van Moolenbroek 		if (skip_count < isc_buffer_usedlength(buffer))
1013*00b67f09SDavid van Moolenbroek 			break;
1014*00b67f09SDavid van Moolenbroek 		skip_count -= isc_buffer_usedlength(buffer);
1015*00b67f09SDavid van Moolenbroek 		buffer = ISC_LIST_NEXT(buffer, link);
1016*00b67f09SDavid van Moolenbroek 	}
1017*00b67f09SDavid van Moolenbroek 
1018*00b67f09SDavid van Moolenbroek 	while (buffer != NULL) {
1019*00b67f09SDavid van Moolenbroek 		INSIST(iovcount < MAXSCATTERGATHER_SEND);
1020*00b67f09SDavid van Moolenbroek 
1021*00b67f09SDavid van Moolenbroek 		isc_buffer_usedregion(buffer, &used);
1022*00b67f09SDavid van Moolenbroek 
1023*00b67f09SDavid van Moolenbroek 		if (used.length > 0) {
1024*00b67f09SDavid van Moolenbroek 			int uselen = (int)(used.length - skip_count);
1025*00b67f09SDavid van Moolenbroek 			cpbuffer = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(buflist_t));
1026*00b67f09SDavid van Moolenbroek 			RUNTIME_CHECK(cpbuffer != NULL);
1027*00b67f09SDavid van Moolenbroek 			cpbuffer->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, uselen);
1028*00b67f09SDavid van Moolenbroek 			RUNTIME_CHECK(cpbuffer->buf != NULL);
1029*00b67f09SDavid van Moolenbroek 
1030*00b67f09SDavid van Moolenbroek 			socket_log(__LINE__, sock, NULL, TRACE,
1031*00b67f09SDavid van Moolenbroek 			   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
1032*00b67f09SDavid van Moolenbroek 			   "alloc_buffer %p %d %p %d", cpbuffer, sizeof(buflist_t),
1033*00b67f09SDavid van Moolenbroek 			   cpbuffer->buf, write_count);
1034*00b67f09SDavid van Moolenbroek 
1035*00b67f09SDavid van Moolenbroek 			memmove(cpbuffer->buf,(used.base + skip_count), uselen);
1036*00b67f09SDavid van Moolenbroek 			cpbuffer->buflen = uselen;
1037*00b67f09SDavid van Moolenbroek 			iov[iovcount].buf = cpbuffer->buf;
1038*00b67f09SDavid van Moolenbroek 			iov[iovcount].len = (u_long)(used.length - skip_count);
1039*00b67f09SDavid van Moolenbroek 			write_count += uselen;
1040*00b67f09SDavid van Moolenbroek 			skip_count = 0;
1041*00b67f09SDavid van Moolenbroek 			iovcount++;
1042*00b67f09SDavid van Moolenbroek 		}
1043*00b67f09SDavid van Moolenbroek 		buffer = ISC_LIST_NEXT(buffer, link);
1044*00b67f09SDavid van Moolenbroek 	}
1045*00b67f09SDavid van Moolenbroek 
1046*00b67f09SDavid van Moolenbroek 	INSIST(skip_count == 0);
1047*00b67f09SDavid van Moolenbroek 
1048*00b67f09SDavid van Moolenbroek  config:
1049*00b67f09SDavid van Moolenbroek 	msg->msg_iov = iov;
1050*00b67f09SDavid van Moolenbroek 	msg->msg_iovlen = iovcount;
1051*00b67f09SDavid van Moolenbroek 	msg->msg_totallen = (u_int)write_count;
1052*00b67f09SDavid van Moolenbroek }
1053*00b67f09SDavid van Moolenbroek 
1054*00b67f09SDavid van Moolenbroek static void
set_dev_address(isc_sockaddr_t * address,isc_socket_t * sock,isc_socketevent_t * dev)1055*00b67f09SDavid van Moolenbroek set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock,
1056*00b67f09SDavid van Moolenbroek 		isc_socketevent_t *dev)
1057*00b67f09SDavid van Moolenbroek {
1058*00b67f09SDavid van Moolenbroek 	if (sock->type == isc_sockettype_udp) {
1059*00b67f09SDavid van Moolenbroek 		if (address != NULL)
1060*00b67f09SDavid van Moolenbroek 			dev->address = *address;
1061*00b67f09SDavid van Moolenbroek 		else
1062*00b67f09SDavid van Moolenbroek 			dev->address = sock->address;
1063*00b67f09SDavid van Moolenbroek 	} else if (sock->type == isc_sockettype_tcp) {
1064*00b67f09SDavid van Moolenbroek 		INSIST(address == NULL);
1065*00b67f09SDavid van Moolenbroek 		dev->address = sock->address;
1066*00b67f09SDavid van Moolenbroek 	}
1067*00b67f09SDavid van Moolenbroek }
1068*00b67f09SDavid van Moolenbroek 
1069*00b67f09SDavid van Moolenbroek static void
destroy_socketevent(isc_event_t * event)1070*00b67f09SDavid van Moolenbroek destroy_socketevent(isc_event_t *event) {
1071*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *ev = (isc_socketevent_t *)event;
1072*00b67f09SDavid van Moolenbroek 
1073*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LIST_EMPTY(ev->bufferlist));
1074*00b67f09SDavid van Moolenbroek 
1075*00b67f09SDavid van Moolenbroek 	(ev->destroy)(event);
1076*00b67f09SDavid van Moolenbroek }
1077*00b67f09SDavid van Moolenbroek 
1078*00b67f09SDavid van Moolenbroek static isc_socketevent_t *
allocate_socketevent(isc_mem_t * mctx,isc_socket_t * sock,isc_eventtype_t eventtype,isc_taskaction_t action,void * arg)1079*00b67f09SDavid van Moolenbroek allocate_socketevent(isc_mem_t *mctx, isc_socket_t *sock,
1080*00b67f09SDavid van Moolenbroek 		     isc_eventtype_t eventtype, isc_taskaction_t action,
1081*00b67f09SDavid van Moolenbroek 		     void *arg)
1082*00b67f09SDavid van Moolenbroek {
1083*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *ev;
1084*00b67f09SDavid van Moolenbroek 
1085*00b67f09SDavid van Moolenbroek 	ev = (isc_socketevent_t *)isc_event_allocate(mctx, sock, eventtype,
1086*00b67f09SDavid van Moolenbroek 						     action, arg,
1087*00b67f09SDavid van Moolenbroek 						     sizeof(*ev));
1088*00b67f09SDavid van Moolenbroek 	if (ev == NULL)
1089*00b67f09SDavid van Moolenbroek 		return (NULL);
1090*00b67f09SDavid van Moolenbroek 
1091*00b67f09SDavid van Moolenbroek 	ev->result = ISC_R_IOERROR; // XXXMLG temporary change to detect failure to set
1092*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(ev, ev_link);
1093*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(ev->bufferlist);
1094*00b67f09SDavid van Moolenbroek 	ev->region.base = NULL;
1095*00b67f09SDavid van Moolenbroek 	ev->n = 0;
1096*00b67f09SDavid van Moolenbroek 	ev->offset = 0;
1097*00b67f09SDavid van Moolenbroek 	ev->attributes = 0;
1098*00b67f09SDavid van Moolenbroek 	ev->destroy = ev->ev_destroy;
1099*00b67f09SDavid van Moolenbroek 	ev->ev_destroy = destroy_socketevent;
1100*00b67f09SDavid van Moolenbroek 	ev->dscp = 0;
1101*00b67f09SDavid van Moolenbroek 
1102*00b67f09SDavid van Moolenbroek 	return (ev);
1103*00b67f09SDavid van Moolenbroek }
1104*00b67f09SDavid van Moolenbroek 
1105*00b67f09SDavid van Moolenbroek #if defined(ISC_SOCKET_DEBUG)
1106*00b67f09SDavid van Moolenbroek static void
dump_msg(struct msghdr * msg,isc_socket_t * sock)1107*00b67f09SDavid van Moolenbroek dump_msg(struct msghdr *msg, isc_socket_t *sock) {
1108*00b67f09SDavid van Moolenbroek 	unsigned int i;
1109*00b67f09SDavid van Moolenbroek 
1110*00b67f09SDavid van Moolenbroek 	printf("MSGHDR %p, Socket #: %u\n", msg, sock->fd);
1111*00b67f09SDavid van Moolenbroek 	printf("\tname %p, namelen %d\n", msg->msg_name, msg->msg_namelen);
1112*00b67f09SDavid van Moolenbroek 	printf("\tiov %p, iovlen %d\n", msg->msg_iov, msg->msg_iovlen);
1113*00b67f09SDavid van Moolenbroek 	for (i = 0; i < (unsigned int)msg->msg_iovlen; i++)
1114*00b67f09SDavid van Moolenbroek 		printf("\t\t%u\tbase %p, len %u\n", i,
1115*00b67f09SDavid van Moolenbroek 		       msg->msg_iov[i].buf, msg->msg_iov[i].len);
1116*00b67f09SDavid van Moolenbroek }
1117*00b67f09SDavid van Moolenbroek #endif
1118*00b67f09SDavid van Moolenbroek 
1119*00b67f09SDavid van Moolenbroek /*
1120*00b67f09SDavid van Moolenbroek  * map the error code
1121*00b67f09SDavid van Moolenbroek  */
1122*00b67f09SDavid van Moolenbroek int
map_socket_error(isc_socket_t * sock,int windows_errno,int * isc_errno,char * errorstring,size_t bufsize)1123*00b67f09SDavid van Moolenbroek map_socket_error(isc_socket_t *sock, int windows_errno, int *isc_errno,
1124*00b67f09SDavid van Moolenbroek 		 char *errorstring, size_t bufsize) {
1125*00b67f09SDavid van Moolenbroek 
1126*00b67f09SDavid van Moolenbroek 	int doreturn;
1127*00b67f09SDavid van Moolenbroek 	switch (windows_errno) {
1128*00b67f09SDavid van Moolenbroek 	case WSAECONNREFUSED:
1129*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_CONNREFUSED;
1130*00b67f09SDavid van Moolenbroek 		if (sock->connected)
1131*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_HARD;
1132*00b67f09SDavid van Moolenbroek 		else
1133*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_SOFT;
1134*00b67f09SDavid van Moolenbroek 		break;
1135*00b67f09SDavid van Moolenbroek 	case WSAENETUNREACH:
1136*00b67f09SDavid van Moolenbroek 	case ERROR_NETWORK_UNREACHABLE:
1137*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_NETUNREACH;
1138*00b67f09SDavid van Moolenbroek 		if (sock->connected)
1139*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_HARD;
1140*00b67f09SDavid van Moolenbroek 		else
1141*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_SOFT;
1142*00b67f09SDavid van Moolenbroek 		break;
1143*00b67f09SDavid van Moolenbroek 	case ERROR_PORT_UNREACHABLE:
1144*00b67f09SDavid van Moolenbroek 	case ERROR_HOST_UNREACHABLE:
1145*00b67f09SDavid van Moolenbroek 	case WSAEHOSTUNREACH:
1146*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_HOSTUNREACH;
1147*00b67f09SDavid van Moolenbroek 		if (sock->connected)
1148*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_HARD;
1149*00b67f09SDavid van Moolenbroek 		else
1150*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_SOFT;
1151*00b67f09SDavid van Moolenbroek 		break;
1152*00b67f09SDavid van Moolenbroek 	case WSAENETDOWN:
1153*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_NETDOWN;
1154*00b67f09SDavid van Moolenbroek 		if (sock->connected)
1155*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_HARD;
1156*00b67f09SDavid van Moolenbroek 		else
1157*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_SOFT;
1158*00b67f09SDavid van Moolenbroek 		break;
1159*00b67f09SDavid van Moolenbroek 	case WSAEHOSTDOWN:
1160*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_HOSTDOWN;
1161*00b67f09SDavid van Moolenbroek 		if (sock->connected)
1162*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_HARD;
1163*00b67f09SDavid van Moolenbroek 		else
1164*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_SOFT;
1165*00b67f09SDavid van Moolenbroek 		break;
1166*00b67f09SDavid van Moolenbroek 	case WSAEACCES:
1167*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_NOPERM;
1168*00b67f09SDavid van Moolenbroek 		if (sock->connected)
1169*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_HARD;
1170*00b67f09SDavid van Moolenbroek 		else
1171*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_SOFT;
1172*00b67f09SDavid van Moolenbroek 		break;
1173*00b67f09SDavid van Moolenbroek 	case WSAECONNRESET:
1174*00b67f09SDavid van Moolenbroek 	case WSAENETRESET:
1175*00b67f09SDavid van Moolenbroek 	case WSAECONNABORTED:
1176*00b67f09SDavid van Moolenbroek 	case WSAEDISCON:
1177*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_CONNECTIONRESET;
1178*00b67f09SDavid van Moolenbroek 		if (sock->connected)
1179*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_HARD;
1180*00b67f09SDavid van Moolenbroek 		else
1181*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_SOFT;
1182*00b67f09SDavid van Moolenbroek 		break;
1183*00b67f09SDavid van Moolenbroek 	case WSAENOTCONN:
1184*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_NOTCONNECTED;
1185*00b67f09SDavid van Moolenbroek 		if (sock->connected)
1186*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_HARD;
1187*00b67f09SDavid van Moolenbroek 		else
1188*00b67f09SDavid van Moolenbroek 			doreturn = DOIO_SOFT;
1189*00b67f09SDavid van Moolenbroek 		break;
1190*00b67f09SDavid van Moolenbroek 	case ERROR_OPERATION_ABORTED:
1191*00b67f09SDavid van Moolenbroek 	case ERROR_CONNECTION_ABORTED:
1192*00b67f09SDavid van Moolenbroek 	case ERROR_REQUEST_ABORTED:
1193*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_CONNECTIONRESET;
1194*00b67f09SDavid van Moolenbroek 		doreturn = DOIO_HARD;
1195*00b67f09SDavid van Moolenbroek 		break;
1196*00b67f09SDavid van Moolenbroek 	case WSAENOBUFS:
1197*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_NORESOURCES;
1198*00b67f09SDavid van Moolenbroek 		doreturn = DOIO_HARD;
1199*00b67f09SDavid van Moolenbroek 		break;
1200*00b67f09SDavid van Moolenbroek 	case WSAEAFNOSUPPORT:
1201*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_FAMILYNOSUPPORT;
1202*00b67f09SDavid van Moolenbroek 		doreturn = DOIO_HARD;
1203*00b67f09SDavid van Moolenbroek 		break;
1204*00b67f09SDavid van Moolenbroek 	case WSAEADDRNOTAVAIL:
1205*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_ADDRNOTAVAIL;
1206*00b67f09SDavid van Moolenbroek 		doreturn = DOIO_HARD;
1207*00b67f09SDavid van Moolenbroek 		break;
1208*00b67f09SDavid van Moolenbroek 	case WSAEDESTADDRREQ:
1209*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_BADADDRESSFORM;
1210*00b67f09SDavid van Moolenbroek 		doreturn = DOIO_HARD;
1211*00b67f09SDavid van Moolenbroek 		break;
1212*00b67f09SDavid van Moolenbroek 	case ERROR_NETNAME_DELETED:
1213*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_NETDOWN;
1214*00b67f09SDavid van Moolenbroek 		doreturn = DOIO_HARD;
1215*00b67f09SDavid van Moolenbroek 		break;
1216*00b67f09SDavid van Moolenbroek 	default:
1217*00b67f09SDavid van Moolenbroek 		*isc_errno = ISC_R_IOERROR;
1218*00b67f09SDavid van Moolenbroek 		doreturn = DOIO_HARD;
1219*00b67f09SDavid van Moolenbroek 		break;
1220*00b67f09SDavid van Moolenbroek 	}
1221*00b67f09SDavid van Moolenbroek 	if (doreturn == DOIO_HARD) {
1222*00b67f09SDavid van Moolenbroek 		isc__strerror(windows_errno, errorstring, bufsize);
1223*00b67f09SDavid van Moolenbroek 	}
1224*00b67f09SDavid van Moolenbroek 	return (doreturn);
1225*00b67f09SDavid van Moolenbroek }
1226*00b67f09SDavid van Moolenbroek 
1227*00b67f09SDavid van Moolenbroek static void
fill_recv(isc_socket_t * sock,isc_socketevent_t * dev)1228*00b67f09SDavid van Moolenbroek fill_recv(isc_socket_t *sock, isc_socketevent_t *dev) {
1229*00b67f09SDavid van Moolenbroek 	isc_region_t r;
1230*00b67f09SDavid van Moolenbroek 	int copylen;
1231*00b67f09SDavid van Moolenbroek 	isc_buffer_t *buffer;
1232*00b67f09SDavid van Moolenbroek 
1233*00b67f09SDavid van Moolenbroek 	INSIST(dev->n < dev->minimum);
1234*00b67f09SDavid van Moolenbroek 	INSIST(sock->recvbuf.remaining > 0);
1235*00b67f09SDavid van Moolenbroek 	INSIST(sock->pending_recv == 0);
1236*00b67f09SDavid van Moolenbroek 
1237*00b67f09SDavid van Moolenbroek 	if (sock->type == isc_sockettype_udp) {
1238*00b67f09SDavid van Moolenbroek 		dev->address.length = sock->recvbuf.from_addr_len;
1239*00b67f09SDavid van Moolenbroek 		memmove(&dev->address.type, &sock->recvbuf.from_addr,
1240*00b67f09SDavid van Moolenbroek 			sock->recvbuf.from_addr_len);
1241*00b67f09SDavid van Moolenbroek 		if (isc_sockaddr_getport(&dev->address) == 0) {
1242*00b67f09SDavid van Moolenbroek 			if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
1243*00b67f09SDavid van Moolenbroek 				socket_log(__LINE__, sock, &dev->address, IOEVENT,
1244*00b67f09SDavid van Moolenbroek 					   isc_msgcat, ISC_MSGSET_SOCKET,
1245*00b67f09SDavid van Moolenbroek 					   ISC_MSG_ZEROPORT,
1246*00b67f09SDavid van Moolenbroek 					   "dropping source port zero packet");
1247*00b67f09SDavid van Moolenbroek 			}
1248*00b67f09SDavid van Moolenbroek 			sock->recvbuf.remaining = 0;
1249*00b67f09SDavid van Moolenbroek 			return;
1250*00b67f09SDavid van Moolenbroek 		}
1251*00b67f09SDavid van Moolenbroek 	} else if (sock->type == isc_sockettype_tcp) {
1252*00b67f09SDavid van Moolenbroek 		dev->address = sock->address;
1253*00b67f09SDavid van Moolenbroek 	}
1254*00b67f09SDavid van Moolenbroek 
1255*00b67f09SDavid van Moolenbroek 	/*
1256*00b67f09SDavid van Moolenbroek 	 * Run through the list of buffers we were given, and find the
1257*00b67f09SDavid van Moolenbroek 	 * first one with space.  Once it is found, loop through, filling
1258*00b67f09SDavid van Moolenbroek 	 * the buffers as much as possible.
1259*00b67f09SDavid van Moolenbroek 	 */
1260*00b67f09SDavid van Moolenbroek 	buffer = ISC_LIST_HEAD(dev->bufferlist);
1261*00b67f09SDavid van Moolenbroek 	if (buffer != NULL) { // Multi-buffer receive
1262*00b67f09SDavid van Moolenbroek 		while (buffer != NULL && sock->recvbuf.remaining > 0) {
1263*00b67f09SDavid van Moolenbroek 			REQUIRE(ISC_BUFFER_VALID(buffer));
1264*00b67f09SDavid van Moolenbroek 			if (isc_buffer_availablelength(buffer) > 0) {
1265*00b67f09SDavid van Moolenbroek 				isc_buffer_availableregion(buffer, &r);
1266*00b67f09SDavid van Moolenbroek 				copylen = min(r.length,
1267*00b67f09SDavid van Moolenbroek 					      sock->recvbuf.remaining);
1268*00b67f09SDavid van Moolenbroek 				memmove(r.base, sock->recvbuf.consume_position,
1269*00b67f09SDavid van Moolenbroek 					copylen);
1270*00b67f09SDavid van Moolenbroek 				sock->recvbuf.consume_position += copylen;
1271*00b67f09SDavid van Moolenbroek 				sock->recvbuf.remaining -= copylen;
1272*00b67f09SDavid van Moolenbroek 				isc_buffer_add(buffer, copylen);
1273*00b67f09SDavid van Moolenbroek 				dev->n += copylen;
1274*00b67f09SDavid van Moolenbroek 			}
1275*00b67f09SDavid van Moolenbroek 			buffer = ISC_LIST_NEXT(buffer, link);
1276*00b67f09SDavid van Moolenbroek 		}
1277*00b67f09SDavid van Moolenbroek 	} else { // Single-buffer receive
1278*00b67f09SDavid van Moolenbroek 		copylen = min(dev->region.length - dev->n, sock->recvbuf.remaining);
1279*00b67f09SDavid van Moolenbroek 		memmove(dev->region.base + dev->n,
1280*00b67f09SDavid van Moolenbroek 			sock->recvbuf.consume_position, copylen);
1281*00b67f09SDavid van Moolenbroek 		sock->recvbuf.consume_position += copylen;
1282*00b67f09SDavid van Moolenbroek 		sock->recvbuf.remaining -= copylen;
1283*00b67f09SDavid van Moolenbroek 		dev->n += copylen;
1284*00b67f09SDavid van Moolenbroek 	}
1285*00b67f09SDavid van Moolenbroek 
1286*00b67f09SDavid van Moolenbroek 	/*
1287*00b67f09SDavid van Moolenbroek 	 * UDP receives are all-consuming.  That is, if we have 4k worth of
1288*00b67f09SDavid van Moolenbroek 	 * data in our receive buffer, and the caller only gave us
1289*00b67f09SDavid van Moolenbroek 	 * 1k of space, we will toss the remaining 3k of data.  TCP
1290*00b67f09SDavid van Moolenbroek 	 * will keep the extra data around and use it for later requests.
1291*00b67f09SDavid van Moolenbroek 	 */
1292*00b67f09SDavid van Moolenbroek 	if (sock->type == isc_sockettype_udp)
1293*00b67f09SDavid van Moolenbroek 		sock->recvbuf.remaining = 0;
1294*00b67f09SDavid van Moolenbroek }
1295*00b67f09SDavid van Moolenbroek 
1296*00b67f09SDavid van Moolenbroek /*
1297*00b67f09SDavid van Moolenbroek  * Copy out as much data from the internal buffer to done events.
1298*00b67f09SDavid van Moolenbroek  * As each done event is filled, send it along its way.
1299*00b67f09SDavid van Moolenbroek  */
1300*00b67f09SDavid van Moolenbroek static void
completeio_recv(isc_socket_t * sock)1301*00b67f09SDavid van Moolenbroek completeio_recv(isc_socket_t *sock)
1302*00b67f09SDavid van Moolenbroek {
1303*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *dev;
1304*00b67f09SDavid van Moolenbroek 
1305*00b67f09SDavid van Moolenbroek 	/*
1306*00b67f09SDavid van Moolenbroek 	 * If we are in the process of filling our buffer, we cannot
1307*00b67f09SDavid van Moolenbroek 	 * touch it yet, so don't.
1308*00b67f09SDavid van Moolenbroek 	 */
1309*00b67f09SDavid van Moolenbroek 	if (sock->pending_recv > 0)
1310*00b67f09SDavid van Moolenbroek 		return;
1311*00b67f09SDavid van Moolenbroek 
1312*00b67f09SDavid van Moolenbroek 	while (sock->recvbuf.remaining > 0 && !ISC_LIST_EMPTY(sock->recv_list)) {
1313*00b67f09SDavid van Moolenbroek 		dev = ISC_LIST_HEAD(sock->recv_list);
1314*00b67f09SDavid van Moolenbroek 
1315*00b67f09SDavid van Moolenbroek 		/*
1316*00b67f09SDavid van Moolenbroek 		 * See if we have sufficient data in our receive buffer
1317*00b67f09SDavid van Moolenbroek 		 * to handle this.  If we do, copy out the data.
1318*00b67f09SDavid van Moolenbroek 		 */
1319*00b67f09SDavid van Moolenbroek 		fill_recv(sock, dev);
1320*00b67f09SDavid van Moolenbroek 
1321*00b67f09SDavid van Moolenbroek 		/*
1322*00b67f09SDavid van Moolenbroek 		 * Did we satisfy it?
1323*00b67f09SDavid van Moolenbroek 		 */
1324*00b67f09SDavid van Moolenbroek 		if (dev->n >= dev->minimum) {
1325*00b67f09SDavid van Moolenbroek 			dev->result = ISC_R_SUCCESS;
1326*00b67f09SDavid van Moolenbroek 			send_recvdone_event(sock, &dev);
1327*00b67f09SDavid van Moolenbroek 		}
1328*00b67f09SDavid van Moolenbroek 	}
1329*00b67f09SDavid van Moolenbroek }
1330*00b67f09SDavid van Moolenbroek 
1331*00b67f09SDavid van Moolenbroek /*
1332*00b67f09SDavid van Moolenbroek  * Returns:
1333*00b67f09SDavid van Moolenbroek  *	DOIO_SUCCESS	The operation succeeded.  dev->result contains
1334*00b67f09SDavid van Moolenbroek  *			ISC_R_SUCCESS.
1335*00b67f09SDavid van Moolenbroek  *
1336*00b67f09SDavid van Moolenbroek  *	DOIO_HARD	A hard or unexpected I/O error was encountered.
1337*00b67f09SDavid van Moolenbroek  *			dev->result contains the appropriate error.
1338*00b67f09SDavid van Moolenbroek  *
1339*00b67f09SDavid van Moolenbroek  *	DOIO_SOFT	A soft I/O error was encountered.  No senddone
1340*00b67f09SDavid van Moolenbroek  *			event was sent.  The operation should be retried.
1341*00b67f09SDavid van Moolenbroek  *
1342*00b67f09SDavid van Moolenbroek  *	No other return values are possible.
1343*00b67f09SDavid van Moolenbroek  */
1344*00b67f09SDavid van Moolenbroek static int
completeio_send(isc_socket_t * sock,isc_socketevent_t * dev,struct msghdr * messagehdr,int cc,int send_errno)1345*00b67f09SDavid van Moolenbroek completeio_send(isc_socket_t *sock, isc_socketevent_t *dev,
1346*00b67f09SDavid van Moolenbroek 		struct msghdr *messagehdr, int cc, int send_errno)
1347*00b67f09SDavid van Moolenbroek {
1348*00b67f09SDavid van Moolenbroek 	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
1349*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
1350*00b67f09SDavid van Moolenbroek 
1351*00b67f09SDavid van Moolenbroek 	if (send_errno != 0) {
1352*00b67f09SDavid van Moolenbroek 		if (SOFT_ERROR(send_errno))
1353*00b67f09SDavid van Moolenbroek 			return (DOIO_SOFT);
1354*00b67f09SDavid van Moolenbroek 
1355*00b67f09SDavid van Moolenbroek 		return (map_socket_error(sock, send_errno, &dev->result,
1356*00b67f09SDavid van Moolenbroek 			strbuf, sizeof(strbuf)));
1357*00b67f09SDavid van Moolenbroek 
1358*00b67f09SDavid van Moolenbroek 		/*
1359*00b67f09SDavid van Moolenbroek 		 * The other error types depend on whether or not the
1360*00b67f09SDavid van Moolenbroek 		 * socket is UDP or TCP.  If it is UDP, some errors
1361*00b67f09SDavid van Moolenbroek 		 * that we expect to be fatal under TCP are merely
1362*00b67f09SDavid van Moolenbroek 		 * annoying, and are really soft errors.
1363*00b67f09SDavid van Moolenbroek 		 *
1364*00b67f09SDavid van Moolenbroek 		 * However, these soft errors are still returned as
1365*00b67f09SDavid van Moolenbroek 		 * a status.
1366*00b67f09SDavid van Moolenbroek 		 */
1367*00b67f09SDavid van Moolenbroek 		isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf));
1368*00b67f09SDavid van Moolenbroek 		isc__strerror(send_errno, strbuf, sizeof(strbuf));
1369*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__, "completeio_send: %s: %s",
1370*00b67f09SDavid van Moolenbroek 				 addrbuf, strbuf);
1371*00b67f09SDavid van Moolenbroek 		dev->result = isc__errno2result(send_errno);
1372*00b67f09SDavid van Moolenbroek 		return (DOIO_HARD);
1373*00b67f09SDavid van Moolenbroek 	}
1374*00b67f09SDavid van Moolenbroek 
1375*00b67f09SDavid van Moolenbroek 	/*
1376*00b67f09SDavid van Moolenbroek 	 * If we write less than we expected, update counters, poke.
1377*00b67f09SDavid van Moolenbroek 	 */
1378*00b67f09SDavid van Moolenbroek 	dev->n += cc;
1379*00b67f09SDavid van Moolenbroek 	if (cc != messagehdr->msg_totallen)
1380*00b67f09SDavid van Moolenbroek 		return (DOIO_SOFT);
1381*00b67f09SDavid van Moolenbroek 
1382*00b67f09SDavid van Moolenbroek 	/*
1383*00b67f09SDavid van Moolenbroek 	 * Exactly what we wanted to write.  We're done with this
1384*00b67f09SDavid van Moolenbroek 	 * entry.  Post its completion event.
1385*00b67f09SDavid van Moolenbroek 	 */
1386*00b67f09SDavid van Moolenbroek 	dev->result = ISC_R_SUCCESS;
1387*00b67f09SDavid van Moolenbroek 	return (DOIO_SUCCESS);
1388*00b67f09SDavid van Moolenbroek }
1389*00b67f09SDavid van Moolenbroek 
1390*00b67f09SDavid van Moolenbroek static int
startio_send(isc_socket_t * sock,isc_socketevent_t * dev,int * nbytes,int * send_errno)1391*00b67f09SDavid van Moolenbroek startio_send(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
1392*00b67f09SDavid van Moolenbroek 	     int *send_errno)
1393*00b67f09SDavid van Moolenbroek {
1394*00b67f09SDavid van Moolenbroek 	char *cmsg = NULL;
1395*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
1396*00b67f09SDavid van Moolenbroek 	IoCompletionInfo *lpo;
1397*00b67f09SDavid van Moolenbroek 	int status;
1398*00b67f09SDavid van Moolenbroek 	struct msghdr *msghdr;
1399*00b67f09SDavid van Moolenbroek 
1400*00b67f09SDavid van Moolenbroek 	lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
1401*00b67f09SDavid van Moolenbroek 					    HEAP_ZERO_MEMORY,
1402*00b67f09SDavid van Moolenbroek 					    sizeof(IoCompletionInfo));
1403*00b67f09SDavid van Moolenbroek 	RUNTIME_CHECK(lpo != NULL);
1404*00b67f09SDavid van Moolenbroek 	lpo->request_type = SOCKET_SEND;
1405*00b67f09SDavid van Moolenbroek 	lpo->dev = dev;
1406*00b67f09SDavid van Moolenbroek 	msghdr = &lpo->messagehdr;
1407*00b67f09SDavid van Moolenbroek 	memset(msghdr, 0, sizeof(struct msghdr));
1408*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(lpo->bufferlist);
1409*00b67f09SDavid van Moolenbroek 
1410*00b67f09SDavid van Moolenbroek 	build_msghdr_send(sock, dev, msghdr, cmsg, sock->iov, lpo);
1411*00b67f09SDavid van Moolenbroek 
1412*00b67f09SDavid van Moolenbroek 	*nbytes = internal_sendmsg(sock, lpo, msghdr, 0, send_errno);
1413*00b67f09SDavid van Moolenbroek 
1414*00b67f09SDavid van Moolenbroek 	if (*nbytes <= 0) {
1415*00b67f09SDavid van Moolenbroek 		/*
1416*00b67f09SDavid van Moolenbroek 		 * I/O has been initiated
1417*00b67f09SDavid van Moolenbroek 		 * completion will be through the completion port
1418*00b67f09SDavid van Moolenbroek 		 */
1419*00b67f09SDavid van Moolenbroek 		if (PENDING_ERROR(*send_errno)) {
1420*00b67f09SDavid van Moolenbroek 			status = DOIO_PENDING;
1421*00b67f09SDavid van Moolenbroek 			goto done;
1422*00b67f09SDavid van Moolenbroek 		}
1423*00b67f09SDavid van Moolenbroek 
1424*00b67f09SDavid van Moolenbroek 		if (SOFT_ERROR(*send_errno)) {
1425*00b67f09SDavid van Moolenbroek 			status = DOIO_SOFT;
1426*00b67f09SDavid van Moolenbroek 			goto done;
1427*00b67f09SDavid van Moolenbroek 		}
1428*00b67f09SDavid van Moolenbroek 
1429*00b67f09SDavid van Moolenbroek 		/*
1430*00b67f09SDavid van Moolenbroek 		 * If we got this far then something is wrong
1431*00b67f09SDavid van Moolenbroek 		 */
1432*00b67f09SDavid van Moolenbroek 		if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
1433*00b67f09SDavid van Moolenbroek 			isc__strerror(*send_errno, strbuf, sizeof(strbuf));
1434*00b67f09SDavid van Moolenbroek 			socket_log(__LINE__, sock, NULL, IOEVENT,
1435*00b67f09SDavid van Moolenbroek 				   isc_msgcat, ISC_MSGSET_SOCKET,
1436*00b67f09SDavid van Moolenbroek 				   ISC_MSG_INTERNALSEND,
1437*00b67f09SDavid van Moolenbroek 				   "startio_send: internal_sendmsg(%d) %d "
1438*00b67f09SDavid van Moolenbroek 				   "bytes, err %d/%s",
1439*00b67f09SDavid van Moolenbroek 				   sock->fd, *nbytes, *send_errno, strbuf);
1440*00b67f09SDavid van Moolenbroek 		}
1441*00b67f09SDavid van Moolenbroek 		status = DOIO_HARD;
1442*00b67f09SDavid van Moolenbroek 		goto done;
1443*00b67f09SDavid van Moolenbroek 	}
1444*00b67f09SDavid van Moolenbroek 	dev->result = ISC_R_SUCCESS;
1445*00b67f09SDavid van Moolenbroek 	status = DOIO_SOFT;
1446*00b67f09SDavid van Moolenbroek  done:
1447*00b67f09SDavid van Moolenbroek 	_set_state(sock, SOCK_DATA);
1448*00b67f09SDavid van Moolenbroek 	return (status);
1449*00b67f09SDavid van Moolenbroek }
1450*00b67f09SDavid van Moolenbroek 
1451*00b67f09SDavid van Moolenbroek static void
use_min_mtu(isc_socket_t * sock)1452*00b67f09SDavid van Moolenbroek use_min_mtu(isc_socket_t *sock) {
1453*00b67f09SDavid van Moolenbroek #ifdef IPV6_USE_MIN_MTU
1454*00b67f09SDavid van Moolenbroek 	/* use minimum MTU */
1455*00b67f09SDavid van Moolenbroek 	if (sock->pf == AF_INET6) {
1456*00b67f09SDavid van Moolenbroek 		int on = 1;
1457*00b67f09SDavid van Moolenbroek 		(void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
1458*00b67f09SDavid van Moolenbroek 				(void *)&on, sizeof(on));
1459*00b67f09SDavid van Moolenbroek 	}
1460*00b67f09SDavid van Moolenbroek #else
1461*00b67f09SDavid van Moolenbroek 	UNUSED(sock);
1462*00b67f09SDavid van Moolenbroek #endif
1463*00b67f09SDavid van Moolenbroek }
1464*00b67f09SDavid van Moolenbroek 
1465*00b67f09SDavid van Moolenbroek static isc_result_t
allocate_socket(isc_socketmgr_t * manager,isc_sockettype_t type,isc_socket_t ** socketp)1466*00b67f09SDavid van Moolenbroek allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
1467*00b67f09SDavid van Moolenbroek 		isc_socket_t **socketp) {
1468*00b67f09SDavid van Moolenbroek 	isc_socket_t *sock;
1469*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1470*00b67f09SDavid van Moolenbroek 
1471*00b67f09SDavid van Moolenbroek 	sock = isc_mem_get(manager->mctx, sizeof(*sock));
1472*00b67f09SDavid van Moolenbroek 
1473*00b67f09SDavid van Moolenbroek 	if (sock == NULL)
1474*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
1475*00b67f09SDavid van Moolenbroek 
1476*00b67f09SDavid van Moolenbroek 	sock->magic = 0;
1477*00b67f09SDavid van Moolenbroek 	sock->references = 0;
1478*00b67f09SDavid van Moolenbroek 
1479*00b67f09SDavid van Moolenbroek 	sock->manager = manager;
1480*00b67f09SDavid van Moolenbroek 	sock->type = type;
1481*00b67f09SDavid van Moolenbroek 	sock->fd = INVALID_SOCKET;
1482*00b67f09SDavid van Moolenbroek 
1483*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(sock, link);
1484*00b67f09SDavid van Moolenbroek 
1485*00b67f09SDavid van Moolenbroek 	/*
1486*00b67f09SDavid van Moolenbroek 	 * Set up list of readers and writers to be initially empty.
1487*00b67f09SDavid van Moolenbroek 	 */
1488*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(sock->recv_list);
1489*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(sock->send_list);
1490*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(sock->accept_list);
1491*00b67f09SDavid van Moolenbroek 	sock->connect_ev = NULL;
1492*00b67f09SDavid van Moolenbroek 	sock->pending_accept = 0;
1493*00b67f09SDavid van Moolenbroek 	sock->pending_recv = 0;
1494*00b67f09SDavid van Moolenbroek 	sock->pending_send = 0;
1495*00b67f09SDavid van Moolenbroek 	sock->pending_iocp = 0;
1496*00b67f09SDavid van Moolenbroek 	sock->listener = 0;
1497*00b67f09SDavid van Moolenbroek 	sock->connected = 0;
1498*00b67f09SDavid van Moolenbroek 	sock->pending_connect = 0;
1499*00b67f09SDavid van Moolenbroek 	sock->bound = 0;
1500*00b67f09SDavid van Moolenbroek 	sock->dupped = 0;
1501*00b67f09SDavid van Moolenbroek 	memset(sock->name, 0, sizeof(sock->name));	// zero the name field
1502*00b67f09SDavid van Moolenbroek 	_set_state(sock, SOCK_INITIALIZED);
1503*00b67f09SDavid van Moolenbroek 
1504*00b67f09SDavid van Moolenbroek 	sock->recvbuf.len = 65536;
1505*00b67f09SDavid van Moolenbroek 	sock->recvbuf.consume_position = sock->recvbuf.base;
1506*00b67f09SDavid van Moolenbroek 	sock->recvbuf.remaining = 0;
1507*00b67f09SDavid van Moolenbroek 	sock->recvbuf.base = isc_mem_get(manager->mctx, sock->recvbuf.len); // max buffer size
1508*00b67f09SDavid van Moolenbroek 	if (sock->recvbuf.base == NULL) {
1509*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
1510*00b67f09SDavid van Moolenbroek 		goto error;
1511*00b67f09SDavid van Moolenbroek 	}
1512*00b67f09SDavid van Moolenbroek 
1513*00b67f09SDavid van Moolenbroek 	/*
1514*00b67f09SDavid van Moolenbroek 	 * Initialize the lock.
1515*00b67f09SDavid van Moolenbroek 	 */
1516*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&sock->lock);
1517*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1518*00b67f09SDavid van Moolenbroek 		goto error;
1519*00b67f09SDavid van Moolenbroek 
1520*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
1521*00b67f09SDavid van Moolenbroek 		   "allocated");
1522*00b67f09SDavid van Moolenbroek 
1523*00b67f09SDavid van Moolenbroek 	sock->magic = SOCKET_MAGIC;
1524*00b67f09SDavid van Moolenbroek 	*socketp = sock;
1525*00b67f09SDavid van Moolenbroek 
1526*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1527*00b67f09SDavid van Moolenbroek 
1528*00b67f09SDavid van Moolenbroek  error:
1529*00b67f09SDavid van Moolenbroek 	if (sock->recvbuf.base != NULL)
1530*00b67f09SDavid van Moolenbroek 		isc_mem_put(manager->mctx, sock->recvbuf.base, sock->recvbuf.len);
1531*00b67f09SDavid van Moolenbroek 	isc_mem_put(manager->mctx, sock, sizeof(*sock));
1532*00b67f09SDavid van Moolenbroek 
1533*00b67f09SDavid van Moolenbroek 	return (result);
1534*00b67f09SDavid van Moolenbroek }
1535*00b67f09SDavid van Moolenbroek 
1536*00b67f09SDavid van Moolenbroek /*
1537*00b67f09SDavid van Moolenbroek  * Verify that the socket state is consistent.
1538*00b67f09SDavid van Moolenbroek  */
1539*00b67f09SDavid van Moolenbroek static void
consistent(isc_socket_t * sock)1540*00b67f09SDavid van Moolenbroek consistent(isc_socket_t *sock) {
1541*00b67f09SDavid van Moolenbroek 
1542*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *dev;
1543*00b67f09SDavid van Moolenbroek 	isc_socket_newconnev_t *nev;
1544*00b67f09SDavid van Moolenbroek 	unsigned int count;
1545*00b67f09SDavid van Moolenbroek 	char *crash_reason;
1546*00b67f09SDavid van Moolenbroek 	isc_boolean_t crash = ISC_FALSE;
1547*00b67f09SDavid van Moolenbroek 
1548*00b67f09SDavid van Moolenbroek 	REQUIRE(sock->pending_iocp == sock->pending_recv + sock->pending_send
1549*00b67f09SDavid van Moolenbroek 		+ sock->pending_accept + sock->pending_connect);
1550*00b67f09SDavid van Moolenbroek 
1551*00b67f09SDavid van Moolenbroek 	dev = ISC_LIST_HEAD(sock->send_list);
1552*00b67f09SDavid van Moolenbroek 	count = 0;
1553*00b67f09SDavid van Moolenbroek 	while (dev != NULL) {
1554*00b67f09SDavid van Moolenbroek 		count++;
1555*00b67f09SDavid van Moolenbroek 		dev = ISC_LIST_NEXT(dev, ev_link);
1556*00b67f09SDavid van Moolenbroek 	}
1557*00b67f09SDavid van Moolenbroek 	if (count > sock->pending_send) {
1558*00b67f09SDavid van Moolenbroek 		crash = ISC_TRUE;
1559*00b67f09SDavid van Moolenbroek 		crash_reason = "send_list > sock->pending_send";
1560*00b67f09SDavid van Moolenbroek 	}
1561*00b67f09SDavid van Moolenbroek 
1562*00b67f09SDavid van Moolenbroek 	nev = ISC_LIST_HEAD(sock->accept_list);
1563*00b67f09SDavid van Moolenbroek 	count = 0;
1564*00b67f09SDavid van Moolenbroek 	while (nev != NULL) {
1565*00b67f09SDavid van Moolenbroek 		count++;
1566*00b67f09SDavid van Moolenbroek 		nev = ISC_LIST_NEXT(nev, ev_link);
1567*00b67f09SDavid van Moolenbroek 	}
1568*00b67f09SDavid van Moolenbroek 	if (count > sock->pending_accept) {
1569*00b67f09SDavid van Moolenbroek 		crash = ISC_TRUE;
1570*00b67f09SDavid van Moolenbroek 		crash_reason = "send_list > sock->pending_send";
1571*00b67f09SDavid van Moolenbroek 	}
1572*00b67f09SDavid van Moolenbroek 
1573*00b67f09SDavid van Moolenbroek 	if (crash) {
1574*00b67f09SDavid van Moolenbroek 		socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
1575*00b67f09SDavid van Moolenbroek 			   ISC_MSG_DESTROYING, "SOCKET INCONSISTENT: %s",
1576*00b67f09SDavid van Moolenbroek 			   crash_reason);
1577*00b67f09SDavid van Moolenbroek 		sock_dump(sock);
1578*00b67f09SDavid van Moolenbroek 		INSIST(crash == ISC_FALSE);
1579*00b67f09SDavid van Moolenbroek 	}
1580*00b67f09SDavid van Moolenbroek }
1581*00b67f09SDavid van Moolenbroek 
1582*00b67f09SDavid van Moolenbroek /*
1583*00b67f09SDavid van Moolenbroek  * Maybe free the socket.
1584*00b67f09SDavid van Moolenbroek  *
1585*00b67f09SDavid van Moolenbroek  * This function will verify tht the socket is no longer in use in any way,
1586*00b67f09SDavid van Moolenbroek  * either internally or externally.  This is the only place where this
1587*00b67f09SDavid van Moolenbroek  * check is to be made; if some bit of code believes that IT is done with
1588*00b67f09SDavid van Moolenbroek  * the socket (e.g., some reference counter reaches zero), it should call
1589*00b67f09SDavid van Moolenbroek  * this function.
1590*00b67f09SDavid van Moolenbroek  *
1591*00b67f09SDavid van Moolenbroek  * When calling this function, the socket must be locked, and the manager
1592*00b67f09SDavid van Moolenbroek  * must be unlocked.
1593*00b67f09SDavid van Moolenbroek  *
1594*00b67f09SDavid van Moolenbroek  * When this function returns, *socketp will be NULL.  No tricks to try
1595*00b67f09SDavid van Moolenbroek  * to hold on to this pointer are allowed.
1596*00b67f09SDavid van Moolenbroek  */
1597*00b67f09SDavid van Moolenbroek static void
maybe_free_socket(isc_socket_t ** socketp,int lineno)1598*00b67f09SDavid van Moolenbroek maybe_free_socket(isc_socket_t **socketp, int lineno) {
1599*00b67f09SDavid van Moolenbroek 	isc_socket_t *sock = *socketp;
1600*00b67f09SDavid van Moolenbroek 	*socketp = NULL;
1601*00b67f09SDavid van Moolenbroek 
1602*00b67f09SDavid van Moolenbroek 	INSIST(VALID_SOCKET(sock));
1603*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
1604*00b67f09SDavid van Moolenbroek 
1605*00b67f09SDavid van Moolenbroek 	if (sock->pending_iocp > 0
1606*00b67f09SDavid van Moolenbroek 	    || sock->pending_recv > 0
1607*00b67f09SDavid van Moolenbroek 	    || sock->pending_send > 0
1608*00b67f09SDavid van Moolenbroek 	    || sock->pending_accept > 0
1609*00b67f09SDavid van Moolenbroek 	    || sock->references > 0
1610*00b67f09SDavid van Moolenbroek 	    || sock->pending_connect == 1
1611*00b67f09SDavid van Moolenbroek 	    || !ISC_LIST_EMPTY(sock->recv_list)
1612*00b67f09SDavid van Moolenbroek 	    || !ISC_LIST_EMPTY(sock->send_list)
1613*00b67f09SDavid van Moolenbroek 	    || !ISC_LIST_EMPTY(sock->accept_list)
1614*00b67f09SDavid van Moolenbroek 	    || sock->fd != INVALID_SOCKET) {
1615*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
1616*00b67f09SDavid van Moolenbroek 		return;
1617*00b67f09SDavid van Moolenbroek 	}
1618*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
1619*00b67f09SDavid van Moolenbroek 
1620*00b67f09SDavid van Moolenbroek 	free_socket(&sock, lineno);
1621*00b67f09SDavid van Moolenbroek }
1622*00b67f09SDavid van Moolenbroek 
1623*00b67f09SDavid van Moolenbroek void
free_socket(isc_socket_t ** sockp,int lineno)1624*00b67f09SDavid van Moolenbroek free_socket(isc_socket_t **sockp, int lineno) {
1625*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *manager;
1626*00b67f09SDavid van Moolenbroek 	isc_socket_t *sock = *sockp;
1627*00b67f09SDavid van Moolenbroek 	*sockp = NULL;
1628*00b67f09SDavid van Moolenbroek 
1629*00b67f09SDavid van Moolenbroek 	/*
1630*00b67f09SDavid van Moolenbroek 	 * Seems we can free the socket after all.
1631*00b67f09SDavid van Moolenbroek 	 */
1632*00b67f09SDavid van Moolenbroek 	manager = sock->manager;
1633*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat,
1634*00b67f09SDavid van Moolenbroek 		   ISC_MSGSET_SOCKET, ISC_MSG_DESTROYING,
1635*00b67f09SDavid van Moolenbroek 		   "freeing socket line %d fd %d lock %p semaphore %p",
1636*00b67f09SDavid van Moolenbroek 		   lineno, sock->fd, &sock->lock, sock->lock.LockSemaphore);
1637*00b67f09SDavid van Moolenbroek 
1638*00b67f09SDavid van Moolenbroek 	sock->magic = 0;
1639*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&sock->lock);
1640*00b67f09SDavid van Moolenbroek 
1641*00b67f09SDavid van Moolenbroek 	if (sock->recvbuf.base != NULL)
1642*00b67f09SDavid van Moolenbroek 		isc_mem_put(manager->mctx, sock->recvbuf.base,
1643*00b67f09SDavid van Moolenbroek 			    sock->recvbuf.len);
1644*00b67f09SDavid van Moolenbroek 
1645*00b67f09SDavid van Moolenbroek 	LOCK(&manager->lock);
1646*00b67f09SDavid van Moolenbroek 	if (ISC_LINK_LINKED(sock, link))
1647*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(manager->socklist, sock, link);
1648*00b67f09SDavid van Moolenbroek 	isc_mem_put(manager->mctx, sock, sizeof(*sock));
1649*00b67f09SDavid van Moolenbroek 
1650*00b67f09SDavid van Moolenbroek 	if (ISC_LIST_EMPTY(manager->socklist))
1651*00b67f09SDavid van Moolenbroek 		SIGNAL(&manager->shutdown_ok);
1652*00b67f09SDavid van Moolenbroek 	UNLOCK(&manager->lock);
1653*00b67f09SDavid van Moolenbroek }
1654*00b67f09SDavid van Moolenbroek 
1655*00b67f09SDavid van Moolenbroek /*
1656*00b67f09SDavid van Moolenbroek  * Create a new 'type' socket managed by 'manager'.  Events
1657*00b67f09SDavid van Moolenbroek  * will be posted to 'task' and when dispatched 'action' will be
1658*00b67f09SDavid van Moolenbroek  * called with 'arg' as the arg value.  The new socket is returned
1659*00b67f09SDavid van Moolenbroek  * in 'socketp'.
1660*00b67f09SDavid van Moolenbroek  */
1661*00b67f09SDavid van Moolenbroek static isc_result_t
socket_create(isc_socketmgr_t * manager,int pf,isc_sockettype_t type,isc_socket_t ** socketp,isc_socket_t * dup_socket)1662*00b67f09SDavid van Moolenbroek socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
1663*00b67f09SDavid van Moolenbroek 	      isc_socket_t **socketp, isc_socket_t *dup_socket)
1664*00b67f09SDavid van Moolenbroek {
1665*00b67f09SDavid van Moolenbroek 	isc_socket_t *sock = NULL;
1666*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1667*00b67f09SDavid van Moolenbroek #if defined(USE_CMSG)
1668*00b67f09SDavid van Moolenbroek 	int on = 1;
1669*00b67f09SDavid van Moolenbroek #endif
1670*00b67f09SDavid van Moolenbroek #if defined(SO_RCVBUF)
1671*00b67f09SDavid van Moolenbroek 	ISC_SOCKADDR_LEN_T optlen;
1672*00b67f09SDavid van Moolenbroek 	int size;
1673*00b67f09SDavid van Moolenbroek #endif
1674*00b67f09SDavid van Moolenbroek 	int socket_errno;
1675*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
1676*00b67f09SDavid van Moolenbroek 
1677*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
1678*00b67f09SDavid van Moolenbroek 	REQUIRE(socketp != NULL && *socketp == NULL);
1679*00b67f09SDavid van Moolenbroek 	REQUIRE(type != isc_sockettype_fdwatch);
1680*00b67f09SDavid van Moolenbroek 
1681*00b67f09SDavid van Moolenbroek #ifndef SOCK_RAW
1682*00b67f09SDavid van Moolenbroek 	if (type == isc_sockettype_raw)
1683*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOTIMPLEMENTED);
1684*00b67f09SDavid van Moolenbroek #endif
1685*00b67f09SDavid van Moolenbroek 
1686*00b67f09SDavid van Moolenbroek 	result = allocate_socket(manager, type, &sock);
1687*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1688*00b67f09SDavid van Moolenbroek 		return (result);
1689*00b67f09SDavid van Moolenbroek 
1690*00b67f09SDavid van Moolenbroek 	sock->pf = pf;
1691*00b67f09SDavid van Moolenbroek 	switch (type) {
1692*00b67f09SDavid van Moolenbroek 	case isc_sockettype_udp:
1693*00b67f09SDavid van Moolenbroek 		sock->fd = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
1694*00b67f09SDavid van Moolenbroek 		if (sock->fd != INVALID_SOCKET) {
1695*00b67f09SDavid van Moolenbroek 			result = connection_reset_fix(sock->fd);
1696*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS) {
1697*00b67f09SDavid van Moolenbroek 				socket_log(__LINE__, sock,
1698*00b67f09SDavid van Moolenbroek 					NULL, EVENT, NULL, 0, 0,
1699*00b67f09SDavid van Moolenbroek 					"closed %d %d %d "
1700*00b67f09SDavid van Moolenbroek 					"con_reset_fix_failed",
1701*00b67f09SDavid van Moolenbroek 					sock->pending_recv,
1702*00b67f09SDavid van Moolenbroek 					sock->pending_send,
1703*00b67f09SDavid van Moolenbroek 					sock->references);
1704*00b67f09SDavid van Moolenbroek 				closesocket(sock->fd);
1705*00b67f09SDavid van Moolenbroek 				_set_state(sock, SOCK_CLOSED);
1706*00b67f09SDavid van Moolenbroek 				sock->fd = INVALID_SOCKET;
1707*00b67f09SDavid van Moolenbroek 				free_socket(&sock, __LINE__);
1708*00b67f09SDavid van Moolenbroek 				return (result);
1709*00b67f09SDavid van Moolenbroek 			}
1710*00b67f09SDavid van Moolenbroek 		}
1711*00b67f09SDavid van Moolenbroek 		break;
1712*00b67f09SDavid van Moolenbroek 	case isc_sockettype_tcp:
1713*00b67f09SDavid van Moolenbroek 		sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP);
1714*00b67f09SDavid van Moolenbroek 		break;
1715*00b67f09SDavid van Moolenbroek #ifdef SOCK_RAW
1716*00b67f09SDavid van Moolenbroek 	case isc_sockettype_raw:
1717*00b67f09SDavid van Moolenbroek 		sock->fd = socket(pf, SOCK_RAW, 0);
1718*00b67f09SDavid van Moolenbroek #ifdef PF_ROUTE
1719*00b67f09SDavid van Moolenbroek 		if (pf == PF_ROUTE)
1720*00b67f09SDavid van Moolenbroek 			sock->bound = 1;
1721*00b67f09SDavid van Moolenbroek #endif
1722*00b67f09SDavid van Moolenbroek 		break;
1723*00b67f09SDavid van Moolenbroek #endif
1724*00b67f09SDavid van Moolenbroek 	}
1725*00b67f09SDavid van Moolenbroek 
1726*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
1727*00b67f09SDavid van Moolenbroek 		socket_errno = WSAGetLastError();
1728*00b67f09SDavid van Moolenbroek 		free_socket(&sock, __LINE__);
1729*00b67f09SDavid van Moolenbroek 
1730*00b67f09SDavid van Moolenbroek 		switch (socket_errno) {
1731*00b67f09SDavid van Moolenbroek 		case WSAEMFILE:
1732*00b67f09SDavid van Moolenbroek 		case WSAENOBUFS:
1733*00b67f09SDavid van Moolenbroek 			return (ISC_R_NORESOURCES);
1734*00b67f09SDavid van Moolenbroek 
1735*00b67f09SDavid van Moolenbroek 		case WSAEPROTONOSUPPORT:
1736*00b67f09SDavid van Moolenbroek 		case WSAEPFNOSUPPORT:
1737*00b67f09SDavid van Moolenbroek 		case WSAEAFNOSUPPORT:
1738*00b67f09SDavid van Moolenbroek 			return (ISC_R_FAMILYNOSUPPORT);
1739*00b67f09SDavid van Moolenbroek 
1740*00b67f09SDavid van Moolenbroek 		default:
1741*00b67f09SDavid van Moolenbroek 			isc__strerror(socket_errno, strbuf, sizeof(strbuf));
1742*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
1743*00b67f09SDavid van Moolenbroek 					 "socket() %s: %s",
1744*00b67f09SDavid van Moolenbroek 					 isc_msgcat_get(isc_msgcat,
1745*00b67f09SDavid van Moolenbroek 							ISC_MSGSET_GENERAL,
1746*00b67f09SDavid van Moolenbroek 							ISC_MSG_FAILED,
1747*00b67f09SDavid van Moolenbroek 							"failed"),
1748*00b67f09SDavid van Moolenbroek 					 strbuf);
1749*00b67f09SDavid van Moolenbroek 			return (ISC_R_UNEXPECTED);
1750*00b67f09SDavid van Moolenbroek 		}
1751*00b67f09SDavid van Moolenbroek 	}
1752*00b67f09SDavid van Moolenbroek 
1753*00b67f09SDavid van Moolenbroek 	result = make_nonblock(sock->fd);
1754*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1755*00b67f09SDavid van Moolenbroek 		socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
1756*00b67f09SDavid van Moolenbroek 			"closed %d %d %d make_nonblock_failed",
1757*00b67f09SDavid van Moolenbroek 			sock->pending_recv, sock->pending_send,
1758*00b67f09SDavid van Moolenbroek 			sock->references);
1759*00b67f09SDavid van Moolenbroek 		closesocket(sock->fd);
1760*00b67f09SDavid van Moolenbroek 		sock->fd = INVALID_SOCKET;
1761*00b67f09SDavid van Moolenbroek 		free_socket(&sock, __LINE__);
1762*00b67f09SDavid van Moolenbroek 		return (result);
1763*00b67f09SDavid van Moolenbroek 	}
1764*00b67f09SDavid van Moolenbroek 
1765*00b67f09SDavid van Moolenbroek 	/*
1766*00b67f09SDavid van Moolenbroek 	 * Use minimum mtu if possible.
1767*00b67f09SDavid van Moolenbroek 	 */
1768*00b67f09SDavid van Moolenbroek 	use_min_mtu(sock);
1769*00b67f09SDavid van Moolenbroek 
1770*00b67f09SDavid van Moolenbroek #if defined(USE_CMSG) || defined(SO_RCVBUF)
1771*00b67f09SDavid van Moolenbroek 	if (type == isc_sockettype_udp) {
1772*00b67f09SDavid van Moolenbroek 
1773*00b67f09SDavid van Moolenbroek #if defined(USE_CMSG)
1774*00b67f09SDavid van Moolenbroek #if defined(ISC_PLATFORM_HAVEIPV6)
1775*00b67f09SDavid van Moolenbroek #ifdef IPV6_RECVPKTINFO
1776*00b67f09SDavid van Moolenbroek 		/* 2292bis */
1777*00b67f09SDavid van Moolenbroek 		if ((pf == AF_INET6)
1778*00b67f09SDavid van Moolenbroek 		    && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
1779*00b67f09SDavid van Moolenbroek 				   (char *)&on, sizeof(on)) < 0)) {
1780*00b67f09SDavid van Moolenbroek 			isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
1781*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
1782*00b67f09SDavid van Moolenbroek 					 "setsockopt(%d, IPV6_RECVPKTINFO) "
1783*00b67f09SDavid van Moolenbroek 					 "%s: %s", sock->fd,
1784*00b67f09SDavid van Moolenbroek 					 isc_msgcat_get(isc_msgcat,
1785*00b67f09SDavid van Moolenbroek 							ISC_MSGSET_GENERAL,
1786*00b67f09SDavid van Moolenbroek 							ISC_MSG_FAILED,
1787*00b67f09SDavid van Moolenbroek 							"failed"),
1788*00b67f09SDavid van Moolenbroek 					 strbuf);
1789*00b67f09SDavid van Moolenbroek 		}
1790*00b67f09SDavid van Moolenbroek #else
1791*00b67f09SDavid van Moolenbroek 		/* 2292 */
1792*00b67f09SDavid van Moolenbroek 		if ((pf == AF_INET6)
1793*00b67f09SDavid van Moolenbroek 		    && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO,
1794*00b67f09SDavid van Moolenbroek 				   (char *)&on, sizeof(on)) < 0)) {
1795*00b67f09SDavid van Moolenbroek 			isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
1796*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
1797*00b67f09SDavid van Moolenbroek 					 "setsockopt(%d, IPV6_PKTINFO) %s: %s",
1798*00b67f09SDavid van Moolenbroek 					 sock->fd,
1799*00b67f09SDavid van Moolenbroek 					 isc_msgcat_get(isc_msgcat,
1800*00b67f09SDavid van Moolenbroek 							ISC_MSGSET_GENERAL,
1801*00b67f09SDavid van Moolenbroek 							ISC_MSG_FAILED,
1802*00b67f09SDavid van Moolenbroek 							"failed"),
1803*00b67f09SDavid van Moolenbroek 					 strbuf);
1804*00b67f09SDavid van Moolenbroek 		}
1805*00b67f09SDavid van Moolenbroek #endif /* IPV6_RECVPKTINFO */
1806*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_HAVEIPV6 */
1807*00b67f09SDavid van Moolenbroek #endif /* defined(USE_CMSG) */
1808*00b67f09SDavid van Moolenbroek 
1809*00b67f09SDavid van Moolenbroek #if defined(SO_RCVBUF)
1810*00b67f09SDavid van Moolenbroek 	       optlen = sizeof(size);
1811*00b67f09SDavid van Moolenbroek 	       if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
1812*00b67f09SDavid van Moolenbroek 			      (char *)&size, &optlen) >= 0 &&
1813*00b67f09SDavid van Moolenbroek 		    size < RCVBUFSIZE) {
1814*00b67f09SDavid van Moolenbroek 		       size = RCVBUFSIZE;
1815*00b67f09SDavid van Moolenbroek 		       (void)setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
1816*00b67f09SDavid van Moolenbroek 					(char *)&size, sizeof(size));
1817*00b67f09SDavid van Moolenbroek 	       }
1818*00b67f09SDavid van Moolenbroek #endif
1819*00b67f09SDavid van Moolenbroek 
1820*00b67f09SDavid van Moolenbroek 	}
1821*00b67f09SDavid van Moolenbroek #endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */
1822*00b67f09SDavid van Moolenbroek 
1823*00b67f09SDavid van Moolenbroek 	_set_state(sock, SOCK_OPEN);
1824*00b67f09SDavid van Moolenbroek 	sock->references = 1;
1825*00b67f09SDavid van Moolenbroek 	*socketp = sock;
1826*00b67f09SDavid van Moolenbroek 
1827*00b67f09SDavid van Moolenbroek 	iocompletionport_update(sock);
1828*00b67f09SDavid van Moolenbroek 
1829*00b67f09SDavid van Moolenbroek 	if (dup_socket) {
1830*00b67f09SDavid van Moolenbroek #ifndef ISC_ALLOW_MAPPED
1831*00b67f09SDavid van Moolenbroek 		isc__socket_ipv6only(sock, ISC_TRUE);
1832*00b67f09SDavid van Moolenbroek #endif
1833*00b67f09SDavid van Moolenbroek 
1834*00b67f09SDavid van Moolenbroek 		if (dup_socket->bound) {
1835*00b67f09SDavid van Moolenbroek 			isc_sockaddr_t local;
1836*00b67f09SDavid van Moolenbroek 
1837*00b67f09SDavid van Moolenbroek 			result = isc__socket_getsockname(dup_socket, &local);
1838*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS) {
1839*00b67f09SDavid van Moolenbroek 				isc_socket_close(sock);
1840*00b67f09SDavid van Moolenbroek 				return (result);
1841*00b67f09SDavid van Moolenbroek 			}
1842*00b67f09SDavid van Moolenbroek 			result = isc__socket_bind(sock, &local,
1843*00b67f09SDavid van Moolenbroek 						  ISC_SOCKET_REUSEADDRESS);
1844*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS) {
1845*00b67f09SDavid van Moolenbroek 				isc_socket_close(sock);
1846*00b67f09SDavid van Moolenbroek 				return (result);
1847*00b67f09SDavid van Moolenbroek 			}
1848*00b67f09SDavid van Moolenbroek 		}
1849*00b67f09SDavid van Moolenbroek 		sock->dupped = 1;
1850*00b67f09SDavid van Moolenbroek 	}
1851*00b67f09SDavid van Moolenbroek 
1852*00b67f09SDavid van Moolenbroek 	/*
1853*00b67f09SDavid van Moolenbroek 	 * Note we don't have to lock the socket like we normally would because
1854*00b67f09SDavid van Moolenbroek 	 * there are no external references to it yet.
1855*00b67f09SDavid van Moolenbroek 	 */
1856*00b67f09SDavid van Moolenbroek 	LOCK(&manager->lock);
1857*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(manager->socklist, sock, link);
1858*00b67f09SDavid van Moolenbroek 	InterlockedIncrement(&manager->totalSockets);
1859*00b67f09SDavid van Moolenbroek 	UNLOCK(&manager->lock);
1860*00b67f09SDavid van Moolenbroek 
1861*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat,
1862*00b67f09SDavid van Moolenbroek 		   ISC_MSGSET_SOCKET, ISC_MSG_CREATED,
1863*00b67f09SDavid van Moolenbroek 		   "created %u type %u", sock->fd, type);
1864*00b67f09SDavid van Moolenbroek 
1865*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1866*00b67f09SDavid van Moolenbroek }
1867*00b67f09SDavid van Moolenbroek 
1868*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_create(isc_socketmgr_t * manager,int pf,isc_sockettype_t type,isc_socket_t ** socketp)1869*00b67f09SDavid van Moolenbroek isc__socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
1870*00b67f09SDavid van Moolenbroek 		   isc_socket_t **socketp)
1871*00b67f09SDavid van Moolenbroek {
1872*00b67f09SDavid van Moolenbroek 	return (socket_create(manager, pf, type, socketp, NULL));
1873*00b67f09SDavid van Moolenbroek }
1874*00b67f09SDavid van Moolenbroek 
1875*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_dup(isc_socket_t * sock,isc_socket_t ** socketp)1876*00b67f09SDavid van Moolenbroek isc__socket_dup(isc_socket_t *sock, isc_socket_t **socketp) {
1877*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
1878*00b67f09SDavid van Moolenbroek 	REQUIRE(socketp != NULL && *socketp == NULL);
1879*00b67f09SDavid van Moolenbroek 
1880*00b67f09SDavid van Moolenbroek 	return (socket_create(sock->manager, sock->pf, sock->type,
1881*00b67f09SDavid van Moolenbroek 			      socketp, sock));
1882*00b67f09SDavid van Moolenbroek }
1883*00b67f09SDavid van Moolenbroek 
1884*00b67f09SDavid van Moolenbroek isc_result_t
isc_socket_open(isc_socket_t * sock)1885*00b67f09SDavid van Moolenbroek isc_socket_open(isc_socket_t *sock) {
1886*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
1887*00b67f09SDavid van Moolenbroek 	REQUIRE(sock->type != isc_sockettype_fdwatch);
1888*00b67f09SDavid van Moolenbroek 
1889*00b67f09SDavid van Moolenbroek 	return (ISC_R_NOTIMPLEMENTED);
1890*00b67f09SDavid van Moolenbroek }
1891*00b67f09SDavid van Moolenbroek 
1892*00b67f09SDavid van Moolenbroek /*
1893*00b67f09SDavid van Moolenbroek  * Attach to a socket.  Caller must explicitly detach when it is done.
1894*00b67f09SDavid van Moolenbroek  */
1895*00b67f09SDavid van Moolenbroek void
isc__socket_attach(isc_socket_t * sock,isc_socket_t ** socketp)1896*00b67f09SDavid van Moolenbroek isc__socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
1897*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
1898*00b67f09SDavid van Moolenbroek 	REQUIRE(socketp != NULL && *socketp == NULL);
1899*00b67f09SDavid van Moolenbroek 
1900*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
1901*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
1902*00b67f09SDavid van Moolenbroek 	sock->references++;
1903*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
1904*00b67f09SDavid van Moolenbroek 
1905*00b67f09SDavid van Moolenbroek 	*socketp = sock;
1906*00b67f09SDavid van Moolenbroek }
1907*00b67f09SDavid van Moolenbroek 
1908*00b67f09SDavid van Moolenbroek /*
1909*00b67f09SDavid van Moolenbroek  * Dereference a socket.  If this is the last reference to it, clean things
1910*00b67f09SDavid van Moolenbroek  * up by destroying the socket.
1911*00b67f09SDavid van Moolenbroek  */
1912*00b67f09SDavid van Moolenbroek void
isc__socket_detach(isc_socket_t ** socketp)1913*00b67f09SDavid van Moolenbroek isc__socket_detach(isc_socket_t **socketp) {
1914*00b67f09SDavid van Moolenbroek 	isc_socket_t *sock;
1915*00b67f09SDavid van Moolenbroek 
1916*00b67f09SDavid van Moolenbroek 	REQUIRE(socketp != NULL);
1917*00b67f09SDavid van Moolenbroek 	sock = *socketp;
1918*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
1919*00b67f09SDavid van Moolenbroek 	REQUIRE(sock->type != isc_sockettype_fdwatch);
1920*00b67f09SDavid van Moolenbroek 
1921*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
1922*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
1923*00b67f09SDavid van Moolenbroek 	REQUIRE(sock->references > 0);
1924*00b67f09SDavid van Moolenbroek 	sock->references--;
1925*00b67f09SDavid van Moolenbroek 
1926*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
1927*00b67f09SDavid van Moolenbroek 		"detach_socket %d %d %d",
1928*00b67f09SDavid van Moolenbroek 		sock->pending_recv, sock->pending_send,
1929*00b67f09SDavid van Moolenbroek 		sock->references);
1930*00b67f09SDavid van Moolenbroek 
1931*00b67f09SDavid van Moolenbroek 	if (sock->references == 0 && sock->fd != INVALID_SOCKET) {
1932*00b67f09SDavid van Moolenbroek 		closesocket(sock->fd);
1933*00b67f09SDavid van Moolenbroek 		sock->fd = INVALID_SOCKET;
1934*00b67f09SDavid van Moolenbroek 		_set_state(sock, SOCK_CLOSED);
1935*00b67f09SDavid van Moolenbroek 	}
1936*00b67f09SDavid van Moolenbroek 
1937*00b67f09SDavid van Moolenbroek 	maybe_free_socket(&sock, __LINE__);
1938*00b67f09SDavid van Moolenbroek 
1939*00b67f09SDavid van Moolenbroek 	*socketp = NULL;
1940*00b67f09SDavid van Moolenbroek }
1941*00b67f09SDavid van Moolenbroek 
1942*00b67f09SDavid van Moolenbroek isc_result_t
isc_socket_close(isc_socket_t * sock)1943*00b67f09SDavid van Moolenbroek isc_socket_close(isc_socket_t *sock) {
1944*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
1945*00b67f09SDavid van Moolenbroek 	REQUIRE(sock->type != isc_sockettype_fdwatch);
1946*00b67f09SDavid van Moolenbroek 
1947*00b67f09SDavid van Moolenbroek 	return (ISC_R_NOTIMPLEMENTED);
1948*00b67f09SDavid van Moolenbroek }
1949*00b67f09SDavid van Moolenbroek 
1950*00b67f09SDavid van Moolenbroek /*
1951*00b67f09SDavid van Moolenbroek  * Dequeue an item off the given socket's read queue, set the result code
1952*00b67f09SDavid van Moolenbroek  * in the done event to the one provided, and send it to the task it was
1953*00b67f09SDavid van Moolenbroek  * destined for.
1954*00b67f09SDavid van Moolenbroek  *
1955*00b67f09SDavid van Moolenbroek  * If the event to be sent is on a list, remove it before sending.  If
1956*00b67f09SDavid van Moolenbroek  * asked to, send and detach from the task as well.
1957*00b67f09SDavid van Moolenbroek  *
1958*00b67f09SDavid van Moolenbroek  * Caller must have the socket locked if the event is attached to the socket.
1959*00b67f09SDavid van Moolenbroek  */
1960*00b67f09SDavid van Moolenbroek static void
send_recvdone_event(isc_socket_t * sock,isc_socketevent_t ** dev)1961*00b67f09SDavid van Moolenbroek send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
1962*00b67f09SDavid van Moolenbroek 	isc_task_t *task;
1963*00b67f09SDavid van Moolenbroek 
1964*00b67f09SDavid van Moolenbroek 	task = (*dev)->ev_sender;
1965*00b67f09SDavid van Moolenbroek 	(*dev)->ev_sender = sock;
1966*00b67f09SDavid van Moolenbroek 
1967*00b67f09SDavid van Moolenbroek 	if (ISC_LINK_LINKED(*dev, ev_link))
1968*00b67f09SDavid van Moolenbroek 		ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
1969*00b67f09SDavid van Moolenbroek 
1970*00b67f09SDavid van Moolenbroek 	if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
1971*00b67f09SDavid van Moolenbroek 	    == ISC_SOCKEVENTATTR_ATTACHED)
1972*00b67f09SDavid van Moolenbroek 		isc_task_sendanddetach(&task, (isc_event_t **)dev);
1973*00b67f09SDavid van Moolenbroek 	else
1974*00b67f09SDavid van Moolenbroek 		isc_task_send(task, (isc_event_t **)dev);
1975*00b67f09SDavid van Moolenbroek 
1976*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
1977*00b67f09SDavid van Moolenbroek }
1978*00b67f09SDavid van Moolenbroek 
1979*00b67f09SDavid van Moolenbroek /*
1980*00b67f09SDavid van Moolenbroek  * See comments for send_recvdone_event() above.
1981*00b67f09SDavid van Moolenbroek  */
1982*00b67f09SDavid van Moolenbroek static void
send_senddone_event(isc_socket_t * sock,isc_socketevent_t ** dev)1983*00b67f09SDavid van Moolenbroek send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
1984*00b67f09SDavid van Moolenbroek 	isc_task_t *task;
1985*00b67f09SDavid van Moolenbroek 
1986*00b67f09SDavid van Moolenbroek 	INSIST(dev != NULL && *dev != NULL);
1987*00b67f09SDavid van Moolenbroek 
1988*00b67f09SDavid van Moolenbroek 	task = (*dev)->ev_sender;
1989*00b67f09SDavid van Moolenbroek 	(*dev)->ev_sender = sock;
1990*00b67f09SDavid van Moolenbroek 
1991*00b67f09SDavid van Moolenbroek 	if (ISC_LINK_LINKED(*dev, ev_link))
1992*00b67f09SDavid van Moolenbroek 		ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);
1993*00b67f09SDavid van Moolenbroek 
1994*00b67f09SDavid van Moolenbroek 	if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
1995*00b67f09SDavid van Moolenbroek 	    == ISC_SOCKEVENTATTR_ATTACHED)
1996*00b67f09SDavid van Moolenbroek 		isc_task_sendanddetach(&task, (isc_event_t **)dev);
1997*00b67f09SDavid van Moolenbroek 	else
1998*00b67f09SDavid van Moolenbroek 		isc_task_send(task, (isc_event_t **)dev);
1999*00b67f09SDavid van Moolenbroek 
2000*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
2001*00b67f09SDavid van Moolenbroek }
2002*00b67f09SDavid van Moolenbroek 
2003*00b67f09SDavid van Moolenbroek /*
2004*00b67f09SDavid van Moolenbroek  * See comments for send_recvdone_event() above.
2005*00b67f09SDavid van Moolenbroek  */
2006*00b67f09SDavid van Moolenbroek static void
send_acceptdone_event(isc_socket_t * sock,isc_socket_newconnev_t ** adev)2007*00b67f09SDavid van Moolenbroek send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev) {
2008*00b67f09SDavid van Moolenbroek 	isc_task_t *task;
2009*00b67f09SDavid van Moolenbroek 
2010*00b67f09SDavid van Moolenbroek 	INSIST(adev != NULL && *adev != NULL);
2011*00b67f09SDavid van Moolenbroek 
2012*00b67f09SDavid van Moolenbroek 	task = (*adev)->ev_sender;
2013*00b67f09SDavid van Moolenbroek 	(*adev)->ev_sender = sock;
2014*00b67f09SDavid van Moolenbroek 
2015*00b67f09SDavid van Moolenbroek 	if (ISC_LINK_LINKED(*adev, ev_link))
2016*00b67f09SDavid van Moolenbroek 		ISC_LIST_DEQUEUE(sock->accept_list, *adev, ev_link);
2017*00b67f09SDavid van Moolenbroek 
2018*00b67f09SDavid van Moolenbroek 	isc_task_sendanddetach(&task, (isc_event_t **)adev);
2019*00b67f09SDavid van Moolenbroek 
2020*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
2021*00b67f09SDavid van Moolenbroek }
2022*00b67f09SDavid van Moolenbroek 
2023*00b67f09SDavid van Moolenbroek /*
2024*00b67f09SDavid van Moolenbroek  * See comments for send_recvdone_event() above.
2025*00b67f09SDavid van Moolenbroek  */
2026*00b67f09SDavid van Moolenbroek static void
send_connectdone_event(isc_socket_t * sock,isc_socket_connev_t ** cdev)2027*00b67f09SDavid van Moolenbroek send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev) {
2028*00b67f09SDavid van Moolenbroek 	isc_task_t *task;
2029*00b67f09SDavid van Moolenbroek 
2030*00b67f09SDavid van Moolenbroek 	INSIST(cdev != NULL && *cdev != NULL);
2031*00b67f09SDavid van Moolenbroek 
2032*00b67f09SDavid van Moolenbroek 	task = (*cdev)->ev_sender;
2033*00b67f09SDavid van Moolenbroek 	(*cdev)->ev_sender = sock;
2034*00b67f09SDavid van Moolenbroek 
2035*00b67f09SDavid van Moolenbroek 	sock->connect_ev = NULL;
2036*00b67f09SDavid van Moolenbroek 
2037*00b67f09SDavid van Moolenbroek 	isc_task_sendanddetach(&task, (isc_event_t **)cdev);
2038*00b67f09SDavid van Moolenbroek 
2039*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
2040*00b67f09SDavid van Moolenbroek }
2041*00b67f09SDavid van Moolenbroek 
2042*00b67f09SDavid van Moolenbroek /*
2043*00b67f09SDavid van Moolenbroek  * On entry to this function, the event delivered is the internal
2044*00b67f09SDavid van Moolenbroek  * readable event, and the first item on the accept_list should be
2045*00b67f09SDavid van Moolenbroek  * the done event we want to send.  If the list is empty, this is a no-op,
2046*00b67f09SDavid van Moolenbroek  * so just close the new connection, unlock, and return.
2047*00b67f09SDavid van Moolenbroek  *
2048*00b67f09SDavid van Moolenbroek  * Note the socket is locked before entering here
2049*00b67f09SDavid van Moolenbroek  */
2050*00b67f09SDavid van Moolenbroek static void
internal_accept(isc_socket_t * sock,IoCompletionInfo * lpo,int accept_errno)2051*00b67f09SDavid van Moolenbroek internal_accept(isc_socket_t *sock, IoCompletionInfo *lpo, int accept_errno) {
2052*00b67f09SDavid van Moolenbroek 	isc_socket_newconnev_t *adev;
2053*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
2054*00b67f09SDavid van Moolenbroek 	isc_socket_t *nsock;
2055*00b67f09SDavid van Moolenbroek 	struct sockaddr *localaddr;
2056*00b67f09SDavid van Moolenbroek 	int localaddr_len = sizeof(*localaddr);
2057*00b67f09SDavid van Moolenbroek 	struct sockaddr *remoteaddr;
2058*00b67f09SDavid van Moolenbroek 	int remoteaddr_len = sizeof(*remoteaddr);
2059*00b67f09SDavid van Moolenbroek 
2060*00b67f09SDavid van Moolenbroek 	INSIST(VALID_SOCKET(sock));
2061*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
2062*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
2063*00b67f09SDavid van Moolenbroek 
2064*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, TRACE,
2065*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
2066*00b67f09SDavid van Moolenbroek 		   "internal_accept called");
2067*00b67f09SDavid van Moolenbroek 
2068*00b67f09SDavid van Moolenbroek 	INSIST(sock->listener);
2069*00b67f09SDavid van Moolenbroek 
2070*00b67f09SDavid van Moolenbroek 	INSIST(sock->pending_iocp > 0);
2071*00b67f09SDavid van Moolenbroek 	sock->pending_iocp--;
2072*00b67f09SDavid van Moolenbroek 	INSIST(sock->pending_accept > 0);
2073*00b67f09SDavid van Moolenbroek 	sock->pending_accept--;
2074*00b67f09SDavid van Moolenbroek 
2075*00b67f09SDavid van Moolenbroek 	adev = lpo->adev;
2076*00b67f09SDavid van Moolenbroek 
2077*00b67f09SDavid van Moolenbroek 	/*
2078*00b67f09SDavid van Moolenbroek 	 * If the event is no longer in the list we can just return.
2079*00b67f09SDavid van Moolenbroek 	 */
2080*00b67f09SDavid van Moolenbroek 	if (!acceptdone_is_active(sock, adev))
2081*00b67f09SDavid van Moolenbroek 		goto done;
2082*00b67f09SDavid van Moolenbroek 
2083*00b67f09SDavid van Moolenbroek 	nsock = adev->newsocket;
2084*00b67f09SDavid van Moolenbroek 
2085*00b67f09SDavid van Moolenbroek 	/*
2086*00b67f09SDavid van Moolenbroek 	 * Pull off the done event.
2087*00b67f09SDavid van Moolenbroek 	 */
2088*00b67f09SDavid van Moolenbroek 	ISC_LIST_UNLINK(sock->accept_list, adev, ev_link);
2089*00b67f09SDavid van Moolenbroek 
2090*00b67f09SDavid van Moolenbroek 	/*
2091*00b67f09SDavid van Moolenbroek 	 * Extract the addresses from the socket, copy them into the structure,
2092*00b67f09SDavid van Moolenbroek 	 * and return the new socket.
2093*00b67f09SDavid van Moolenbroek 	 */
2094*00b67f09SDavid van Moolenbroek 	ISCGetAcceptExSockaddrs(lpo->acceptbuffer, 0,
2095*00b67f09SDavid van Moolenbroek 		sizeof(SOCKADDR_STORAGE) + 16, sizeof(SOCKADDR_STORAGE) + 16,
2096*00b67f09SDavid van Moolenbroek 		(LPSOCKADDR *)&localaddr, &localaddr_len,
2097*00b67f09SDavid van Moolenbroek 		(LPSOCKADDR *)&remoteaddr, &remoteaddr_len);
2098*00b67f09SDavid van Moolenbroek 	memmove(&adev->address.type, remoteaddr, remoteaddr_len);
2099*00b67f09SDavid van Moolenbroek 	adev->address.length = remoteaddr_len;
2100*00b67f09SDavid van Moolenbroek 	nsock->address = adev->address;
2101*00b67f09SDavid van Moolenbroek 	nsock->pf = adev->address.type.sa.sa_family;
2102*00b67f09SDavid van Moolenbroek 
2103*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, nsock, &nsock->address, TRACE,
2104*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
2105*00b67f09SDavid van Moolenbroek 		   "internal_accept parent %p", sock);
2106*00b67f09SDavid van Moolenbroek 
2107*00b67f09SDavid van Moolenbroek 	result = make_nonblock(adev->newsocket->fd);
2108*00b67f09SDavid van Moolenbroek 	INSIST(result == ISC_R_SUCCESS);
2109*00b67f09SDavid van Moolenbroek 
2110*00b67f09SDavid van Moolenbroek 	/*
2111*00b67f09SDavid van Moolenbroek 	 * Use minimum mtu if possible.
2112*00b67f09SDavid van Moolenbroek 	 */
2113*00b67f09SDavid van Moolenbroek 	use_min_mtu(adev->newsocket);
2114*00b67f09SDavid van Moolenbroek 
2115*00b67f09SDavid van Moolenbroek 	INSIST(setsockopt(nsock->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
2116*00b67f09SDavid van Moolenbroek 			  (char *)&sock->fd, sizeof(sock->fd)) == 0);
2117*00b67f09SDavid van Moolenbroek 
2118*00b67f09SDavid van Moolenbroek 	/*
2119*00b67f09SDavid van Moolenbroek 	 * Hook it up into the manager.
2120*00b67f09SDavid van Moolenbroek 	 */
2121*00b67f09SDavid van Moolenbroek 	nsock->bound = 1;
2122*00b67f09SDavid van Moolenbroek 	nsock->connected = 1;
2123*00b67f09SDavid van Moolenbroek 	_set_state(nsock, SOCK_OPEN);
2124*00b67f09SDavid van Moolenbroek 
2125*00b67f09SDavid van Moolenbroek 	LOCK(&nsock->manager->lock);
2126*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(nsock->manager->socklist, nsock, link);
2127*00b67f09SDavid van Moolenbroek 	InterlockedIncrement(&nsock->manager->totalSockets);
2128*00b67f09SDavid van Moolenbroek 	UNLOCK(&nsock->manager->lock);
2129*00b67f09SDavid van Moolenbroek 
2130*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, &nsock->address, CREATION,
2131*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
2132*00b67f09SDavid van Moolenbroek 		   "accepted_connection new_socket %p fd %d",
2133*00b67f09SDavid van Moolenbroek 		   nsock, nsock->fd);
2134*00b67f09SDavid van Moolenbroek 
2135*00b67f09SDavid van Moolenbroek 	adev->result = result;
2136*00b67f09SDavid van Moolenbroek 	send_acceptdone_event(sock, &adev);
2137*00b67f09SDavid van Moolenbroek 
2138*00b67f09SDavid van Moolenbroek done:
2139*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
2140*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
2141*00b67f09SDavid van Moolenbroek 
2142*00b67f09SDavid van Moolenbroek 	HeapFree(hHeapHandle, 0, lpo->acceptbuffer);
2143*00b67f09SDavid van Moolenbroek 	lpo->acceptbuffer = NULL;
2144*00b67f09SDavid van Moolenbroek }
2145*00b67f09SDavid van Moolenbroek 
2146*00b67f09SDavid van Moolenbroek /*
2147*00b67f09SDavid van Moolenbroek  * Called when a socket with a pending connect() finishes.
2148*00b67f09SDavid van Moolenbroek  * Note that the socket is locked before entering.
2149*00b67f09SDavid van Moolenbroek  */
2150*00b67f09SDavid van Moolenbroek static void
internal_connect(isc_socket_t * sock,IoCompletionInfo * lpo,int connect_errno)2151*00b67f09SDavid van Moolenbroek internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) {
2152*00b67f09SDavid van Moolenbroek 	isc_socket_connev_t *cdev;
2153*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
2154*00b67f09SDavid van Moolenbroek 
2155*00b67f09SDavid van Moolenbroek 	INSIST(VALID_SOCKET(sock));
2156*00b67f09SDavid van Moolenbroek 
2157*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
2158*00b67f09SDavid van Moolenbroek 
2159*00b67f09SDavid van Moolenbroek 	INSIST(sock->pending_iocp > 0);
2160*00b67f09SDavid van Moolenbroek 	sock->pending_iocp--;
2161*00b67f09SDavid van Moolenbroek 	INSIST(sock->pending_connect == 1);
2162*00b67f09SDavid van Moolenbroek 	sock->pending_connect = 0;
2163*00b67f09SDavid van Moolenbroek 
2164*00b67f09SDavid van Moolenbroek 	/*
2165*00b67f09SDavid van Moolenbroek 	 * Has this event been canceled?
2166*00b67f09SDavid van Moolenbroek 	 */
2167*00b67f09SDavid van Moolenbroek 	cdev = lpo->cdev;
2168*00b67f09SDavid van Moolenbroek 	if (!connectdone_is_active(sock, cdev)) {
2169*00b67f09SDavid van Moolenbroek 		sock->pending_connect = 0;
2170*00b67f09SDavid van Moolenbroek 		if (sock->fd != INVALID_SOCKET) {
2171*00b67f09SDavid van Moolenbroek 			closesocket(sock->fd);
2172*00b67f09SDavid van Moolenbroek 			sock->fd = INVALID_SOCKET;
2173*00b67f09SDavid van Moolenbroek 			_set_state(sock, SOCK_CLOSED);
2174*00b67f09SDavid van Moolenbroek 		}
2175*00b67f09SDavid van Moolenbroek 		CONSISTENT(sock);
2176*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
2177*00b67f09SDavid van Moolenbroek 		return;
2178*00b67f09SDavid van Moolenbroek 	}
2179*00b67f09SDavid van Moolenbroek 
2180*00b67f09SDavid van Moolenbroek 	/*
2181*00b67f09SDavid van Moolenbroek 	 * Check possible Windows network event error status here.
2182*00b67f09SDavid van Moolenbroek 	 */
2183*00b67f09SDavid van Moolenbroek 	if (connect_errno != 0) {
2184*00b67f09SDavid van Moolenbroek 		/*
2185*00b67f09SDavid van Moolenbroek 		 * If the error is SOFT, just try again on this
2186*00b67f09SDavid van Moolenbroek 		 * fd and pretend nothing strange happened.
2187*00b67f09SDavid van Moolenbroek 		 */
2188*00b67f09SDavid van Moolenbroek 		if (SOFT_ERROR(connect_errno) ||
2189*00b67f09SDavid van Moolenbroek 		    connect_errno == WSAEINPROGRESS) {
2190*00b67f09SDavid van Moolenbroek 			sock->pending_connect = 1;
2191*00b67f09SDavid van Moolenbroek 			CONSISTENT(sock);
2192*00b67f09SDavid van Moolenbroek 			UNLOCK(&sock->lock);
2193*00b67f09SDavid van Moolenbroek 			return;
2194*00b67f09SDavid van Moolenbroek 		}
2195*00b67f09SDavid van Moolenbroek 
2196*00b67f09SDavid van Moolenbroek 		/*
2197*00b67f09SDavid van Moolenbroek 		 * Translate other errors into ISC_R_* flavors.
2198*00b67f09SDavid van Moolenbroek 		 */
2199*00b67f09SDavid van Moolenbroek 		switch (connect_errno) {
2200*00b67f09SDavid van Moolenbroek #define ERROR_MATCH(a, b) case a: cdev->result = b; break;
2201*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAEACCES, ISC_R_NOPERM);
2202*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAEADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
2203*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAEAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
2204*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAECONNREFUSED, ISC_R_CONNREFUSED);
2205*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAEHOSTUNREACH, ISC_R_HOSTUNREACH);
2206*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAEHOSTDOWN, ISC_R_HOSTDOWN);
2207*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAENETUNREACH, ISC_R_NETUNREACH);
2208*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAENETDOWN, ISC_R_NETDOWN);
2209*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAENOBUFS, ISC_R_NORESOURCES);
2210*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAECONNRESET, ISC_R_CONNECTIONRESET);
2211*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAECONNABORTED, ISC_R_CONNECTIONRESET);
2212*00b67f09SDavid van Moolenbroek 			ERROR_MATCH(WSAETIMEDOUT, ISC_R_TIMEDOUT);
2213*00b67f09SDavid van Moolenbroek #undef ERROR_MATCH
2214*00b67f09SDavid van Moolenbroek 		default:
2215*00b67f09SDavid van Moolenbroek 			cdev->result = ISC_R_UNEXPECTED;
2216*00b67f09SDavid van Moolenbroek 			isc__strerror(connect_errno, strbuf, sizeof(strbuf));
2217*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
2218*00b67f09SDavid van Moolenbroek 					 "internal_connect: connect() %s",
2219*00b67f09SDavid van Moolenbroek 					 strbuf);
2220*00b67f09SDavid van Moolenbroek 		}
2221*00b67f09SDavid van Moolenbroek 	} else {
2222*00b67f09SDavid van Moolenbroek 		INSIST(setsockopt(sock->fd, SOL_SOCKET,
2223*00b67f09SDavid van Moolenbroek 				  SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == 0);
2224*00b67f09SDavid van Moolenbroek 		cdev->result = ISC_R_SUCCESS;
2225*00b67f09SDavid van Moolenbroek 		sock->connected = 1;
2226*00b67f09SDavid van Moolenbroek 		socket_log(__LINE__, sock, &sock->address, IOEVENT,
2227*00b67f09SDavid van Moolenbroek 			   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
2228*00b67f09SDavid van Moolenbroek 			   "internal_connect: success");
2229*00b67f09SDavid van Moolenbroek 	}
2230*00b67f09SDavid van Moolenbroek 
2231*00b67f09SDavid van Moolenbroek 	send_connectdone_event(sock, &cdev);
2232*00b67f09SDavid van Moolenbroek 
2233*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
2234*00b67f09SDavid van Moolenbroek }
2235*00b67f09SDavid van Moolenbroek 
2236*00b67f09SDavid van Moolenbroek /*
2237*00b67f09SDavid van Moolenbroek  * Loop through the socket, returning ISC_R_EOF for each done event pending.
2238*00b67f09SDavid van Moolenbroek  */
2239*00b67f09SDavid van Moolenbroek static void
send_recvdone_abort(isc_socket_t * sock,isc_result_t result)2240*00b67f09SDavid van Moolenbroek send_recvdone_abort(isc_socket_t *sock, isc_result_t result) {
2241*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *dev;
2242*00b67f09SDavid van Moolenbroek 
2243*00b67f09SDavid van Moolenbroek 	while (!ISC_LIST_EMPTY(sock->recv_list)) {
2244*00b67f09SDavid van Moolenbroek 		dev = ISC_LIST_HEAD(sock->recv_list);
2245*00b67f09SDavid van Moolenbroek 		dev->result = result;
2246*00b67f09SDavid van Moolenbroek 		send_recvdone_event(sock, &dev);
2247*00b67f09SDavid van Moolenbroek 	}
2248*00b67f09SDavid van Moolenbroek }
2249*00b67f09SDavid van Moolenbroek 
2250*00b67f09SDavid van Moolenbroek /*
2251*00b67f09SDavid van Moolenbroek  * Take the data we received in our private buffer, and if any recv() calls on
2252*00b67f09SDavid van Moolenbroek  * our list are satisfied, send the corresponding done event.
2253*00b67f09SDavid van Moolenbroek  *
2254*00b67f09SDavid van Moolenbroek  * If we need more data (there are still items on the recv_list after we consume all
2255*00b67f09SDavid van Moolenbroek  * our data) then arrange for another system recv() call to fill our buffers.
2256*00b67f09SDavid van Moolenbroek  */
2257*00b67f09SDavid van Moolenbroek static void
internal_recv(isc_socket_t * sock,int nbytes)2258*00b67f09SDavid van Moolenbroek internal_recv(isc_socket_t *sock, int nbytes)
2259*00b67f09SDavid van Moolenbroek {
2260*00b67f09SDavid van Moolenbroek 	INSIST(VALID_SOCKET(sock));
2261*00b67f09SDavid van Moolenbroek 
2262*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
2263*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
2264*00b67f09SDavid van Moolenbroek 
2265*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, IOEVENT,
2266*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
2267*00b67f09SDavid van Moolenbroek 		   "internal_recv: %d bytes received", nbytes);
2268*00b67f09SDavid van Moolenbroek 
2269*00b67f09SDavid van Moolenbroek 	/*
2270*00b67f09SDavid van Moolenbroek 	 * If we got here, the I/O operation succeeded.  However, we might still have removed this
2271*00b67f09SDavid van Moolenbroek 	 * event from our notification list (or never placed it on it due to immediate completion.)
2272*00b67f09SDavid van Moolenbroek 	 * Handle the reference counting here, and handle the cancellation event just after.
2273*00b67f09SDavid van Moolenbroek 	 */
2274*00b67f09SDavid van Moolenbroek 	INSIST(sock->pending_iocp > 0);
2275*00b67f09SDavid van Moolenbroek 	sock->pending_iocp--;
2276*00b67f09SDavid van Moolenbroek 	INSIST(sock->pending_recv > 0);
2277*00b67f09SDavid van Moolenbroek 	sock->pending_recv--;
2278*00b67f09SDavid van Moolenbroek 
2279*00b67f09SDavid van Moolenbroek 	/*
2280*00b67f09SDavid van Moolenbroek 	 * The only way we could have gotten here is that our I/O has successfully completed.
2281*00b67f09SDavid van Moolenbroek 	 * Update our pointers, and move on.  The only odd case here is that we might not
2282*00b67f09SDavid van Moolenbroek 	 * have received enough data on a TCP stream to satisfy the minimum requirements.  If
2283*00b67f09SDavid van Moolenbroek 	 * this is the case, we will re-issue the recv() call for what we need.
2284*00b67f09SDavid van Moolenbroek 	 *
2285*00b67f09SDavid van Moolenbroek 	 * We do check for a recv() of 0 bytes on a TCP stream.  This means the remote end
2286*00b67f09SDavid van Moolenbroek 	 * has closed.
2287*00b67f09SDavid van Moolenbroek 	 */
2288*00b67f09SDavid van Moolenbroek 	if (nbytes == 0 && sock->type == isc_sockettype_tcp) {
2289*00b67f09SDavid van Moolenbroek 		send_recvdone_abort(sock, ISC_R_EOF);
2290*00b67f09SDavid van Moolenbroek 		maybe_free_socket(&sock, __LINE__);
2291*00b67f09SDavid van Moolenbroek 		return;
2292*00b67f09SDavid van Moolenbroek 	}
2293*00b67f09SDavid van Moolenbroek 	sock->recvbuf.remaining = nbytes;
2294*00b67f09SDavid van Moolenbroek 	sock->recvbuf.consume_position = sock->recvbuf.base;
2295*00b67f09SDavid van Moolenbroek 	completeio_recv(sock);
2296*00b67f09SDavid van Moolenbroek 
2297*00b67f09SDavid van Moolenbroek 	/*
2298*00b67f09SDavid van Moolenbroek 	 * If there are more receivers waiting for data, queue another receive
2299*00b67f09SDavid van Moolenbroek 	 * here.
2300*00b67f09SDavid van Moolenbroek 	 */
2301*00b67f09SDavid van Moolenbroek 	queue_receive_request(sock);
2302*00b67f09SDavid van Moolenbroek 
2303*00b67f09SDavid van Moolenbroek 	/*
2304*00b67f09SDavid van Moolenbroek 	 * Unlock and/or destroy if we are the last thing this socket has left to do.
2305*00b67f09SDavid van Moolenbroek 	 */
2306*00b67f09SDavid van Moolenbroek 	maybe_free_socket(&sock, __LINE__);
2307*00b67f09SDavid van Moolenbroek }
2308*00b67f09SDavid van Moolenbroek 
2309*00b67f09SDavid van Moolenbroek static void
internal_send(isc_socket_t * sock,isc_socketevent_t * dev,struct msghdr * messagehdr,int nbytes,int send_errno,IoCompletionInfo * lpo)2310*00b67f09SDavid van Moolenbroek internal_send(isc_socket_t *sock, isc_socketevent_t *dev,
2311*00b67f09SDavid van Moolenbroek 	      struct msghdr *messagehdr, int nbytes, int send_errno, IoCompletionInfo *lpo)
2312*00b67f09SDavid van Moolenbroek {
2313*00b67f09SDavid van Moolenbroek 	buflist_t *buffer;
2314*00b67f09SDavid van Moolenbroek 
2315*00b67f09SDavid van Moolenbroek 	/*
2316*00b67f09SDavid van Moolenbroek 	 * Find out what socket this is and lock it.
2317*00b67f09SDavid van Moolenbroek 	 */
2318*00b67f09SDavid van Moolenbroek 	INSIST(VALID_SOCKET(sock));
2319*00b67f09SDavid van Moolenbroek 
2320*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
2321*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
2322*00b67f09SDavid van Moolenbroek 
2323*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, IOEVENT,
2324*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
2325*00b67f09SDavid van Moolenbroek 		   "internal_send: task got socket event %p", dev);
2326*00b67f09SDavid van Moolenbroek 
2327*00b67f09SDavid van Moolenbroek 	buffer = ISC_LIST_HEAD(lpo->bufferlist);
2328*00b67f09SDavid van Moolenbroek 	while (buffer != NULL) {
2329*00b67f09SDavid van Moolenbroek 		ISC_LIST_DEQUEUE(lpo->bufferlist, buffer, link);
2330*00b67f09SDavid van Moolenbroek 
2331*00b67f09SDavid van Moolenbroek 		socket_log(__LINE__, sock, NULL, TRACE,
2332*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
2333*00b67f09SDavid van Moolenbroek 		   "free_buffer %p %p", buffer, buffer->buf);
2334*00b67f09SDavid van Moolenbroek 
2335*00b67f09SDavid van Moolenbroek 		HeapFree(hHeapHandle, 0, buffer->buf);
2336*00b67f09SDavid van Moolenbroek 		HeapFree(hHeapHandle, 0, buffer);
2337*00b67f09SDavid van Moolenbroek 		buffer = ISC_LIST_HEAD(lpo->bufferlist);
2338*00b67f09SDavid van Moolenbroek 	}
2339*00b67f09SDavid van Moolenbroek 
2340*00b67f09SDavid van Moolenbroek 	INSIST(sock->pending_iocp > 0);
2341*00b67f09SDavid van Moolenbroek 	sock->pending_iocp--;
2342*00b67f09SDavid van Moolenbroek 	INSIST(sock->pending_send > 0);
2343*00b67f09SDavid van Moolenbroek 	sock->pending_send--;
2344*00b67f09SDavid van Moolenbroek 
2345*00b67f09SDavid van Moolenbroek 	/* If the event is no longer in the list we can just return */
2346*00b67f09SDavid van Moolenbroek 	if (!senddone_is_active(sock, dev))
2347*00b67f09SDavid van Moolenbroek 		goto done;
2348*00b67f09SDavid van Moolenbroek 
2349*00b67f09SDavid van Moolenbroek 	/*
2350*00b67f09SDavid van Moolenbroek 	 * Set the error code and send things on its way.
2351*00b67f09SDavid van Moolenbroek 	 */
2352*00b67f09SDavid van Moolenbroek 	switch (completeio_send(sock, dev, messagehdr, nbytes, send_errno)) {
2353*00b67f09SDavid van Moolenbroek 	case DOIO_SOFT:
2354*00b67f09SDavid van Moolenbroek 		break;
2355*00b67f09SDavid van Moolenbroek 	case DOIO_HARD:
2356*00b67f09SDavid van Moolenbroek 	case DOIO_SUCCESS:
2357*00b67f09SDavid van Moolenbroek 		send_senddone_event(sock, &dev);
2358*00b67f09SDavid van Moolenbroek 		break;
2359*00b67f09SDavid van Moolenbroek 	}
2360*00b67f09SDavid van Moolenbroek 
2361*00b67f09SDavid van Moolenbroek  done:
2362*00b67f09SDavid van Moolenbroek 	maybe_free_socket(&sock, __LINE__);
2363*00b67f09SDavid van Moolenbroek }
2364*00b67f09SDavid van Moolenbroek 
2365*00b67f09SDavid van Moolenbroek /*
2366*00b67f09SDavid van Moolenbroek  * These return if the done event passed in is on the list (or for connect, is
2367*00b67f09SDavid van Moolenbroek  * the one we're waiting for.  Using these ensures we will not double-send an
2368*00b67f09SDavid van Moolenbroek  * event.
2369*00b67f09SDavid van Moolenbroek  */
2370*00b67f09SDavid van Moolenbroek static isc_boolean_t
senddone_is_active(isc_socket_t * sock,isc_socketevent_t * dev)2371*00b67f09SDavid van Moolenbroek senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev)
2372*00b67f09SDavid van Moolenbroek {
2373*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *ldev;
2374*00b67f09SDavid van Moolenbroek 
2375*00b67f09SDavid van Moolenbroek 	ldev = ISC_LIST_HEAD(sock->send_list);
2376*00b67f09SDavid van Moolenbroek 	while (ldev != NULL && ldev != dev)
2377*00b67f09SDavid van Moolenbroek 		ldev = ISC_LIST_NEXT(ldev, ev_link);
2378*00b67f09SDavid van Moolenbroek 
2379*00b67f09SDavid van Moolenbroek 	return (ldev == NULL ? ISC_FALSE : ISC_TRUE);
2380*00b67f09SDavid van Moolenbroek }
2381*00b67f09SDavid van Moolenbroek 
2382*00b67f09SDavid van Moolenbroek static isc_boolean_t
acceptdone_is_active(isc_socket_t * sock,isc_socket_newconnev_t * dev)2383*00b67f09SDavid van Moolenbroek acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev)
2384*00b67f09SDavid van Moolenbroek {
2385*00b67f09SDavid van Moolenbroek 	isc_socket_newconnev_t *ldev;
2386*00b67f09SDavid van Moolenbroek 
2387*00b67f09SDavid van Moolenbroek 	ldev = ISC_LIST_HEAD(sock->accept_list);
2388*00b67f09SDavid van Moolenbroek 	while (ldev != NULL && ldev != dev)
2389*00b67f09SDavid van Moolenbroek 		ldev = ISC_LIST_NEXT(ldev, ev_link);
2390*00b67f09SDavid van Moolenbroek 
2391*00b67f09SDavid van Moolenbroek 	return (ldev == NULL ? ISC_FALSE : ISC_TRUE);
2392*00b67f09SDavid van Moolenbroek }
2393*00b67f09SDavid van Moolenbroek 
2394*00b67f09SDavid van Moolenbroek static isc_boolean_t
connectdone_is_active(isc_socket_t * sock,isc_socket_connev_t * dev)2395*00b67f09SDavid van Moolenbroek connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev)
2396*00b67f09SDavid van Moolenbroek {
2397*00b67f09SDavid van Moolenbroek 	return (sock->connect_ev == dev ? ISC_TRUE : ISC_FALSE);
2398*00b67f09SDavid van Moolenbroek }
2399*00b67f09SDavid van Moolenbroek 
2400*00b67f09SDavid van Moolenbroek //
2401*00b67f09SDavid van Moolenbroek // The Windows network stack seems to have two very distinct paths depending
2402*00b67f09SDavid van Moolenbroek // on what is installed.  Specifically, if something is looking at network
2403*00b67f09SDavid van Moolenbroek // connections (like an anti-virus or anti-malware application, such as
2404*00b67f09SDavid van Moolenbroek // McAfee products) Windows may return additional error conditions which
2405*00b67f09SDavid van Moolenbroek // were not previously returned.
2406*00b67f09SDavid van Moolenbroek //
2407*00b67f09SDavid van Moolenbroek // One specific one is when a TCP SYN scan is used.  In this situation,
2408*00b67f09SDavid van Moolenbroek // Windows responds with the SYN-ACK, but the scanner never responds with
2409*00b67f09SDavid van Moolenbroek // the 3rd packet, the ACK.  Windows consiers this a partially open connection.
2410*00b67f09SDavid van Moolenbroek // Most Unix networking stacks, and Windows without McAfee installed, will
2411*00b67f09SDavid van Moolenbroek // not return this to the caller.  However, with this product installed,
2412*00b67f09SDavid van Moolenbroek // Windows returns this as a failed status on the Accept() call.  Here, we
2413*00b67f09SDavid van Moolenbroek // will just re-issue the ISCAcceptEx() call as if nothing had happened.
2414*00b67f09SDavid van Moolenbroek //
2415*00b67f09SDavid van Moolenbroek // This code should only be called when the listening socket has received
2416*00b67f09SDavid van Moolenbroek // such an error.  Additionally, the "parent" socket must be locked.
2417*00b67f09SDavid van Moolenbroek // Additionally, the lpo argument is re-used here, and must not be freed
2418*00b67f09SDavid van Moolenbroek // by the caller.
2419*00b67f09SDavid van Moolenbroek //
2420*00b67f09SDavid van Moolenbroek static isc_result_t
restart_accept(isc_socket_t * parent,IoCompletionInfo * lpo)2421*00b67f09SDavid van Moolenbroek restart_accept(isc_socket_t *parent, IoCompletionInfo *lpo)
2422*00b67f09SDavid van Moolenbroek {
2423*00b67f09SDavid van Moolenbroek 	isc_socket_t *nsock = lpo->adev->newsocket;
2424*00b67f09SDavid van Moolenbroek 	SOCKET new_fd;
2425*00b67f09SDavid van Moolenbroek 
2426*00b67f09SDavid van Moolenbroek 	/*
2427*00b67f09SDavid van Moolenbroek 	 * AcceptEx() requires we pass in a socket.  Note that we carefully
2428*00b67f09SDavid van Moolenbroek 	 * do not close the previous socket in case of an error message returned by
2429*00b67f09SDavid van Moolenbroek 	 * our new socket() call.  If we return an error here, our caller will
2430*00b67f09SDavid van Moolenbroek 	 * clean up.
2431*00b67f09SDavid van Moolenbroek 	 */
2432*00b67f09SDavid van Moolenbroek 	new_fd = socket(parent->pf, SOCK_STREAM, IPPROTO_TCP);
2433*00b67f09SDavid van Moolenbroek 	if (nsock->fd == INVALID_SOCKET) {
2434*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE); // parent will ask windows for error message
2435*00b67f09SDavid van Moolenbroek 	}
2436*00b67f09SDavid van Moolenbroek 	closesocket(nsock->fd);
2437*00b67f09SDavid van Moolenbroek 	nsock->fd = new_fd;
2438*00b67f09SDavid van Moolenbroek 
2439*00b67f09SDavid van Moolenbroek 	memset(&lpo->overlapped, 0, sizeof(lpo->overlapped));
2440*00b67f09SDavid van Moolenbroek 
2441*00b67f09SDavid van Moolenbroek 	ISCAcceptEx(parent->fd,
2442*00b67f09SDavid van Moolenbroek 		    nsock->fd,				/* Accepted Socket */
2443*00b67f09SDavid van Moolenbroek 		    lpo->acceptbuffer,			/* Buffer for initial Recv */
2444*00b67f09SDavid van Moolenbroek 		    0,					/* Length of Buffer */
2445*00b67f09SDavid van Moolenbroek 		    sizeof(SOCKADDR_STORAGE) + 16,	/* Local address length + 16 */
2446*00b67f09SDavid van Moolenbroek 		    sizeof(SOCKADDR_STORAGE) + 16,	/* Remote address lengh + 16 */
2447*00b67f09SDavid van Moolenbroek 		    (LPDWORD)&lpo->received_bytes,	/* Bytes Recved */
2448*00b67f09SDavid van Moolenbroek 		    (LPOVERLAPPED)lpo			/* Overlapped structure */
2449*00b67f09SDavid van Moolenbroek 		    );
2450*00b67f09SDavid van Moolenbroek 
2451*00b67f09SDavid van Moolenbroek 	InterlockedDecrement(&nsock->manager->iocp_total);
2452*00b67f09SDavid van Moolenbroek 	iocompletionport_update(nsock);
2453*00b67f09SDavid van Moolenbroek 
2454*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
2455*00b67f09SDavid van Moolenbroek }
2456*00b67f09SDavid van Moolenbroek 
2457*00b67f09SDavid van Moolenbroek /*
2458*00b67f09SDavid van Moolenbroek  * This is the I/O Completion Port Worker Function. It loops forever
2459*00b67f09SDavid van Moolenbroek  * waiting for I/O to complete and then forwards them for further
2460*00b67f09SDavid van Moolenbroek  * processing. There are a number of these in separate threads.
2461*00b67f09SDavid van Moolenbroek  */
2462*00b67f09SDavid van Moolenbroek static isc_threadresult_t WINAPI
SocketIoThread(LPVOID ThreadContext)2463*00b67f09SDavid van Moolenbroek SocketIoThread(LPVOID ThreadContext) {
2464*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *manager = ThreadContext;
2465*00b67f09SDavid van Moolenbroek 	BOOL bSuccess = FALSE;
2466*00b67f09SDavid van Moolenbroek 	DWORD nbytes;
2467*00b67f09SDavid van Moolenbroek 	IoCompletionInfo *lpo = NULL;
2468*00b67f09SDavid van Moolenbroek 	isc_socket_t *sock = NULL;
2469*00b67f09SDavid van Moolenbroek 	int request;
2470*00b67f09SDavid van Moolenbroek 	struct msghdr *messagehdr = NULL;
2471*00b67f09SDavid van Moolenbroek 	int errval;
2472*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
2473*00b67f09SDavid van Moolenbroek 	int errstatus;
2474*00b67f09SDavid van Moolenbroek 
2475*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
2476*00b67f09SDavid van Moolenbroek 
2477*00b67f09SDavid van Moolenbroek 	/*
2478*00b67f09SDavid van Moolenbroek 	 * Set the thread priority high enough so I/O will
2479*00b67f09SDavid van Moolenbroek 	 * preempt normal recv packet processing, but not
2480*00b67f09SDavid van Moolenbroek 	 * higher than the timer sync thread.
2481*00b67f09SDavid van Moolenbroek 	 */
2482*00b67f09SDavid van Moolenbroek 	if (!SetThreadPriority(GetCurrentThread(),
2483*00b67f09SDavid van Moolenbroek 			       THREAD_PRIORITY_ABOVE_NORMAL)) {
2484*00b67f09SDavid van Moolenbroek 		errval = GetLastError();
2485*00b67f09SDavid van Moolenbroek 		isc__strerror(errval, strbuf, sizeof(strbuf));
2486*00b67f09SDavid van Moolenbroek 		FATAL_ERROR(__FILE__, __LINE__,
2487*00b67f09SDavid van Moolenbroek 				isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
2488*00b67f09SDavid van Moolenbroek 				ISC_MSG_FAILED,
2489*00b67f09SDavid van Moolenbroek 				"Can't set thread priority: %s"),
2490*00b67f09SDavid van Moolenbroek 				strbuf);
2491*00b67f09SDavid van Moolenbroek 	}
2492*00b67f09SDavid van Moolenbroek 
2493*00b67f09SDavid van Moolenbroek 	/*
2494*00b67f09SDavid van Moolenbroek 	 * Loop forever waiting on I/O Completions and then processing them
2495*00b67f09SDavid van Moolenbroek 	 */
2496*00b67f09SDavid van Moolenbroek 	while (TRUE) {
2497*00b67f09SDavid van Moolenbroek 		wait_again:
2498*00b67f09SDavid van Moolenbroek 		bSuccess = GetQueuedCompletionStatus(manager->hIoCompletionPort,
2499*00b67f09SDavid van Moolenbroek 						     &nbytes,
2500*00b67f09SDavid van Moolenbroek 						     (PULONG_PTR)&sock,
2501*00b67f09SDavid van Moolenbroek 						     (LPWSAOVERLAPPED *)&lpo,
2502*00b67f09SDavid van Moolenbroek 						     INFINITE);
2503*00b67f09SDavid van Moolenbroek 		if (lpo == NULL) /* Received request to exit */
2504*00b67f09SDavid van Moolenbroek 			break;
2505*00b67f09SDavid van Moolenbroek 
2506*00b67f09SDavid van Moolenbroek 		REQUIRE(VALID_SOCKET(sock));
2507*00b67f09SDavid van Moolenbroek 
2508*00b67f09SDavid van Moolenbroek 		request = lpo->request_type;
2509*00b67f09SDavid van Moolenbroek 
2510*00b67f09SDavid van Moolenbroek 		errstatus = 0;
2511*00b67f09SDavid van Moolenbroek 		if (!bSuccess) {
2512*00b67f09SDavid van Moolenbroek 			isc_result_t isc_result;
2513*00b67f09SDavid van Moolenbroek 
2514*00b67f09SDavid van Moolenbroek 			/*
2515*00b67f09SDavid van Moolenbroek 			 * Did the I/O operation complete?
2516*00b67f09SDavid van Moolenbroek 			 */
2517*00b67f09SDavid van Moolenbroek 			errstatus = GetLastError();
2518*00b67f09SDavid van Moolenbroek 			isc_result = isc__errno2resultx(errstatus, __FILE__, __LINE__);
2519*00b67f09SDavid van Moolenbroek 
2520*00b67f09SDavid van Moolenbroek 			LOCK(&sock->lock);
2521*00b67f09SDavid van Moolenbroek 			CONSISTENT(sock);
2522*00b67f09SDavid van Moolenbroek 			switch (request) {
2523*00b67f09SDavid van Moolenbroek 			case SOCKET_RECV:
2524*00b67f09SDavid van Moolenbroek 				INSIST(sock->pending_iocp > 0);
2525*00b67f09SDavid van Moolenbroek 				sock->pending_iocp--;
2526*00b67f09SDavid van Moolenbroek 				INSIST(sock->pending_recv > 0);
2527*00b67f09SDavid van Moolenbroek 				sock->pending_recv--;
2528*00b67f09SDavid van Moolenbroek 				if (!sock->connected &&
2529*00b67f09SDavid van Moolenbroek 				    ((errstatus == ERROR_HOST_UNREACHABLE) ||
2530*00b67f09SDavid van Moolenbroek 				     (errstatus == WSAENETRESET) ||
2531*00b67f09SDavid van Moolenbroek 				     (errstatus == WSAECONNRESET))) {
2532*00b67f09SDavid van Moolenbroek 					/* ignore soft errors */
2533*00b67f09SDavid van Moolenbroek 					queue_receive_request(sock);
2534*00b67f09SDavid van Moolenbroek 					break;
2535*00b67f09SDavid van Moolenbroek 				}
2536*00b67f09SDavid van Moolenbroek 				send_recvdone_abort(sock, isc_result);
2537*00b67f09SDavid van Moolenbroek 				if (isc_result == ISC_R_UNEXPECTED) {
2538*00b67f09SDavid van Moolenbroek 					UNEXPECTED_ERROR(__FILE__, __LINE__,
2539*00b67f09SDavid van Moolenbroek 						"SOCKET_RECV: Windows error code: %d, returning ISC error %d",
2540*00b67f09SDavid van Moolenbroek 						errstatus, isc_result);
2541*00b67f09SDavid van Moolenbroek 				}
2542*00b67f09SDavid van Moolenbroek 				break;
2543*00b67f09SDavid van Moolenbroek 
2544*00b67f09SDavid van Moolenbroek 			case SOCKET_SEND:
2545*00b67f09SDavid van Moolenbroek 				INSIST(sock->pending_iocp > 0);
2546*00b67f09SDavid van Moolenbroek 				sock->pending_iocp--;
2547*00b67f09SDavid van Moolenbroek 				INSIST(sock->pending_send > 0);
2548*00b67f09SDavid van Moolenbroek 				sock->pending_send--;
2549*00b67f09SDavid van Moolenbroek 				if (senddone_is_active(sock, lpo->dev)) {
2550*00b67f09SDavid van Moolenbroek 					lpo->dev->result = isc_result;
2551*00b67f09SDavid van Moolenbroek 					socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
2552*00b67f09SDavid van Moolenbroek 						"canceled_send");
2553*00b67f09SDavid van Moolenbroek 					send_senddone_event(sock, &lpo->dev);
2554*00b67f09SDavid van Moolenbroek 				}
2555*00b67f09SDavid van Moolenbroek 				break;
2556*00b67f09SDavid van Moolenbroek 
2557*00b67f09SDavid van Moolenbroek 			case SOCKET_ACCEPT:
2558*00b67f09SDavid van Moolenbroek 				INSIST(sock->pending_iocp > 0);
2559*00b67f09SDavid van Moolenbroek 				INSIST(sock->pending_accept > 0);
2560*00b67f09SDavid van Moolenbroek 
2561*00b67f09SDavid van Moolenbroek 				socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
2562*00b67f09SDavid van Moolenbroek 					"Accept: errstatus=%d isc_result=%d", errstatus, isc_result);
2563*00b67f09SDavid van Moolenbroek 
2564*00b67f09SDavid van Moolenbroek 				if (acceptdone_is_active(sock, lpo->adev)) {
2565*00b67f09SDavid van Moolenbroek 					if (restart_accept(sock, lpo) == ISC_R_SUCCESS) {
2566*00b67f09SDavid van Moolenbroek 						UNLOCK(&sock->lock);
2567*00b67f09SDavid van Moolenbroek 						goto wait_again;
2568*00b67f09SDavid van Moolenbroek 					} else {
2569*00b67f09SDavid van Moolenbroek 						errstatus = GetLastError();
2570*00b67f09SDavid van Moolenbroek 						isc_result = isc__errno2resultx(errstatus, __FILE__, __LINE__);
2571*00b67f09SDavid van Moolenbroek 						socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
2572*00b67f09SDavid van Moolenbroek 							"restart_accept() failed: errstatus=%d isc_result=%d",
2573*00b67f09SDavid van Moolenbroek 							errstatus, isc_result);
2574*00b67f09SDavid van Moolenbroek 					}
2575*00b67f09SDavid van Moolenbroek 				}
2576*00b67f09SDavid van Moolenbroek 
2577*00b67f09SDavid van Moolenbroek 				sock->pending_iocp--;
2578*00b67f09SDavid van Moolenbroek 				sock->pending_accept--;
2579*00b67f09SDavid van Moolenbroek 				if (acceptdone_is_active(sock, lpo->adev)) {
2580*00b67f09SDavid van Moolenbroek 					closesocket(lpo->adev->newsocket->fd);
2581*00b67f09SDavid van Moolenbroek 					lpo->adev->newsocket->fd = INVALID_SOCKET;
2582*00b67f09SDavid van Moolenbroek 					lpo->adev->newsocket->references--;
2583*00b67f09SDavid van Moolenbroek 					free_socket(&lpo->adev->newsocket, __LINE__);
2584*00b67f09SDavid van Moolenbroek 					lpo->adev->result = isc_result;
2585*00b67f09SDavid van Moolenbroek 					socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
2586*00b67f09SDavid van Moolenbroek 						"canceled_accept");
2587*00b67f09SDavid van Moolenbroek 					send_acceptdone_event(sock, &lpo->adev);
2588*00b67f09SDavid van Moolenbroek 				}
2589*00b67f09SDavid van Moolenbroek 				break;
2590*00b67f09SDavid van Moolenbroek 
2591*00b67f09SDavid van Moolenbroek 			case SOCKET_CONNECT:
2592*00b67f09SDavid van Moolenbroek 				INSIST(sock->pending_iocp > 0);
2593*00b67f09SDavid van Moolenbroek 				sock->pending_iocp--;
2594*00b67f09SDavid van Moolenbroek 				INSIST(sock->pending_connect == 1);
2595*00b67f09SDavid van Moolenbroek 				sock->pending_connect = 0;
2596*00b67f09SDavid van Moolenbroek 				if (connectdone_is_active(sock, lpo->cdev)) {
2597*00b67f09SDavid van Moolenbroek 					lpo->cdev->result = isc_result;
2598*00b67f09SDavid van Moolenbroek 					socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
2599*00b67f09SDavid van Moolenbroek 						"canceled_connect");
2600*00b67f09SDavid van Moolenbroek 					send_connectdone_event(sock, &lpo->cdev);
2601*00b67f09SDavid van Moolenbroek 				}
2602*00b67f09SDavid van Moolenbroek 				break;
2603*00b67f09SDavid van Moolenbroek 			}
2604*00b67f09SDavid van Moolenbroek 			maybe_free_socket(&sock, __LINE__);
2605*00b67f09SDavid van Moolenbroek 
2606*00b67f09SDavid van Moolenbroek 			if (lpo != NULL)
2607*00b67f09SDavid van Moolenbroek 				HeapFree(hHeapHandle, 0, lpo);
2608*00b67f09SDavid van Moolenbroek 			continue;
2609*00b67f09SDavid van Moolenbroek 		}
2610*00b67f09SDavid van Moolenbroek 
2611*00b67f09SDavid van Moolenbroek 		messagehdr = &lpo->messagehdr;
2612*00b67f09SDavid van Moolenbroek 
2613*00b67f09SDavid van Moolenbroek 		switch (request) {
2614*00b67f09SDavid van Moolenbroek 		case SOCKET_RECV:
2615*00b67f09SDavid van Moolenbroek 			internal_recv(sock, nbytes);
2616*00b67f09SDavid van Moolenbroek 			break;
2617*00b67f09SDavid van Moolenbroek 		case SOCKET_SEND:
2618*00b67f09SDavid van Moolenbroek 			internal_send(sock, lpo->dev, messagehdr, nbytes, errstatus, lpo);
2619*00b67f09SDavid van Moolenbroek 			break;
2620*00b67f09SDavid van Moolenbroek 		case SOCKET_ACCEPT:
2621*00b67f09SDavid van Moolenbroek 			internal_accept(sock, lpo, errstatus);
2622*00b67f09SDavid van Moolenbroek 			break;
2623*00b67f09SDavid van Moolenbroek 		case SOCKET_CONNECT:
2624*00b67f09SDavid van Moolenbroek 			internal_connect(sock, lpo, errstatus);
2625*00b67f09SDavid van Moolenbroek 			break;
2626*00b67f09SDavid van Moolenbroek 		}
2627*00b67f09SDavid van Moolenbroek 
2628*00b67f09SDavid van Moolenbroek 		if (lpo != NULL)
2629*00b67f09SDavid van Moolenbroek 			HeapFree(hHeapHandle, 0, lpo);
2630*00b67f09SDavid van Moolenbroek 	}
2631*00b67f09SDavid van Moolenbroek 
2632*00b67f09SDavid van Moolenbroek 	/*
2633*00b67f09SDavid van Moolenbroek 	 * Exit Completion Port Thread
2634*00b67f09SDavid van Moolenbroek 	 */
2635*00b67f09SDavid van Moolenbroek 	manager_log(manager, TRACE,
2636*00b67f09SDavid van Moolenbroek 		    isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
2637*00b67f09SDavid van Moolenbroek 				   ISC_MSG_EXITING, "SocketIoThread exiting"));
2638*00b67f09SDavid van Moolenbroek 	return ((isc_threadresult_t)0);
2639*00b67f09SDavid van Moolenbroek }
2640*00b67f09SDavid van Moolenbroek 
2641*00b67f09SDavid van Moolenbroek /*
2642*00b67f09SDavid van Moolenbroek  * Create a new socket manager.
2643*00b67f09SDavid van Moolenbroek  */
2644*00b67f09SDavid van Moolenbroek isc_result_t
isc__socketmgr_create(isc_mem_t * mctx,isc_socketmgr_t ** managerp)2645*00b67f09SDavid van Moolenbroek isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
2646*00b67f09SDavid van Moolenbroek 	return (isc_socketmgr_create2(mctx, managerp, 0));
2647*00b67f09SDavid van Moolenbroek }
2648*00b67f09SDavid van Moolenbroek 
2649*00b67f09SDavid van Moolenbroek isc_result_t
isc__socketmgr_create2(isc_mem_t * mctx,isc_socketmgr_t ** managerp,unsigned int maxsocks)2650*00b67f09SDavid van Moolenbroek isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
2651*00b67f09SDavid van Moolenbroek 		       unsigned int maxsocks)
2652*00b67f09SDavid van Moolenbroek {
2653*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *manager;
2654*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2655*00b67f09SDavid van Moolenbroek 
2656*00b67f09SDavid van Moolenbroek 	REQUIRE(managerp != NULL && *managerp == NULL);
2657*00b67f09SDavid van Moolenbroek 
2658*00b67f09SDavid van Moolenbroek 	if (maxsocks != 0)
2659*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOTIMPLEMENTED);
2660*00b67f09SDavid van Moolenbroek 
2661*00b67f09SDavid van Moolenbroek 	manager = isc_mem_get(mctx, sizeof(*manager));
2662*00b67f09SDavid van Moolenbroek 	if (manager == NULL)
2663*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
2664*00b67f09SDavid van Moolenbroek 
2665*00b67f09SDavid van Moolenbroek 	InitSockets();
2666*00b67f09SDavid van Moolenbroek 
2667*00b67f09SDavid van Moolenbroek 	manager->magic = SOCKET_MANAGER_MAGIC;
2668*00b67f09SDavid van Moolenbroek 	manager->mctx = NULL;
2669*00b67f09SDavid van Moolenbroek 	manager->stats = NULL;
2670*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(manager->socklist);
2671*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&manager->lock);
2672*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2673*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, manager, sizeof(*manager));
2674*00b67f09SDavid van Moolenbroek 		return (result);
2675*00b67f09SDavid van Moolenbroek 	}
2676*00b67f09SDavid van Moolenbroek 	if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) {
2677*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&manager->lock);
2678*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, manager, sizeof(*manager));
2679*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
2680*00b67f09SDavid van Moolenbroek 				 "isc_condition_init() %s",
2681*00b67f09SDavid van Moolenbroek 				 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
2682*00b67f09SDavid van Moolenbroek 						ISC_MSG_FAILED, "failed"));
2683*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
2684*00b67f09SDavid van Moolenbroek 	}
2685*00b67f09SDavid van Moolenbroek 
2686*00b67f09SDavid van Moolenbroek 	isc_mem_attach(mctx, &manager->mctx);
2687*00b67f09SDavid van Moolenbroek 
2688*00b67f09SDavid van Moolenbroek 	iocompletionport_init(manager);	/* Create the Completion Ports */
2689*00b67f09SDavid van Moolenbroek 
2690*00b67f09SDavid van Moolenbroek 	manager->bShutdown = ISC_FALSE;
2691*00b67f09SDavid van Moolenbroek 	manager->totalSockets = 0;
2692*00b67f09SDavid van Moolenbroek 	manager->iocp_total = 0;
2693*00b67f09SDavid van Moolenbroek 
2694*00b67f09SDavid van Moolenbroek 	*managerp = manager;
2695*00b67f09SDavid van Moolenbroek 
2696*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
2697*00b67f09SDavid van Moolenbroek }
2698*00b67f09SDavid van Moolenbroek 
2699*00b67f09SDavid van Moolenbroek isc_result_t
isc_socketmgr_getmaxsockets(isc_socketmgr_t * manager,unsigned int * nsockp)2700*00b67f09SDavid van Moolenbroek isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp) {
2701*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
2702*00b67f09SDavid van Moolenbroek 	REQUIRE(nsockp != NULL);
2703*00b67f09SDavid van Moolenbroek 
2704*00b67f09SDavid van Moolenbroek 	return (ISC_R_NOTIMPLEMENTED);
2705*00b67f09SDavid van Moolenbroek }
2706*00b67f09SDavid van Moolenbroek 
2707*00b67f09SDavid van Moolenbroek void
isc_socketmgr_setstats(isc_socketmgr_t * manager,isc_stats_t * stats)2708*00b67f09SDavid van Moolenbroek isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) {
2709*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
2710*00b67f09SDavid van Moolenbroek 	REQUIRE(ISC_LIST_EMPTY(manager->socklist));
2711*00b67f09SDavid van Moolenbroek 	REQUIRE(manager->stats == NULL);
2712*00b67f09SDavid van Moolenbroek 	REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max);
2713*00b67f09SDavid van Moolenbroek 
2714*00b67f09SDavid van Moolenbroek 	isc_stats_attach(stats, &manager->stats);
2715*00b67f09SDavid van Moolenbroek }
2716*00b67f09SDavid van Moolenbroek 
2717*00b67f09SDavid van Moolenbroek void
isc__socketmgr_destroy(isc_socketmgr_t ** managerp)2718*00b67f09SDavid van Moolenbroek isc__socketmgr_destroy(isc_socketmgr_t **managerp) {
2719*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *manager;
2720*00b67f09SDavid van Moolenbroek 	int i;
2721*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx;
2722*00b67f09SDavid van Moolenbroek 
2723*00b67f09SDavid van Moolenbroek 	/*
2724*00b67f09SDavid van Moolenbroek 	 * Destroy a socket manager.
2725*00b67f09SDavid van Moolenbroek 	 */
2726*00b67f09SDavid van Moolenbroek 
2727*00b67f09SDavid van Moolenbroek 	REQUIRE(managerp != NULL);
2728*00b67f09SDavid van Moolenbroek 	manager = *managerp;
2729*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
2730*00b67f09SDavid van Moolenbroek 
2731*00b67f09SDavid van Moolenbroek 	LOCK(&manager->lock);
2732*00b67f09SDavid van Moolenbroek 
2733*00b67f09SDavid van Moolenbroek 	/*
2734*00b67f09SDavid van Moolenbroek 	 * Wait for all sockets to be destroyed.
2735*00b67f09SDavid van Moolenbroek 	 */
2736*00b67f09SDavid van Moolenbroek 	while (!ISC_LIST_EMPTY(manager->socklist)) {
2737*00b67f09SDavid van Moolenbroek 		manager_log(manager, CREATION,
2738*00b67f09SDavid van Moolenbroek 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
2739*00b67f09SDavid van Moolenbroek 					   ISC_MSG_SOCKETSREMAIN,
2740*00b67f09SDavid van Moolenbroek 					   "sockets exist"));
2741*00b67f09SDavid van Moolenbroek 		WAIT(&manager->shutdown_ok, &manager->lock);
2742*00b67f09SDavid van Moolenbroek 	}
2743*00b67f09SDavid van Moolenbroek 
2744*00b67f09SDavid van Moolenbroek 	UNLOCK(&manager->lock);
2745*00b67f09SDavid van Moolenbroek 
2746*00b67f09SDavid van Moolenbroek 	/*
2747*00b67f09SDavid van Moolenbroek 	 * Here, we need to had some wait code for the completion port
2748*00b67f09SDavid van Moolenbroek 	 * thread.
2749*00b67f09SDavid van Moolenbroek 	 */
2750*00b67f09SDavid van Moolenbroek 	signal_iocompletionport_exit(manager);
2751*00b67f09SDavid van Moolenbroek 	manager->bShutdown = ISC_TRUE;
2752*00b67f09SDavid van Moolenbroek 
2753*00b67f09SDavid van Moolenbroek 	/*
2754*00b67f09SDavid van Moolenbroek 	 * Wait for threads to exit.
2755*00b67f09SDavid van Moolenbroek 	 */
2756*00b67f09SDavid van Moolenbroek 	for (i = 0; i < manager->maxIOCPThreads; i++) {
2757*00b67f09SDavid van Moolenbroek 		if (isc_thread_join((isc_thread_t) manager->hIOCPThreads[i],
2758*00b67f09SDavid van Moolenbroek 			NULL) != ISC_R_SUCCESS)
2759*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
2760*00b67f09SDavid van Moolenbroek 				 "isc_thread_join() for Completion Port %s",
2761*00b67f09SDavid van Moolenbroek 				 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
2762*00b67f09SDavid van Moolenbroek 						ISC_MSG_FAILED, "failed"));
2763*00b67f09SDavid van Moolenbroek 	}
2764*00b67f09SDavid van Moolenbroek 	/*
2765*00b67f09SDavid van Moolenbroek 	 * Clean up.
2766*00b67f09SDavid van Moolenbroek 	 */
2767*00b67f09SDavid van Moolenbroek 
2768*00b67f09SDavid van Moolenbroek 	CloseHandle(manager->hIoCompletionPort);
2769*00b67f09SDavid van Moolenbroek 
2770*00b67f09SDavid van Moolenbroek 	(void)isc_condition_destroy(&manager->shutdown_ok);
2771*00b67f09SDavid van Moolenbroek 
2772*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&manager->lock);
2773*00b67f09SDavid van Moolenbroek 	if (manager->stats != NULL)
2774*00b67f09SDavid van Moolenbroek 		isc_stats_detach(&manager->stats);
2775*00b67f09SDavid van Moolenbroek 	manager->magic = 0;
2776*00b67f09SDavid van Moolenbroek 	mctx= manager->mctx;
2777*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, manager, sizeof(*manager));
2778*00b67f09SDavid van Moolenbroek 
2779*00b67f09SDavid van Moolenbroek 	isc_mem_detach(&mctx);
2780*00b67f09SDavid van Moolenbroek 
2781*00b67f09SDavid van Moolenbroek 	*managerp = NULL;
2782*00b67f09SDavid van Moolenbroek }
2783*00b67f09SDavid van Moolenbroek 
2784*00b67f09SDavid van Moolenbroek static void
queue_receive_event(isc_socket_t * sock,isc_task_t * task,isc_socketevent_t * dev)2785*00b67f09SDavid van Moolenbroek queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev)
2786*00b67f09SDavid van Moolenbroek {
2787*00b67f09SDavid van Moolenbroek 	isc_task_t *ntask = NULL;
2788*00b67f09SDavid van Moolenbroek 
2789*00b67f09SDavid van Moolenbroek 	isc_task_attach(task, &ntask);
2790*00b67f09SDavid van Moolenbroek 	dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
2791*00b67f09SDavid van Moolenbroek 
2792*00b67f09SDavid van Moolenbroek 	/*
2793*00b67f09SDavid van Moolenbroek 	 * Enqueue the request.
2794*00b67f09SDavid van Moolenbroek 	 */
2795*00b67f09SDavid van Moolenbroek 	INSIST(!ISC_LINK_LINKED(dev, ev_link));
2796*00b67f09SDavid van Moolenbroek 	ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
2797*00b67f09SDavid van Moolenbroek 
2798*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
2799*00b67f09SDavid van Moolenbroek 		   "queue_receive_event: event %p -> task %p",
2800*00b67f09SDavid van Moolenbroek 		   dev, ntask);
2801*00b67f09SDavid van Moolenbroek }
2802*00b67f09SDavid van Moolenbroek 
2803*00b67f09SDavid van Moolenbroek /*
2804*00b67f09SDavid van Moolenbroek  * Check the pending receive queue, and if we have data pending, give it to this
2805*00b67f09SDavid van Moolenbroek  * caller.  If we have none, queue an I/O request.  If this caller is not the first
2806*00b67f09SDavid van Moolenbroek  * on the list, then we will just queue this event and return.
2807*00b67f09SDavid van Moolenbroek  *
2808*00b67f09SDavid van Moolenbroek  * Caller must have the socket locked.
2809*00b67f09SDavid van Moolenbroek  */
2810*00b67f09SDavid van Moolenbroek static isc_result_t
socket_recv(isc_socket_t * sock,isc_socketevent_t * dev,isc_task_t * task,unsigned int flags)2811*00b67f09SDavid van Moolenbroek socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
2812*00b67f09SDavid van Moolenbroek 	    unsigned int flags)
2813*00b67f09SDavid van Moolenbroek {
2814*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
2815*00b67f09SDavid van Moolenbroek 
2816*00b67f09SDavid van Moolenbroek 	dev->ev_sender = task;
2817*00b67f09SDavid van Moolenbroek 
2818*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET)
2819*00b67f09SDavid van Moolenbroek 		return (ISC_R_EOF);
2820*00b67f09SDavid van Moolenbroek 
2821*00b67f09SDavid van Moolenbroek 	/*
2822*00b67f09SDavid van Moolenbroek 	 * Queue our event on the list of things to do.  Call our function to
2823*00b67f09SDavid van Moolenbroek 	 * attempt to fill buffers as much as possible, and return done events.
2824*00b67f09SDavid van Moolenbroek 	 * We are going to lie about our handling of the ISC_SOCKFLAG_IMMEDIATE
2825*00b67f09SDavid van Moolenbroek 	 * here and tell our caller that we could not satisfy it immediately.
2826*00b67f09SDavid van Moolenbroek 	 */
2827*00b67f09SDavid van Moolenbroek 	queue_receive_event(sock, task, dev);
2828*00b67f09SDavid van Moolenbroek 	if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
2829*00b67f09SDavid van Moolenbroek 		result = ISC_R_INPROGRESS;
2830*00b67f09SDavid van Moolenbroek 
2831*00b67f09SDavid van Moolenbroek 	completeio_recv(sock);
2832*00b67f09SDavid van Moolenbroek 
2833*00b67f09SDavid van Moolenbroek 	/*
2834*00b67f09SDavid van Moolenbroek 	 * If there are more receivers waiting for data, queue another receive
2835*00b67f09SDavid van Moolenbroek 	 * here.  If the
2836*00b67f09SDavid van Moolenbroek 	 */
2837*00b67f09SDavid van Moolenbroek 	queue_receive_request(sock);
2838*00b67f09SDavid van Moolenbroek 
2839*00b67f09SDavid van Moolenbroek 	return (result);
2840*00b67f09SDavid van Moolenbroek }
2841*00b67f09SDavid van Moolenbroek 
2842*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_recvv(isc_socket_t * sock,isc_bufferlist_t * buflist,unsigned int minimum,isc_task_t * task,isc_taskaction_t action,void * arg)2843*00b67f09SDavid van Moolenbroek isc__socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
2844*00b67f09SDavid van Moolenbroek 		 unsigned int minimum, isc_task_t *task,
2845*00b67f09SDavid van Moolenbroek 		 isc_taskaction_t action, void *arg)
2846*00b67f09SDavid van Moolenbroek {
2847*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *dev;
2848*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *manager;
2849*00b67f09SDavid van Moolenbroek 	unsigned int iocount;
2850*00b67f09SDavid van Moolenbroek 	isc_buffer_t *buffer;
2851*00b67f09SDavid van Moolenbroek 	isc_result_t ret;
2852*00b67f09SDavid van Moolenbroek 
2853*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
2854*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
2855*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
2856*00b67f09SDavid van Moolenbroek 
2857*00b67f09SDavid van Moolenbroek 	/*
2858*00b67f09SDavid van Moolenbroek 	 * Make sure that the socket is not closed.  XXXMLG change error here?
2859*00b67f09SDavid van Moolenbroek 	 */
2860*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
2861*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
2862*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
2863*00b67f09SDavid van Moolenbroek 	}
2864*00b67f09SDavid van Moolenbroek 
2865*00b67f09SDavid van Moolenbroek 	REQUIRE(buflist != NULL);
2866*00b67f09SDavid van Moolenbroek 	REQUIRE(!ISC_LIST_EMPTY(*buflist));
2867*00b67f09SDavid van Moolenbroek 	REQUIRE(task != NULL);
2868*00b67f09SDavid van Moolenbroek 	REQUIRE(action != NULL);
2869*00b67f09SDavid van Moolenbroek 
2870*00b67f09SDavid van Moolenbroek 	manager = sock->manager;
2871*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
2872*00b67f09SDavid van Moolenbroek 
2873*00b67f09SDavid van Moolenbroek 	iocount = isc_bufferlist_availablecount(buflist);
2874*00b67f09SDavid van Moolenbroek 	REQUIRE(iocount > 0);
2875*00b67f09SDavid van Moolenbroek 
2876*00b67f09SDavid van Moolenbroek 	INSIST(sock->bound);
2877*00b67f09SDavid van Moolenbroek 
2878*00b67f09SDavid van Moolenbroek 	dev = allocate_socketevent(manager->mctx, sock,
2879*00b67f09SDavid van Moolenbroek 				   ISC_SOCKEVENT_RECVDONE, action, arg);
2880*00b67f09SDavid van Moolenbroek 	if (dev == NULL) {
2881*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
2882*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
2883*00b67f09SDavid van Moolenbroek 	}
2884*00b67f09SDavid van Moolenbroek 
2885*00b67f09SDavid van Moolenbroek 	/*
2886*00b67f09SDavid van Moolenbroek 	 * UDP sockets are always partial read
2887*00b67f09SDavid van Moolenbroek 	 */
2888*00b67f09SDavid van Moolenbroek 	if (sock->type == isc_sockettype_udp)
2889*00b67f09SDavid van Moolenbroek 		dev->minimum = 1;
2890*00b67f09SDavid van Moolenbroek 	else {
2891*00b67f09SDavid van Moolenbroek 		if (minimum == 0)
2892*00b67f09SDavid van Moolenbroek 			dev->minimum = iocount;
2893*00b67f09SDavid van Moolenbroek 		else
2894*00b67f09SDavid van Moolenbroek 			dev->minimum = minimum;
2895*00b67f09SDavid van Moolenbroek 	}
2896*00b67f09SDavid van Moolenbroek 
2897*00b67f09SDavid van Moolenbroek 	/*
2898*00b67f09SDavid van Moolenbroek 	 * Move each buffer from the passed in list to our internal one.
2899*00b67f09SDavid van Moolenbroek 	 */
2900*00b67f09SDavid van Moolenbroek 	buffer = ISC_LIST_HEAD(*buflist);
2901*00b67f09SDavid van Moolenbroek 	while (buffer != NULL) {
2902*00b67f09SDavid van Moolenbroek 		ISC_LIST_DEQUEUE(*buflist, buffer, link);
2903*00b67f09SDavid van Moolenbroek 		ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
2904*00b67f09SDavid van Moolenbroek 		buffer = ISC_LIST_HEAD(*buflist);
2905*00b67f09SDavid van Moolenbroek 	}
2906*00b67f09SDavid van Moolenbroek 
2907*00b67f09SDavid van Moolenbroek 	ret = socket_recv(sock, dev, task, 0);
2908*00b67f09SDavid van Moolenbroek 
2909*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
2910*00b67f09SDavid van Moolenbroek 	return (ret);
2911*00b67f09SDavid van Moolenbroek }
2912*00b67f09SDavid van Moolenbroek 
2913*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_recv(isc_socket_t * sock,isc_region_t * region,unsigned int minimum,isc_task_t * task,isc_taskaction_t action,void * arg)2914*00b67f09SDavid van Moolenbroek isc__socket_recv(isc_socket_t *sock, isc_region_t *region,
2915*00b67f09SDavid van Moolenbroek 		 unsigned int minimum, isc_task_t *task,
2916*00b67f09SDavid van Moolenbroek 		 isc_taskaction_t action, void *arg)
2917*00b67f09SDavid van Moolenbroek {
2918*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *dev;
2919*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *manager;
2920*00b67f09SDavid van Moolenbroek 	isc_result_t ret;
2921*00b67f09SDavid van Moolenbroek 
2922*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
2923*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
2924*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
2925*00b67f09SDavid van Moolenbroek 
2926*00b67f09SDavid van Moolenbroek 	/*
2927*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
2928*00b67f09SDavid van Moolenbroek 	 */
2929*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
2930*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
2931*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
2932*00b67f09SDavid van Moolenbroek 	}
2933*00b67f09SDavid van Moolenbroek 	REQUIRE(action != NULL);
2934*00b67f09SDavid van Moolenbroek 
2935*00b67f09SDavid van Moolenbroek 	manager = sock->manager;
2936*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
2937*00b67f09SDavid van Moolenbroek 
2938*00b67f09SDavid van Moolenbroek 	INSIST(sock->bound);
2939*00b67f09SDavid van Moolenbroek 
2940*00b67f09SDavid van Moolenbroek 	dev = allocate_socketevent(manager->mctx, sock,
2941*00b67f09SDavid van Moolenbroek 				   ISC_SOCKEVENT_RECVDONE, action, arg);
2942*00b67f09SDavid van Moolenbroek 	if (dev == NULL) {
2943*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
2944*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
2945*00b67f09SDavid van Moolenbroek 	}
2946*00b67f09SDavid van Moolenbroek 
2947*00b67f09SDavid van Moolenbroek 	ret = isc_socket_recv2(sock, region, minimum, task, dev, 0);
2948*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
2949*00b67f09SDavid van Moolenbroek 	return (ret);
2950*00b67f09SDavid van Moolenbroek }
2951*00b67f09SDavid van Moolenbroek 
2952*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_recv2(isc_socket_t * sock,isc_region_t * region,unsigned int minimum,isc_task_t * task,isc_socketevent_t * event,unsigned int flags)2953*00b67f09SDavid van Moolenbroek isc__socket_recv2(isc_socket_t *sock, isc_region_t *region,
2954*00b67f09SDavid van Moolenbroek 		  unsigned int minimum, isc_task_t *task,
2955*00b67f09SDavid van Moolenbroek 		  isc_socketevent_t *event, unsigned int flags)
2956*00b67f09SDavid van Moolenbroek {
2957*00b67f09SDavid van Moolenbroek 	isc_result_t ret;
2958*00b67f09SDavid van Moolenbroek 
2959*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
2960*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
2961*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
2962*00b67f09SDavid van Moolenbroek 
2963*00b67f09SDavid van Moolenbroek 	event->result = ISC_R_UNEXPECTED;
2964*00b67f09SDavid van Moolenbroek 	event->ev_sender = sock;
2965*00b67f09SDavid van Moolenbroek 	/*
2966*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
2967*00b67f09SDavid van Moolenbroek 	 */
2968*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
2969*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
2970*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
2971*00b67f09SDavid van Moolenbroek 	}
2972*00b67f09SDavid van Moolenbroek 
2973*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(event->bufferlist);
2974*00b67f09SDavid van Moolenbroek 	event->region = *region;
2975*00b67f09SDavid van Moolenbroek 	event->n = 0;
2976*00b67f09SDavid van Moolenbroek 	event->offset = 0;
2977*00b67f09SDavid van Moolenbroek 	event->attributes = 0;
2978*00b67f09SDavid van Moolenbroek 
2979*00b67f09SDavid van Moolenbroek 	/*
2980*00b67f09SDavid van Moolenbroek 	 * UDP sockets are always partial read.
2981*00b67f09SDavid van Moolenbroek 	 */
2982*00b67f09SDavid van Moolenbroek 	if (sock->type == isc_sockettype_udp)
2983*00b67f09SDavid van Moolenbroek 		event->minimum = 1;
2984*00b67f09SDavid van Moolenbroek 	else {
2985*00b67f09SDavid van Moolenbroek 		if (minimum == 0)
2986*00b67f09SDavid van Moolenbroek 			event->minimum = region->length;
2987*00b67f09SDavid van Moolenbroek 		else
2988*00b67f09SDavid van Moolenbroek 			event->minimum = minimum;
2989*00b67f09SDavid van Moolenbroek 	}
2990*00b67f09SDavid van Moolenbroek 
2991*00b67f09SDavid van Moolenbroek 	ret = socket_recv(sock, event, task, flags);
2992*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
2993*00b67f09SDavid van Moolenbroek 	return (ret);
2994*00b67f09SDavid van Moolenbroek }
2995*00b67f09SDavid van Moolenbroek 
2996*00b67f09SDavid van Moolenbroek /*
2997*00b67f09SDavid van Moolenbroek  * Caller must have the socket locked.
2998*00b67f09SDavid van Moolenbroek  */
2999*00b67f09SDavid van Moolenbroek static isc_result_t
socket_send(isc_socket_t * sock,isc_socketevent_t * dev,isc_task_t * task,isc_sockaddr_t * address,struct in6_pktinfo * pktinfo,unsigned int flags)3000*00b67f09SDavid van Moolenbroek socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
3001*00b67f09SDavid van Moolenbroek 	    isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
3002*00b67f09SDavid van Moolenbroek 	    unsigned int flags)
3003*00b67f09SDavid van Moolenbroek {
3004*00b67f09SDavid van Moolenbroek 	int io_state;
3005*00b67f09SDavid van Moolenbroek 	int send_errno = 0;
3006*00b67f09SDavid van Moolenbroek 	int cc = 0;
3007*00b67f09SDavid van Moolenbroek 	isc_task_t *ntask = NULL;
3008*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
3009*00b67f09SDavid van Moolenbroek 
3010*00b67f09SDavid van Moolenbroek 	dev->ev_sender = task;
3011*00b67f09SDavid van Moolenbroek 
3012*00b67f09SDavid van Moolenbroek 	set_dev_address(address, sock, dev);
3013*00b67f09SDavid van Moolenbroek 	if (pktinfo != NULL) {
3014*00b67f09SDavid van Moolenbroek 		socket_log(__LINE__, sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET,
3015*00b67f09SDavid van Moolenbroek 			   ISC_MSG_PKTINFOPROVIDED,
3016*00b67f09SDavid van Moolenbroek 			   "pktinfo structure provided, ifindex %u (set to 0)",
3017*00b67f09SDavid van Moolenbroek 			   pktinfo->ipi6_ifindex);
3018*00b67f09SDavid van Moolenbroek 
3019*00b67f09SDavid van Moolenbroek 		dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
3020*00b67f09SDavid van Moolenbroek 		dev->pktinfo = *pktinfo;
3021*00b67f09SDavid van Moolenbroek 		/*
3022*00b67f09SDavid van Moolenbroek 		 * Set the pktinfo index to 0 here, to let the kernel decide
3023*00b67f09SDavid van Moolenbroek 		 * what interface it should send on.
3024*00b67f09SDavid van Moolenbroek 		 */
3025*00b67f09SDavid van Moolenbroek 		dev->pktinfo.ipi6_ifindex = 0;
3026*00b67f09SDavid van Moolenbroek 	}
3027*00b67f09SDavid van Moolenbroek 
3028*00b67f09SDavid van Moolenbroek 	io_state = startio_send(sock, dev, &cc, &send_errno);
3029*00b67f09SDavid van Moolenbroek 	switch (io_state) {
3030*00b67f09SDavid van Moolenbroek 	case DOIO_PENDING:	/* I/O started. Enqueue completion event. */
3031*00b67f09SDavid van Moolenbroek 	case DOIO_SOFT:
3032*00b67f09SDavid van Moolenbroek 		/*
3033*00b67f09SDavid van Moolenbroek 		 * We couldn't send all or part of the request right now, so
3034*00b67f09SDavid van Moolenbroek 		 * queue it unless ISC_SOCKFLAG_NORETRY is set.
3035*00b67f09SDavid van Moolenbroek 		 */
3036*00b67f09SDavid van Moolenbroek 		if ((flags & ISC_SOCKFLAG_NORETRY) == 0 ||
3037*00b67f09SDavid van Moolenbroek 		    io_state == DOIO_PENDING) {
3038*00b67f09SDavid van Moolenbroek 			isc_task_attach(task, &ntask);
3039*00b67f09SDavid van Moolenbroek 			dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
3040*00b67f09SDavid van Moolenbroek 
3041*00b67f09SDavid van Moolenbroek 			/*
3042*00b67f09SDavid van Moolenbroek 			 * Enqueue the request.
3043*00b67f09SDavid van Moolenbroek 			 */
3044*00b67f09SDavid van Moolenbroek 			INSIST(!ISC_LINK_LINKED(dev, ev_link));
3045*00b67f09SDavid van Moolenbroek 			ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
3046*00b67f09SDavid van Moolenbroek 
3047*00b67f09SDavid van Moolenbroek 			socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
3048*00b67f09SDavid van Moolenbroek 				   "socket_send: event %p -> task %p",
3049*00b67f09SDavid van Moolenbroek 				   dev, ntask);
3050*00b67f09SDavid van Moolenbroek 
3051*00b67f09SDavid van Moolenbroek 			if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
3052*00b67f09SDavid van Moolenbroek 				result = ISC_R_INPROGRESS;
3053*00b67f09SDavid van Moolenbroek 			break;
3054*00b67f09SDavid van Moolenbroek 		}
3055*00b67f09SDavid van Moolenbroek 
3056*00b67f09SDavid van Moolenbroek 	case DOIO_SUCCESS:
3057*00b67f09SDavid van Moolenbroek 		break;
3058*00b67f09SDavid van Moolenbroek 	}
3059*00b67f09SDavid van Moolenbroek 
3060*00b67f09SDavid van Moolenbroek 	return (result);
3061*00b67f09SDavid van Moolenbroek }
3062*00b67f09SDavid van Moolenbroek 
3063*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_send(isc_socket_t * sock,isc_region_t * region,isc_task_t * task,isc_taskaction_t action,void * arg)3064*00b67f09SDavid van Moolenbroek isc__socket_send(isc_socket_t *sock, isc_region_t *region,
3065*00b67f09SDavid van Moolenbroek 		 isc_task_t *task, isc_taskaction_t action, void *arg)
3066*00b67f09SDavid van Moolenbroek {
3067*00b67f09SDavid van Moolenbroek 	/*
3068*00b67f09SDavid van Moolenbroek 	 * REQUIRE() checking is performed in isc_socket_sendto().
3069*00b67f09SDavid van Moolenbroek 	 */
3070*00b67f09SDavid van Moolenbroek 	return (isc_socket_sendto(sock, region, task, action, arg, NULL,
3071*00b67f09SDavid van Moolenbroek 				  NULL));
3072*00b67f09SDavid van Moolenbroek }
3073*00b67f09SDavid van Moolenbroek 
3074*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_sendto(isc_socket_t * sock,isc_region_t * region,isc_task_t * task,isc_taskaction_t action,void * arg,isc_sockaddr_t * address,struct in6_pktinfo * pktinfo)3075*00b67f09SDavid van Moolenbroek isc__socket_sendto(isc_socket_t *sock, isc_region_t *region,
3076*00b67f09SDavid van Moolenbroek 		   isc_task_t *task, isc_taskaction_t action, void *arg,
3077*00b67f09SDavid van Moolenbroek 		   isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
3078*00b67f09SDavid van Moolenbroek {
3079*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *dev;
3080*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *manager;
3081*00b67f09SDavid van Moolenbroek 	isc_result_t ret;
3082*00b67f09SDavid van Moolenbroek 
3083*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3084*00b67f09SDavid van Moolenbroek 	REQUIRE(sock->type != isc_sockettype_fdwatch);
3085*00b67f09SDavid van Moolenbroek 
3086*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3087*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3088*00b67f09SDavid van Moolenbroek 
3089*00b67f09SDavid van Moolenbroek 	/*
3090*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3091*00b67f09SDavid van Moolenbroek 	 */
3092*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3093*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3094*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
3095*00b67f09SDavid van Moolenbroek 	}
3096*00b67f09SDavid van Moolenbroek 	REQUIRE(region != NULL);
3097*00b67f09SDavid van Moolenbroek 	REQUIRE(task != NULL);
3098*00b67f09SDavid van Moolenbroek 	REQUIRE(action != NULL);
3099*00b67f09SDavid van Moolenbroek 
3100*00b67f09SDavid van Moolenbroek 	manager = sock->manager;
3101*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
3102*00b67f09SDavid van Moolenbroek 
3103*00b67f09SDavid van Moolenbroek 	INSIST(sock->bound);
3104*00b67f09SDavid van Moolenbroek 
3105*00b67f09SDavid van Moolenbroek 	dev = allocate_socketevent(manager->mctx, sock,
3106*00b67f09SDavid van Moolenbroek 				   ISC_SOCKEVENT_SENDDONE, action, arg);
3107*00b67f09SDavid van Moolenbroek 	if (dev == NULL) {
3108*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3109*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
3110*00b67f09SDavid van Moolenbroek 	}
3111*00b67f09SDavid van Moolenbroek 	dev->region = *region;
3112*00b67f09SDavid van Moolenbroek 
3113*00b67f09SDavid van Moolenbroek 	ret = socket_send(sock, dev, task, address, pktinfo, 0);
3114*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3115*00b67f09SDavid van Moolenbroek 	return (ret);
3116*00b67f09SDavid van Moolenbroek }
3117*00b67f09SDavid van Moolenbroek 
3118*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_sendv(isc_socket_t * sock,isc_bufferlist_t * buflist,isc_task_t * task,isc_taskaction_t action,void * arg)3119*00b67f09SDavid van Moolenbroek isc__socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
3120*00b67f09SDavid van Moolenbroek 		  isc_task_t *task, isc_taskaction_t action, void *arg)
3121*00b67f09SDavid van Moolenbroek {
3122*00b67f09SDavid van Moolenbroek 	return (isc_socket_sendtov2(sock, buflist, task, action, arg, NULL,
3123*00b67f09SDavid van Moolenbroek 				    NULL, 0));
3124*00b67f09SDavid van Moolenbroek }
3125*00b67f09SDavid van Moolenbroek 
3126*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_sendtov(isc_socket_t * sock,isc_bufferlist_t * buflist,isc_task_t * task,isc_taskaction_t action,void * arg,isc_sockaddr_t * address,struct in6_pktinfo * pktinfo)3127*00b67f09SDavid van Moolenbroek isc__socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
3128*00b67f09SDavid van Moolenbroek 		    isc_task_t *task, isc_taskaction_t action, void *arg,
3129*00b67f09SDavid van Moolenbroek 		    isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
3130*00b67f09SDavid van Moolenbroek {
3131*00b67f09SDavid van Moolenbroek 	return (isc_socket_sendtov2(sock, buflist, task, action, arg, address,
3132*00b67f09SDavid van Moolenbroek 				    pktinfo, 0));
3133*00b67f09SDavid van Moolenbroek }
3134*00b67f09SDavid van Moolenbroek 
3135*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_sendtov2(isc_socket_t * sock,isc_bufferlist_t * buflist,isc_task_t * task,isc_taskaction_t action,void * arg,isc_sockaddr_t * address,struct in6_pktinfo * pktinfo,unsigned int flags)3136*00b67f09SDavid van Moolenbroek isc__socket_sendtov2(isc_socket_t *sock, isc_bufferlist_t *buflist,
3137*00b67f09SDavid van Moolenbroek 		     isc_task_t *task, isc_taskaction_t action, void *arg,
3138*00b67f09SDavid van Moolenbroek 		     isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
3139*00b67f09SDavid van Moolenbroek 		     unsigned int flags)
3140*00b67f09SDavid van Moolenbroek {
3141*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *dev;
3142*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *manager;
3143*00b67f09SDavid van Moolenbroek 	unsigned int iocount;
3144*00b67f09SDavid van Moolenbroek 	isc_buffer_t *buffer;
3145*00b67f09SDavid van Moolenbroek 	isc_result_t ret;
3146*00b67f09SDavid van Moolenbroek 
3147*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3148*00b67f09SDavid van Moolenbroek 
3149*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3150*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3151*00b67f09SDavid van Moolenbroek 
3152*00b67f09SDavid van Moolenbroek 	/*
3153*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3154*00b67f09SDavid van Moolenbroek 	 */
3155*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3156*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3157*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
3158*00b67f09SDavid van Moolenbroek 	}
3159*00b67f09SDavid van Moolenbroek 	REQUIRE(buflist != NULL);
3160*00b67f09SDavid van Moolenbroek 	REQUIRE(!ISC_LIST_EMPTY(*buflist));
3161*00b67f09SDavid van Moolenbroek 	REQUIRE(task != NULL);
3162*00b67f09SDavid van Moolenbroek 	REQUIRE(action != NULL);
3163*00b67f09SDavid van Moolenbroek 
3164*00b67f09SDavid van Moolenbroek 	manager = sock->manager;
3165*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
3166*00b67f09SDavid van Moolenbroek 
3167*00b67f09SDavid van Moolenbroek 	iocount = isc_bufferlist_usedcount(buflist);
3168*00b67f09SDavid van Moolenbroek 	REQUIRE(iocount > 0);
3169*00b67f09SDavid van Moolenbroek 
3170*00b67f09SDavid van Moolenbroek 	dev = allocate_socketevent(manager->mctx, sock,
3171*00b67f09SDavid van Moolenbroek 				   ISC_SOCKEVENT_SENDDONE, action, arg);
3172*00b67f09SDavid van Moolenbroek 	if (dev == NULL) {
3173*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3174*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
3175*00b67f09SDavid van Moolenbroek 	}
3176*00b67f09SDavid van Moolenbroek 
3177*00b67f09SDavid van Moolenbroek 	/*
3178*00b67f09SDavid van Moolenbroek 	 * Move each buffer from the passed in list to our internal one.
3179*00b67f09SDavid van Moolenbroek 	 */
3180*00b67f09SDavid van Moolenbroek 	buffer = ISC_LIST_HEAD(*buflist);
3181*00b67f09SDavid van Moolenbroek 	while (buffer != NULL) {
3182*00b67f09SDavid van Moolenbroek 		ISC_LIST_DEQUEUE(*buflist, buffer, link);
3183*00b67f09SDavid van Moolenbroek 		ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
3184*00b67f09SDavid van Moolenbroek 		buffer = ISC_LIST_HEAD(*buflist);
3185*00b67f09SDavid van Moolenbroek 	}
3186*00b67f09SDavid van Moolenbroek 
3187*00b67f09SDavid van Moolenbroek 	ret = socket_send(sock, dev, task, address, pktinfo, flags);
3188*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3189*00b67f09SDavid van Moolenbroek 	return (ret);
3190*00b67f09SDavid van Moolenbroek }
3191*00b67f09SDavid van Moolenbroek 
3192*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_sendto2(isc_socket_t * sock,isc_region_t * region,isc_task_t * task,isc_sockaddr_t * address,struct in6_pktinfo * pktinfo,isc_socketevent_t * event,unsigned int flags)3193*00b67f09SDavid van Moolenbroek isc__socket_sendto2(isc_socket_t *sock, isc_region_t *region,
3194*00b67f09SDavid van Moolenbroek 		    isc_task_t *task,
3195*00b67f09SDavid van Moolenbroek 		    isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
3196*00b67f09SDavid van Moolenbroek 		    isc_socketevent_t *event, unsigned int flags)
3197*00b67f09SDavid van Moolenbroek {
3198*00b67f09SDavid van Moolenbroek 	isc_result_t ret;
3199*00b67f09SDavid van Moolenbroek 
3200*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3201*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3202*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3203*00b67f09SDavid van Moolenbroek 
3204*00b67f09SDavid van Moolenbroek 	REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0);
3205*00b67f09SDavid van Moolenbroek 	if ((flags & ISC_SOCKFLAG_NORETRY) != 0)
3206*00b67f09SDavid van Moolenbroek 		REQUIRE(sock->type == isc_sockettype_udp);
3207*00b67f09SDavid van Moolenbroek 	event->ev_sender = sock;
3208*00b67f09SDavid van Moolenbroek 	event->result = ISC_R_UNEXPECTED;
3209*00b67f09SDavid van Moolenbroek 	/*
3210*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3211*00b67f09SDavid van Moolenbroek 	 */
3212*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3213*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3214*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
3215*00b67f09SDavid van Moolenbroek 	}
3216*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(event->bufferlist);
3217*00b67f09SDavid van Moolenbroek 	event->region = *region;
3218*00b67f09SDavid van Moolenbroek 	event->n = 0;
3219*00b67f09SDavid van Moolenbroek 	event->offset = 0;
3220*00b67f09SDavid van Moolenbroek 	event->attributes = 0;
3221*00b67f09SDavid van Moolenbroek 
3222*00b67f09SDavid van Moolenbroek 	ret = socket_send(sock, event, task, address, pktinfo, flags);
3223*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3224*00b67f09SDavid van Moolenbroek 	return (ret);
3225*00b67f09SDavid van Moolenbroek }
3226*00b67f09SDavid van Moolenbroek 
3227*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_bind(isc_socket_t * sock,isc_sockaddr_t * sockaddr,unsigned int options)3228*00b67f09SDavid van Moolenbroek isc__socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr,
3229*00b67f09SDavid van Moolenbroek 		 unsigned int options) {
3230*00b67f09SDavid van Moolenbroek 	int bind_errno;
3231*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
3232*00b67f09SDavid van Moolenbroek 	int on = 1;
3233*00b67f09SDavid van Moolenbroek 
3234*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3235*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3236*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3237*00b67f09SDavid van Moolenbroek 
3238*00b67f09SDavid van Moolenbroek 	/*
3239*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3240*00b67f09SDavid van Moolenbroek 	 */
3241*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3242*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3243*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
3244*00b67f09SDavid van Moolenbroek 	}
3245*00b67f09SDavid van Moolenbroek 
3246*00b67f09SDavid van Moolenbroek 	INSIST(!sock->bound);
3247*00b67f09SDavid van Moolenbroek 	INSIST(!sock->dupped);
3248*00b67f09SDavid van Moolenbroek 
3249*00b67f09SDavid van Moolenbroek 	if (sock->pf != sockaddr->type.sa.sa_family) {
3250*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3251*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAMILYMISMATCH);
3252*00b67f09SDavid van Moolenbroek 	}
3253*00b67f09SDavid van Moolenbroek 	/*
3254*00b67f09SDavid van Moolenbroek 	 * Only set SO_REUSEADDR when we want a specific port.
3255*00b67f09SDavid van Moolenbroek 	 */
3256*00b67f09SDavid van Moolenbroek 	if ((options & ISC_SOCKET_REUSEADDRESS) != 0 &&
3257*00b67f09SDavid van Moolenbroek 	    isc_sockaddr_getport(sockaddr) != (in_port_t)0 &&
3258*00b67f09SDavid van Moolenbroek 	    setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
3259*00b67f09SDavid van Moolenbroek 		       sizeof(on)) < 0) {
3260*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
3261*00b67f09SDavid van Moolenbroek 				 "setsockopt(%d) %s", sock->fd,
3262*00b67f09SDavid van Moolenbroek 				 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
3263*00b67f09SDavid van Moolenbroek 						ISC_MSG_FAILED, "failed"));
3264*00b67f09SDavid van Moolenbroek 		/* Press on... */
3265*00b67f09SDavid van Moolenbroek 	}
3266*00b67f09SDavid van Moolenbroek 	if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) {
3267*00b67f09SDavid van Moolenbroek 		bind_errno = WSAGetLastError();
3268*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3269*00b67f09SDavid van Moolenbroek 		switch (bind_errno) {
3270*00b67f09SDavid van Moolenbroek 		case WSAEACCES:
3271*00b67f09SDavid van Moolenbroek 			return (ISC_R_NOPERM);
3272*00b67f09SDavid van Moolenbroek 		case WSAEADDRNOTAVAIL:
3273*00b67f09SDavid van Moolenbroek 			return (ISC_R_ADDRNOTAVAIL);
3274*00b67f09SDavid van Moolenbroek 		case WSAEADDRINUSE:
3275*00b67f09SDavid van Moolenbroek 			return (ISC_R_ADDRINUSE);
3276*00b67f09SDavid van Moolenbroek 		case WSAEINVAL:
3277*00b67f09SDavid van Moolenbroek 			return (ISC_R_BOUND);
3278*00b67f09SDavid van Moolenbroek 		default:
3279*00b67f09SDavid van Moolenbroek 			isc__strerror(bind_errno, strbuf, sizeof(strbuf));
3280*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s",
3281*00b67f09SDavid van Moolenbroek 					 strbuf);
3282*00b67f09SDavid van Moolenbroek 			return (ISC_R_UNEXPECTED);
3283*00b67f09SDavid van Moolenbroek 		}
3284*00b67f09SDavid van Moolenbroek 	}
3285*00b67f09SDavid van Moolenbroek 
3286*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, sockaddr, TRACE,
3287*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "bound");
3288*00b67f09SDavid van Moolenbroek 	sock->bound = 1;
3289*00b67f09SDavid van Moolenbroek 
3290*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3291*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
3292*00b67f09SDavid van Moolenbroek }
3293*00b67f09SDavid van Moolenbroek 
3294*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_filter(isc_socket_t * sock,const char * filter)3295*00b67f09SDavid van Moolenbroek isc__socket_filter(isc_socket_t *sock, const char *filter) {
3296*00b67f09SDavid van Moolenbroek 	UNUSED(sock);
3297*00b67f09SDavid van Moolenbroek 	UNUSED(filter);
3298*00b67f09SDavid van Moolenbroek 
3299*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3300*00b67f09SDavid van Moolenbroek 	return (ISC_R_NOTIMPLEMENTED);
3301*00b67f09SDavid van Moolenbroek }
3302*00b67f09SDavid van Moolenbroek 
3303*00b67f09SDavid van Moolenbroek /*
3304*00b67f09SDavid van Moolenbroek  * Set up to listen on a given socket.  We do this by creating an internal
3305*00b67f09SDavid van Moolenbroek  * event that will be dispatched when the socket has read activity.  The
3306*00b67f09SDavid van Moolenbroek  * watcher will send the internal event to the task when there is a new
3307*00b67f09SDavid van Moolenbroek  * connection.
3308*00b67f09SDavid van Moolenbroek  *
3309*00b67f09SDavid van Moolenbroek  * Unlike in read, we don't preallocate a done event here.  Every time there
3310*00b67f09SDavid van Moolenbroek  * is a new connection we'll have to allocate a new one anyway, so we might
3311*00b67f09SDavid van Moolenbroek  * as well keep things simple rather than having to track them.
3312*00b67f09SDavid van Moolenbroek  */
3313*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_listen(isc_socket_t * sock,unsigned int backlog)3314*00b67f09SDavid van Moolenbroek isc__socket_listen(isc_socket_t *sock, unsigned int backlog) {
3315*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
3316*00b67f09SDavid van Moolenbroek 
3317*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3318*00b67f09SDavid van Moolenbroek 
3319*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3320*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3321*00b67f09SDavid van Moolenbroek 
3322*00b67f09SDavid van Moolenbroek 	/*
3323*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3324*00b67f09SDavid van Moolenbroek 	 */
3325*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3326*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3327*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
3328*00b67f09SDavid van Moolenbroek 	}
3329*00b67f09SDavid van Moolenbroek 
3330*00b67f09SDavid van Moolenbroek 	REQUIRE(!sock->listener);
3331*00b67f09SDavid van Moolenbroek 	REQUIRE(sock->bound);
3332*00b67f09SDavid van Moolenbroek 	REQUIRE(sock->type == isc_sockettype_tcp);
3333*00b67f09SDavid van Moolenbroek 
3334*00b67f09SDavid van Moolenbroek 	if (backlog == 0)
3335*00b67f09SDavid van Moolenbroek 		backlog = SOMAXCONN;
3336*00b67f09SDavid van Moolenbroek 
3337*00b67f09SDavid van Moolenbroek 	if (listen(sock->fd, (int)backlog) < 0) {
3338*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3339*00b67f09SDavid van Moolenbroek 		isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
3340*00b67f09SDavid van Moolenbroek 
3341*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf);
3342*00b67f09SDavid van Moolenbroek 
3343*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
3344*00b67f09SDavid van Moolenbroek 	}
3345*00b67f09SDavid van Moolenbroek 
3346*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, TRACE,
3347*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "listening");
3348*00b67f09SDavid van Moolenbroek 	sock->listener = 1;
3349*00b67f09SDavid van Moolenbroek 	_set_state(sock, SOCK_LISTEN);
3350*00b67f09SDavid van Moolenbroek 
3351*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3352*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
3353*00b67f09SDavid van Moolenbroek }
3354*00b67f09SDavid van Moolenbroek 
3355*00b67f09SDavid van Moolenbroek /*
3356*00b67f09SDavid van Moolenbroek  * This should try to do aggressive accept() XXXMLG
3357*00b67f09SDavid van Moolenbroek  */
3358*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_accept(isc_socket_t * sock,isc_task_t * task,isc_taskaction_t action,void * arg)3359*00b67f09SDavid van Moolenbroek isc__socket_accept(isc_socket_t *sock,
3360*00b67f09SDavid van Moolenbroek 		   isc_task_t *task, isc_taskaction_t action, void *arg)
3361*00b67f09SDavid van Moolenbroek {
3362*00b67f09SDavid van Moolenbroek 	isc_socket_newconnev_t *adev;
3363*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *manager;
3364*00b67f09SDavid van Moolenbroek 	isc_task_t *ntask = NULL;
3365*00b67f09SDavid van Moolenbroek 	isc_socket_t *nsock;
3366*00b67f09SDavid van Moolenbroek 	isc_result_t result;
3367*00b67f09SDavid van Moolenbroek 	IoCompletionInfo *lpo;
3368*00b67f09SDavid van Moolenbroek 
3369*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3370*00b67f09SDavid van Moolenbroek 
3371*00b67f09SDavid van Moolenbroek 	manager = sock->manager;
3372*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
3373*00b67f09SDavid van Moolenbroek 
3374*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3375*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3376*00b67f09SDavid van Moolenbroek 
3377*00b67f09SDavid van Moolenbroek 	/*
3378*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3379*00b67f09SDavid van Moolenbroek 	 */
3380*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3381*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3382*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
3383*00b67f09SDavid van Moolenbroek 	}
3384*00b67f09SDavid van Moolenbroek 
3385*00b67f09SDavid van Moolenbroek 	REQUIRE(sock->listener);
3386*00b67f09SDavid van Moolenbroek 
3387*00b67f09SDavid van Moolenbroek 	/*
3388*00b67f09SDavid van Moolenbroek 	 * Sender field is overloaded here with the task we will be sending
3389*00b67f09SDavid van Moolenbroek 	 * this event to.  Just before the actual event is delivered the
3390*00b67f09SDavid van Moolenbroek 	 * actual ev_sender will be touched up to be the socket.
3391*00b67f09SDavid van Moolenbroek 	 */
3392*00b67f09SDavid van Moolenbroek 	adev = (isc_socket_newconnev_t *)
3393*00b67f09SDavid van Moolenbroek 		isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN,
3394*00b67f09SDavid van Moolenbroek 				   action, arg, sizeof(*adev));
3395*00b67f09SDavid van Moolenbroek 	if (adev == NULL) {
3396*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3397*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
3398*00b67f09SDavid van Moolenbroek 	}
3399*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(adev, ev_link);
3400*00b67f09SDavid van Moolenbroek 
3401*00b67f09SDavid van Moolenbroek 	result = allocate_socket(manager, sock->type, &nsock);
3402*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
3403*00b67f09SDavid van Moolenbroek 		isc_event_free((isc_event_t **)&adev);
3404*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3405*00b67f09SDavid van Moolenbroek 		return (result);
3406*00b67f09SDavid van Moolenbroek 	}
3407*00b67f09SDavid van Moolenbroek 
3408*00b67f09SDavid van Moolenbroek 	/*
3409*00b67f09SDavid van Moolenbroek 	 * AcceptEx() requires we pass in a socket.
3410*00b67f09SDavid van Moolenbroek 	 */
3411*00b67f09SDavid van Moolenbroek 	nsock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP);
3412*00b67f09SDavid van Moolenbroek 	if (nsock->fd == INVALID_SOCKET) {
3413*00b67f09SDavid van Moolenbroek 		free_socket(&nsock, __LINE__);
3414*00b67f09SDavid van Moolenbroek 		isc_event_free((isc_event_t **)&adev);
3415*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3416*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE); // XXXMLG need real error message
3417*00b67f09SDavid van Moolenbroek 	}
3418*00b67f09SDavid van Moolenbroek 
3419*00b67f09SDavid van Moolenbroek 	/*
3420*00b67f09SDavid van Moolenbroek 	 * Attach to socket and to task.
3421*00b67f09SDavid van Moolenbroek 	 */
3422*00b67f09SDavid van Moolenbroek 	isc_task_attach(task, &ntask);
3423*00b67f09SDavid van Moolenbroek 	if (isc_task_exiting(ntask)) {
3424*00b67f09SDavid van Moolenbroek 		free_socket(&nsock, __LINE__);
3425*00b67f09SDavid van Moolenbroek 		isc_task_detach(&ntask);
3426*00b67f09SDavid van Moolenbroek 		isc_event_free(ISC_EVENT_PTR(&adev));
3427*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3428*00b67f09SDavid van Moolenbroek 		return (ISC_R_SHUTTINGDOWN);
3429*00b67f09SDavid van Moolenbroek 	}
3430*00b67f09SDavid van Moolenbroek 	nsock->references++;
3431*00b67f09SDavid van Moolenbroek 
3432*00b67f09SDavid van Moolenbroek 	adev->ev_sender = ntask;
3433*00b67f09SDavid van Moolenbroek 	adev->newsocket = nsock;
3434*00b67f09SDavid van Moolenbroek 	_set_state(nsock, SOCK_ACCEPT);
3435*00b67f09SDavid van Moolenbroek 
3436*00b67f09SDavid van Moolenbroek 	/*
3437*00b67f09SDavid van Moolenbroek 	 * Queue io completion for an accept().
3438*00b67f09SDavid van Moolenbroek 	 */
3439*00b67f09SDavid van Moolenbroek 	lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
3440*00b67f09SDavid van Moolenbroek 					    HEAP_ZERO_MEMORY,
3441*00b67f09SDavid van Moolenbroek 					    sizeof(IoCompletionInfo));
3442*00b67f09SDavid van Moolenbroek 	RUNTIME_CHECK(lpo != NULL);
3443*00b67f09SDavid van Moolenbroek 	lpo->acceptbuffer = (void *)HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY,
3444*00b67f09SDavid van Moolenbroek 		(sizeof(SOCKADDR_STORAGE) + 16) * 2);
3445*00b67f09SDavid van Moolenbroek 	RUNTIME_CHECK(lpo->acceptbuffer != NULL);
3446*00b67f09SDavid van Moolenbroek 
3447*00b67f09SDavid van Moolenbroek 	lpo->adev = adev;
3448*00b67f09SDavid van Moolenbroek 	lpo->request_type = SOCKET_ACCEPT;
3449*00b67f09SDavid van Moolenbroek 
3450*00b67f09SDavid van Moolenbroek 	ISCAcceptEx(sock->fd,
3451*00b67f09SDavid van Moolenbroek 		    nsock->fd,				/* Accepted Socket */
3452*00b67f09SDavid van Moolenbroek 		    lpo->acceptbuffer,			/* Buffer for initial Recv */
3453*00b67f09SDavid van Moolenbroek 		    0,					/* Length of Buffer */
3454*00b67f09SDavid van Moolenbroek 		    sizeof(SOCKADDR_STORAGE) + 16,		/* Local address length + 16 */
3455*00b67f09SDavid van Moolenbroek 		    sizeof(SOCKADDR_STORAGE) + 16,		/* Remote address lengh + 16 */
3456*00b67f09SDavid van Moolenbroek 		    (LPDWORD)&lpo->received_bytes,	/* Bytes Recved */
3457*00b67f09SDavid van Moolenbroek 		    (LPOVERLAPPED)lpo			/* Overlapped structure */
3458*00b67f09SDavid van Moolenbroek 		    );
3459*00b67f09SDavid van Moolenbroek 	iocompletionport_update(nsock);
3460*00b67f09SDavid van Moolenbroek 
3461*00b67f09SDavid van Moolenbroek 	socket_log(__LINE__, sock, NULL, TRACE,
3462*00b67f09SDavid van Moolenbroek 		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND,
3463*00b67f09SDavid van Moolenbroek 		   "accepting for nsock %p fd %d", nsock, nsock->fd);
3464*00b67f09SDavid van Moolenbroek 
3465*00b67f09SDavid van Moolenbroek 	/*
3466*00b67f09SDavid van Moolenbroek 	 * Enqueue the event
3467*00b67f09SDavid van Moolenbroek 	 */
3468*00b67f09SDavid van Moolenbroek 	ISC_LIST_ENQUEUE(sock->accept_list, adev, ev_link);
3469*00b67f09SDavid van Moolenbroek 	sock->pending_accept++;
3470*00b67f09SDavid van Moolenbroek 	sock->pending_iocp++;
3471*00b67f09SDavid van Moolenbroek 
3472*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3473*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
3474*00b67f09SDavid van Moolenbroek }
3475*00b67f09SDavid van Moolenbroek 
3476*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_connect(isc_socket_t * sock,isc_sockaddr_t * addr,isc_task_t * task,isc_taskaction_t action,void * arg)3477*00b67f09SDavid van Moolenbroek isc__socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr,
3478*00b67f09SDavid van Moolenbroek 		    isc_task_t *task, isc_taskaction_t action, void *arg)
3479*00b67f09SDavid van Moolenbroek {
3480*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
3481*00b67f09SDavid van Moolenbroek 	isc_socket_connev_t *cdev;
3482*00b67f09SDavid van Moolenbroek 	isc_task_t *ntask = NULL;
3483*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *manager;
3484*00b67f09SDavid van Moolenbroek 	IoCompletionInfo *lpo;
3485*00b67f09SDavid van Moolenbroek 	int bind_errno;
3486*00b67f09SDavid van Moolenbroek 
3487*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3488*00b67f09SDavid van Moolenbroek 	REQUIRE(addr != NULL);
3489*00b67f09SDavid van Moolenbroek 	REQUIRE(task != NULL);
3490*00b67f09SDavid van Moolenbroek 	REQUIRE(action != NULL);
3491*00b67f09SDavid van Moolenbroek 
3492*00b67f09SDavid van Moolenbroek 	manager = sock->manager;
3493*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_MANAGER(manager));
3494*00b67f09SDavid van Moolenbroek 	REQUIRE(addr != NULL);
3495*00b67f09SDavid van Moolenbroek 
3496*00b67f09SDavid van Moolenbroek 	if (isc_sockaddr_ismulticast(addr))
3497*00b67f09SDavid van Moolenbroek 		return (ISC_R_MULTICAST);
3498*00b67f09SDavid van Moolenbroek 
3499*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3500*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3501*00b67f09SDavid van Moolenbroek 
3502*00b67f09SDavid van Moolenbroek 	/*
3503*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3504*00b67f09SDavid van Moolenbroek 	 */
3505*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3506*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3507*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
3508*00b67f09SDavid van Moolenbroek 	}
3509*00b67f09SDavid van Moolenbroek 
3510*00b67f09SDavid van Moolenbroek 	/*
3511*00b67f09SDavid van Moolenbroek 	 * Windows sockets won't connect unless the socket is bound.
3512*00b67f09SDavid van Moolenbroek 	 */
3513*00b67f09SDavid van Moolenbroek 	if (!sock->bound) {
3514*00b67f09SDavid van Moolenbroek 		isc_sockaddr_t any;
3515*00b67f09SDavid van Moolenbroek 
3516*00b67f09SDavid van Moolenbroek 		isc_sockaddr_anyofpf(&any, isc_sockaddr_pf(addr));
3517*00b67f09SDavid van Moolenbroek 		if (bind(sock->fd, &any.type.sa, any.length) < 0) {
3518*00b67f09SDavid van Moolenbroek 			bind_errno = WSAGetLastError();
3519*00b67f09SDavid van Moolenbroek 			UNLOCK(&sock->lock);
3520*00b67f09SDavid van Moolenbroek 			switch (bind_errno) {
3521*00b67f09SDavid van Moolenbroek 			case WSAEACCES:
3522*00b67f09SDavid van Moolenbroek 				return (ISC_R_NOPERM);
3523*00b67f09SDavid van Moolenbroek 			case WSAEADDRNOTAVAIL:
3524*00b67f09SDavid van Moolenbroek 				return (ISC_R_ADDRNOTAVAIL);
3525*00b67f09SDavid van Moolenbroek 			case WSAEADDRINUSE:
3526*00b67f09SDavid van Moolenbroek 				return (ISC_R_ADDRINUSE);
3527*00b67f09SDavid van Moolenbroek 			case WSAEINVAL:
3528*00b67f09SDavid van Moolenbroek 				return (ISC_R_BOUND);
3529*00b67f09SDavid van Moolenbroek 			default:
3530*00b67f09SDavid van Moolenbroek 				isc__strerror(bind_errno, strbuf,
3531*00b67f09SDavid van Moolenbroek 					      sizeof(strbuf));
3532*00b67f09SDavid van Moolenbroek 				UNEXPECTED_ERROR(__FILE__, __LINE__,
3533*00b67f09SDavid van Moolenbroek 						 "bind: %s", strbuf);
3534*00b67f09SDavid van Moolenbroek 				return (ISC_R_UNEXPECTED);
3535*00b67f09SDavid van Moolenbroek 			}
3536*00b67f09SDavid van Moolenbroek 		}
3537*00b67f09SDavid van Moolenbroek 		sock->bound = 1;
3538*00b67f09SDavid van Moolenbroek 	}
3539*00b67f09SDavid van Moolenbroek 
3540*00b67f09SDavid van Moolenbroek 	REQUIRE(!sock->pending_connect);
3541*00b67f09SDavid van Moolenbroek 
3542*00b67f09SDavid van Moolenbroek 	cdev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
3543*00b67f09SDavid van Moolenbroek 							ISC_SOCKEVENT_CONNECT,
3544*00b67f09SDavid van Moolenbroek 							action,	arg,
3545*00b67f09SDavid van Moolenbroek 							sizeof(*cdev));
3546*00b67f09SDavid van Moolenbroek 	if (cdev == NULL) {
3547*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3548*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
3549*00b67f09SDavid van Moolenbroek 	}
3550*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(cdev, ev_link);
3551*00b67f09SDavid van Moolenbroek 
3552*00b67f09SDavid van Moolenbroek 	if (sock->type == isc_sockettype_tcp) {
3553*00b67f09SDavid van Moolenbroek 		/*
3554*00b67f09SDavid van Moolenbroek 		 * Queue io completion for an accept().
3555*00b67f09SDavid van Moolenbroek 		 */
3556*00b67f09SDavid van Moolenbroek 		lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
3557*00b67f09SDavid van Moolenbroek 						    HEAP_ZERO_MEMORY,
3558*00b67f09SDavid van Moolenbroek 						    sizeof(IoCompletionInfo));
3559*00b67f09SDavid van Moolenbroek 		lpo->cdev = cdev;
3560*00b67f09SDavid van Moolenbroek 		lpo->request_type = SOCKET_CONNECT;
3561*00b67f09SDavid van Moolenbroek 
3562*00b67f09SDavid van Moolenbroek 		sock->address = *addr;
3563*00b67f09SDavid van Moolenbroek 		ISCConnectEx(sock->fd, &addr->type.sa, addr->length,
3564*00b67f09SDavid van Moolenbroek 			NULL, 0, NULL, (LPOVERLAPPED)lpo);
3565*00b67f09SDavid van Moolenbroek 
3566*00b67f09SDavid van Moolenbroek 		/*
3567*00b67f09SDavid van Moolenbroek 		 * Attach to task.
3568*00b67f09SDavid van Moolenbroek 		 */
3569*00b67f09SDavid van Moolenbroek 		isc_task_attach(task, &ntask);
3570*00b67f09SDavid van Moolenbroek 		cdev->ev_sender = ntask;
3571*00b67f09SDavid van Moolenbroek 
3572*00b67f09SDavid van Moolenbroek 		sock->pending_connect = 1;
3573*00b67f09SDavid van Moolenbroek 		_set_state(sock, SOCK_CONNECT);
3574*00b67f09SDavid van Moolenbroek 
3575*00b67f09SDavid van Moolenbroek 		/*
3576*00b67f09SDavid van Moolenbroek 		 * Enqueue the request.
3577*00b67f09SDavid van Moolenbroek 		 */
3578*00b67f09SDavid van Moolenbroek 		sock->connect_ev = cdev;
3579*00b67f09SDavid van Moolenbroek 		sock->pending_iocp++;
3580*00b67f09SDavid van Moolenbroek 	} else {
3581*00b67f09SDavid van Moolenbroek 		WSAConnect(sock->fd, &addr->type.sa, addr->length, NULL, NULL, NULL, NULL);
3582*00b67f09SDavid van Moolenbroek 		cdev->result = ISC_R_SUCCESS;
3583*00b67f09SDavid van Moolenbroek 		isc_task_send(task, (isc_event_t **)&cdev);
3584*00b67f09SDavid van Moolenbroek 	}
3585*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3586*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3587*00b67f09SDavid van Moolenbroek 
3588*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
3589*00b67f09SDavid van Moolenbroek }
3590*00b67f09SDavid van Moolenbroek 
3591*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_getpeername(isc_socket_t * sock,isc_sockaddr_t * addressp)3592*00b67f09SDavid van Moolenbroek isc__socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) {
3593*00b67f09SDavid van Moolenbroek 	isc_result_t result;
3594*00b67f09SDavid van Moolenbroek 
3595*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3596*00b67f09SDavid van Moolenbroek 	REQUIRE(addressp != NULL);
3597*00b67f09SDavid van Moolenbroek 
3598*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3599*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3600*00b67f09SDavid van Moolenbroek 
3601*00b67f09SDavid van Moolenbroek 	/*
3602*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3603*00b67f09SDavid van Moolenbroek 	 */
3604*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3605*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3606*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
3607*00b67f09SDavid van Moolenbroek 	}
3608*00b67f09SDavid van Moolenbroek 
3609*00b67f09SDavid van Moolenbroek 	if (sock->connected) {
3610*00b67f09SDavid van Moolenbroek 		*addressp = sock->address;
3611*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
3612*00b67f09SDavid van Moolenbroek 	} else {
3613*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOTCONNECTED;
3614*00b67f09SDavid van Moolenbroek 	}
3615*00b67f09SDavid van Moolenbroek 
3616*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3617*00b67f09SDavid van Moolenbroek 
3618*00b67f09SDavid van Moolenbroek 	return (result);
3619*00b67f09SDavid van Moolenbroek }
3620*00b67f09SDavid van Moolenbroek 
3621*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_getsockname(isc_socket_t * sock,isc_sockaddr_t * addressp)3622*00b67f09SDavid van Moolenbroek isc__socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) {
3623*00b67f09SDavid van Moolenbroek 	ISC_SOCKADDR_LEN_T len;
3624*00b67f09SDavid van Moolenbroek 	isc_result_t result;
3625*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
3626*00b67f09SDavid van Moolenbroek 
3627*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3628*00b67f09SDavid van Moolenbroek 	REQUIRE(addressp != NULL);
3629*00b67f09SDavid van Moolenbroek 
3630*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3631*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3632*00b67f09SDavid van Moolenbroek 
3633*00b67f09SDavid van Moolenbroek 	/*
3634*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3635*00b67f09SDavid van Moolenbroek 	 */
3636*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3637*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3638*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
3639*00b67f09SDavid van Moolenbroek 	}
3640*00b67f09SDavid van Moolenbroek 
3641*00b67f09SDavid van Moolenbroek 	if (!sock->bound) {
3642*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOTBOUND;
3643*00b67f09SDavid van Moolenbroek 		goto out;
3644*00b67f09SDavid van Moolenbroek 	}
3645*00b67f09SDavid van Moolenbroek 
3646*00b67f09SDavid van Moolenbroek 	result = ISC_R_SUCCESS;
3647*00b67f09SDavid van Moolenbroek 
3648*00b67f09SDavid van Moolenbroek 	len = sizeof(addressp->type);
3649*00b67f09SDavid van Moolenbroek 	if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) {
3650*00b67f09SDavid van Moolenbroek 		isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
3651*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s",
3652*00b67f09SDavid van Moolenbroek 				 strbuf);
3653*00b67f09SDavid van Moolenbroek 		result = ISC_R_UNEXPECTED;
3654*00b67f09SDavid van Moolenbroek 		goto out;
3655*00b67f09SDavid van Moolenbroek 	}
3656*00b67f09SDavid van Moolenbroek 	addressp->length = (unsigned int)len;
3657*00b67f09SDavid van Moolenbroek 
3658*00b67f09SDavid van Moolenbroek  out:
3659*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3660*00b67f09SDavid van Moolenbroek 
3661*00b67f09SDavid van Moolenbroek 	return (result);
3662*00b67f09SDavid van Moolenbroek }
3663*00b67f09SDavid van Moolenbroek 
3664*00b67f09SDavid van Moolenbroek /*
3665*00b67f09SDavid van Moolenbroek  * Run through the list of events on this socket, and cancel the ones
3666*00b67f09SDavid van Moolenbroek  * queued for task "task" of type "how".  "how" is a bitmask.
3667*00b67f09SDavid van Moolenbroek  */
3668*00b67f09SDavid van Moolenbroek void
isc__socket_cancel(isc_socket_t * sock,isc_task_t * task,unsigned int how)3669*00b67f09SDavid van Moolenbroek isc__socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
3670*00b67f09SDavid van Moolenbroek 
3671*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3672*00b67f09SDavid van Moolenbroek 
3673*00b67f09SDavid van Moolenbroek 	/*
3674*00b67f09SDavid van Moolenbroek 	 * Quick exit if there is nothing to do.  Don't even bother locking
3675*00b67f09SDavid van Moolenbroek 	 * in this case.
3676*00b67f09SDavid van Moolenbroek 	 */
3677*00b67f09SDavid van Moolenbroek 	if (how == 0)
3678*00b67f09SDavid van Moolenbroek 		return;
3679*00b67f09SDavid van Moolenbroek 
3680*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3681*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3682*00b67f09SDavid van Moolenbroek 
3683*00b67f09SDavid van Moolenbroek 	/*
3684*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3685*00b67f09SDavid van Moolenbroek 	 */
3686*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3687*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3688*00b67f09SDavid van Moolenbroek 		return;
3689*00b67f09SDavid van Moolenbroek 	}
3690*00b67f09SDavid van Moolenbroek 
3691*00b67f09SDavid van Moolenbroek 	/*
3692*00b67f09SDavid van Moolenbroek 	 * All of these do the same thing, more or less.
3693*00b67f09SDavid van Moolenbroek 	 * Each will:
3694*00b67f09SDavid van Moolenbroek 	 *	o If the internal event is marked as "posted" try to
3695*00b67f09SDavid van Moolenbroek 	 *	  remove it from the task's queue.  If this fails, mark it
3696*00b67f09SDavid van Moolenbroek 	 *	  as canceled instead, and let the task clean it up later.
3697*00b67f09SDavid van Moolenbroek 	 *	o For each I/O request for that task of that type, post
3698*00b67f09SDavid van Moolenbroek 	 *	  its done event with status of "ISC_R_CANCELED".
3699*00b67f09SDavid van Moolenbroek 	 *	o Reset any state needed.
3700*00b67f09SDavid van Moolenbroek 	 */
3701*00b67f09SDavid van Moolenbroek 
3702*00b67f09SDavid van Moolenbroek 	if ((how & ISC_SOCKCANCEL_RECV) == ISC_SOCKCANCEL_RECV) {
3703*00b67f09SDavid van Moolenbroek 		isc_socketevent_t      *dev;
3704*00b67f09SDavid van Moolenbroek 		isc_socketevent_t      *next;
3705*00b67f09SDavid van Moolenbroek 		isc_task_t	       *current_task;
3706*00b67f09SDavid van Moolenbroek 
3707*00b67f09SDavid van Moolenbroek 		dev = ISC_LIST_HEAD(sock->recv_list);
3708*00b67f09SDavid van Moolenbroek 		while (dev != NULL) {
3709*00b67f09SDavid van Moolenbroek 			current_task = dev->ev_sender;
3710*00b67f09SDavid van Moolenbroek 			next = ISC_LIST_NEXT(dev, ev_link);
3711*00b67f09SDavid van Moolenbroek 			if ((task == NULL) || (task == current_task)) {
3712*00b67f09SDavid van Moolenbroek 				dev->result = ISC_R_CANCELED;
3713*00b67f09SDavid van Moolenbroek 				send_recvdone_event(sock, &dev);
3714*00b67f09SDavid van Moolenbroek 			}
3715*00b67f09SDavid van Moolenbroek 			dev = next;
3716*00b67f09SDavid van Moolenbroek 		}
3717*00b67f09SDavid van Moolenbroek 	}
3718*00b67f09SDavid van Moolenbroek 	how &= ~ISC_SOCKCANCEL_RECV;
3719*00b67f09SDavid van Moolenbroek 
3720*00b67f09SDavid van Moolenbroek 	if ((how & ISC_SOCKCANCEL_SEND) == ISC_SOCKCANCEL_SEND) {
3721*00b67f09SDavid van Moolenbroek 		isc_socketevent_t      *dev;
3722*00b67f09SDavid van Moolenbroek 		isc_socketevent_t      *next;
3723*00b67f09SDavid van Moolenbroek 		isc_task_t	       *current_task;
3724*00b67f09SDavid van Moolenbroek 
3725*00b67f09SDavid van Moolenbroek 		dev = ISC_LIST_HEAD(sock->send_list);
3726*00b67f09SDavid van Moolenbroek 
3727*00b67f09SDavid van Moolenbroek 		while (dev != NULL) {
3728*00b67f09SDavid van Moolenbroek 			current_task = dev->ev_sender;
3729*00b67f09SDavid van Moolenbroek 			next = ISC_LIST_NEXT(dev, ev_link);
3730*00b67f09SDavid van Moolenbroek 			if ((task == NULL) || (task == current_task)) {
3731*00b67f09SDavid van Moolenbroek 				dev->result = ISC_R_CANCELED;
3732*00b67f09SDavid van Moolenbroek 				send_senddone_event(sock, &dev);
3733*00b67f09SDavid van Moolenbroek 			}
3734*00b67f09SDavid van Moolenbroek 			dev = next;
3735*00b67f09SDavid van Moolenbroek 		}
3736*00b67f09SDavid van Moolenbroek 	}
3737*00b67f09SDavid van Moolenbroek 	how &= ~ISC_SOCKCANCEL_SEND;
3738*00b67f09SDavid van Moolenbroek 
3739*00b67f09SDavid van Moolenbroek 	if (((how & ISC_SOCKCANCEL_ACCEPT) == ISC_SOCKCANCEL_ACCEPT)
3740*00b67f09SDavid van Moolenbroek 	    && !ISC_LIST_EMPTY(sock->accept_list)) {
3741*00b67f09SDavid van Moolenbroek 		isc_socket_newconnev_t *dev;
3742*00b67f09SDavid van Moolenbroek 		isc_socket_newconnev_t *next;
3743*00b67f09SDavid van Moolenbroek 		isc_task_t	       *current_task;
3744*00b67f09SDavid van Moolenbroek 
3745*00b67f09SDavid van Moolenbroek 		dev = ISC_LIST_HEAD(sock->accept_list);
3746*00b67f09SDavid van Moolenbroek 		while (dev != NULL) {
3747*00b67f09SDavid van Moolenbroek 			current_task = dev->ev_sender;
3748*00b67f09SDavid van Moolenbroek 			next = ISC_LIST_NEXT(dev, ev_link);
3749*00b67f09SDavid van Moolenbroek 
3750*00b67f09SDavid van Moolenbroek 			if ((task == NULL) || (task == current_task)) {
3751*00b67f09SDavid van Moolenbroek 
3752*00b67f09SDavid van Moolenbroek 				dev->newsocket->references--;
3753*00b67f09SDavid van Moolenbroek 				closesocket(dev->newsocket->fd);
3754*00b67f09SDavid van Moolenbroek 				dev->newsocket->fd = INVALID_SOCKET;
3755*00b67f09SDavid van Moolenbroek 				free_socket(&dev->newsocket, __LINE__);
3756*00b67f09SDavid van Moolenbroek 
3757*00b67f09SDavid van Moolenbroek 				dev->result = ISC_R_CANCELED;
3758*00b67f09SDavid van Moolenbroek 				send_acceptdone_event(sock, &dev);
3759*00b67f09SDavid van Moolenbroek 			}
3760*00b67f09SDavid van Moolenbroek 
3761*00b67f09SDavid van Moolenbroek 			dev = next;
3762*00b67f09SDavid van Moolenbroek 		}
3763*00b67f09SDavid van Moolenbroek 	}
3764*00b67f09SDavid van Moolenbroek 	how &= ~ISC_SOCKCANCEL_ACCEPT;
3765*00b67f09SDavid van Moolenbroek 
3766*00b67f09SDavid van Moolenbroek 	/*
3767*00b67f09SDavid van Moolenbroek 	 * Connecting is not a list.
3768*00b67f09SDavid van Moolenbroek 	 */
3769*00b67f09SDavid van Moolenbroek 	if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT)
3770*00b67f09SDavid van Moolenbroek 	    && sock->connect_ev != NULL) {
3771*00b67f09SDavid van Moolenbroek 		isc_socket_connev_t    *dev;
3772*00b67f09SDavid van Moolenbroek 		isc_task_t	       *current_task;
3773*00b67f09SDavid van Moolenbroek 
3774*00b67f09SDavid van Moolenbroek 		INSIST(sock->pending_connect);
3775*00b67f09SDavid van Moolenbroek 
3776*00b67f09SDavid van Moolenbroek 		dev = sock->connect_ev;
3777*00b67f09SDavid van Moolenbroek 		current_task = dev->ev_sender;
3778*00b67f09SDavid van Moolenbroek 
3779*00b67f09SDavid van Moolenbroek 		if ((task == NULL) || (task == current_task)) {
3780*00b67f09SDavid van Moolenbroek 			closesocket(sock->fd);
3781*00b67f09SDavid van Moolenbroek 			sock->fd = INVALID_SOCKET;
3782*00b67f09SDavid van Moolenbroek 			_set_state(sock, SOCK_CLOSED);
3783*00b67f09SDavid van Moolenbroek 
3784*00b67f09SDavid van Moolenbroek 			sock->connect_ev = NULL;
3785*00b67f09SDavid van Moolenbroek 			dev->result = ISC_R_CANCELED;
3786*00b67f09SDavid van Moolenbroek 			send_connectdone_event(sock, &dev);
3787*00b67f09SDavid van Moolenbroek 		}
3788*00b67f09SDavid van Moolenbroek 	}
3789*00b67f09SDavid van Moolenbroek 	how &= ~ISC_SOCKCANCEL_CONNECT;
3790*00b67f09SDavid van Moolenbroek 
3791*00b67f09SDavid van Moolenbroek 	maybe_free_socket(&sock, __LINE__);
3792*00b67f09SDavid van Moolenbroek }
3793*00b67f09SDavid van Moolenbroek 
3794*00b67f09SDavid van Moolenbroek isc_sockettype_t
isc__socket_gettype(isc_socket_t * sock)3795*00b67f09SDavid van Moolenbroek isc__socket_gettype(isc_socket_t *sock) {
3796*00b67f09SDavid van Moolenbroek 	isc_sockettype_t type;
3797*00b67f09SDavid van Moolenbroek 
3798*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3799*00b67f09SDavid van Moolenbroek 
3800*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3801*00b67f09SDavid van Moolenbroek 
3802*00b67f09SDavid van Moolenbroek 	/*
3803*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3804*00b67f09SDavid van Moolenbroek 	 */
3805*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3806*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3807*00b67f09SDavid van Moolenbroek 		return (ISC_R_CONNREFUSED);
3808*00b67f09SDavid van Moolenbroek 	}
3809*00b67f09SDavid van Moolenbroek 
3810*00b67f09SDavid van Moolenbroek 	type = sock->type;
3811*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3812*00b67f09SDavid van Moolenbroek 	return (type);
3813*00b67f09SDavid van Moolenbroek }
3814*00b67f09SDavid van Moolenbroek 
3815*00b67f09SDavid van Moolenbroek isc_boolean_t
isc__socket_isbound(isc_socket_t * sock)3816*00b67f09SDavid van Moolenbroek isc__socket_isbound(isc_socket_t *sock) {
3817*00b67f09SDavid van Moolenbroek 	isc_boolean_t val;
3818*00b67f09SDavid van Moolenbroek 
3819*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3820*00b67f09SDavid van Moolenbroek 
3821*00b67f09SDavid van Moolenbroek 	LOCK(&sock->lock);
3822*00b67f09SDavid van Moolenbroek 	CONSISTENT(sock);
3823*00b67f09SDavid van Moolenbroek 
3824*00b67f09SDavid van Moolenbroek 	/*
3825*00b67f09SDavid van Moolenbroek 	 * make sure that the socket's not closed
3826*00b67f09SDavid van Moolenbroek 	 */
3827*00b67f09SDavid van Moolenbroek 	if (sock->fd == INVALID_SOCKET) {
3828*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
3829*00b67f09SDavid van Moolenbroek 		return (ISC_FALSE);
3830*00b67f09SDavid van Moolenbroek 	}
3831*00b67f09SDavid van Moolenbroek 
3832*00b67f09SDavid van Moolenbroek 	val = ((sock->bound) ? ISC_TRUE : ISC_FALSE);
3833*00b67f09SDavid van Moolenbroek 	UNLOCK(&sock->lock);
3834*00b67f09SDavid van Moolenbroek 
3835*00b67f09SDavid van Moolenbroek 	return (val);
3836*00b67f09SDavid van Moolenbroek }
3837*00b67f09SDavid van Moolenbroek 
3838*00b67f09SDavid van Moolenbroek void
isc__socket_ipv6only(isc_socket_t * sock,isc_boolean_t yes)3839*00b67f09SDavid van Moolenbroek isc__socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) {
3840*00b67f09SDavid van Moolenbroek #if defined(IPV6_V6ONLY)
3841*00b67f09SDavid van Moolenbroek 	int onoff = yes ? 1 : 0;
3842*00b67f09SDavid van Moolenbroek #else
3843*00b67f09SDavid van Moolenbroek 	UNUSED(yes);
3844*00b67f09SDavid van Moolenbroek #endif
3845*00b67f09SDavid van Moolenbroek 
3846*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3847*00b67f09SDavid van Moolenbroek 
3848*00b67f09SDavid van Moolenbroek #ifdef IPV6_V6ONLY
3849*00b67f09SDavid van Moolenbroek 	if (sock->pf == AF_INET6) {
3850*00b67f09SDavid van Moolenbroek 		(void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
3851*00b67f09SDavid van Moolenbroek 				 (char *)&onoff, sizeof(onoff));
3852*00b67f09SDavid van Moolenbroek 	}
3853*00b67f09SDavid van Moolenbroek #endif
3854*00b67f09SDavid van Moolenbroek }
3855*00b67f09SDavid van Moolenbroek 
3856*00b67f09SDavid van Moolenbroek void
isc__socket_dscp(isc_socket_t * sock,isc_dscp_t dscp)3857*00b67f09SDavid van Moolenbroek isc__socket_dscp(isc_socket_t *sock, isc_dscp_t dscp) {
3858*00b67f09SDavid van Moolenbroek #if !defined(IP_TOS) && !defined(IPV6_TCLASS)
3859*00b67f09SDavid van Moolenbroek 	UNUSED(dscp);
3860*00b67f09SDavid van Moolenbroek #else
3861*00b67f09SDavid van Moolenbroek 	if (dscp < 0)
3862*00b67f09SDavid van Moolenbroek 		return;
3863*00b67f09SDavid van Moolenbroek 
3864*00b67f09SDavid van Moolenbroek 	dscp <<= 2;
3865*00b67f09SDavid van Moolenbroek 	dscp &= 0xff;
3866*00b67f09SDavid van Moolenbroek #endif
3867*00b67f09SDavid van Moolenbroek 
3868*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(sock));
3869*00b67f09SDavid van Moolenbroek 
3870*00b67f09SDavid van Moolenbroek #ifdef IP_TOS
3871*00b67f09SDavid van Moolenbroek 	if (sock->pf == AF_INET) {
3872*00b67f09SDavid van Moolenbroek 		(void)setsockopt(sock->fd, IPPROTO_IP, IP_TOS,
3873*00b67f09SDavid van Moolenbroek 				 (char *)&dscp, sizeof(dscp));
3874*00b67f09SDavid van Moolenbroek 	}
3875*00b67f09SDavid van Moolenbroek #endif
3876*00b67f09SDavid van Moolenbroek #ifdef IPV6_TCLASS
3877*00b67f09SDavid van Moolenbroek 	if (sock->pf == AF_INET6) {
3878*00b67f09SDavid van Moolenbroek 		(void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_TCLASS,
3879*00b67f09SDavid van Moolenbroek 				 (char *)&dscp, sizeof(dscp));
3880*00b67f09SDavid van Moolenbroek 	}
3881*00b67f09SDavid van Moolenbroek #endif
3882*00b67f09SDavid van Moolenbroek }
3883*00b67f09SDavid van Moolenbroek 
3884*00b67f09SDavid van Moolenbroek void
isc__socket_cleanunix(isc_sockaddr_t * addr,isc_boolean_t active)3885*00b67f09SDavid van Moolenbroek isc__socket_cleanunix(isc_sockaddr_t *addr, isc_boolean_t active) {
3886*00b67f09SDavid van Moolenbroek 	UNUSED(addr);
3887*00b67f09SDavid van Moolenbroek 	UNUSED(active);
3888*00b67f09SDavid van Moolenbroek }
3889*00b67f09SDavid van Moolenbroek 
3890*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_permunix(isc_sockaddr_t * addr,isc_uint32_t perm,isc_uint32_t owner,isc_uint32_t group)3891*00b67f09SDavid van Moolenbroek isc__socket_permunix(isc_sockaddr_t *addr, isc_uint32_t perm,
3892*00b67f09SDavid van Moolenbroek 		     isc_uint32_t owner,	isc_uint32_t group)
3893*00b67f09SDavid van Moolenbroek {
3894*00b67f09SDavid van Moolenbroek 	UNUSED(addr);
3895*00b67f09SDavid van Moolenbroek 	UNUSED(perm);
3896*00b67f09SDavid van Moolenbroek 	UNUSED(owner);
3897*00b67f09SDavid van Moolenbroek 	UNUSED(group);
3898*00b67f09SDavid van Moolenbroek 	return (ISC_R_NOTIMPLEMENTED);
3899*00b67f09SDavid van Moolenbroek }
3900*00b67f09SDavid van Moolenbroek 
3901*00b67f09SDavid van Moolenbroek void
isc__socket_setname(isc_socket_t * socket,const char * name,void * tag)3902*00b67f09SDavid van Moolenbroek isc__socket_setname(isc_socket_t *socket, const char *name, void *tag) {
3903*00b67f09SDavid van Moolenbroek 
3904*00b67f09SDavid van Moolenbroek 	/*
3905*00b67f09SDavid van Moolenbroek 	 * Name 'socket'.
3906*00b67f09SDavid van Moolenbroek 	 */
3907*00b67f09SDavid van Moolenbroek 
3908*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_SOCKET(socket));
3909*00b67f09SDavid van Moolenbroek 
3910*00b67f09SDavid van Moolenbroek 	LOCK(&socket->lock);
3911*00b67f09SDavid van Moolenbroek 	memset(socket->name, 0, sizeof(socket->name));
3912*00b67f09SDavid van Moolenbroek 	strncpy(socket->name, name, sizeof(socket->name) - 1);
3913*00b67f09SDavid van Moolenbroek 	socket->tag = tag;
3914*00b67f09SDavid van Moolenbroek 	UNLOCK(&socket->lock);
3915*00b67f09SDavid van Moolenbroek }
3916*00b67f09SDavid van Moolenbroek 
3917*00b67f09SDavid van Moolenbroek const char *
isc__socket_getname(isc_socket_t * socket)3918*00b67f09SDavid van Moolenbroek isc__socket_getname(isc_socket_t *socket) {
3919*00b67f09SDavid van Moolenbroek 	return (socket->name);
3920*00b67f09SDavid van Moolenbroek }
3921*00b67f09SDavid van Moolenbroek 
3922*00b67f09SDavid van Moolenbroek void *
isc__socket_gettag(isc_socket_t * socket)3923*00b67f09SDavid van Moolenbroek isc__socket_gettag(isc_socket_t *socket) {
3924*00b67f09SDavid van Moolenbroek 	return (socket->tag);
3925*00b67f09SDavid van Moolenbroek }
3926*00b67f09SDavid van Moolenbroek 
3927*00b67f09SDavid van Moolenbroek int
isc__socket_getfd(isc_socket_t * socket)3928*00b67f09SDavid van Moolenbroek isc__socket_getfd(isc_socket_t *socket) {
3929*00b67f09SDavid van Moolenbroek 	return ((short) socket->fd);
3930*00b67f09SDavid van Moolenbroek }
3931*00b67f09SDavid van Moolenbroek 
3932*00b67f09SDavid van Moolenbroek void
isc__socketmgr_setreserved(isc_socketmgr_t * manager,isc_uint32_t reserved)3933*00b67f09SDavid van Moolenbroek isc__socketmgr_setreserved(isc_socketmgr_t *manager, isc_uint32_t reserved) {
3934*00b67f09SDavid van Moolenbroek 	UNUSED(manager);
3935*00b67f09SDavid van Moolenbroek 	UNUSED(reserved);
3936*00b67f09SDavid van Moolenbroek }
3937*00b67f09SDavid van Moolenbroek 
3938*00b67f09SDavid van Moolenbroek void
isc___socketmgr_maxudp(isc_socketmgr_t * manager,int maxudp)3939*00b67f09SDavid van Moolenbroek isc___socketmgr_maxudp(isc_socketmgr_t *manager, int maxudp) {
3940*00b67f09SDavid van Moolenbroek 
3941*00b67f09SDavid van Moolenbroek 	UNUSED(manager);
3942*00b67f09SDavid van Moolenbroek 	UNUSED(maxudp);
3943*00b67f09SDavid van Moolenbroek }
3944*00b67f09SDavid van Moolenbroek 
3945*00b67f09SDavid van Moolenbroek isc_socketevent_t *
isc_socket_socketevent(isc_mem_t * mctx,void * sender,isc_eventtype_t eventtype,isc_taskaction_t action,void * arg)3946*00b67f09SDavid van Moolenbroek isc_socket_socketevent(isc_mem_t *mctx, void *sender,
3947*00b67f09SDavid van Moolenbroek 		       isc_eventtype_t eventtype, isc_taskaction_t action,
3948*00b67f09SDavid van Moolenbroek 		       void *arg)
3949*00b67f09SDavid van Moolenbroek {
3950*00b67f09SDavid van Moolenbroek 	return (allocate_socketevent(mctx, sender, eventtype, action, arg));
3951*00b67f09SDavid van Moolenbroek }
3952*00b67f09SDavid van Moolenbroek 
3953*00b67f09SDavid van Moolenbroek #ifdef HAVE_LIBXML2
3954*00b67f09SDavid van Moolenbroek 
3955*00b67f09SDavid van Moolenbroek static const char *
_socktype(isc_sockettype_t type)3956*00b67f09SDavid van Moolenbroek _socktype(isc_sockettype_t type) {
3957*00b67f09SDavid van Moolenbroek 	if (type == isc_sockettype_udp)
3958*00b67f09SDavid van Moolenbroek 		return ("udp");
3959*00b67f09SDavid van Moolenbroek 	else if (type == isc_sockettype_tcp)
3960*00b67f09SDavid van Moolenbroek 		return ("tcp");
3961*00b67f09SDavid van Moolenbroek 	else if (type == isc_sockettype_unix)
3962*00b67f09SDavid van Moolenbroek 		return ("unix");
3963*00b67f09SDavid van Moolenbroek 	else if (type == isc_sockettype_fdwatch)
3964*00b67f09SDavid van Moolenbroek 		return ("fdwatch");
3965*00b67f09SDavid van Moolenbroek 	else
3966*00b67f09SDavid van Moolenbroek 		return ("not-initialized");
3967*00b67f09SDavid van Moolenbroek }
3968*00b67f09SDavid van Moolenbroek 
3969*00b67f09SDavid van Moolenbroek #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(/*CONSTCOND*/0)
3970*00b67f09SDavid van Moolenbroek int
isc_socketmgr_renderxml(isc_socketmgr_t * mgr,xmlTextWriterPtr writer)3971*00b67f09SDavid van Moolenbroek isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer)
3972*00b67f09SDavid van Moolenbroek {
3973*00b67f09SDavid van Moolenbroek 	isc_socket_t *sock = NULL;
3974*00b67f09SDavid van Moolenbroek 	char peerbuf[ISC_SOCKADDR_FORMATSIZE];
3975*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t addr;
3976*00b67f09SDavid van Moolenbroek 	ISC_SOCKADDR_LEN_T len;
3977*00b67f09SDavid van Moolenbroek 	int xmlrc;
3978*00b67f09SDavid van Moolenbroek 
3979*00b67f09SDavid van Moolenbroek 	LOCK(&mgr->lock);
3980*00b67f09SDavid van Moolenbroek 
3981*00b67f09SDavid van Moolenbroek #ifndef ISC_PLATFORM_USETHREADS
3982*00b67f09SDavid van Moolenbroek 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
3983*00b67f09SDavid van Moolenbroek 	TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->refs));
3984*00b67f09SDavid van Moolenbroek 	TRY0(xmlTextWriterEndElement(writer));
3985*00b67f09SDavid van Moolenbroek #endif
3986*00b67f09SDavid van Moolenbroek 
3987*00b67f09SDavid van Moolenbroek 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "sockets"));
3988*00b67f09SDavid van Moolenbroek 	sock = ISC_LIST_HEAD(mgr->socklist);
3989*00b67f09SDavid van Moolenbroek 	while (sock != NULL) {
3990*00b67f09SDavid van Moolenbroek 		LOCK(&sock->lock);
3991*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socket"));
3992*00b67f09SDavid van Moolenbroek 
3993*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
3994*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterWriteFormatString(writer, "%p", sock));
3995*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterEndElement(writer));
3996*00b67f09SDavid van Moolenbroek 
3997*00b67f09SDavid van Moolenbroek 		if (sock->name[0] != 0) {
3998*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterStartElement(writer,
3999*00b67f09SDavid van Moolenbroek 						       ISC_XMLCHAR "name"));
4000*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterWriteFormatString(writer, "%s",
4001*00b67f09SDavid van Moolenbroek 							    sock->name));
4002*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterEndElement(writer)); /* name */
4003*00b67f09SDavid van Moolenbroek 		}
4004*00b67f09SDavid van Moolenbroek 
4005*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterStartElement(writer,
4006*00b67f09SDavid van Moolenbroek 					       ISC_XMLCHAR "references"));
4007*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterWriteFormatString(writer, "%d",
4008*00b67f09SDavid van Moolenbroek 						    sock->references));
4009*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterEndElement(writer));
4010*00b67f09SDavid van Moolenbroek 
4011*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterWriteElement(writer, ISC_XMLCHAR "type",
4012*00b67f09SDavid van Moolenbroek 					  ISC_XMLCHAR _socktype(sock->type)));
4013*00b67f09SDavid van Moolenbroek 
4014*00b67f09SDavid van Moolenbroek 		if (sock->connected) {
4015*00b67f09SDavid van Moolenbroek 			isc_sockaddr_format(&sock->address, peerbuf,
4016*00b67f09SDavid van Moolenbroek 					    sizeof(peerbuf));
4017*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterWriteElement(writer,
4018*00b67f09SDavid van Moolenbroek 						  ISC_XMLCHAR "peer-address",
4019*00b67f09SDavid van Moolenbroek 						  ISC_XMLCHAR peerbuf));
4020*00b67f09SDavid van Moolenbroek 		}
4021*00b67f09SDavid van Moolenbroek 
4022*00b67f09SDavid van Moolenbroek 		len = sizeof(addr);
4023*00b67f09SDavid van Moolenbroek 		if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) {
4024*00b67f09SDavid van Moolenbroek 			isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf));
4025*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterWriteElement(writer,
4026*00b67f09SDavid van Moolenbroek 						  ISC_XMLCHAR "local-address",
4027*00b67f09SDavid van Moolenbroek 						  ISC_XMLCHAR peerbuf));
4028*00b67f09SDavid van Moolenbroek 		}
4029*00b67f09SDavid van Moolenbroek 
4030*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "states"));
4031*00b67f09SDavid van Moolenbroek 		if (sock->pending_recv)
4032*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterWriteElement(writer,
4033*00b67f09SDavid van Moolenbroek 						ISC_XMLCHAR "state",
4034*00b67f09SDavid van Moolenbroek 						ISC_XMLCHAR "pending-receive"));
4035*00b67f09SDavid van Moolenbroek 		if (sock->pending_send)
4036*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterWriteElement(writer,
4037*00b67f09SDavid van Moolenbroek 						  ISC_XMLCHAR "state",
4038*00b67f09SDavid van Moolenbroek 						  ISC_XMLCHAR "pending-send"));
4039*00b67f09SDavid van Moolenbroek 		if (sock->pending_accept)
4040*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterWriteElement(writer,
4041*00b67f09SDavid van Moolenbroek 						 ISC_XMLCHAR "state",
4042*00b67f09SDavid van Moolenbroek 						 ISC_XMLCHAR "pending_accept"));
4043*00b67f09SDavid van Moolenbroek 		if (sock->listener)
4044*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterWriteElement(writer,
4045*00b67f09SDavid van Moolenbroek 						       ISC_XMLCHAR "state",
4046*00b67f09SDavid van Moolenbroek 						       ISC_XMLCHAR "listener"));
4047*00b67f09SDavid van Moolenbroek 		if (sock->connected)
4048*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterWriteElement(writer,
4049*00b67f09SDavid van Moolenbroek 						     ISC_XMLCHAR "state",
4050*00b67f09SDavid van Moolenbroek 						     ISC_XMLCHAR "connected"));
4051*00b67f09SDavid van Moolenbroek 		if (sock->pending_connect)
4052*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterWriteElement(writer,
4053*00b67f09SDavid van Moolenbroek 						  ISC_XMLCHAR "state",
4054*00b67f09SDavid van Moolenbroek 						  ISC_XMLCHAR "connecting"));
4055*00b67f09SDavid van Moolenbroek 		if (sock->bound)
4056*00b67f09SDavid van Moolenbroek 			TRY0(xmlTextWriterWriteElement(writer,
4057*00b67f09SDavid van Moolenbroek 						  ISC_XMLCHAR "state",
4058*00b67f09SDavid van Moolenbroek 						  ISC_XMLCHAR "bound"));
4059*00b67f09SDavid van Moolenbroek 
4060*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterEndElement(writer)); /* states */
4061*00b67f09SDavid van Moolenbroek 
4062*00b67f09SDavid van Moolenbroek 		TRY0(xmlTextWriterEndElement(writer)); /* socket */
4063*00b67f09SDavid van Moolenbroek 
4064*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
4065*00b67f09SDavid van Moolenbroek 		sock = ISC_LIST_NEXT(sock, link);
4066*00b67f09SDavid van Moolenbroek 	}
4067*00b67f09SDavid van Moolenbroek 	TRY0(xmlTextWriterEndElement(writer)); /* sockets */
4068*00b67f09SDavid van Moolenbroek 
4069*00b67f09SDavid van Moolenbroek error:
4070*00b67f09SDavid van Moolenbroek 	if (sock != NULL)
4071*00b67f09SDavid van Moolenbroek 		UNLOCK(&sock->lock);
4072*00b67f09SDavid van Moolenbroek 
4073*00b67f09SDavid van Moolenbroek 	UNLOCK(&mgr->lock);
4074*00b67f09SDavid van Moolenbroek 
4075*00b67f09SDavid van Moolenbroek 	return (xmlrc);
4076*00b67f09SDavid van Moolenbroek }
4077*00b67f09SDavid van Moolenbroek #endif /* HAVE_LIBXML2 */
4078*00b67f09SDavid van Moolenbroek 
4079*00b67f09SDavid van Moolenbroek /*
4080*00b67f09SDavid van Moolenbroek  * Replace ../socket_api.c
4081*00b67f09SDavid van Moolenbroek  */
4082*00b67f09SDavid van Moolenbroek 
4083*00b67f09SDavid van Moolenbroek isc_result_t
isc__socket_register(void)4084*00b67f09SDavid van Moolenbroek isc__socket_register(void) {
4085*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
4086*00b67f09SDavid van Moolenbroek }
4087*00b67f09SDavid van Moolenbroek 
4088*00b67f09SDavid van Moolenbroek isc_result_t
isc_socketmgr_createinctx(isc_mem_t * mctx,isc_appctx_t * actx,isc_socketmgr_t ** managerp)4089*00b67f09SDavid van Moolenbroek isc_socketmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
4090*00b67f09SDavid van Moolenbroek 			  isc_socketmgr_t **managerp)
4091*00b67f09SDavid van Moolenbroek {
4092*00b67f09SDavid van Moolenbroek 	isc_result_t result;
4093*00b67f09SDavid van Moolenbroek 
4094*00b67f09SDavid van Moolenbroek 	result = isc_socketmgr_create(mctx, managerp);
4095*00b67f09SDavid van Moolenbroek 
4096*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS)
4097*00b67f09SDavid van Moolenbroek 		isc_appctx_setsocketmgr(actx, *managerp);
4098*00b67f09SDavid van Moolenbroek 
4099*00b67f09SDavid van Moolenbroek 	return (result);
4100*00b67f09SDavid van Moolenbroek }
4101