ws2_32: Use IOCTL_AFD_WINE_CONNECT in connect().
[wine.git] / dlls / ws2_32 / socket.c
blob889f0327bafa5e092c61a5fdbaabb8ac53e84859
1 /*
2 * based on Windows Sockets 1.1 specs
4 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
5 * Copyright (C) 2001 Stefan Leichter
6 * Copyright (C) 2004 Hans Leidekker
7 * Copyright (C) 2005 Marcus Meissner
8 * Copyright (C) 2006-2008 Kai Blin
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * NOTE: If you make any changes to fix a particular app, make sure
25 * they don't break something else like Netscape or telnet and ftp
26 * clients and servers (www.winsite.com got a lot of those).
29 #include "config.h"
30 #include "wine/port.h"
32 #include "ws2_32_private.h"
34 #if defined(linux) && !defined(IP_UNICAST_IF)
35 #define IP_UNICAST_IF 50
36 #endif
38 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
39 # define sipx_network sipx_addr.x_net
40 # define sipx_node sipx_addr.x_host.c_host
41 #endif /* __FreeBSD__ */
43 #if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE)
44 /* TCP_KEEPALIVE is the Mac OS name for TCP_KEEPIDLE */
45 #define TCP_KEEPIDLE TCP_KEEPALIVE
46 #endif
48 #define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
50 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
51 WINE_DECLARE_DEBUG_CHANNEL(winediag);
53 static const WSAPROTOCOL_INFOW supported_protocols[] =
56 .dwServiceFlags1 = XP1_IFS_HANDLES | XP1_EXPEDITED_DATA | XP1_GRACEFUL_CLOSE
57 | XP1_GUARANTEED_ORDER | XP1_GUARANTEED_DELIVERY,
58 .dwProviderFlags = PFL_MATCHES_PROTOCOL_ZERO,
59 .ProviderId = {0xe70f1aa0, 0xab8b, 0x11cf, {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
60 .dwCatalogEntryId = 1001,
61 .ProtocolChain.ChainLen = 1,
62 .iVersion = 2,
63 .iAddressFamily = WS_AF_INET,
64 .iMaxSockAddr = sizeof(struct WS_sockaddr_in),
65 .iMinSockAddr = sizeof(struct WS_sockaddr_in),
66 .iSocketType = WS_SOCK_STREAM,
67 .iProtocol = WS_IPPROTO_TCP,
68 .szProtocol = {'T','C','P','/','I','P',0},
71 .dwServiceFlags1 = XP1_IFS_HANDLES | XP1_SUPPORT_BROADCAST
72 | XP1_SUPPORT_MULTIPOINT | XP1_MESSAGE_ORIENTED | XP1_CONNECTIONLESS,
73 .dwProviderFlags = PFL_MATCHES_PROTOCOL_ZERO,
74 .ProviderId = {0xe70f1aa0, 0xab8b, 0x11cf, {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
75 .dwCatalogEntryId = 1002,
76 .ProtocolChain.ChainLen = 1,
77 .iVersion = 2,
78 .iAddressFamily = WS_AF_INET,
79 .iMaxSockAddr = sizeof(struct WS_sockaddr_in),
80 .iMinSockAddr = sizeof(struct WS_sockaddr_in),
81 .iSocketType = WS_SOCK_DGRAM,
82 .iProtocol = WS_IPPROTO_UDP,
83 .dwMessageSize = 0xffbb,
84 .szProtocol = {'U','D','P','/','I','P',0},
87 .dwServiceFlags1 = XP1_IFS_HANDLES | XP1_EXPEDITED_DATA | XP1_GRACEFUL_CLOSE
88 | XP1_GUARANTEED_ORDER | XP1_GUARANTEED_DELIVERY,
89 .dwProviderFlags = PFL_MATCHES_PROTOCOL_ZERO,
90 .ProviderId = {0xf9eab0c0, 0x26d4, 0x11d0, {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
91 .dwCatalogEntryId = 1004,
92 .ProtocolChain.ChainLen = 1,
93 .iVersion = 2,
94 .iAddressFamily = WS_AF_INET6,
95 .iMaxSockAddr = sizeof(struct WS_sockaddr_in6),
96 .iMinSockAddr = sizeof(struct WS_sockaddr_in6),
97 .iSocketType = WS_SOCK_STREAM,
98 .iProtocol = WS_IPPROTO_TCP,
99 .szProtocol = {'T','C','P','/','I','P','v','6',0},
102 .dwServiceFlags1 = XP1_IFS_HANDLES | XP1_SUPPORT_BROADCAST
103 | XP1_SUPPORT_MULTIPOINT | XP1_MESSAGE_ORIENTED | XP1_CONNECTIONLESS,
104 .dwProviderFlags = PFL_MATCHES_PROTOCOL_ZERO,
105 .ProviderId = {0xf9eab0c0, 0x26d4, 0x11d0, {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
106 .dwCatalogEntryId = 1005,
107 .ProtocolChain.ChainLen = 1,
108 .iVersion = 2,
109 .iAddressFamily = WS_AF_INET6,
110 .iMaxSockAddr = sizeof(struct WS_sockaddr_in6),
111 .iMinSockAddr = sizeof(struct WS_sockaddr_in6),
112 .iSocketType = WS_SOCK_DGRAM,
113 .iProtocol = WS_IPPROTO_UDP,
114 .dwMessageSize = 0xffbb,
115 .szProtocol = {'U','D','P','/','I','P','v','6',0},
118 .dwServiceFlags1 = XP1_PARTIAL_MESSAGE | XP1_SUPPORT_BROADCAST
119 | XP1_SUPPORT_MULTIPOINT | XP1_MESSAGE_ORIENTED | XP1_CONNECTIONLESS,
120 .dwProviderFlags = PFL_MATCHES_PROTOCOL_ZERO,
121 .ProviderId = {0x11058240, 0xbe47, 0x11cf, {0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
122 .dwCatalogEntryId = 1030,
123 .ProtocolChain.ChainLen = 1,
124 .iVersion = 2,
125 .iAddressFamily = WS_AF_IPX,
126 .iMaxSockAddr = sizeof(struct WS_sockaddr),
127 .iMinSockAddr = sizeof(struct WS_sockaddr_ipx),
128 .iSocketType = WS_SOCK_DGRAM,
129 .iProtocol = WS_NSPROTO_IPX,
130 .iProtocolMaxOffset = 255,
131 .dwMessageSize = 0x240,
132 .szProtocol = {'I','P','X',0},
135 .dwServiceFlags1 = XP1_IFS_HANDLES | XP1_PSEUDO_STREAM | XP1_MESSAGE_ORIENTED
136 | XP1_GUARANTEED_ORDER | XP1_GUARANTEED_DELIVERY,
137 .dwProviderFlags = PFL_MATCHES_PROTOCOL_ZERO,
138 .ProviderId = {0x11058241, 0xbe47, 0x11cf, {0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
139 .dwCatalogEntryId = 1031,
140 .ProtocolChain.ChainLen = 1,
141 .iVersion = 2,
142 .iAddressFamily = WS_AF_IPX,
143 .iMaxSockAddr = sizeof(struct WS_sockaddr),
144 .iMinSockAddr = sizeof(struct WS_sockaddr_ipx),
145 .iSocketType = WS_SOCK_SEQPACKET,
146 .iProtocol = WS_NSPROTO_SPX,
147 .dwMessageSize = UINT_MAX,
148 .szProtocol = {'S','P','X',0},
151 .dwServiceFlags1 = XP1_IFS_HANDLES | XP1_GRACEFUL_CLOSE | XP1_PSEUDO_STREAM
152 | XP1_MESSAGE_ORIENTED | XP1_GUARANTEED_ORDER | XP1_GUARANTEED_DELIVERY,
153 .dwProviderFlags = PFL_MATCHES_PROTOCOL_ZERO,
154 .ProviderId = {0x11058241, 0xbe47, 0x11cf, {0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
155 .dwCatalogEntryId = 1033,
156 .ProtocolChain.ChainLen = 1,
157 .iVersion = 2,
158 .iAddressFamily = WS_AF_IPX,
159 .iMaxSockAddr = sizeof(struct WS_sockaddr),
160 .iMinSockAddr = sizeof(struct WS_sockaddr_ipx),
161 .iSocketType = WS_SOCK_SEQPACKET,
162 .iProtocol = WS_NSPROTO_SPXII,
163 .dwMessageSize = UINT_MAX,
164 .szProtocol = {'S','P','X',' ','I','I',0},
168 #if defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER)
169 # define LINUX_BOUND_IF
170 struct interface_filter {
171 struct sock_filter iface_memaddr;
172 struct sock_filter iface_rule;
173 struct sock_filter ip_memaddr;
174 struct sock_filter ip_rule;
175 struct sock_filter return_keep;
176 struct sock_filter return_dump;
178 # define FILTER_JUMP_DUMP(here) (u_char)(offsetof(struct interface_filter, return_dump) \
179 -offsetof(struct interface_filter, here)-sizeof(struct sock_filter)) \
180 /sizeof(struct sock_filter)
181 # define FILTER_JUMP_KEEP(here) (u_char)(offsetof(struct interface_filter, return_keep) \
182 -offsetof(struct interface_filter, here)-sizeof(struct sock_filter)) \
183 /sizeof(struct sock_filter)
184 # define FILTER_JUMP_NEXT() (u_char)(0)
185 # define SKF_NET_DESTIP 16 /* offset in the network header to the destination IP */
186 static struct interface_filter generic_interface_filter = {
187 /* This filter rule allows incoming packets on the specified interface, which works for all
188 * remotely generated packets and for locally generated broadcast packets. */
189 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, SKF_AD_OFF+SKF_AD_IFINDEX),
190 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xdeadbeef, FILTER_JUMP_KEEP(iface_rule), FILTER_JUMP_NEXT()),
191 /* This rule allows locally generated packets targeted at the specific IP address of the chosen
192 * adapter (local packets not destined for the broadcast address do not have IFINDEX set) */
193 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, SKF_NET_OFF+SKF_NET_DESTIP),
194 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xdeadbeef, FILTER_JUMP_KEEP(ip_rule), FILTER_JUMP_DUMP(ip_rule)),
195 BPF_STMT(BPF_RET+BPF_K, (u_int)-1), /* keep packet */
196 BPF_STMT(BPF_RET+BPF_K, 0) /* dump packet */
198 #endif /* LINUX_BOUND_IF */
200 extern ssize_t CDECL __wine_locked_recvmsg( int fd, struct msghdr *hdr, int flags );
203 * The actual definition of WSASendTo, wrapped in a different function name
204 * so that internal calls from ws2_32 itself will not trigger programs like
205 * Garena, which hooks WSASendTo/WSARecvFrom calls.
207 static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
208 LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
209 const struct WS_sockaddr *to, int tolen,
210 LPWSAOVERLAPPED lpOverlapped,
211 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
214 * Internal fundamental receive function, essentially WSARecvFrom with an
215 * additional parameter to support message control headers.
217 static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
218 LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,
219 struct WS_sockaddr *lpFrom,
220 LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
221 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
222 LPWSABUF lpControlBuffer );
224 DECLARE_CRITICAL_SECTION(cs_if_addr_cache);
225 DECLARE_CRITICAL_SECTION(cs_socket_list);
227 static in_addr_t *if_addr_cache;
228 static unsigned int if_addr_cache_size;
230 static SOCKET *socket_list;
231 static unsigned int socket_list_size;
233 const char *debugstr_sockaddr( const struct WS_sockaddr *a )
235 if (!a) return "(nil)";
236 switch (a->sa_family)
238 case WS_AF_INET:
240 char buf[16];
241 const char *p;
242 struct WS_sockaddr_in *sin = (struct WS_sockaddr_in *)a;
244 p = WS_inet_ntop( WS_AF_INET, &sin->sin_addr, buf, sizeof(buf) );
245 if (!p)
246 p = "(unknown IPv4 address)";
248 return wine_dbg_sprintf("{ family AF_INET, address %s, port %d }",
249 p, ntohs(sin->sin_port));
251 case WS_AF_INET6:
253 char buf[46];
254 const char *p;
255 struct WS_sockaddr_in6 *sin = (struct WS_sockaddr_in6 *)a;
257 p = WS_inet_ntop( WS_AF_INET6, &sin->sin6_addr, buf, sizeof(buf) );
258 if (!p)
259 p = "(unknown IPv6 address)";
260 return wine_dbg_sprintf("{ family AF_INET6, address %s, port %d }",
261 p, ntohs(sin->sin6_port));
263 case WS_AF_IPX:
265 int i;
266 char netnum[16], nodenum[16];
267 struct WS_sockaddr_ipx *sin = (struct WS_sockaddr_ipx *)a;
269 for (i = 0;i < 4; i++) sprintf(netnum + i * 2, "%02X", (unsigned char) sin->sa_netnum[i]);
270 for (i = 0;i < 6; i++) sprintf(nodenum + i * 2, "%02X", (unsigned char) sin->sa_nodenum[i]);
272 return wine_dbg_sprintf("{ family AF_IPX, address %s.%s, ipx socket %d }",
273 netnum, nodenum, sin->sa_socket);
275 case WS_AF_IRDA:
277 DWORD addr;
279 memcpy( &addr, ((const SOCKADDR_IRDA *)a)->irdaDeviceID, sizeof(addr) );
280 addr = ntohl( addr );
281 return wine_dbg_sprintf("{ family AF_IRDA, addr %08x, name %s }",
282 addr,
283 ((const SOCKADDR_IRDA *)a)->irdaServiceName);
285 default:
286 return wine_dbg_sprintf("{ family %d }", a->sa_family);
290 static inline const char *debugstr_sockopt(int level, int optname)
292 const char *stropt = NULL, *strlevel = NULL;
294 #define DEBUG_SOCKLEVEL(x) case (x): strlevel = #x
295 #define DEBUG_SOCKOPT(x) case (x): stropt = #x; break
297 switch(level)
299 DEBUG_SOCKLEVEL(WS_SOL_SOCKET);
300 switch(optname)
302 DEBUG_SOCKOPT(WS_SO_ACCEPTCONN);
303 DEBUG_SOCKOPT(WS_SO_BROADCAST);
304 DEBUG_SOCKOPT(WS_SO_BSP_STATE);
305 DEBUG_SOCKOPT(WS_SO_CONDITIONAL_ACCEPT);
306 DEBUG_SOCKOPT(WS_SO_CONNECT_TIME);
307 DEBUG_SOCKOPT(WS_SO_DEBUG);
308 DEBUG_SOCKOPT(WS_SO_DONTLINGER);
309 DEBUG_SOCKOPT(WS_SO_DONTROUTE);
310 DEBUG_SOCKOPT(WS_SO_ERROR);
311 DEBUG_SOCKOPT(WS_SO_EXCLUSIVEADDRUSE);
312 DEBUG_SOCKOPT(WS_SO_GROUP_ID);
313 DEBUG_SOCKOPT(WS_SO_GROUP_PRIORITY);
314 DEBUG_SOCKOPT(WS_SO_KEEPALIVE);
315 DEBUG_SOCKOPT(WS_SO_LINGER);
316 DEBUG_SOCKOPT(WS_SO_MAX_MSG_SIZE);
317 DEBUG_SOCKOPT(WS_SO_OOBINLINE);
318 DEBUG_SOCKOPT(WS_SO_OPENTYPE);
319 DEBUG_SOCKOPT(WS_SO_PROTOCOL_INFOA);
320 DEBUG_SOCKOPT(WS_SO_PROTOCOL_INFOW);
321 DEBUG_SOCKOPT(WS_SO_RCVBUF);
322 DEBUG_SOCKOPT(WS_SO_RCVTIMEO);
323 DEBUG_SOCKOPT(WS_SO_REUSEADDR);
324 DEBUG_SOCKOPT(WS_SO_SNDBUF);
325 DEBUG_SOCKOPT(WS_SO_SNDTIMEO);
326 DEBUG_SOCKOPT(WS_SO_TYPE);
327 DEBUG_SOCKOPT(WS_SO_UPDATE_CONNECT_CONTEXT);
329 break;
331 DEBUG_SOCKLEVEL(WS_NSPROTO_IPX);
332 switch(optname)
334 DEBUG_SOCKOPT(WS_IPX_PTYPE);
335 DEBUG_SOCKOPT(WS_IPX_FILTERPTYPE);
336 DEBUG_SOCKOPT(WS_IPX_DSTYPE);
337 DEBUG_SOCKOPT(WS_IPX_RECVHDR);
338 DEBUG_SOCKOPT(WS_IPX_MAXSIZE);
339 DEBUG_SOCKOPT(WS_IPX_ADDRESS);
340 DEBUG_SOCKOPT(WS_IPX_MAX_ADAPTER_NUM);
342 break;
344 DEBUG_SOCKLEVEL(WS_SOL_IRLMP);
345 switch(optname)
347 DEBUG_SOCKOPT(WS_IRLMP_ENUMDEVICES);
349 break;
351 DEBUG_SOCKLEVEL(WS_IPPROTO_TCP);
352 switch(optname)
354 DEBUG_SOCKOPT(WS_TCP_BSDURGENT);
355 DEBUG_SOCKOPT(WS_TCP_EXPEDITED_1122);
356 DEBUG_SOCKOPT(WS_TCP_NODELAY);
358 break;
360 DEBUG_SOCKLEVEL(WS_IPPROTO_IP);
361 switch(optname)
363 DEBUG_SOCKOPT(WS_IP_ADD_MEMBERSHIP);
364 DEBUG_SOCKOPT(WS_IP_DONTFRAGMENT);
365 DEBUG_SOCKOPT(WS_IP_DROP_MEMBERSHIP);
366 DEBUG_SOCKOPT(WS_IP_HDRINCL);
367 DEBUG_SOCKOPT(WS_IP_MULTICAST_IF);
368 DEBUG_SOCKOPT(WS_IP_MULTICAST_LOOP);
369 DEBUG_SOCKOPT(WS_IP_MULTICAST_TTL);
370 DEBUG_SOCKOPT(WS_IP_OPTIONS);
371 DEBUG_SOCKOPT(WS_IP_PKTINFO);
372 DEBUG_SOCKOPT(WS_IP_RECEIVE_BROADCAST);
373 DEBUG_SOCKOPT(WS_IP_TOS);
374 DEBUG_SOCKOPT(WS_IP_TTL);
375 DEBUG_SOCKOPT(WS_IP_UNICAST_IF);
377 break;
379 DEBUG_SOCKLEVEL(WS_IPPROTO_IPV6);
380 switch(optname)
382 DEBUG_SOCKOPT(WS_IPV6_ADD_MEMBERSHIP);
383 DEBUG_SOCKOPT(WS_IPV6_DROP_MEMBERSHIP);
384 DEBUG_SOCKOPT(WS_IPV6_MULTICAST_IF);
385 DEBUG_SOCKOPT(WS_IPV6_MULTICAST_HOPS);
386 DEBUG_SOCKOPT(WS_IPV6_MULTICAST_LOOP);
387 DEBUG_SOCKOPT(WS_IPV6_UNICAST_HOPS);
388 DEBUG_SOCKOPT(WS_IPV6_V6ONLY);
389 DEBUG_SOCKOPT(WS_IPV6_UNICAST_IF);
390 DEBUG_SOCKOPT(WS_IPV6_DONTFRAG);
392 break;
394 #undef DEBUG_SOCKLEVEL
395 #undef DEBUG_SOCKOPT
397 if (!strlevel)
398 strlevel = wine_dbg_sprintf("WS_0x%x", level);
399 if (!stropt)
400 stropt = wine_dbg_sprintf("WS_0x%x", optname);
402 return wine_dbg_sprintf("level %s, name %s", strlevel + 3, stropt + 3);
405 static inline const char *debugstr_optval(const char *optval, int optlenval)
407 if (optval && !IS_INTRESOURCE(optval) && optlenval >= 1 && optlenval <= sizeof(DWORD))
409 DWORD value = 0;
410 memcpy(&value, optval, optlenval);
411 return wine_dbg_sprintf("%p (%u)", optval, value);
413 return wine_dbg_sprintf("%p", optval);
416 /* HANDLE<->SOCKET conversion (SOCKET is UINT_PTR). */
417 #define SOCKET2HANDLE(s) ((HANDLE)(s))
418 #define HANDLE2SOCKET(h) ((SOCKET)(h))
420 static BOOL socket_list_add(SOCKET socket)
422 unsigned int i, new_size;
423 SOCKET *new_array;
425 EnterCriticalSection(&cs_socket_list);
426 for (i = 0; i < socket_list_size; ++i)
428 if (!socket_list[i])
430 socket_list[i] = socket;
431 LeaveCriticalSection(&cs_socket_list);
432 return TRUE;
435 new_size = max(socket_list_size * 2, 8);
436 if (!(new_array = heap_realloc(socket_list, new_size * sizeof(*socket_list))))
438 LeaveCriticalSection(&cs_socket_list);
439 return FALSE;
441 socket_list = new_array;
442 memset(socket_list + socket_list_size, 0, (new_size - socket_list_size) * sizeof(*socket_list));
443 socket_list[socket_list_size] = socket;
444 socket_list_size = new_size;
445 LeaveCriticalSection(&cs_socket_list);
446 return TRUE;
449 static void socket_list_remove(SOCKET socket)
451 unsigned int i;
453 EnterCriticalSection(&cs_socket_list);
454 for (i = 0; i < socket_list_size; ++i)
456 if (socket_list[i] == socket)
458 socket_list[i] = 0;
459 break;
462 LeaveCriticalSection(&cs_socket_list);
465 /****************************************************************
466 * Async IO declarations
467 ****************************************************************/
469 typedef NTSTATUS async_callback_t( void *user, IO_STATUS_BLOCK *io, NTSTATUS status );
471 struct ws2_async_io
473 async_callback_t *callback; /* must be the first field */
474 struct ws2_async_io *next;
477 struct ws2_async_shutdown
479 struct ws2_async_io io;
480 HANDLE hSocket;
481 IO_STATUS_BLOCK iosb;
482 int type;
485 struct ws2_async
487 struct ws2_async_io io;
488 HANDLE hSocket;
489 LPWSAOVERLAPPED user_overlapped;
490 LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_func;
491 IO_STATUS_BLOCK local_iosb;
492 struct WS_sockaddr *addr;
493 union
495 int val; /* for send operations */
496 int *ptr; /* for recv operations */
497 } addrlen;
498 DWORD flags;
499 DWORD *lpFlags;
500 WSABUF *control;
501 unsigned int n_iovecs;
502 unsigned int first_iovec;
503 struct iovec iovec[1];
506 struct ws2_accept_async
508 struct ws2_async_io io;
509 HANDLE listen_socket;
510 HANDLE accept_socket;
511 LPOVERLAPPED user_overlapped;
512 ULONG_PTR cvalue;
513 PVOID buf; /* buffer to write data to */
514 int data_len;
515 int local_len;
516 int remote_len;
517 struct ws2_async *read;
520 struct ws2_transmitfile_async
522 struct ws2_async_io io;
523 char *buffer;
524 HANDLE file;
525 DWORD file_read;
526 DWORD file_bytes;
527 DWORD bytes_per_send;
528 TRANSMIT_FILE_BUFFERS buffers;
529 DWORD flags;
530 LARGE_INTEGER offset;
531 struct ws2_async write;
534 static struct ws2_async_io *async_io_freelist;
536 static void release_async_io( struct ws2_async_io *io )
538 for (;;)
540 struct ws2_async_io *next = async_io_freelist;
541 io->next = next;
542 if (InterlockedCompareExchangePointer( (void **)&async_io_freelist, io, next ) == next) return;
546 static struct ws2_async_io *alloc_async_io( DWORD size, async_callback_t callback )
548 /* first free remaining previous fileinfos */
550 struct ws2_async_io *io = InterlockedExchangePointer( (void **)&async_io_freelist, NULL );
552 while (io)
554 struct ws2_async_io *next = io->next;
555 HeapFree( GetProcessHeap(), 0, io );
556 io = next;
559 io = HeapAlloc( GetProcessHeap(), 0, size );
560 if (io) io->callback = callback;
561 return io;
564 static NTSTATUS register_async( int type, HANDLE handle, struct ws2_async_io *async, HANDLE event,
565 PIO_APC_ROUTINE apc, void *apc_context, IO_STATUS_BLOCK *io )
567 NTSTATUS status;
569 SERVER_START_REQ( register_async )
571 req->type = type;
572 req->async.handle = wine_server_obj_handle( handle );
573 req->async.user = wine_server_client_ptr( async );
574 req->async.iosb = wine_server_client_ptr( io );
575 req->async.event = wine_server_obj_handle( event );
576 req->async.apc = wine_server_client_ptr( apc );
577 req->async.apc_context = wine_server_client_ptr( apc_context );
578 status = wine_server_call( req );
580 SERVER_END_REQ;
582 return status;
585 /****************************************************************/
587 /* ----------------------------------- internal data */
589 /* ws_... struct conversion flags */
591 typedef struct /* WSAAsyncSelect() control struct */
593 HANDLE service, event, sock;
594 HWND hWnd;
595 UINT uMsg;
596 LONG lEvent;
597 } ws_select_info;
599 #define WS_MAX_SOCKETS_PER_PROCESS 128 /* reasonable guess */
600 #define WS_MAX_UDP_DATAGRAM 1024
601 static INT WINAPI WSA_DefaultBlockingHook( FARPROC x );
603 int num_startup;
604 static FARPROC blocking_hook = (FARPROC)WSA_DefaultBlockingHook;
606 /* function prototypes */
607 static int ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, int *size);
609 int WSAIOCTL_GetInterfaceCount(void);
610 int WSAIOCTL_GetInterfaceName(int intNumber, char *intName);
612 static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS CompletionStatus, ULONG Information, BOOL force );
614 #define MAP_OPTION(opt) { WS_##opt, opt }
616 static const int ws_flags_map[][2] =
618 MAP_OPTION( MSG_OOB ),
619 MAP_OPTION( MSG_PEEK ),
620 MAP_OPTION( MSG_DONTROUTE ),
621 MAP_OPTION( MSG_WAITALL ),
622 { WS_MSG_PARTIAL, 0 },
625 static const int ws_sock_map[][2] =
627 MAP_OPTION( SO_DEBUG ),
628 MAP_OPTION( SO_ACCEPTCONN ),
629 MAP_OPTION( SO_REUSEADDR ),
630 MAP_OPTION( SO_KEEPALIVE ),
631 MAP_OPTION( SO_DONTROUTE ),
632 MAP_OPTION( SO_BROADCAST ),
633 MAP_OPTION( SO_LINGER ),
634 MAP_OPTION( SO_OOBINLINE ),
635 MAP_OPTION( SO_SNDBUF ),
636 MAP_OPTION( SO_RCVBUF ),
637 MAP_OPTION( SO_ERROR ),
638 MAP_OPTION( SO_TYPE ),
639 #ifdef SO_RCVTIMEO
640 MAP_OPTION( SO_RCVTIMEO ),
641 #endif
642 #ifdef SO_SNDTIMEO
643 MAP_OPTION( SO_SNDTIMEO ),
644 #endif
647 static const int ws_tcp_map[][2] =
649 #ifdef TCP_NODELAY
650 MAP_OPTION( TCP_NODELAY ),
651 #endif
654 static const int ws_ip_map[][2] =
656 MAP_OPTION( IP_MULTICAST_IF ),
657 MAP_OPTION( IP_MULTICAST_TTL ),
658 MAP_OPTION( IP_MULTICAST_LOOP ),
659 MAP_OPTION( IP_ADD_MEMBERSHIP ),
660 MAP_OPTION( IP_DROP_MEMBERSHIP ),
661 MAP_OPTION( IP_ADD_SOURCE_MEMBERSHIP ),
662 MAP_OPTION( IP_DROP_SOURCE_MEMBERSHIP ),
663 MAP_OPTION( IP_BLOCK_SOURCE ),
664 MAP_OPTION( IP_UNBLOCK_SOURCE ),
665 MAP_OPTION( IP_OPTIONS ),
666 #ifdef IP_HDRINCL
667 MAP_OPTION( IP_HDRINCL ),
668 #endif
669 MAP_OPTION( IP_TOS ),
670 MAP_OPTION( IP_TTL ),
671 #if defined(IP_PKTINFO)
672 MAP_OPTION( IP_PKTINFO ),
673 #elif defined(IP_RECVDSTADDR)
674 { WS_IP_PKTINFO, IP_RECVDSTADDR },
675 #endif
676 #ifdef IP_UNICAST_IF
677 MAP_OPTION( IP_UNICAST_IF ),
678 #endif
681 static const int ws_ipv6_map[][2] =
683 #ifdef IPV6_ADD_MEMBERSHIP
684 MAP_OPTION( IPV6_ADD_MEMBERSHIP ),
685 #endif
686 #ifdef IPV6_DROP_MEMBERSHIP
687 MAP_OPTION( IPV6_DROP_MEMBERSHIP ),
688 #endif
689 MAP_OPTION( IPV6_MULTICAST_IF ),
690 MAP_OPTION( IPV6_MULTICAST_HOPS ),
691 MAP_OPTION( IPV6_MULTICAST_LOOP ),
692 MAP_OPTION( IPV6_UNICAST_HOPS ),
693 MAP_OPTION( IPV6_V6ONLY ),
694 #ifdef IPV6_UNICAST_IF
695 MAP_OPTION( IPV6_UNICAST_IF ),
696 #endif
699 static const int ws_socktype_map[][2] =
701 MAP_OPTION( SOCK_DGRAM ),
702 MAP_OPTION( SOCK_STREAM ),
703 MAP_OPTION( SOCK_RAW ),
704 {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
707 static const int ws_poll_map[][2] =
709 MAP_OPTION( POLLERR ),
710 MAP_OPTION( POLLHUP ),
711 MAP_OPTION( POLLNVAL ),
712 MAP_OPTION( POLLWRNORM ),
713 MAP_OPTION( POLLWRBAND ),
714 MAP_OPTION( POLLRDNORM ),
715 { WS_POLLRDBAND, POLLPRI }
718 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
719 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
720 static inline WSACMSGHDR *fill_control_message(int level, int type, WSACMSGHDR *current, ULONG *maxsize, void *data, int len)
722 ULONG msgsize = sizeof(WSACMSGHDR) + WSA_CMSG_ALIGN(len);
723 char *ptr = (char *) current + sizeof(WSACMSGHDR);
725 /* Make sure there is at least enough room for this entry */
726 if (msgsize > *maxsize)
727 return NULL;
728 *maxsize -= msgsize;
729 /* Fill in the entry */
730 current->cmsg_len = sizeof(WSACMSGHDR) + len;
731 current->cmsg_level = level;
732 current->cmsg_type = type;
733 memcpy(ptr, data, len);
734 /* Return the pointer to where next entry should go */
735 return (WSACMSGHDR *) (ptr + WSA_CMSG_ALIGN(len));
737 #endif /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
739 static inline int convert_control_headers(struct msghdr *hdr, WSABUF *control)
741 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
742 WSACMSGHDR *cmsg_win = (WSACMSGHDR *) control->buf, *ptr;
743 ULONG ctlsize = control->len;
744 struct cmsghdr *cmsg_unix;
746 ptr = cmsg_win;
747 /* Loop over all the headers, converting as appropriate */
748 for (cmsg_unix = CMSG_FIRSTHDR(hdr); cmsg_unix != NULL; cmsg_unix = CMSG_NXTHDR(hdr, cmsg_unix))
750 switch(cmsg_unix->cmsg_level)
752 case IPPROTO_IP:
753 switch(cmsg_unix->cmsg_type)
755 #if defined(IP_PKTINFO)
756 case IP_PKTINFO:
758 /* Convert the Unix IP_PKTINFO structure to the Windows version */
759 struct in_pktinfo *data_unix = (struct in_pktinfo *) CMSG_DATA(cmsg_unix);
760 struct WS_in_pktinfo data_win;
762 memcpy(&data_win.ipi_addr,&data_unix->ipi_addr.s_addr,4); /* 4 bytes = 32 address bits */
763 data_win.ipi_ifindex = data_unix->ipi_ifindex;
764 ptr = fill_control_message(WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize,
765 (void*)&data_win, sizeof(data_win));
766 if (!ptr) goto error;
767 } break;
768 #elif defined(IP_RECVDSTADDR)
769 case IP_RECVDSTADDR:
771 struct in_addr *addr_unix = (struct in_addr *) CMSG_DATA(cmsg_unix);
772 struct WS_in_pktinfo data_win;
774 memcpy(&data_win.ipi_addr, &addr_unix->s_addr, 4); /* 4 bytes = 32 address bits */
775 data_win.ipi_ifindex = 0; /* FIXME */
776 ptr = fill_control_message(WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize,
777 (void*)&data_win, sizeof(data_win));
778 if (!ptr) goto error;
779 } break;
780 #endif /* IP_PKTINFO */
781 default:
782 FIXME("Unhandled IPPROTO_IP message header type %d\n", cmsg_unix->cmsg_type);
783 break;
785 break;
786 default:
787 FIXME("Unhandled message header level %d\n", cmsg_unix->cmsg_level);
788 break;
792 /* Set the length of the returned control headers */
793 control->len = (char*)ptr - (char*)cmsg_win;
794 return 1;
795 error:
796 control->len = 0;
797 return 0;
798 #else /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
799 control->len = 0;
800 return 1;
801 #endif /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
803 #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */
805 /* ----------------------------------- error handling */
807 static NTSTATUS sock_get_ntstatus( int err )
809 switch ( err )
811 case EBADF: return STATUS_INVALID_HANDLE;
812 case EBUSY: return STATUS_DEVICE_BUSY;
813 case EPERM:
814 case EACCES: return STATUS_ACCESS_DENIED;
815 case EFAULT: return STATUS_ACCESS_VIOLATION;
816 case EINVAL: return STATUS_INVALID_PARAMETER;
817 case ENFILE:
818 case EMFILE: return STATUS_TOO_MANY_OPENED_FILES;
819 case EINPROGRESS:
820 case EWOULDBLOCK: return STATUS_DEVICE_NOT_READY;
821 case EALREADY: return STATUS_NETWORK_BUSY;
822 case ENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH;
823 case EDESTADDRREQ: return STATUS_INVALID_PARAMETER;
824 case EMSGSIZE: return STATUS_BUFFER_OVERFLOW;
825 case EPROTONOSUPPORT:
826 case ESOCKTNOSUPPORT:
827 case EPFNOSUPPORT:
828 case EAFNOSUPPORT:
829 case EPROTOTYPE: return STATUS_NOT_SUPPORTED;
830 case ENOPROTOOPT: return STATUS_INVALID_PARAMETER;
831 case EOPNOTSUPP: return STATUS_NOT_SUPPORTED;
832 case EADDRINUSE: return STATUS_SHARING_VIOLATION;
833 case EADDRNOTAVAIL: return STATUS_INVALID_PARAMETER;
834 case ECONNREFUSED: return STATUS_CONNECTION_REFUSED;
835 case ESHUTDOWN: return STATUS_PIPE_DISCONNECTED;
836 case ENOTCONN: return STATUS_INVALID_CONNECTION;
837 case ETIMEDOUT: return STATUS_IO_TIMEOUT;
838 case ENETUNREACH: return STATUS_NETWORK_UNREACHABLE;
839 case ENETDOWN: return STATUS_NETWORK_BUSY;
840 case EPIPE:
841 case ECONNRESET: return STATUS_CONNECTION_RESET;
842 case ECONNABORTED: return STATUS_CONNECTION_ABORTED;
844 case 0: return STATUS_SUCCESS;
845 default:
846 WARN("Unknown errno %d!\n", err);
847 return STATUS_UNSUCCESSFUL;
851 UINT sock_get_error( int err )
853 switch(err)
855 case EINTR: return WSAEINTR;
856 case EPERM:
857 case EACCES: return WSAEACCES;
858 case EFAULT: return WSAEFAULT;
859 case EINVAL: return WSAEINVAL;
860 case EMFILE: return WSAEMFILE;
861 case EINPROGRESS:
862 case EWOULDBLOCK: return WSAEWOULDBLOCK;
863 case EALREADY: return WSAEALREADY;
864 case EBADF:
865 case ENOTSOCK: return WSAENOTSOCK;
866 case EDESTADDRREQ: return WSAEDESTADDRREQ;
867 case EMSGSIZE: return WSAEMSGSIZE;
868 case EPROTOTYPE: return WSAEPROTOTYPE;
869 case ENOPROTOOPT: return WSAENOPROTOOPT;
870 case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
871 case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
872 case EOPNOTSUPP: return WSAEOPNOTSUPP;
873 case EPFNOSUPPORT: return WSAEPFNOSUPPORT;
874 case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
875 case EADDRINUSE: return WSAEADDRINUSE;
876 case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
877 case ENETDOWN: return WSAENETDOWN;
878 case ENETUNREACH: return WSAENETUNREACH;
879 case ENETRESET: return WSAENETRESET;
880 case ECONNABORTED: return WSAECONNABORTED;
881 case EPIPE:
882 case ECONNRESET: return WSAECONNRESET;
883 case ENOBUFS: return WSAENOBUFS;
884 case EISCONN: return WSAEISCONN;
885 case ENOTCONN: return WSAENOTCONN;
886 case ESHUTDOWN: return WSAESHUTDOWN;
887 case ETOOMANYREFS: return WSAETOOMANYREFS;
888 case ETIMEDOUT: return WSAETIMEDOUT;
889 case ECONNREFUSED: return WSAECONNREFUSED;
890 case ELOOP: return WSAELOOP;
891 case ENAMETOOLONG: return WSAENAMETOOLONG;
892 case EHOSTDOWN: return WSAEHOSTDOWN;
893 case EHOSTUNREACH: return WSAEHOSTUNREACH;
894 case ENOTEMPTY: return WSAENOTEMPTY;
895 #ifdef EPROCLIM
896 case EPROCLIM: return WSAEPROCLIM;
897 #endif
898 #ifdef EUSERS
899 case EUSERS: return WSAEUSERS;
900 #endif
901 #ifdef EDQUOT
902 case EDQUOT: return WSAEDQUOT;
903 #endif
904 #ifdef ESTALE
905 case ESTALE: return WSAESTALE;
906 #endif
907 #ifdef EREMOTE
908 case EREMOTE: return WSAEREMOTE;
909 #endif
911 /* just in case we ever get here and there are no problems */
912 case 0: return 0;
913 default:
914 WARN("Unknown errno %d!\n", err);
915 return WSAEOPNOTSUPP;
919 static UINT wsaErrno(void)
921 int loc_errno = errno;
922 WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno));
924 return sock_get_error( loc_errno );
927 /* most ws2 overlapped functions return an ntstatus-based error code */
928 static NTSTATUS wsaErrStatus(void)
930 int loc_errno = errno;
931 WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno));
933 return sock_get_ntstatus(loc_errno);
936 static NTSTATUS sock_error_to_ntstatus( DWORD err )
938 switch (err)
940 case 0: return STATUS_SUCCESS;
941 case WSAEBADF: return STATUS_INVALID_HANDLE;
942 case WSAEACCES: return STATUS_ACCESS_DENIED;
943 case WSAEFAULT: return STATUS_ACCESS_VIOLATION;
944 case WSAEINVAL: return STATUS_INVALID_PARAMETER;
945 case WSAEMFILE: return STATUS_TOO_MANY_OPENED_FILES;
946 case WSAEINPROGRESS:
947 case WSAEWOULDBLOCK: return STATUS_DEVICE_NOT_READY;
948 case WSAEALREADY: return STATUS_NETWORK_BUSY;
949 case WSAENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH;
950 case WSAEDESTADDRREQ: return STATUS_INVALID_PARAMETER;
951 case WSAEMSGSIZE: return STATUS_BUFFER_OVERFLOW;
952 case WSAEPROTONOSUPPORT:
953 case WSAESOCKTNOSUPPORT:
954 case WSAEPFNOSUPPORT:
955 case WSAEAFNOSUPPORT:
956 case WSAEPROTOTYPE: return STATUS_NOT_SUPPORTED;
957 case WSAENOPROTOOPT: return STATUS_INVALID_PARAMETER;
958 case WSAEOPNOTSUPP: return STATUS_NOT_SUPPORTED;
959 case WSAEADDRINUSE: return STATUS_SHARING_VIOLATION;
960 case WSAEADDRNOTAVAIL: return STATUS_INVALID_PARAMETER;
961 case WSAECONNREFUSED: return STATUS_CONNECTION_REFUSED;
962 case WSAESHUTDOWN: return STATUS_PIPE_DISCONNECTED;
963 case WSAENOTCONN: return STATUS_INVALID_CONNECTION;
964 case WSAETIMEDOUT: return STATUS_IO_TIMEOUT;
965 case WSAENETUNREACH: return STATUS_NETWORK_UNREACHABLE;
966 case WSAENETDOWN: return STATUS_NETWORK_BUSY;
967 case WSAECONNRESET: return STATUS_CONNECTION_RESET;
968 case WSAECONNABORTED: return STATUS_CONNECTION_ABORTED;
969 default:
970 FIXME("unmapped error %u\n", err);
971 return STATUS_UNSUCCESSFUL;
975 static DWORD NtStatusToWSAError( NTSTATUS status )
977 static const struct
979 NTSTATUS status;
980 DWORD error;
982 errors[] =
984 {STATUS_PENDING, ERROR_IO_PENDING},
986 {STATUS_BUFFER_OVERFLOW, WSAEMSGSIZE},
988 {STATUS_NOT_IMPLEMENTED, WSAEOPNOTSUPP},
989 {STATUS_ACCESS_VIOLATION, WSAEFAULT},
990 {STATUS_PAGEFILE_QUOTA, WSAENOBUFS},
991 {STATUS_INVALID_HANDLE, WSAENOTSOCK},
992 {STATUS_NO_SUCH_DEVICE, WSAENETDOWN},
993 {STATUS_NO_SUCH_FILE, WSAENETDOWN},
994 {STATUS_NO_MEMORY, WSAENOBUFS},
995 {STATUS_CONFLICTING_ADDRESSES, WSAENOBUFS},
996 {STATUS_ACCESS_DENIED, WSAEACCES},
997 {STATUS_BUFFER_TOO_SMALL, WSAEFAULT},
998 {STATUS_OBJECT_TYPE_MISMATCH, WSAENOTSOCK},
999 {STATUS_OBJECT_NAME_NOT_FOUND, WSAENETDOWN},
1000 {STATUS_OBJECT_PATH_NOT_FOUND, WSAENETDOWN},
1001 {STATUS_SHARING_VIOLATION, WSAEADDRINUSE},
1002 {STATUS_QUOTA_EXCEEDED, WSAENOBUFS},
1003 {STATUS_TOO_MANY_PAGING_FILES, WSAENOBUFS},
1004 {STATUS_INSUFFICIENT_RESOURCES, WSAENOBUFS},
1005 {STATUS_WORKING_SET_QUOTA, WSAENOBUFS},
1006 {STATUS_DEVICE_NOT_READY, WSAEWOULDBLOCK},
1007 {STATUS_PIPE_DISCONNECTED, WSAESHUTDOWN},
1008 {STATUS_IO_TIMEOUT, WSAETIMEDOUT},
1009 {STATUS_NOT_SUPPORTED, WSAEOPNOTSUPP},
1010 {STATUS_REMOTE_NOT_LISTENING, WSAECONNREFUSED},
1011 {STATUS_BAD_NETWORK_PATH, WSAENETUNREACH},
1012 {STATUS_NETWORK_BUSY, WSAENETDOWN},
1013 {STATUS_INVALID_NETWORK_RESPONSE, WSAENETDOWN},
1014 {STATUS_UNEXPECTED_NETWORK_ERROR, WSAENETDOWN},
1015 {STATUS_REQUEST_NOT_ACCEPTED, WSAEWOULDBLOCK},
1016 {STATUS_CANCELLED, ERROR_OPERATION_ABORTED},
1017 {STATUS_COMMITMENT_LIMIT, WSAENOBUFS},
1018 {STATUS_LOCAL_DISCONNECT, WSAECONNABORTED},
1019 {STATUS_REMOTE_DISCONNECT, WSAECONNRESET},
1020 {STATUS_REMOTE_RESOURCES, WSAENOBUFS},
1021 {STATUS_LINK_FAILED, WSAECONNRESET},
1022 {STATUS_LINK_TIMEOUT, WSAETIMEDOUT},
1023 {STATUS_INVALID_CONNECTION, WSAENOTCONN},
1024 {STATUS_INVALID_ADDRESS, WSAEADDRNOTAVAIL},
1025 {STATUS_INVALID_BUFFER_SIZE, WSAEMSGSIZE},
1026 {STATUS_INVALID_ADDRESS_COMPONENT, WSAEADDRNOTAVAIL},
1027 {STATUS_TOO_MANY_ADDRESSES, WSAENOBUFS},
1028 {STATUS_ADDRESS_ALREADY_EXISTS, WSAEADDRINUSE},
1029 {STATUS_CONNECTION_DISCONNECTED, WSAECONNRESET},
1030 {STATUS_CONNECTION_RESET, WSAECONNRESET},
1031 {STATUS_TRANSACTION_ABORTED, WSAECONNABORTED},
1032 {STATUS_CONNECTION_REFUSED, WSAECONNREFUSED},
1033 {STATUS_GRACEFUL_DISCONNECT, WSAEDISCON},
1034 {STATUS_CONNECTION_ACTIVE, WSAEISCONN},
1035 {STATUS_NETWORK_UNREACHABLE, WSAENETUNREACH},
1036 {STATUS_HOST_UNREACHABLE, WSAEHOSTUNREACH},
1037 {STATUS_PROTOCOL_UNREACHABLE, WSAENETUNREACH},
1038 {STATUS_PORT_UNREACHABLE, WSAECONNRESET},
1039 {STATUS_REQUEST_ABORTED, WSAEINTR},
1040 {STATUS_CONNECTION_ABORTED, WSAECONNABORTED},
1041 {STATUS_DATATYPE_MISALIGNMENT_ERROR,WSAEFAULT},
1042 {STATUS_HOST_DOWN, WSAEHOSTDOWN},
1043 {0x80070000 | ERROR_IO_INCOMPLETE, ERROR_IO_INCOMPLETE},
1044 {0xc0010000 | ERROR_IO_INCOMPLETE, ERROR_IO_INCOMPLETE},
1045 {0xc0070000 | ERROR_IO_INCOMPLETE, ERROR_IO_INCOMPLETE},
1048 unsigned int i;
1050 for (i = 0; i < ARRAY_SIZE(errors); ++i)
1052 if (errors[i].status == status)
1053 return errors[i].error;
1056 return NT_SUCCESS(status) ? RtlNtStatusToDosErrorNoTeb(status) : WSAEINVAL;
1059 /* set last error code from NT status without mapping WSA errors */
1060 static inline unsigned int set_error( unsigned int err )
1062 if (err)
1064 err = NtStatusToWSAError( err );
1065 SetLastError( err );
1067 return err;
1070 static inline int get_sock_fd( SOCKET s, DWORD access, unsigned int *options )
1072 int fd;
1073 if (set_error( wine_server_handle_to_fd( SOCKET2HANDLE(s), access, &fd, options ) ))
1074 return -1;
1075 return fd;
1078 static inline void release_sock_fd( SOCKET s, int fd )
1080 close( fd );
1083 static void _enable_event( HANDLE s, unsigned int event,
1084 unsigned int sstate, unsigned int cstate )
1086 SERVER_START_REQ( enable_socket_event )
1088 req->handle = wine_server_obj_handle( s );
1089 req->mask = event;
1090 req->sstate = sstate;
1091 req->cstate = cstate;
1092 wine_server_call( req );
1094 SERVER_END_REQ;
1097 static DWORD sock_is_blocking(SOCKET s, BOOL *ret)
1099 DWORD err;
1100 SERVER_START_REQ( get_socket_event )
1102 req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) );
1103 req->service = FALSE;
1104 req->c_event = 0;
1105 err = NtStatusToWSAError( wine_server_call( req ));
1106 *ret = (reply->state & FD_WINE_NONBLOCKING) == 0;
1108 SERVER_END_REQ;
1109 return err;
1112 static unsigned int _get_sock_mask(SOCKET s)
1114 unsigned int ret;
1115 SERVER_START_REQ( get_socket_event )
1117 req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) );
1118 req->service = FALSE;
1119 req->c_event = 0;
1120 wine_server_call( req );
1121 ret = reply->mask;
1123 SERVER_END_REQ;
1124 return ret;
1127 static void _sync_sock_state(SOCKET s)
1129 BOOL dummy;
1130 /* do a dummy wineserver request in order to let
1131 the wineserver run through its select loop once */
1132 sock_is_blocking(s, &dummy);
1135 static void _get_sock_errors(SOCKET s, int *events)
1137 SERVER_START_REQ( get_socket_event )
1139 req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) );
1140 req->service = FALSE;
1141 req->c_event = 0;
1142 wine_server_set_reply( req, events, sizeof(int) * FD_MAX_EVENTS );
1143 wine_server_call( req );
1145 SERVER_END_REQ;
1148 static int _get_fd_type(int fd)
1150 int sock_type = -1;
1151 socklen_t optlen = sizeof(sock_type);
1152 getsockopt(fd, SOL_SOCKET, SO_TYPE, (char*) &sock_type, &optlen);
1153 return sock_type;
1156 static BOOL set_dont_fragment(SOCKET s, int level, BOOL value)
1158 int fd, optname;
1160 if (level == IPPROTO_IP)
1162 #ifdef IP_DONTFRAG
1163 optname = IP_DONTFRAG;
1164 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) && defined(IP_PMTUDISC_DONT)
1165 optname = IP_MTU_DISCOVER;
1166 value = value ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
1167 #else
1168 static int once;
1169 if (!once++)
1170 FIXME("IP_DONTFRAGMENT for IPv4 not supported in this platform\n");
1171 return TRUE; /* fake success */
1172 #endif
1174 else
1176 #ifdef IPV6_DONTFRAG
1177 optname = IPV6_DONTFRAG;
1178 #elif defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) && defined(IPV6_PMTUDISC_DONT)
1179 optname = IPV6_MTU_DISCOVER;
1180 value = value ? IPV6_PMTUDISC_DO : IPV6_PMTUDISC_DONT;
1181 #else
1182 static int once;
1183 if (!once++)
1184 FIXME("IP_DONTFRAGMENT for IPv6 not supported in this platform\n");
1185 return TRUE; /* fake success */
1186 #endif
1189 fd = get_sock_fd(s, 0, NULL);
1190 if (fd == -1) return FALSE;
1192 if (!setsockopt(fd, level, optname, &value, sizeof(value)))
1193 value = TRUE;
1194 else
1196 WSASetLastError(wsaErrno());
1197 value = FALSE;
1200 release_sock_fd(s, fd);
1201 return value;
1204 static BOOL get_dont_fragment(SOCKET s, int level, BOOL *out)
1206 int fd, optname, value, not_expected;
1207 socklen_t optlen = sizeof(value);
1209 if (level == IPPROTO_IP)
1211 #ifdef IP_DONTFRAG
1212 optname = IP_DONTFRAG;
1213 not_expected = 0;
1214 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1215 optname = IP_MTU_DISCOVER;
1216 not_expected = IP_PMTUDISC_DONT;
1217 #else
1218 static int once;
1219 if (!once++)
1220 FIXME("IP_DONTFRAGMENT for IPv4 not supported in this platform\n");
1221 return TRUE; /* fake success */
1222 #endif
1224 else
1226 #ifdef IPV6_DONTFRAG
1227 optname = IPV6_DONTFRAG;
1228 not_expected = 0;
1229 #elif defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT)
1230 optname = IPV6_MTU_DISCOVER;
1231 not_expected = IPV6_PMTUDISC_DONT;
1232 #else
1233 static int once;
1234 if (!once++)
1235 FIXME("IP_DONTFRAGMENT for IPv6 not supported in this platform\n");
1236 return TRUE; /* fake success */
1237 #endif
1240 fd = get_sock_fd(s, 0, NULL);
1241 if (fd == -1) return FALSE;
1243 if (!getsockopt(fd, level, optname, &value, &optlen))
1245 *out = value != not_expected;
1246 value = TRUE;
1248 else
1250 WSASetLastError(wsaErrno());
1251 value = FALSE;
1254 release_sock_fd(s, fd);
1255 return value;
1258 struct per_thread_data *get_per_thread_data(void)
1260 struct per_thread_data * ptb = NtCurrentTeb()->WinSockData;
1261 /* lazy initialization */
1262 if (!ptb)
1264 ptb = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ptb) );
1265 NtCurrentTeb()->WinSockData = ptb;
1267 return ptb;
1270 static void free_per_thread_data(void)
1272 struct per_thread_data * ptb = NtCurrentTeb()->WinSockData;
1274 if (!ptb) return;
1276 CloseHandle( ptb->sync_event );
1278 /* delete scratch buffers */
1279 HeapFree( GetProcessHeap(), 0, ptb->he_buffer );
1280 HeapFree( GetProcessHeap(), 0, ptb->se_buffer );
1281 HeapFree( GetProcessHeap(), 0, ptb->pe_buffer );
1282 HeapFree( GetProcessHeap(), 0, ptb->fd_cache );
1284 HeapFree( GetProcessHeap(), 0, ptb );
1285 NtCurrentTeb()->WinSockData = NULL;
1288 static HANDLE get_sync_event(void)
1290 struct per_thread_data *data;
1292 if (!(data = get_per_thread_data())) return NULL;
1293 if (!data->sync_event)
1294 data->sync_event = CreateEventW( NULL, TRUE, FALSE, NULL );
1295 return data->sync_event;
1298 /***********************************************************************
1299 * DllMain (WS2_32.init)
1301 BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
1303 if (reason == DLL_THREAD_DETACH)
1304 free_per_thread_data();
1305 return TRUE;
1308 /***********************************************************************
1309 * convert_flags()
1311 * Converts send/recv flags from Windows format.
1312 * Return the converted flag bits, unsupported flags remain unchanged.
1314 static int convert_flags(int flags)
1316 int i, out;
1317 if (!flags) return 0;
1319 for (out = i = 0; flags && i < ARRAY_SIZE(ws_flags_map); i++)
1321 if (ws_flags_map[i][0] & flags)
1323 out |= ws_flags_map[i][1];
1324 flags &= ~ws_flags_map[i][0];
1327 if (flags)
1329 FIXME("Unknown send/recv flags 0x%x, using anyway...\n", flags);
1330 out |= flags;
1332 return out;
1335 /***********************************************************************
1336 * convert_sockopt()
1338 * Converts socket flags from Windows format.
1339 * Return 1 if converted, 0 if not (error).
1341 static int convert_sockopt(INT *level, INT *optname)
1343 unsigned int i;
1344 switch (*level)
1346 case WS_SOL_SOCKET:
1347 *level = SOL_SOCKET;
1348 for(i = 0; i < ARRAY_SIZE(ws_sock_map); i++) {
1349 if( ws_sock_map[i][0] == *optname )
1351 *optname = ws_sock_map[i][1];
1352 return 1;
1355 FIXME("Unknown SOL_SOCKET optname 0x%x\n", *optname);
1356 break;
1357 case WS_IPPROTO_TCP:
1358 *level = IPPROTO_TCP;
1359 for(i = 0; i < ARRAY_SIZE(ws_tcp_map); i++) {
1360 if ( ws_tcp_map[i][0] == *optname )
1362 *optname = ws_tcp_map[i][1];
1363 return 1;
1366 FIXME("Unknown IPPROTO_TCP optname 0x%x\n", *optname);
1367 break;
1368 case WS_IPPROTO_IP:
1369 *level = IPPROTO_IP;
1370 for(i = 0; i < ARRAY_SIZE(ws_ip_map); i++) {
1371 if (ws_ip_map[i][0] == *optname )
1373 *optname = ws_ip_map[i][1];
1374 return 1;
1377 FIXME("Unknown IPPROTO_IP optname 0x%x\n", *optname);
1378 break;
1379 case WS_IPPROTO_IPV6:
1380 *level = IPPROTO_IPV6;
1381 for(i = 0; i < ARRAY_SIZE(ws_ipv6_map); i++) {
1382 if (ws_ipv6_map[i][0] == *optname )
1384 *optname = ws_ipv6_map[i][1];
1385 return 1;
1388 FIXME("Unknown IPPROTO_IPV6 optname 0x%x\n", *optname);
1389 break;
1390 default: FIXME("Unimplemented or unknown socket level\n");
1392 return 0;
1395 /* Utility: get the SO_RCVTIMEO or SO_SNDTIMEO socket option
1396 * from an fd and return the value converted to milli seconds
1397 * or 0 if there is an infinite time out */
1398 static inline INT64 get_rcvsnd_timeo( int fd, BOOL is_recv)
1400 struct timeval tv;
1401 socklen_t len = sizeof(tv);
1402 int optname, res;
1404 if (is_recv)
1405 #ifdef SO_RCVTIMEO
1406 optname = SO_RCVTIMEO;
1407 #else
1408 return 0;
1409 #endif
1410 else
1411 #ifdef SO_SNDTIMEO
1412 optname = SO_SNDTIMEO;
1413 #else
1414 return 0;
1415 #endif
1417 res = getsockopt(fd, SOL_SOCKET, optname, &tv, &len);
1418 if (res < 0)
1419 return 0;
1420 return (UINT64)tv.tv_sec * 1000 + tv.tv_usec / 1000;
1423 /* utility: given an fd, will block until one of the events occurs */
1424 static inline int do_block( int fd, int events, int timeout )
1426 struct pollfd pfd;
1427 int ret;
1429 pfd.fd = fd;
1430 pfd.events = events;
1432 while ((ret = poll(&pfd, 1, timeout)) < 0)
1434 if (errno != EINTR)
1435 return -1;
1437 if( ret == 0 )
1438 return 0;
1439 return pfd.revents;
1443 convert_socktype_w2u(int windowssocktype) {
1444 unsigned int i;
1446 for (i = 0; i < ARRAY_SIZE(ws_socktype_map); i++)
1447 if (ws_socktype_map[i][0] == windowssocktype)
1448 return ws_socktype_map[i][1];
1449 FIXME("unhandled Windows socket type %d\n", windowssocktype);
1450 return -1;
1454 convert_socktype_u2w(int unixsocktype) {
1455 unsigned int i;
1457 for (i = 0; i < ARRAY_SIZE(ws_socktype_map); i++)
1458 if (ws_socktype_map[i][1] == unixsocktype)
1459 return ws_socktype_map[i][0];
1460 FIXME("unhandled UNIX socket type %d\n", unixsocktype);
1461 return -1;
1464 static int convert_poll_w2u(int events)
1466 int i, ret;
1467 for (i = ret = 0; events && i < ARRAY_SIZE(ws_poll_map); i++)
1469 if (ws_poll_map[i][0] & events)
1471 ret |= ws_poll_map[i][1];
1472 events &= ~ws_poll_map[i][0];
1476 if (events)
1477 FIXME("Unsupported WSAPoll() flags 0x%x\n", events);
1478 return ret;
1481 static int convert_poll_u2w(int events)
1483 int i, ret;
1484 for (i = ret = 0; events && i < ARRAY_SIZE(ws_poll_map); i++)
1486 if (ws_poll_map[i][1] & events)
1488 ret |= ws_poll_map[i][0];
1489 events &= ~ws_poll_map[i][1];
1493 if (events)
1494 FIXME("Unsupported poll() flags 0x%x\n", events);
1495 return ret;
1498 static int set_ipx_packettype(int sock, int ptype)
1500 #ifdef HAS_IPX
1501 int fd = get_sock_fd( sock, 0, NULL ), ret = 0;
1502 TRACE("trying to set IPX_PTYPE: %d (fd: %d)\n", ptype, fd);
1504 if (fd == -1) return SOCKET_ERROR;
1506 /* We try to set the ipx type on ipx socket level. */
1507 #ifdef SOL_IPX
1508 if(setsockopt(fd, SOL_IPX, IPX_TYPE, &ptype, sizeof(ptype)) == -1)
1510 ERR("IPX: could not set ipx option type; expect weird behaviour\n");
1511 ret = SOCKET_ERROR;
1513 #else
1515 struct ipx val;
1516 /* Should we retrieve val using a getsockopt call and then
1517 * set the modified one? */
1518 val.ipx_pt = ptype;
1519 setsockopt(fd, 0, SO_DEFAULT_HEADERS, &val, sizeof(struct ipx));
1521 #endif
1522 release_sock_fd( sock, fd );
1523 return ret;
1524 #else
1525 WARN("IPX support is not enabled, can't set packet type\n");
1526 return SOCKET_ERROR;
1527 #endif
1530 /* ----------------------------------- API -----
1532 * Init / cleanup / error checking.
1535 /***********************************************************************
1536 * WSAStartup (WS2_32.115)
1538 int WINAPI WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData)
1540 TRACE("verReq=%x\n", wVersionRequested);
1542 if (LOBYTE(wVersionRequested) < 1)
1543 return WSAVERNOTSUPPORTED;
1545 if (!lpWSAData) return WSAEINVAL;
1547 num_startup++;
1549 /* that's the whole of the negotiation for now */
1550 lpWSAData->wVersion = wVersionRequested;
1551 /* return winsock information */
1552 lpWSAData->wHighVersion = 0x0202;
1553 strcpy(lpWSAData->szDescription, "WinSock 2.0" );
1554 strcpy(lpWSAData->szSystemStatus, "Running" );
1555 lpWSAData->iMaxSockets = WS_MAX_SOCKETS_PER_PROCESS;
1556 lpWSAData->iMaxUdpDg = WS_MAX_UDP_DATAGRAM;
1557 /* don't do anything with lpWSAData->lpVendorInfo */
1558 /* (some apps don't allocate the space for this field) */
1560 TRACE("succeeded starts: %d\n", num_startup);
1561 return 0;
1565 /***********************************************************************
1566 * WSACleanup (WS2_32.116)
1568 INT WINAPI WSACleanup(void)
1570 TRACE("decreasing startup count from %d\n", num_startup);
1571 if (num_startup)
1573 if (!--num_startup)
1575 unsigned int i;
1577 for (i = 0; i < socket_list_size; ++i)
1578 CloseHandle(SOCKET2HANDLE(socket_list[i]));
1579 memset(socket_list, 0, socket_list_size * sizeof(*socket_list));
1581 return 0;
1583 SetLastError(WSANOTINITIALISED);
1584 return SOCKET_ERROR;
1588 /***********************************************************************
1589 * WSAGetLastError (WS2_32.111)
1591 INT WINAPI WSAGetLastError(void)
1593 return GetLastError();
1596 /***********************************************************************
1597 * WSASetLastError (WS2_32.112)
1599 void WINAPI WSASetLastError(INT iError) {
1600 SetLastError(iError);
1603 static inline BOOL supported_pf(int pf)
1605 switch (pf)
1607 case WS_AF_INET:
1608 case WS_AF_INET6:
1609 return TRUE;
1610 #ifdef HAS_IPX
1611 case WS_AF_IPX:
1612 return TRUE;
1613 #endif
1614 #ifdef HAS_IRDA
1615 case WS_AF_IRDA:
1616 return TRUE;
1617 #endif
1618 default:
1619 return FALSE;
1623 /**********************************************************************/
1625 /* Returns the length of the converted address if successful, 0 if it was too
1626 * small to start with or unknown family or invalid address buffer.
1628 unsigned int ws_sockaddr_ws2u( const struct WS_sockaddr *wsaddr, int wsaddrlen,
1629 union generic_unix_sockaddr *uaddr )
1631 unsigned int uaddrlen = 0;
1633 if (!wsaddr)
1634 return 0;
1636 switch (wsaddr->sa_family)
1638 #ifdef HAS_IPX
1639 case WS_AF_IPX:
1641 const struct WS_sockaddr_ipx* wsipx=(const struct WS_sockaddr_ipx*)wsaddr;
1642 struct sockaddr_ipx* uipx = (struct sockaddr_ipx *)uaddr;
1644 if (wsaddrlen<sizeof(struct WS_sockaddr_ipx))
1645 return 0;
1647 uaddrlen = sizeof(struct sockaddr_ipx);
1648 memset( uaddr, 0, uaddrlen );
1649 uipx->sipx_family=AF_IPX;
1650 uipx->sipx_port=wsipx->sa_socket;
1651 /* copy sa_netnum and sa_nodenum to sipx_network and sipx_node
1652 * in one go
1654 memcpy(&uipx->sipx_network,wsipx->sa_netnum,sizeof(uipx->sipx_network)+sizeof(uipx->sipx_node));
1655 #ifdef IPX_FRAME_NONE
1656 uipx->sipx_type=IPX_FRAME_NONE;
1657 #endif
1658 break;
1660 #endif
1661 case WS_AF_INET6: {
1662 struct sockaddr_in6* uin6 = (struct sockaddr_in6 *)uaddr;
1663 const struct WS_sockaddr_in6* win6 = (const struct WS_sockaddr_in6*)wsaddr;
1665 /* Note: Windows has 2 versions of the sockaddr_in6 struct, one with
1666 * scope_id, one without.
1668 if (wsaddrlen >= sizeof(struct WS_sockaddr_in6_old)) {
1669 uaddrlen = sizeof(struct sockaddr_in6);
1670 memset( uaddr, 0, uaddrlen );
1671 uin6->sin6_family = AF_INET6;
1672 uin6->sin6_port = win6->sin6_port;
1673 uin6->sin6_flowinfo = win6->sin6_flowinfo;
1674 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
1675 if (wsaddrlen >= sizeof(struct WS_sockaddr_in6)) uin6->sin6_scope_id = win6->sin6_scope_id;
1676 #endif
1677 memcpy(&uin6->sin6_addr,&win6->sin6_addr,16); /* 16 bytes = 128 address bits */
1678 break;
1680 FIXME("bad size %d for WS_sockaddr_in6\n",wsaddrlen);
1681 return 0;
1683 case WS_AF_INET: {
1684 struct sockaddr_in* uin = (struct sockaddr_in *)uaddr;
1685 const struct WS_sockaddr_in* win = (const struct WS_sockaddr_in*)wsaddr;
1687 if (wsaddrlen<sizeof(struct WS_sockaddr_in))
1688 return 0;
1689 uaddrlen = sizeof(struct sockaddr_in);
1690 memset( uaddr, 0, uaddrlen );
1691 uin->sin_family = AF_INET;
1692 uin->sin_port = win->sin_port;
1693 memcpy(&uin->sin_addr,&win->sin_addr,4); /* 4 bytes = 32 address bits */
1694 break;
1696 #ifdef HAS_IRDA
1697 case WS_AF_IRDA: {
1698 struct sockaddr_irda *uin = (struct sockaddr_irda *)uaddr;
1699 const SOCKADDR_IRDA *win = (const SOCKADDR_IRDA *)wsaddr;
1701 if (wsaddrlen < sizeof(SOCKADDR_IRDA))
1702 return 0;
1703 uaddrlen = sizeof(struct sockaddr_irda);
1704 memset( uaddr, 0, uaddrlen );
1705 uin->sir_family = AF_IRDA;
1706 if (!strncmp( win->irdaServiceName, "LSAP-SEL", strlen( "LSAP-SEL" ) ))
1708 unsigned int lsap_sel = 0;
1710 sscanf( win->irdaServiceName, "LSAP-SEL%u", &lsap_sel );
1711 uin->sir_lsap_sel = lsap_sel;
1713 else
1715 uin->sir_lsap_sel = LSAP_ANY;
1716 memcpy( uin->sir_name, win->irdaServiceName, 25 );
1718 memcpy( &uin->sir_addr, win->irdaDeviceID, sizeof(uin->sir_addr) );
1719 break;
1721 #endif
1722 case WS_AF_UNSPEC: {
1723 /* Try to determine the needed space by the passed windows sockaddr space */
1724 switch (wsaddrlen) {
1725 default: /* likely an ipv4 address */
1726 case sizeof(struct WS_sockaddr_in):
1727 uaddrlen = sizeof(struct sockaddr_in);
1728 break;
1729 #ifdef HAS_IPX
1730 case sizeof(struct WS_sockaddr_ipx):
1731 uaddrlen = sizeof(struct sockaddr_ipx);
1732 break;
1733 #endif
1734 #ifdef HAS_IRDA
1735 case sizeof(SOCKADDR_IRDA):
1736 uaddrlen = sizeof(struct sockaddr_irda);
1737 break;
1738 #endif
1739 case sizeof(struct WS_sockaddr_in6):
1740 case sizeof(struct WS_sockaddr_in6_old):
1741 uaddrlen = sizeof(struct sockaddr_in6);
1742 break;
1744 memset( uaddr, 0, uaddrlen );
1745 break;
1747 default:
1748 FIXME("Unknown address family %d, return NULL.\n", wsaddr->sa_family);
1749 return 0;
1751 return uaddrlen;
1754 static BOOL is_sockaddr_bound(const struct sockaddr *uaddr, int uaddrlen)
1756 switch (uaddr->sa_family)
1758 #ifdef HAS_IPX
1759 case AF_IPX:
1761 static const struct sockaddr_ipx emptyAddr;
1762 struct sockaddr_ipx *ipx = (struct sockaddr_ipx*) uaddr;
1763 return ipx->sipx_port
1764 || memcmp(&ipx->sipx_network, &emptyAddr.sipx_network, sizeof(emptyAddr.sipx_network))
1765 || memcmp(&ipx->sipx_node, &emptyAddr.sipx_node, sizeof(emptyAddr.sipx_node));
1767 #endif
1768 case AF_INET6:
1770 static const struct sockaddr_in6 emptyAddr;
1771 const struct sockaddr_in6 *in6 = (const struct sockaddr_in6*) uaddr;
1772 return in6->sin6_port || memcmp(&in6->sin6_addr, &emptyAddr.sin6_addr, sizeof(struct in6_addr));
1774 case AF_INET:
1776 static const struct sockaddr_in emptyAddr;
1777 const struct sockaddr_in *in = (const struct sockaddr_in*) uaddr;
1778 return in->sin_port || memcmp(&in->sin_addr, &emptyAddr.sin_addr, sizeof(struct in_addr));
1780 case AF_UNSPEC:
1781 return FALSE;
1782 default:
1783 FIXME("unknown address family %d\n", uaddr->sa_family);
1784 return TRUE;
1788 /* Returns -1 if getsockname fails, 0 if not bound, 1 otherwise */
1789 static int is_fd_bound(int fd, union generic_unix_sockaddr *uaddr, socklen_t *uaddrlen)
1791 union generic_unix_sockaddr inaddr;
1792 socklen_t inlen;
1793 int res;
1795 if (!uaddr) uaddr = &inaddr;
1796 if (!uaddrlen) uaddrlen = &inlen;
1798 *uaddrlen = sizeof(inaddr);
1799 res = getsockname(fd, &uaddr->addr, uaddrlen);
1800 if (!res) res = is_sockaddr_bound(&uaddr->addr, *uaddrlen);
1801 return res;
1804 /* Returns 0 if successful, -1 if the buffer is too small */
1805 int ws_sockaddr_u2ws(const struct sockaddr *uaddr, struct WS_sockaddr *wsaddr, int *wsaddrlen)
1807 int res;
1809 switch(uaddr->sa_family)
1811 #ifdef HAS_IPX
1812 case AF_IPX:
1814 const struct sockaddr_ipx* uipx=(const struct sockaddr_ipx*)uaddr;
1815 struct WS_sockaddr_ipx* wsipx=(struct WS_sockaddr_ipx*)wsaddr;
1817 res=-1;
1818 switch (*wsaddrlen) /* how much can we copy? */
1820 default:
1821 res=0; /* enough */
1822 *wsaddrlen = sizeof(*wsipx);
1823 wsipx->sa_socket=uipx->sipx_port;
1824 /* fall through */
1825 case 13:
1826 case 12:
1827 memcpy(wsipx->sa_nodenum,uipx->sipx_node,sizeof(wsipx->sa_nodenum));
1828 /* fall through */
1829 case 11:
1830 case 10:
1831 case 9:
1832 case 8:
1833 case 7:
1834 case 6:
1835 memcpy(wsipx->sa_netnum,&uipx->sipx_network,sizeof(wsipx->sa_netnum));
1836 /* fall through */
1837 case 5:
1838 case 4:
1839 case 3:
1840 case 2:
1841 wsipx->sa_family=WS_AF_IPX;
1842 /* fall through */
1843 case 1:
1844 case 0:
1845 /* way too small */
1846 break;
1849 break;
1850 #endif
1851 #ifdef HAS_IRDA
1852 case AF_IRDA: {
1853 const struct sockaddr_irda *uin = (const struct sockaddr_irda *)uaddr;
1854 SOCKADDR_IRDA *win = (SOCKADDR_IRDA *)wsaddr;
1856 if (*wsaddrlen < sizeof(SOCKADDR_IRDA))
1857 return -1;
1858 win->irdaAddressFamily = WS_AF_IRDA;
1859 memcpy( win->irdaDeviceID, &uin->sir_addr, sizeof(win->irdaDeviceID) );
1860 if (uin->sir_lsap_sel != LSAP_ANY)
1861 sprintf( win->irdaServiceName, "LSAP-SEL%u", uin->sir_lsap_sel );
1862 else
1863 memcpy( win->irdaServiceName, uin->sir_name,
1864 sizeof(win->irdaServiceName) );
1865 return 0;
1867 #endif
1868 case AF_INET6: {
1869 const struct sockaddr_in6* uin6 = (const struct sockaddr_in6*)uaddr;
1870 struct WS_sockaddr_in6_old* win6old = (struct WS_sockaddr_in6_old*)wsaddr;
1872 if (*wsaddrlen < sizeof(struct WS_sockaddr_in6_old))
1873 return -1;
1874 win6old->sin6_family = WS_AF_INET6;
1875 win6old->sin6_port = uin6->sin6_port;
1876 win6old->sin6_flowinfo = uin6->sin6_flowinfo;
1877 memcpy(&win6old->sin6_addr,&uin6->sin6_addr,16); /* 16 bytes = 128 address bits */
1878 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
1879 if (*wsaddrlen >= sizeof(struct WS_sockaddr_in6)) {
1880 struct WS_sockaddr_in6* win6 = (struct WS_sockaddr_in6*)wsaddr;
1881 win6->sin6_scope_id = uin6->sin6_scope_id;
1882 *wsaddrlen = sizeof(struct WS_sockaddr_in6);
1884 else
1885 *wsaddrlen = sizeof(struct WS_sockaddr_in6_old);
1886 #else
1887 *wsaddrlen = sizeof(struct WS_sockaddr_in6_old);
1888 #endif
1889 return 0;
1891 case AF_INET: {
1892 const struct sockaddr_in* uin = (const struct sockaddr_in*)uaddr;
1893 struct WS_sockaddr_in* win = (struct WS_sockaddr_in*)wsaddr;
1895 if (*wsaddrlen < sizeof(struct WS_sockaddr_in))
1896 return -1;
1897 win->sin_family = WS_AF_INET;
1898 win->sin_port = uin->sin_port;
1899 memcpy(&win->sin_addr,&uin->sin_addr,4); /* 4 bytes = 32 address bits */
1900 memset(win->sin_zero, 0, 8); /* Make sure the null padding is null */
1901 *wsaddrlen = sizeof(struct WS_sockaddr_in);
1902 return 0;
1904 case AF_UNSPEC: {
1905 memset(wsaddr,0,*wsaddrlen);
1906 return 0;
1908 default:
1909 FIXME("Unknown address family %d\n", uaddr->sa_family);
1910 return -1;
1912 return res;
1915 static INT WS_DuplicateSocket(BOOL unicode, SOCKET s, DWORD dwProcessId, LPWSAPROTOCOL_INFOW lpProtocolInfo)
1917 HANDLE hProcess;
1918 int size;
1919 WSAPROTOCOL_INFOW infow;
1921 TRACE("(unicode %d, socket %04lx, processid %x, buffer %p)\n",
1922 unicode, s, dwProcessId, lpProtocolInfo);
1924 if (!ws_protocol_info(s, unicode, &infow, &size))
1925 return SOCKET_ERROR;
1927 if (!(hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId)))
1929 SetLastError(WSAEINVAL);
1930 return SOCKET_ERROR;
1933 if (!lpProtocolInfo)
1935 CloseHandle(hProcess);
1936 SetLastError(WSAEFAULT);
1937 return SOCKET_ERROR;
1940 /* I don't know what the real Windoze does next, this is a hack */
1941 /* ...we could duplicate and then use ConvertToGlobalHandle on the duplicate, then let
1942 * the target use the global duplicate, or we could copy a reference to us to the structure
1943 * and let the target duplicate it from us, but let's do it as simple as possible */
1944 memcpy(lpProtocolInfo, &infow, size);
1945 DuplicateHandle(GetCurrentProcess(), SOCKET2HANDLE(s),
1946 hProcess, (LPHANDLE)&lpProtocolInfo->dwServiceFlags3,
1947 0, FALSE, DUPLICATE_SAME_ACCESS);
1948 CloseHandle(hProcess);
1949 lpProtocolInfo->dwServiceFlags4 = 0xff00ff00; /* magic */
1950 return 0;
1953 static BOOL ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, int *size)
1955 NTSTATUS status;
1956 int address_family;
1957 int socket_type;
1958 int protocol;
1959 unsigned int i;
1961 *size = unicode ? sizeof(WSAPROTOCOL_INFOW) : sizeof(WSAPROTOCOL_INFOA);
1962 memset(buffer, 0, *size);
1964 SERVER_START_REQ( get_socket_info )
1966 req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) );
1967 status = wine_server_call( req );
1968 if (!status)
1970 address_family = reply->family;
1971 socket_type = reply->type;
1972 protocol = reply->protocol;
1975 SERVER_END_REQ;
1977 if (status)
1979 unsigned int err = NtStatusToWSAError( status );
1980 SetLastError( err == WSAEBADF ? WSAENOTSOCK : err );
1981 return FALSE;
1984 for (i = 0; i < ARRAY_SIZE(supported_protocols); ++i)
1986 const WSAPROTOCOL_INFOW *info = &supported_protocols[i];
1987 if (address_family == info->iAddressFamily &&
1988 socket_type == info->iSocketType &&
1989 protocol >= info->iProtocol && protocol <= info->iProtocol + info->iProtocolMaxOffset)
1991 if (unicode)
1992 *buffer = *info;
1993 else
1995 WSAPROTOCOL_INFOA *bufferA = (WSAPROTOCOL_INFOA *)buffer;
1996 memcpy( bufferA, info, offsetof( WSAPROTOCOL_INFOW, szProtocol ) );
1997 WideCharToMultiByte( CP_ACP, 0, info->szProtocol, -1,
1998 bufferA->szProtocol, sizeof(bufferA->szProtocol), NULL, NULL );
2000 buffer->iProtocol = protocol;
2001 return TRUE;
2004 FIXME("Could not fill protocol information for family %d, type %d, protocol %d.\n",
2005 address_family, socket_type, protocol);
2006 return TRUE;
2009 /**************************************************************************
2010 * Functions for handling overlapped I/O
2011 **************************************************************************/
2013 /* user APC called upon async completion */
2014 static void WINAPI ws2_async_apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
2016 struct ws2_async *wsa = arg;
2018 if (wsa->completion_func) wsa->completion_func( NtStatusToWSAError(iosb->u.Status),
2019 iosb->Information, wsa->user_overlapped,
2020 wsa->flags );
2021 release_async_io( &wsa->io );
2024 /***********************************************************************
2025 * WS2_recv (INTERNAL)
2027 * Workhorse for both synchronous and asynchronous recv() operations.
2029 static int WS2_recv( int fd, struct ws2_async *wsa, int flags )
2031 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
2032 char pktbuf[512];
2033 #endif
2034 struct msghdr hdr;
2035 union generic_unix_sockaddr unix_sockaddr;
2036 int n;
2038 hdr.msg_name = NULL;
2040 if (wsa->addr)
2042 hdr.msg_namelen = sizeof(unix_sockaddr);
2043 hdr.msg_name = &unix_sockaddr;
2045 else
2046 hdr.msg_namelen = 0;
2048 hdr.msg_iov = wsa->iovec + wsa->first_iovec;
2049 hdr.msg_iovlen = wsa->n_iovecs - wsa->first_iovec;
2050 #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
2051 hdr.msg_accrights = NULL;
2052 hdr.msg_accrightslen = 0;
2053 #else
2054 hdr.msg_control = pktbuf;
2055 hdr.msg_controllen = sizeof(pktbuf);
2056 hdr.msg_flags = 0;
2057 #endif
2059 while ((n = __wine_locked_recvmsg( fd, &hdr, flags )) == -1)
2061 if (errno != EINTR)
2062 return -1;
2065 #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
2066 if (wsa->control)
2068 ERR("Message control headers cannot be properly supported on this system.\n");
2069 wsa->control->len = 0;
2071 #else
2072 if (wsa->control && !convert_control_headers(&hdr, wsa->control))
2074 WARN("Application passed insufficient room for control headers.\n");
2075 *wsa->lpFlags |= WS_MSG_CTRUNC;
2076 errno = EMSGSIZE;
2077 return -1;
2079 #endif
2081 /* if this socket is connected and lpFrom is not NULL, Linux doesn't give us
2082 * msg_name and msg_namelen from recvmsg, but it does set msg_namelen to zero.
2084 * quoting linux 2.6 net/ipv4/tcp.c:
2085 * "According to UNIX98, msg_name/msg_namelen are ignored
2086 * on connected socket. I was just happy when found this 8) --ANK"
2088 * likewise MSDN says that lpFrom and lpFromlen are ignored for
2089 * connection-oriented sockets, so don't try to update lpFrom.
2091 if (wsa->addr && hdr.msg_namelen)
2092 ws_sockaddr_u2ws( &unix_sockaddr.addr, wsa->addr, wsa->addrlen.ptr );
2094 return n;
2097 /***********************************************************************
2098 * WS2_async_recv (INTERNAL)
2100 * Handler for overlapped recv() operations.
2102 static NTSTATUS WS2_async_recv( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
2104 struct ws2_async *wsa = user;
2105 int result = 0, fd;
2107 switch (status)
2109 case STATUS_ALERTED:
2110 if ((status = wine_server_handle_to_fd( wsa->hSocket, FILE_READ_DATA, &fd, NULL ) ))
2111 break;
2113 result = WS2_recv( fd, wsa, convert_flags(wsa->flags) );
2114 close( fd );
2115 if (result >= 0)
2117 status = STATUS_SUCCESS;
2118 _enable_event( wsa->hSocket, (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0 );
2120 else
2122 if (errno == EAGAIN)
2124 status = STATUS_PENDING;
2125 _enable_event( wsa->hSocket, (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0 );
2127 else
2129 result = 0;
2130 status = wsaErrStatus();
2133 break;
2135 if (status != STATUS_PENDING)
2137 iosb->u.Status = status;
2138 iosb->Information = result;
2139 if (!wsa->completion_func)
2140 release_async_io( &wsa->io );
2142 return status;
2145 /***********************************************************************
2146 * WS2_send (INTERNAL)
2148 * Workhorse for both synchronous and asynchronous send() operations.
2150 static int WS2_send( int fd, struct ws2_async *wsa, int flags )
2152 struct msghdr hdr;
2153 union generic_unix_sockaddr unix_addr;
2154 int n, ret;
2156 hdr.msg_name = NULL;
2157 hdr.msg_namelen = 0;
2159 if (wsa->addr)
2161 hdr.msg_name = &unix_addr;
2162 hdr.msg_namelen = ws_sockaddr_ws2u( wsa->addr, wsa->addrlen.val, &unix_addr );
2163 if ( !hdr.msg_namelen )
2165 errno = EFAULT;
2166 return -1;
2169 #if defined(HAS_IPX) && defined(SOL_IPX)
2170 if(wsa->addr->sa_family == WS_AF_IPX)
2172 struct sockaddr_ipx* uipx = (struct sockaddr_ipx*)hdr.msg_name;
2173 int val=0;
2174 socklen_t len = sizeof(int);
2176 /* The packet type is stored at the ipx socket level; At least the linux kernel seems
2177 * to do something with it in case hdr.msg_name is NULL. Nonetheless can we use it to store
2178 * the packet type and then we can retrieve it using getsockopt. After that we can set the
2179 * ipx type in the sockaddr_opx structure with the stored value.
2181 if(getsockopt(fd, SOL_IPX, IPX_TYPE, &val, &len) != -1)
2182 uipx->sipx_type = val;
2184 #endif
2187 hdr.msg_iov = wsa->iovec + wsa->first_iovec;
2188 hdr.msg_iovlen = wsa->n_iovecs - wsa->first_iovec;
2189 #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
2190 hdr.msg_accrights = NULL;
2191 hdr.msg_accrightslen = 0;
2192 #else
2193 hdr.msg_control = NULL;
2194 hdr.msg_controllen = 0;
2195 hdr.msg_flags = 0;
2196 #endif
2198 while ((ret = sendmsg(fd, &hdr, flags)) == -1)
2200 if (errno == EISCONN)
2202 hdr.msg_name = 0;
2203 hdr.msg_namelen = 0;
2204 continue;
2206 if (errno != EINTR)
2207 return -1;
2210 n = ret;
2211 while (wsa->first_iovec < wsa->n_iovecs && wsa->iovec[wsa->first_iovec].iov_len <= n)
2212 n -= wsa->iovec[wsa->first_iovec++].iov_len;
2213 if (wsa->first_iovec < wsa->n_iovecs)
2215 wsa->iovec[wsa->first_iovec].iov_base = (char*)wsa->iovec[wsa->first_iovec].iov_base + n;
2216 wsa->iovec[wsa->first_iovec].iov_len -= n;
2218 return ret;
2221 /***********************************************************************
2222 * WS2_async_send (INTERNAL)
2224 * Handler for overlapped send() operations.
2226 static NTSTATUS WS2_async_send( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
2228 struct ws2_async *wsa = user;
2229 int result = 0, fd;
2231 switch (status)
2233 case STATUS_ALERTED:
2234 if ( wsa->n_iovecs <= wsa->first_iovec )
2236 /* Nothing to do */
2237 status = STATUS_SUCCESS;
2238 break;
2240 if ((status = wine_server_handle_to_fd( wsa->hSocket, FILE_WRITE_DATA, &fd, NULL ) ))
2241 break;
2243 /* check to see if the data is ready (non-blocking) */
2244 result = WS2_send( fd, wsa, convert_flags(wsa->flags) );
2245 close( fd );
2247 if (result >= 0)
2249 if (wsa->first_iovec < wsa->n_iovecs)
2250 status = STATUS_PENDING;
2251 else
2252 status = STATUS_SUCCESS;
2254 iosb->Information += result;
2256 else if (errno == EAGAIN)
2258 status = STATUS_PENDING;
2260 else
2262 status = wsaErrStatus();
2264 break;
2266 if (status != STATUS_PENDING)
2268 iosb->u.Status = status;
2269 if (!wsa->completion_func)
2270 release_async_io( &wsa->io );
2272 return status;
2275 /***********************************************************************
2276 * WS2_async_shutdown (INTERNAL)
2278 * Handler for shutdown() operations on overlapped sockets.
2280 static NTSTATUS WS2_async_shutdown( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
2282 struct ws2_async_shutdown *wsa = user;
2283 int fd, err = 1;
2285 switch (status)
2287 case STATUS_ALERTED:
2288 if ((status = wine_server_handle_to_fd( wsa->hSocket, 0, &fd, NULL ) ))
2289 break;
2291 switch ( wsa->type )
2293 case ASYNC_TYPE_READ: err = shutdown( fd, 0 ); break;
2294 case ASYNC_TYPE_WRITE: err = shutdown( fd, 1 ); break;
2296 status = err ? wsaErrStatus() : STATUS_SUCCESS;
2297 close( fd );
2298 break;
2300 iosb->u.Status = status;
2301 iosb->Information = 0;
2302 release_async_io( &wsa->io );
2303 return status;
2306 /***********************************************************************
2307 * WS2_register_async_shutdown (INTERNAL)
2309 * Helper function for WS_shutdown() on overlapped sockets.
2311 static int WS2_register_async_shutdown( SOCKET s, int type )
2313 struct ws2_async_shutdown *wsa;
2314 NTSTATUS status;
2316 TRACE("socket %04lx type %d\n", s, type);
2318 wsa = (struct ws2_async_shutdown *)alloc_async_io( sizeof(*wsa), WS2_async_shutdown );
2319 if ( !wsa )
2320 return WSAEFAULT;
2322 wsa->hSocket = SOCKET2HANDLE(s);
2323 wsa->type = type;
2325 status = register_async( type, wsa->hSocket, &wsa->io, 0, NULL, NULL, &wsa->iosb );
2326 if (status != STATUS_PENDING)
2328 HeapFree( GetProcessHeap(), 0, wsa );
2329 return NtStatusToWSAError( status );
2331 return 0;
2334 /***********************************************************************
2335 * accept (WS2_32.1)
2337 SOCKET WINAPI WS_accept( SOCKET s, struct WS_sockaddr *addr, int *len )
2339 IO_STATUS_BLOCK io;
2340 NTSTATUS status;
2341 obj_handle_t accept_handle;
2342 HANDLE sync_event;
2343 SOCKET ret;
2345 TRACE("%#lx\n", s);
2347 if (!(sync_event = get_sync_event())) return INVALID_SOCKET;
2348 status = NtDeviceIoControlFile( (HANDLE)s, sync_event, NULL, NULL, &io, IOCTL_AFD_WINE_ACCEPT,
2349 NULL, 0, &accept_handle, sizeof(accept_handle) );
2350 if (status == STATUS_PENDING)
2352 if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED)
2353 return SOCKET_ERROR;
2354 status = io.u.Status;
2356 if (status)
2358 WARN("failed; status %#x\n", status);
2359 WSASetLastError( NtStatusToWSAError( status ) );
2360 return INVALID_SOCKET;
2363 ret = HANDLE2SOCKET(wine_server_ptr_handle( accept_handle ));
2364 if (!socket_list_add( ret ))
2366 CloseHandle( SOCKET2HANDLE(ret) );
2367 return INVALID_SOCKET;
2369 if (addr && len && WS_getpeername( ret, addr, len ))
2371 WS_closesocket( ret );
2372 return INVALID_SOCKET;
2375 TRACE("returning %#lx\n", ret);
2376 return ret;
2379 /***********************************************************************
2380 * AcceptEx
2382 static BOOL WINAPI WS2_AcceptEx( SOCKET listener, SOCKET acceptor, void *dest, DWORD recv_len,
2383 DWORD local_len, DWORD remote_len, DWORD *ret_len, OVERLAPPED *overlapped)
2385 struct afd_accept_into_params params =
2387 .accept_handle = acceptor,
2388 .recv_len = recv_len,
2389 .local_len = local_len,
2391 void *cvalue = NULL;
2392 NTSTATUS status;
2394 TRACE( "listener %#lx, acceptor %#lx, dest %p, recv_len %u, local_len %u, remote_len %u, ret_len %p, "
2395 "overlapped %p\n", listener, acceptor, dest, recv_len, local_len, remote_len, ret_len, overlapped );
2397 if (!overlapped)
2399 SetLastError(WSA_INVALID_PARAMETER);
2400 return FALSE;
2403 if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped;
2404 overlapped->Internal = STATUS_PENDING;
2405 overlapped->InternalHigh = 0;
2407 if (!dest)
2409 SetLastError(WSAEINVAL);
2410 return FALSE;
2413 if (!remote_len)
2415 SetLastError(WSAEFAULT);
2416 return FALSE;
2419 status = NtDeviceIoControlFile( SOCKET2HANDLE(listener), overlapped->hEvent, NULL, cvalue,
2420 (IO_STATUS_BLOCK *)overlapped, IOCTL_AFD_WINE_ACCEPT_INTO, &params, sizeof(params),
2421 dest, recv_len + local_len + remote_len );
2423 if (ret_len) *ret_len = overlapped->InternalHigh;
2424 WSASetLastError( NtStatusToWSAError(status) );
2425 return !status;
2428 /***********************************************************************
2429 * WS2_ReadFile (INTERNAL)
2431 * Perform an APC-safe ReadFile operation
2433 static NTSTATUS WS2_ReadFile(HANDLE hFile, PIO_STATUS_BLOCK io_status, char* buffer, ULONG length,
2434 PLARGE_INTEGER offset)
2436 int result = -1, unix_handle;
2437 unsigned int options;
2438 NTSTATUS status;
2440 TRACE( "(%p,%p,0x%08x)\n", hFile, buffer,length );
2442 status = wine_server_handle_to_fd( hFile, FILE_READ_DATA, &unix_handle, &options );
2443 if (status) return status;
2445 while (result == -1)
2447 if (offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
2448 result = pread( unix_handle, buffer, length, offset->QuadPart );
2449 else
2450 result = read( unix_handle, buffer, length );
2451 if (errno != EINTR)
2452 break;
2455 if (!result)
2456 status = (length ? STATUS_END_OF_FILE : STATUS_SUCCESS);
2457 else if (result != -1)
2458 status = STATUS_SUCCESS;
2459 else if (errno != EAGAIN)
2460 status = wsaErrStatus();
2461 else
2462 status = STATUS_PENDING;
2464 close( unix_handle );
2465 TRACE("= 0x%08x (%d)\n", status, result);
2466 if (status == STATUS_SUCCESS || status == STATUS_END_OF_FILE)
2468 io_status->u.Status = status;
2469 io_status->Information = result;
2472 return status;
2475 /***********************************************************************
2476 * WS2_transmitfile_getbuffer (INTERNAL)
2478 * Pick the appropriate buffer for a TransmitFile send operation.
2480 static NTSTATUS WS2_transmitfile_getbuffer( int fd, struct ws2_transmitfile_async *wsa )
2482 /* send any incomplete writes from a previous iteration */
2483 if (wsa->write.first_iovec < wsa->write.n_iovecs)
2484 return STATUS_PENDING;
2486 /* process the header (if applicable) */
2487 if (wsa->buffers.Head)
2489 wsa->write.first_iovec = 0;
2490 wsa->write.n_iovecs = 1;
2491 wsa->write.iovec[0].iov_base = wsa->buffers.Head;
2492 wsa->write.iovec[0].iov_len = wsa->buffers.HeadLength;
2493 wsa->buffers.Head = NULL;
2494 return STATUS_PENDING;
2497 /* process the main file */
2498 if (wsa->file)
2500 DWORD bytes_per_send = wsa->bytes_per_send;
2501 IO_STATUS_BLOCK iosb;
2502 NTSTATUS status;
2504 iosb.Information = 0;
2505 /* when the size of the transfer is limited ensure that we don't go past that limit */
2506 if (wsa->file_bytes != 0)
2507 bytes_per_send = min(bytes_per_send, wsa->file_bytes - wsa->file_read);
2508 status = WS2_ReadFile( wsa->file, &iosb, wsa->buffer, bytes_per_send, &wsa->offset );
2509 if (wsa->offset.QuadPart != FILE_USE_FILE_POINTER_POSITION)
2510 wsa->offset.QuadPart += iosb.Information;
2511 if (status == STATUS_END_OF_FILE)
2512 wsa->file = NULL; /* continue on to the footer */
2513 else if (status != STATUS_SUCCESS)
2514 return status;
2515 else
2517 if (iosb.Information)
2519 wsa->write.first_iovec = 0;
2520 wsa->write.n_iovecs = 1;
2521 wsa->write.iovec[0].iov_base = wsa->buffer;
2522 wsa->write.iovec[0].iov_len = iosb.Information;
2523 wsa->file_read += iosb.Information;
2526 if (wsa->file_bytes != 0 && wsa->file_read >= wsa->file_bytes)
2527 wsa->file = NULL;
2529 return STATUS_PENDING;
2533 /* send the footer (if applicable) */
2534 if (wsa->buffers.Tail)
2536 wsa->write.first_iovec = 0;
2537 wsa->write.n_iovecs = 1;
2538 wsa->write.iovec[0].iov_base = wsa->buffers.Tail;
2539 wsa->write.iovec[0].iov_len = wsa->buffers.TailLength;
2540 wsa->buffers.Tail = NULL;
2541 return STATUS_PENDING;
2544 return STATUS_SUCCESS;
2547 /***********************************************************************
2548 * WS2_transmitfile_base (INTERNAL)
2550 * Shared implementation for both synchronous and asynchronous TransmitFile.
2552 static NTSTATUS WS2_transmitfile_base( int fd, struct ws2_transmitfile_async *wsa )
2554 NTSTATUS status;
2556 status = WS2_transmitfile_getbuffer( fd, wsa );
2557 if (status == STATUS_PENDING)
2559 IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)wsa->write.user_overlapped;
2560 int n;
2562 n = WS2_send( fd, &wsa->write, convert_flags(wsa->write.flags) );
2563 if (n >= 0)
2565 if (iosb) iosb->Information += n;
2567 else if (errno != EAGAIN)
2568 return wsaErrStatus();
2571 return status;
2574 /***********************************************************************
2575 * WS2_async_transmitfile (INTERNAL)
2577 * Asynchronous callback for overlapped TransmitFile operations.
2579 static NTSTATUS WS2_async_transmitfile( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
2581 struct ws2_transmitfile_async *wsa = user;
2582 int fd;
2584 if (status == STATUS_ALERTED)
2586 if (!(status = wine_server_handle_to_fd( wsa->write.hSocket, FILE_WRITE_DATA, &fd, NULL )))
2588 status = WS2_transmitfile_base( fd, wsa );
2589 close( fd );
2591 if (status == STATUS_PENDING)
2592 return status;
2595 iosb->u.Status = status;
2596 release_async_io( &wsa->io );
2597 return status;
2600 /***********************************************************************
2601 * TransmitFile
2603 static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD file_bytes, DWORD bytes_per_send,
2604 LPOVERLAPPED overlapped, LPTRANSMIT_FILE_BUFFERS buffers,
2605 DWORD flags )
2607 union generic_unix_sockaddr uaddr;
2608 socklen_t uaddrlen = sizeof(uaddr);
2609 struct ws2_transmitfile_async *wsa;
2610 NTSTATUS status;
2611 int fd;
2613 TRACE("(%lx, %p, %d, %d, %p, %p, %d)\n", s, h, file_bytes, bytes_per_send, overlapped,
2614 buffers, flags );
2616 fd = get_sock_fd( s, FILE_WRITE_DATA, NULL );
2617 if (fd == -1) return FALSE;
2619 if (getpeername( fd, &uaddr.addr, &uaddrlen ) != 0)
2621 release_sock_fd( s, fd );
2622 WSASetLastError( WSAENOTCONN );
2623 return FALSE;
2625 if (flags)
2626 FIXME("Flags are not currently supported (0x%x).\n", flags);
2628 if (h && GetFileType( h ) != FILE_TYPE_DISK)
2630 FIXME("Non-disk file handles are not currently supported.\n");
2631 release_sock_fd( s, fd );
2632 WSASetLastError( WSAEOPNOTSUPP );
2633 return FALSE;
2636 /* set reasonable defaults when requested */
2637 if (!bytes_per_send)
2638 bytes_per_send = (1 << 16); /* Depends on OS version: PAGE_SIZE, 2*PAGE_SIZE, or 2^16 */
2640 if (!(wsa = (struct ws2_transmitfile_async *)alloc_async_io( sizeof(*wsa) + bytes_per_send,
2641 WS2_async_transmitfile )))
2643 release_sock_fd( s, fd );
2644 WSASetLastError( WSAEFAULT );
2645 return FALSE;
2647 if (buffers)
2648 wsa->buffers = *buffers;
2649 else
2650 memset(&wsa->buffers, 0x0, sizeof(wsa->buffers));
2651 wsa->buffer = (char *)(wsa + 1);
2652 wsa->file = h;
2653 wsa->file_read = 0;
2654 wsa->file_bytes = file_bytes;
2655 wsa->bytes_per_send = bytes_per_send;
2656 wsa->flags = flags;
2657 wsa->offset.QuadPart = FILE_USE_FILE_POINTER_POSITION;
2658 wsa->write.hSocket = SOCKET2HANDLE(s);
2659 wsa->write.addr = NULL;
2660 wsa->write.addrlen.val = 0;
2661 wsa->write.flags = 0;
2662 wsa->write.lpFlags = &wsa->flags;
2663 wsa->write.control = NULL;
2664 wsa->write.n_iovecs = 0;
2665 wsa->write.first_iovec = 0;
2666 wsa->write.user_overlapped = overlapped;
2667 if (overlapped)
2669 IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)overlapped;
2670 int status;
2672 wsa->offset.u.LowPart = overlapped->u.s.Offset;
2673 wsa->offset.u.HighPart = overlapped->u.s.OffsetHigh;
2674 iosb->u.Status = STATUS_PENDING;
2675 iosb->Information = 0;
2676 status = register_async( ASYNC_TYPE_WRITE, SOCKET2HANDLE(s), &wsa->io,
2677 overlapped->hEvent, NULL, NULL, iosb );
2678 if(status != STATUS_PENDING) HeapFree( GetProcessHeap(), 0, wsa );
2679 release_sock_fd( s, fd );
2680 WSASetLastError( NtStatusToWSAError(status) );
2681 return FALSE;
2686 status = WS2_transmitfile_base( fd, wsa );
2687 if (status == STATUS_PENDING)
2689 /* block here */
2690 do_block(fd, POLLOUT, -1);
2691 _sync_sock_state(s); /* let wineserver notice connection */
2694 while (status == STATUS_PENDING);
2695 release_sock_fd( s, fd );
2697 if (status != STATUS_SUCCESS)
2698 WSASetLastError( NtStatusToWSAError(status) );
2699 HeapFree( GetProcessHeap(), 0, wsa );
2700 return (status == STATUS_SUCCESS);
2703 /***********************************************************************
2704 * GetAcceptExSockaddrs
2706 static void WINAPI WS2_GetAcceptExSockaddrs(PVOID buffer, DWORD data_size, DWORD local_size, DWORD remote_size,
2707 struct WS_sockaddr **local_addr, LPINT local_addr_len,
2708 struct WS_sockaddr **remote_addr, LPINT remote_addr_len)
2710 char *cbuf = buffer;
2711 TRACE("(%p, %d, %d, %d, %p, %p, %p, %p)\n", buffer, data_size, local_size, remote_size, local_addr,
2712 local_addr_len, remote_addr, remote_addr_len );
2713 cbuf += data_size;
2715 *local_addr_len = *(int *) cbuf;
2716 *local_addr = (struct WS_sockaddr *)(cbuf + sizeof(int));
2718 cbuf += local_size;
2720 *remote_addr_len = *(int *) cbuf;
2721 *remote_addr = (struct WS_sockaddr *)(cbuf + sizeof(int));
2724 /***********************************************************************
2725 * WSASendMsg
2727 int WINAPI WSASendMsg( SOCKET s, LPWSAMSG msg, DWORD dwFlags, LPDWORD lpNumberOfBytesSent,
2728 LPWSAOVERLAPPED lpOverlapped,
2729 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
2731 if (!msg)
2733 SetLastError( WSAEFAULT );
2734 return SOCKET_ERROR;
2737 return WS2_sendto( s, msg->lpBuffers, msg->dwBufferCount, lpNumberOfBytesSent,
2738 dwFlags, msg->name, msg->namelen,
2739 lpOverlapped, lpCompletionRoutine );
2742 /***********************************************************************
2743 * WSARecvMsg
2745 * Perform a receive operation that is capable of returning message
2746 * control headers. It is important to note that the WSAMSG parameter
2747 * must remain valid throughout the operation, even when an overlapped
2748 * receive is performed.
2750 static int WINAPI WS2_WSARecvMsg( SOCKET s, LPWSAMSG msg, LPDWORD lpNumberOfBytesRecvd,
2751 LPWSAOVERLAPPED lpOverlapped,
2752 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
2754 if (!msg)
2756 SetLastError( WSAEFAULT );
2757 return SOCKET_ERROR;
2760 return WS2_recv_base( s, msg->lpBuffers, msg->dwBufferCount, lpNumberOfBytesRecvd,
2761 &msg->dwFlags, msg->name, &msg->namelen,
2762 lpOverlapped, lpCompletionRoutine, &msg->Control );
2765 /***********************************************************************
2766 * interface_bind (INTERNAL)
2768 * Take bind() calls on any name corresponding to a local network adapter and restrict the given socket to
2769 * operating only on the specified interface. This restriction consists of two components:
2770 * 1) An outgoing packet restriction suggesting the egress interface for all packets.
2771 * 2) An incoming packet restriction dropping packets not meant for the interface.
2772 * If the function succeeds in placing these restrictions (returns TRUE) then the name for the bind() may
2773 * safely be changed to INADDR_ANY, permitting the transmission and receipt of broadcast packets on the
2774 * socket. This behavior is only relevant to UDP sockets and is needed for applications that expect to be able
2775 * to receive broadcast packets on a socket that is bound to a specific network interface.
2777 static BOOL interface_bind( SOCKET s, int fd, struct sockaddr *addr )
2779 struct sockaddr_in *in_sock = (struct sockaddr_in *) addr;
2780 in_addr_t bind_addr = in_sock->sin_addr.s_addr;
2781 PIP_ADAPTER_INFO adapters = NULL, adapter;
2782 BOOL ret = FALSE;
2783 DWORD adap_size;
2784 int enable = 1;
2786 if (bind_addr == htonl(INADDR_ANY) || bind_addr == htonl(INADDR_LOOPBACK))
2787 return FALSE; /* Not binding to a network adapter, special interface binding unnecessary. */
2788 if (_get_fd_type(fd) != SOCK_DGRAM)
2789 return FALSE; /* Special interface binding is only necessary for UDP datagrams. */
2790 if (GetAdaptersInfo(NULL, &adap_size) != ERROR_BUFFER_OVERFLOW)
2791 goto cleanup;
2792 adapters = HeapAlloc(GetProcessHeap(), 0, adap_size);
2793 if (adapters == NULL || GetAdaptersInfo(adapters, &adap_size) != NO_ERROR)
2794 goto cleanup;
2795 /* Search the IPv4 adapter list for the appropriate binding interface */
2796 for (adapter = adapters; adapter != NULL; adapter = adapter->Next)
2798 in_addr_t adapter_addr = (in_addr_t) inet_addr(adapter->IpAddressList.IpAddress.String);
2800 if (bind_addr == adapter_addr)
2802 #if defined(IP_BOUND_IF)
2803 /* IP_BOUND_IF sets both the incoming and outgoing restriction at once */
2804 if (setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &adapter->Index, sizeof(adapter->Index)) != 0)
2805 goto cleanup;
2806 ret = TRUE;
2807 #elif defined(LINUX_BOUND_IF)
2808 in_addr_t ifindex = (in_addr_t) htonl(adapter->Index);
2809 struct interface_filter specific_interface_filter;
2810 struct sock_fprog filter_prog;
2812 if (setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex)) != 0)
2813 goto cleanup; /* Failed to suggest egress interface */
2814 specific_interface_filter = generic_interface_filter;
2815 specific_interface_filter.iface_rule.k = adapter->Index;
2816 specific_interface_filter.ip_rule.k = htonl(adapter_addr);
2817 filter_prog.len = sizeof(generic_interface_filter)/sizeof(struct sock_filter);
2818 filter_prog.filter = (struct sock_filter *) &specific_interface_filter;
2819 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) != 0)
2820 goto cleanup; /* Failed to specify incoming packet filter */
2821 ret = TRUE;
2822 #else
2823 FIXME("Broadcast packets on interface-bound sockets are not currently supported on this platform, "
2824 "receiving broadcast packets will not work on socket %04lx.\n", s);
2825 #endif
2826 if (ret)
2828 EnterCriticalSection(&cs_if_addr_cache);
2829 if (if_addr_cache_size <= adapter->Index)
2831 unsigned int new_size;
2832 in_addr_t *new;
2834 new_size = max(if_addr_cache_size * 2, adapter->Index + 1);
2835 if (!(new = heap_realloc(if_addr_cache, sizeof(*if_addr_cache) * new_size)))
2837 ERR("No memory.\n");
2838 ret = FALSE;
2839 LeaveCriticalSection(&cs_if_addr_cache);
2840 break;
2842 memset(new + if_addr_cache_size, 0, sizeof(*if_addr_cache)
2843 * (new_size - if_addr_cache_size));
2844 if_addr_cache = new;
2845 if_addr_cache_size = new_size;
2847 if (if_addr_cache[adapter->Index] && if_addr_cache[adapter->Index] != adapter_addr)
2848 WARN("Adapter addr for iface index %u has changed.\n", adapter->Index);
2850 if_addr_cache[adapter->Index] = adapter_addr;
2851 LeaveCriticalSection(&cs_if_addr_cache);
2853 break;
2856 /* Will soon be switching to INADDR_ANY: permit address reuse */
2857 if (ret && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == 0)
2858 TRACE("Socket %04lx bound to interface index %d\n", s, adapter->Index);
2859 else
2860 ret = FALSE;
2862 cleanup:
2863 if(!ret)
2864 ERR("Failed to bind to interface, receiving broadcast packets will not work on socket %04lx.\n", s);
2865 HeapFree(GetProcessHeap(), 0, adapters);
2866 return ret;
2869 /***********************************************************************
2870 * bind (WS2_32.2)
2872 int WINAPI WS_bind(SOCKET s, const struct WS_sockaddr* name, int namelen)
2874 int fd = get_sock_fd( s, 0, NULL );
2875 int res = SOCKET_ERROR;
2877 TRACE("socket %04lx, ptr %p %s, length %d\n", s, name, debugstr_sockaddr(name), namelen);
2879 if (fd != -1)
2881 if (!name || (name->sa_family && !supported_pf(name->sa_family)))
2883 SetLastError(WSAEAFNOSUPPORT);
2885 else
2887 union generic_unix_sockaddr uaddr;
2888 unsigned int uaddrlen = ws_sockaddr_ws2u(name, namelen, &uaddr);
2889 if (!uaddrlen)
2891 SetLastError(WSAEFAULT);
2893 else
2895 if (name->sa_family == WS_AF_INET)
2897 struct sockaddr_in *in4 = (struct sockaddr_in*) &uaddr;
2898 if (memcmp(&in4->sin_addr, magic_loopback_addr, 4) == 0)
2900 /* Trying to bind to the default host interface, using
2901 * INADDR_ANY instead*/
2902 WARN("Trying to bind to magic IP address, using "
2903 "INADDR_ANY instead.\n");
2904 in4->sin_addr.s_addr = htonl(INADDR_ANY);
2906 else if (interface_bind(s, fd, &uaddr.addr))
2907 in4->sin_addr.s_addr = htonl(INADDR_ANY);
2909 if (bind(fd, &uaddr.addr, uaddrlen) < 0)
2911 int loc_errno = errno;
2912 WARN("\tfailure - errno = %i\n", errno);
2913 errno = loc_errno;
2914 switch (errno)
2916 case EADDRNOTAVAIL:
2917 SetLastError(WSAEINVAL);
2918 break;
2919 case EADDRINUSE:
2921 int optval = 0;
2922 socklen_t optlen = sizeof(optval);
2923 /* Windows >= 2003 will return different results depending on
2924 * SO_REUSEADDR, WSAEACCES may be returned representing that
2925 * the socket hijacking protection prevented the bind */
2926 if (!getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, &optlen) && optval)
2928 SetLastError(WSAEACCES);
2929 break;
2931 /* fall through */
2933 default:
2934 SetLastError(wsaErrno());
2935 break;
2938 else
2940 res=0; /* success */
2944 release_sock_fd( s, fd );
2946 return res;
2949 /***********************************************************************
2950 * closesocket (WS2_32.3)
2952 int WINAPI WS_closesocket(SOCKET s)
2954 int res = SOCKET_ERROR, fd;
2955 if (num_startup)
2957 fd = get_sock_fd(s, FILE_READ_DATA, NULL);
2958 if (fd >= 0)
2960 release_sock_fd(s, fd);
2961 socket_list_remove(s);
2962 if (CloseHandle(SOCKET2HANDLE(s)))
2963 res = 0;
2966 else
2967 SetLastError(WSANOTINITIALISED);
2968 TRACE("(socket %04lx) -> %d\n", s, res);
2969 return res;
2973 /***********************************************************************
2974 * connect (ws2_32.4)
2976 int WINAPI WS_connect( SOCKET s, const struct WS_sockaddr *addr, int len )
2978 union generic_unix_sockaddr uaddr;
2979 unsigned int uaddrlen = ws_sockaddr_ws2u( addr, len, &uaddr );
2980 struct afd_connect_params *params;
2981 IO_STATUS_BLOCK io;
2982 HANDLE sync_event;
2983 NTSTATUS status;
2985 TRACE( "socket %#lx, addr %s, len %d\n", s, debugstr_sockaddr(addr), len );
2987 if (!uaddrlen)
2989 SetLastError( WSAEFAULT );
2990 return -1;
2993 if (addr->sa_family == WS_AF_INET)
2995 struct sockaddr_in *in4 = (struct sockaddr_in *)&uaddr;
2996 if (!memcmp(&in4->sin_addr, magic_loopback_addr, sizeof(magic_loopback_addr)))
2998 TRACE("Replacing magic address 127.12.34.56 with INADDR_LOOPBACK.\n");
2999 in4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3003 if (!(sync_event = get_sync_event())) return -1;
3005 if (!(params = HeapAlloc( GetProcessHeap(), 0, sizeof(*params) + uaddrlen )))
3007 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
3008 return -1;
3010 params->addr_len = uaddrlen;
3011 params->synchronous = TRUE;
3012 memcpy(params + 1, &uaddr, uaddrlen);
3014 status = NtDeviceIoControlFile( (HANDLE)s, sync_event, NULL, NULL, &io, IOCTL_AFD_WINE_CONNECT,
3015 params, sizeof(*params) + uaddrlen, NULL, 0);
3016 HeapFree( GetProcessHeap(), 0, params );
3017 if (status == STATUS_PENDING)
3019 if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED) return -1;
3020 status = io.u.Status;
3022 if (status)
3024 SetLastError( NtStatusToWSAError( status ) );
3025 return -1;
3027 return 0;
3031 /***********************************************************************
3032 * WSAConnect (WS2_32.30)
3034 int WINAPI WSAConnect( SOCKET s, const struct WS_sockaddr* name, int namelen,
3035 LPWSABUF lpCallerData, LPWSABUF lpCalleeData,
3036 LPQOS lpSQOS, LPQOS lpGQOS )
3038 if ( lpCallerData || lpCalleeData || lpSQOS || lpGQOS )
3039 FIXME("unsupported parameters!\n");
3040 return WS_connect( s, name, namelen );
3044 static BOOL WINAPI WS2_ConnectEx( SOCKET s, const struct WS_sockaddr *name, int namelen,
3045 void *send_buffer, DWORD send_len, DWORD *ret_len, OVERLAPPED *overlapped )
3047 union generic_unix_sockaddr uaddr;
3048 unsigned int uaddrlen = ws_sockaddr_ws2u(name, namelen, &uaddr);
3049 struct afd_connect_params *params;
3050 void *cvalue = NULL;
3051 NTSTATUS status;
3052 int fd, ret;
3054 TRACE( "socket %#lx, ptr %p %s, length %d, send_buffer %p, send_len %u, overlapped %p\n",
3055 s, name, debugstr_sockaddr(name), namelen, send_buffer, send_len, overlapped );
3057 if ((fd = get_sock_fd( s, FILE_READ_DATA, NULL )) == -1)
3058 return FALSE;
3060 if ((ret = is_fd_bound( fd, NULL, NULL )) <= 0)
3062 SetLastError( ret ? wsaErrno() : WSAEINVAL );
3063 release_sock_fd( s, fd );
3064 return FALSE;
3066 release_sock_fd( s, fd );
3068 if (!overlapped)
3070 SetLastError( WSA_INVALID_PARAMETER );
3071 return FALSE;
3074 if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped;
3075 overlapped->Internal = STATUS_PENDING;
3076 overlapped->InternalHigh = 0;
3078 if (!uaddrlen)
3080 SetLastError( WSAEFAULT );
3081 return SOCKET_ERROR;
3084 if (name->sa_family == WS_AF_INET)
3086 struct sockaddr_in *in4 = (struct sockaddr_in *)&uaddr;
3087 if (!memcmp( &in4->sin_addr, magic_loopback_addr, sizeof(magic_loopback_addr) ))
3089 TRACE("Replacing magic address 127.12.34.56 with INADDR_LOOPBACK.\n");
3090 in4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3094 if (!(params = HeapAlloc( GetProcessHeap(), 0, sizeof(*params) + uaddrlen + send_len )))
3096 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
3097 return SOCKET_ERROR;
3099 params->addr_len = uaddrlen;
3100 params->synchronous = FALSE;
3101 memcpy( params + 1, &uaddr, uaddrlen );
3102 memcpy( (char *)(params + 1) + uaddrlen, send_buffer, send_len );
3104 status = NtDeviceIoControlFile( SOCKET2HANDLE(s), overlapped->hEvent, NULL, cvalue,
3105 (IO_STATUS_BLOCK *)overlapped, IOCTL_AFD_WINE_CONNECT,
3106 params, sizeof(*params) + uaddrlen + send_len, NULL, 0 );
3107 HeapFree( GetProcessHeap(), 0, params );
3108 if (ret_len) *ret_len = overlapped->InternalHigh;
3109 SetLastError( NtStatusToWSAError( status ) );
3110 return !status;
3113 /***********************************************************************
3114 * DisconnectEx
3116 static BOOL WINAPI WS2_DisconnectEx( SOCKET s, LPOVERLAPPED ov, DWORD flags, DWORD reserved )
3118 TRACE( "socket %04lx, ov %p, flags 0x%x, reserved 0x%x\n", s, ov, flags, reserved );
3120 if (flags & TF_REUSE_SOCKET)
3121 FIXME( "Reusing socket not supported yet\n" );
3123 if (ov)
3125 ov->Internal = STATUS_PENDING;
3126 ov->InternalHigh = 0;
3129 return !WS_shutdown( s, SD_BOTH );
3132 /***********************************************************************
3133 * getpeername (WS2_32.5)
3135 int WINAPI WS_getpeername(SOCKET s, struct WS_sockaddr *name, int *namelen)
3137 int fd;
3138 int res;
3140 TRACE("socket %04lx, ptr %p, len %08x\n", s, name, namelen ? *namelen : 0);
3142 fd = get_sock_fd( s, 0, NULL );
3143 res = SOCKET_ERROR;
3145 if (fd != -1)
3147 union generic_unix_sockaddr uaddr;
3148 socklen_t uaddrlen = sizeof(uaddr);
3150 if (getpeername(fd, &uaddr.addr, &uaddrlen) == 0)
3152 if (!name || !namelen)
3153 SetLastError(WSAEFAULT);
3154 else if (ws_sockaddr_u2ws(&uaddr.addr, name, namelen) != 0)
3155 /* The buffer was too small */
3156 SetLastError(WSAEFAULT);
3157 else
3159 res = 0;
3160 TRACE("=> %s\n", debugstr_sockaddr(name));
3163 else
3164 SetLastError(wsaErrno());
3165 release_sock_fd( s, fd );
3167 return res;
3170 /* When binding to an UDP address with filter support the getsockname call on the socket
3171 * will always return 0.0.0.0 instead of the filtered interface address. This function
3172 * checks if the socket is interface-bound on UDP and return the correct address.
3173 * This is required because applications often do a bind() with port zero followed by a
3174 * getsockname() to retrieve the port and address acquired.
3176 static void interface_bind_check(int fd, struct sockaddr_in *addr)
3178 #if !defined(IP_BOUND_IF) && !defined(LINUX_BOUND_IF)
3179 return;
3180 #else
3181 unsigned int ifindex;
3182 int ret;
3183 socklen_t len;
3185 /* Check for IPv4, address 0.0.0.0 and UDP socket */
3186 if (addr->sin_family != AF_INET || addr->sin_addr.s_addr != 0)
3187 return;
3188 if (_get_fd_type(fd) != SOCK_DGRAM)
3189 return;
3191 len = sizeof(ifindex);
3192 #if defined(IP_BOUND_IF)
3193 ret = getsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &ifindex, &len);
3194 #elif defined(LINUX_BOUND_IF)
3195 ret = getsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, &len);
3196 if (!ret) ifindex = ntohl(ifindex);
3197 #endif
3198 if (!ret && ifindex)
3200 EnterCriticalSection(&cs_if_addr_cache);
3201 if (ifindex < if_addr_cache_size)
3202 addr->sin_addr.s_addr = if_addr_cache[ifindex];
3203 else
3204 ERR("No cache entry for ifindex %u.\n", ifindex);
3205 LeaveCriticalSection(&cs_if_addr_cache);
3207 #endif
3210 /***********************************************************************
3211 * getsockname (WS2_32.6)
3213 int WINAPI WS_getsockname(SOCKET s, struct WS_sockaddr *name, int *namelen)
3215 int fd;
3216 int res;
3218 TRACE("socket %04lx, ptr %p, len %08x\n", s, name, namelen ? *namelen : 0);
3220 /* Check if what we've received is valid. Should we use IsBadReadPtr? */
3221 if( (name == NULL) || (namelen == NULL) )
3223 SetLastError( WSAEFAULT );
3224 return SOCKET_ERROR;
3227 fd = get_sock_fd( s, 0, NULL );
3228 res = SOCKET_ERROR;
3230 if (fd != -1)
3232 union generic_unix_sockaddr uaddr;
3233 socklen_t uaddrlen;
3234 int bound = is_fd_bound(fd, &uaddr, &uaddrlen);
3236 if (bound <= 0)
3238 SetLastError(bound == -1 ? wsaErrno() : WSAEINVAL);
3240 else if (ws_sockaddr_u2ws(&uaddr.addr, name, namelen) != 0)
3242 /* The buffer was too small */
3243 SetLastError(WSAEFAULT);
3245 else
3247 interface_bind_check(fd, (struct sockaddr_in*) &uaddr);
3248 if (ws_sockaddr_u2ws(&uaddr.addr, name, namelen) != 0)
3250 /* The buffer was too small */
3251 SetLastError(WSAEFAULT);
3253 else
3255 res = 0;
3256 TRACE("=> %s\n", debugstr_sockaddr(name));
3259 release_sock_fd( s, fd );
3261 return res;
3264 /***********************************************************************
3265 * getsockopt (WS2_32.7)
3267 INT WINAPI WS_getsockopt(SOCKET s, INT level,
3268 INT optname, char *optval, INT *optlen)
3270 int fd;
3271 INT ret = 0;
3273 TRACE("(socket %04lx, %s, optval %s, optlen %p (%d))\n", s,
3274 debugstr_sockopt(level, optname), debugstr_optval(optval, 0),
3275 optlen, optlen ? *optlen : 0);
3277 switch(level)
3279 case WS_SOL_SOCKET:
3281 switch(optname)
3283 /* Handle common cases. The special cases are below, sorted
3284 * alphabetically */
3285 case WS_SO_BROADCAST:
3286 case WS_SO_DEBUG:
3287 case WS_SO_KEEPALIVE:
3288 case WS_SO_OOBINLINE:
3289 case WS_SO_RCVBUF:
3290 case WS_SO_REUSEADDR:
3291 case WS_SO_SNDBUF:
3292 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3293 return SOCKET_ERROR;
3294 convert_sockopt(&level, &optname);
3295 if (getsockopt(fd, level, optname, optval, (socklen_t *)optlen) != 0 )
3297 SetLastError(wsaErrno());
3298 ret = SOCKET_ERROR;
3300 release_sock_fd( s, fd );
3301 return ret;
3302 case WS_SO_ACCEPTCONN:
3303 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3304 return SOCKET_ERROR;
3305 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, optval, (socklen_t *)optlen) != 0 )
3307 SetLastError(wsaErrno());
3308 ret = SOCKET_ERROR;
3310 else
3312 /* BSD returns != 0 while Windows return exact == 1 */
3313 if (*(int *)optval) *(int *)optval = 1;
3315 release_sock_fd( s, fd );
3316 return ret;
3317 case WS_SO_BSP_STATE:
3319 int req_size, addr_size;
3320 WSAPROTOCOL_INFOW infow;
3321 CSADDR_INFO *csinfo;
3323 ret = ws_protocol_info(s, TRUE, &infow, &addr_size);
3324 if (ret)
3326 if (infow.iAddressFamily == WS_AF_INET)
3327 addr_size = sizeof(struct sockaddr_in);
3328 else if (infow.iAddressFamily == WS_AF_INET6)
3329 addr_size = sizeof(struct sockaddr_in6);
3330 else
3332 FIXME("Family %d is unsupported for SO_BSP_STATE\n", infow.iAddressFamily);
3333 SetLastError(WSAEAFNOSUPPORT);
3334 return SOCKET_ERROR;
3337 req_size = sizeof(CSADDR_INFO) + addr_size * 2;
3338 if (*optlen < req_size)
3340 ret = 0;
3341 SetLastError(WSAEFAULT);
3343 else
3345 union generic_unix_sockaddr uaddr;
3346 socklen_t uaddrlen;
3348 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3349 return SOCKET_ERROR;
3351 csinfo = (CSADDR_INFO*) optval;
3353 /* Check if the sock is bound */
3354 if (is_fd_bound(fd, &uaddr, &uaddrlen) == 1)
3356 csinfo->LocalAddr.lpSockaddr =
3357 (LPSOCKADDR) (optval + sizeof(CSADDR_INFO));
3358 ws_sockaddr_u2ws(&uaddr.addr, csinfo->LocalAddr.lpSockaddr, &addr_size);
3359 csinfo->LocalAddr.iSockaddrLength = addr_size;
3361 else
3363 csinfo->LocalAddr.lpSockaddr = NULL;
3364 csinfo->LocalAddr.iSockaddrLength = 0;
3367 /* Check if the sock is connected */
3368 if (!getpeername(fd, &uaddr.addr, &uaddrlen) &&
3369 is_sockaddr_bound(&uaddr.addr, uaddrlen))
3371 csinfo->RemoteAddr.lpSockaddr =
3372 (LPSOCKADDR) (optval + sizeof(CSADDR_INFO) + addr_size);
3373 ws_sockaddr_u2ws(&uaddr.addr, csinfo->RemoteAddr.lpSockaddr, &addr_size);
3374 csinfo->RemoteAddr.iSockaddrLength = addr_size;
3376 else
3378 csinfo->RemoteAddr.lpSockaddr = NULL;
3379 csinfo->RemoteAddr.iSockaddrLength = 0;
3382 csinfo->iSocketType = infow.iSocketType;
3383 csinfo->iProtocol = infow.iProtocol;
3384 release_sock_fd( s, fd );
3387 return ret ? 0 : SOCKET_ERROR;
3389 case WS_SO_DONTLINGER:
3391 struct linger lingval;
3392 socklen_t len = sizeof(struct linger);
3394 if (!optlen || *optlen < sizeof(BOOL)|| !optval)
3396 SetLastError(WSAEFAULT);
3397 return SOCKET_ERROR;
3399 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3400 return SOCKET_ERROR;
3402 if (getsockopt(fd, SOL_SOCKET, SO_LINGER, &lingval, &len) != 0 )
3404 SetLastError(wsaErrno());
3405 ret = SOCKET_ERROR;
3407 else
3409 *(BOOL *)optval = !lingval.l_onoff;
3410 *optlen = sizeof(BOOL);
3413 release_sock_fd( s, fd );
3414 return ret;
3417 case WS_SO_CONNECT_TIME:
3419 static int pretendtime = 0;
3420 struct WS_sockaddr addr;
3421 int len = sizeof(addr);
3423 if (!optlen || *optlen < sizeof(DWORD) || !optval)
3425 SetLastError(WSAEFAULT);
3426 return SOCKET_ERROR;
3428 if (WS_getpeername(s, &addr, &len) == SOCKET_ERROR)
3429 *(DWORD *)optval = ~0u;
3430 else
3432 if (!pretendtime) FIXME("WS_SO_CONNECT_TIME - faking results\n");
3433 *(DWORD *)optval = pretendtime++;
3435 *optlen = sizeof(DWORD);
3436 return ret;
3438 /* As mentioned in setsockopt, Windows ignores this, so we
3439 * always return true here */
3440 case WS_SO_DONTROUTE:
3441 if (!optlen || *optlen < sizeof(BOOL) || !optval)
3443 SetLastError(WSAEFAULT);
3444 return SOCKET_ERROR;
3446 *(BOOL *)optval = TRUE;
3447 *optlen = sizeof(BOOL);
3448 return 0;
3450 case WS_SO_ERROR:
3452 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3453 return SOCKET_ERROR;
3454 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, optval, (socklen_t *)optlen) != 0 )
3456 SetLastError(wsaErrno());
3457 ret = SOCKET_ERROR;
3459 release_sock_fd( s, fd );
3461 /* The wineserver may have swallowed the error before us */
3462 if (!ret && *(int*) optval == 0)
3464 int i, events[FD_MAX_EVENTS];
3465 _get_sock_errors(s, events);
3466 for (i = 0; i < FD_MAX_EVENTS; i++)
3468 if(events[i])
3470 TRACE("returning SO_ERROR %d from wine server\n", events[i]);
3471 *(int*) optval = events[i];
3472 break;
3476 return ret;
3479 case WS_SO_LINGER:
3481 struct linger lingval;
3482 socklen_t len = sizeof(struct linger);
3484 /* struct linger and LINGER have different sizes */
3485 if (!optlen || *optlen < sizeof(LINGER) || !optval)
3487 SetLastError(WSAEFAULT);
3488 return SOCKET_ERROR;
3490 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3491 return SOCKET_ERROR;
3493 if (_get_fd_type(fd) == SOCK_DGRAM)
3495 SetLastError(WSAENOPROTOOPT);
3496 ret = SOCKET_ERROR;
3498 else if (getsockopt(fd, SOL_SOCKET, SO_LINGER, &lingval, &len) != 0)
3500 SetLastError(wsaErrno());
3501 ret = SOCKET_ERROR;
3503 else
3505 ((LINGER *)optval)->l_onoff = lingval.l_onoff;
3506 ((LINGER *)optval)->l_linger = lingval.l_linger;
3507 *optlen = sizeof(struct linger);
3510 release_sock_fd( s, fd );
3511 return ret;
3514 case WS_SO_MAX_MSG_SIZE:
3515 if (!optlen || *optlen < sizeof(int) || !optval)
3517 SetLastError(WSAEFAULT);
3518 return SOCKET_ERROR;
3520 TRACE("getting global SO_MAX_MSG_SIZE = 65507\n");
3521 *(int *)optval = 65507;
3522 *optlen = sizeof(int);
3523 return 0;
3525 /* SO_OPENTYPE does not require a valid socket handle. */
3526 case WS_SO_OPENTYPE:
3527 if (!optlen || *optlen < sizeof(int) || !optval)
3529 SetLastError(WSAEFAULT);
3530 return SOCKET_ERROR;
3532 *(int *)optval = get_per_thread_data()->opentype;
3533 *optlen = sizeof(int);
3534 TRACE("getting global SO_OPENTYPE = 0x%x\n", *((int*)optval) );
3535 return 0;
3536 case WS_SO_PROTOCOL_INFOA:
3537 case WS_SO_PROTOCOL_INFOW:
3539 int size;
3540 WSAPROTOCOL_INFOW infow;
3542 ret = ws_protocol_info(s, optname == WS_SO_PROTOCOL_INFOW, &infow, &size);
3543 if (ret)
3545 if (!optlen || !optval || *optlen < size)
3547 if(optlen) *optlen = size;
3548 ret = 0;
3549 SetLastError(WSAEFAULT);
3551 else
3552 memcpy(optval, &infow, size);
3554 return ret ? 0 : SOCKET_ERROR;
3556 case WS_SO_RCVTIMEO:
3557 case WS_SO_SNDTIMEO:
3559 INT64 timeout;
3561 if (!optlen || *optlen < sizeof(int)|| !optval)
3563 SetLastError(WSAEFAULT);
3564 return SOCKET_ERROR;
3566 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3567 return SOCKET_ERROR;
3569 timeout = get_rcvsnd_timeo(fd, optname == WS_SO_RCVTIMEO);
3570 *(int *)optval = timeout <= UINT_MAX ? timeout : UINT_MAX;
3572 release_sock_fd( s, fd );
3573 return ret;
3575 case WS_SO_TYPE:
3577 int sock_type;
3578 if (!optlen || *optlen < sizeof(int) || !optval)
3580 SetLastError(WSAEFAULT);
3581 return SOCKET_ERROR;
3583 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3584 return SOCKET_ERROR;
3586 sock_type = _get_fd_type(fd);
3587 if (sock_type == -1)
3589 SetLastError(wsaErrno());
3590 ret = SOCKET_ERROR;
3592 else
3593 (*(int *)optval) = convert_socktype_u2w(sock_type);
3595 release_sock_fd( s, fd );
3596 return ret;
3598 default:
3599 TRACE("Unknown SOL_SOCKET optname: 0x%08x\n", optname);
3600 SetLastError(WSAENOPROTOOPT);
3601 return SOCKET_ERROR;
3602 } /* end switch(optname) */
3603 }/* end case WS_SOL_SOCKET */
3604 #ifdef HAS_IPX
3605 case WS_NSPROTO_IPX:
3607 struct WS_sockaddr_ipx addr;
3608 IPX_ADDRESS_DATA *data;
3609 int namelen;
3610 switch(optname)
3612 case WS_IPX_PTYPE:
3613 if ((fd = get_sock_fd( s, 0, NULL )) == -1) return SOCKET_ERROR;
3614 #ifdef SOL_IPX
3615 if(getsockopt(fd, SOL_IPX, IPX_TYPE, optval, (socklen_t *)optlen) == -1)
3617 ret = SOCKET_ERROR;
3619 #else
3621 struct ipx val;
3622 socklen_t len=sizeof(struct ipx);
3623 if(getsockopt(fd, 0, SO_DEFAULT_HEADERS, &val, &len) == -1 )
3624 ret = SOCKET_ERROR;
3625 else
3626 *optval = (int)val.ipx_pt;
3628 #endif
3629 TRACE("ptype: %d (fd: %d)\n", *(int*)optval, fd);
3630 release_sock_fd( s, fd );
3631 return ret;
3633 case WS_IPX_ADDRESS:
3635 * On a Win2000 system with one network card there are usually
3636 * three ipx devices one with a speed of 28.8kbps, 10Mbps and 100Mbps.
3637 * Using this call you can then retrieve info about this all.
3638 * In case of Linux it is a bit different. Usually you have
3639 * only "one" device active and further it is not possible to
3640 * query things like the linkspeed.
3642 FIXME("IPX_ADDRESS\n");
3643 namelen = sizeof(struct WS_sockaddr_ipx);
3644 memset(&addr, 0, sizeof(struct WS_sockaddr_ipx));
3645 WS_getsockname(s, (struct WS_sockaddr*)&addr, &namelen);
3647 data = (IPX_ADDRESS_DATA*)optval;
3648 memcpy(data->nodenum,addr.sa_nodenum,sizeof(data->nodenum));
3649 memcpy(data->netnum,addr.sa_netnum,sizeof(data->netnum));
3650 data->adapternum = 0;
3651 data->wan = FALSE; /* We are not on a wan for now .. */
3652 data->status = FALSE; /* Since we are not on a wan, the wan link isn't up */
3653 data->maxpkt = 1467; /* This value is the default one, at least on Win2k/WinXP */
3654 data->linkspeed = 100000; /* Set the line speed in 100bit/s to 10 Mbit;
3655 * note 1MB = 1000kB in this case */
3656 return 0;
3658 case WS_IPX_MAX_ADAPTER_NUM:
3659 FIXME("IPX_MAX_ADAPTER_NUM\n");
3660 *(int*)optval = 1; /* As noted under IPX_ADDRESS we have just one card. */
3661 return 0;
3663 default:
3664 FIXME("IPX optname:%x\n", optname);
3665 return SOCKET_ERROR;
3666 }/* end switch(optname) */
3667 } /* end case WS_NSPROTO_IPX */
3668 #endif
3670 #ifdef HAS_IRDA
3671 #define MAX_IRDA_DEVICES 10
3673 case WS_SOL_IRLMP:
3674 switch(optname)
3676 case WS_IRLMP_ENUMDEVICES:
3678 char buf[sizeof(struct irda_device_list) +
3679 (MAX_IRDA_DEVICES - 1) * sizeof(struct irda_device_info)];
3680 int res;
3681 socklen_t len = sizeof(buf);
3683 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3684 return SOCKET_ERROR;
3685 res = getsockopt( fd, SOL_IRLMP, IRLMP_ENUMDEVICES, buf, &len );
3686 release_sock_fd( s, fd );
3687 if (res < 0)
3689 SetLastError(wsaErrno());
3690 return SOCKET_ERROR;
3692 else
3694 struct irda_device_list *src = (struct irda_device_list *)buf;
3695 DEVICELIST *dst = (DEVICELIST *)optval;
3696 INT needed = sizeof(DEVICELIST);
3697 unsigned int i;
3699 if (src->len > 0)
3700 needed += (src->len - 1) * sizeof(IRDA_DEVICE_INFO);
3701 if (*optlen < needed)
3703 SetLastError(WSAEFAULT);
3704 return SOCKET_ERROR;
3706 *optlen = needed;
3707 TRACE("IRLMP_ENUMDEVICES: %d devices found:\n", src->len);
3708 dst->numDevice = src->len;
3709 for (i = 0; i < src->len; i++)
3711 TRACE("saddr = %08x, daddr = %08x, info = %s, hints = %02x%02x\n",
3712 src->dev[i].saddr, src->dev[i].daddr,
3713 src->dev[i].info, src->dev[i].hints[0],
3714 src->dev[i].hints[1]);
3715 memcpy( dst->Device[i].irdaDeviceID,
3716 &src->dev[i].daddr,
3717 sizeof(dst->Device[i].irdaDeviceID) ) ;
3718 memcpy( dst->Device[i].irdaDeviceName,
3719 src->dev[i].info,
3720 sizeof(dst->Device[i].irdaDeviceName) ) ;
3721 memcpy( &dst->Device[i].irdaDeviceHints1,
3722 &src->dev[i].hints[0],
3723 sizeof(dst->Device[i].irdaDeviceHints1) ) ;
3724 memcpy( &dst->Device[i].irdaDeviceHints2,
3725 &src->dev[i].hints[1],
3726 sizeof(dst->Device[i].irdaDeviceHints2) ) ;
3727 dst->Device[i].irdaCharSet = src->dev[i].charset;
3729 return 0;
3732 default:
3733 FIXME("IrDA optname:0x%x\n", optname);
3734 return SOCKET_ERROR;
3736 break; /* case WS_SOL_IRLMP */
3737 #undef MAX_IRDA_DEVICES
3738 #endif
3740 /* Levels WS_IPPROTO_TCP and WS_IPPROTO_IP convert directly */
3741 case WS_IPPROTO_TCP:
3742 switch(optname)
3744 case WS_TCP_NODELAY:
3745 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3746 return SOCKET_ERROR;
3747 convert_sockopt(&level, &optname);
3748 if (getsockopt(fd, level, optname, optval, (socklen_t *)optlen) != 0 )
3750 SetLastError(wsaErrno());
3751 ret = SOCKET_ERROR;
3753 release_sock_fd( s, fd );
3754 return ret;
3756 FIXME("Unknown IPPROTO_TCP optname 0x%08x\n", optname);
3757 return SOCKET_ERROR;
3759 case WS_IPPROTO_IP:
3760 switch(optname)
3762 case WS_IP_ADD_MEMBERSHIP:
3763 case WS_IP_DROP_MEMBERSHIP:
3764 #ifdef IP_HDRINCL
3765 case WS_IP_HDRINCL:
3766 #endif
3767 case WS_IP_MULTICAST_IF:
3768 case WS_IP_MULTICAST_LOOP:
3769 case WS_IP_MULTICAST_TTL:
3770 case WS_IP_OPTIONS:
3771 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
3772 case WS_IP_PKTINFO:
3773 #endif
3774 case WS_IP_TOS:
3775 case WS_IP_TTL:
3776 #ifdef IP_UNICAST_IF
3777 case WS_IP_UNICAST_IF:
3778 #endif
3779 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3780 return SOCKET_ERROR;
3781 convert_sockopt(&level, &optname);
3782 if (getsockopt(fd, level, optname, optval, (socklen_t *)optlen) != 0 )
3784 SetLastError(wsaErrno());
3785 ret = SOCKET_ERROR;
3787 release_sock_fd( s, fd );
3788 return ret;
3789 case WS_IP_DONTFRAGMENT:
3790 return get_dont_fragment(s, IPPROTO_IP, (BOOL *)optval) ? 0 : SOCKET_ERROR;
3792 FIXME("Unknown IPPROTO_IP optname 0x%08x\n", optname);
3793 return SOCKET_ERROR;
3795 case WS_IPPROTO_IPV6:
3796 switch(optname)
3798 #ifdef IPV6_ADD_MEMBERSHIP
3799 case WS_IPV6_ADD_MEMBERSHIP:
3800 #endif
3801 #ifdef IPV6_DROP_MEMBERSHIP
3802 case WS_IPV6_DROP_MEMBERSHIP:
3803 #endif
3804 case WS_IPV6_MULTICAST_IF:
3805 case WS_IPV6_MULTICAST_HOPS:
3806 case WS_IPV6_MULTICAST_LOOP:
3807 case WS_IPV6_UNICAST_HOPS:
3808 case WS_IPV6_V6ONLY:
3809 #ifdef IPV6_UNICAST_IF
3810 case WS_IPV6_UNICAST_IF:
3811 #endif
3812 if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
3813 return SOCKET_ERROR;
3814 convert_sockopt(&level, &optname);
3815 if (getsockopt(fd, level, optname, optval, (socklen_t *)optlen) != 0 )
3817 SetLastError(wsaErrno());
3818 ret = SOCKET_ERROR;
3820 release_sock_fd( s, fd );
3821 return ret;
3822 case WS_IPV6_DONTFRAG:
3823 return get_dont_fragment(s, IPPROTO_IPV6, (BOOL *)optval) ? 0 : SOCKET_ERROR;
3825 FIXME("Unknown IPPROTO_IPV6 optname 0x%08x\n", optname);
3826 return SOCKET_ERROR;
3828 default:
3829 WARN("Unknown level: 0x%08x\n", level);
3830 SetLastError(WSAEINVAL);
3831 return SOCKET_ERROR;
3832 } /* end switch(level) */
3836 static const char *debugstr_wsaioctl(DWORD code)
3838 const char *name = NULL, *buf_type, *family;
3840 #define IOCTL_NAME(x) case x: name = #x; break
3841 switch (code)
3843 IOCTL_NAME(WS_FIONBIO);
3844 IOCTL_NAME(WS_FIONREAD);
3845 IOCTL_NAME(WS_SIOCATMARK);
3846 /* IOCTL_NAME(WS_SIO_ACQUIRE_PORT_RESERVATION); */
3847 IOCTL_NAME(WS_SIO_ADDRESS_LIST_CHANGE);
3848 IOCTL_NAME(WS_SIO_ADDRESS_LIST_QUERY);
3849 IOCTL_NAME(WS_SIO_ASSOCIATE_HANDLE);
3850 /* IOCTL_NAME(WS_SIO_ASSOCIATE_PORT_RESERVATION);
3851 IOCTL_NAME(WS_SIO_BASE_HANDLE);
3852 IOCTL_NAME(WS_SIO_BSP_HANDLE);
3853 IOCTL_NAME(WS_SIO_BSP_HANDLE_SELECT);
3854 IOCTL_NAME(WS_SIO_BSP_HANDLE_POLL);
3855 IOCTL_NAME(WS_SIO_CHK_QOS); */
3856 IOCTL_NAME(WS_SIO_ENABLE_CIRCULAR_QUEUEING);
3857 IOCTL_NAME(WS_SIO_FIND_ROUTE);
3858 IOCTL_NAME(WS_SIO_FLUSH);
3859 IOCTL_NAME(WS_SIO_GET_BROADCAST_ADDRESS);
3860 IOCTL_NAME(WS_SIO_GET_EXTENSION_FUNCTION_POINTER);
3861 IOCTL_NAME(WS_SIO_GET_GROUP_QOS);
3862 IOCTL_NAME(WS_SIO_GET_INTERFACE_LIST);
3863 /* IOCTL_NAME(WS_SIO_GET_INTERFACE_LIST_EX); */
3864 IOCTL_NAME(WS_SIO_GET_QOS);
3865 IOCTL_NAME(WS_SIO_IDEAL_SEND_BACKLOG_CHANGE);
3866 IOCTL_NAME(WS_SIO_IDEAL_SEND_BACKLOG_QUERY);
3867 IOCTL_NAME(WS_SIO_KEEPALIVE_VALS);
3868 IOCTL_NAME(WS_SIO_MULTIPOINT_LOOPBACK);
3869 IOCTL_NAME(WS_SIO_MULTICAST_SCOPE);
3870 /* IOCTL_NAME(WS_SIO_QUERY_RSS_SCALABILITY_INFO);
3871 IOCTL_NAME(WS_SIO_QUERY_WFP_ALE_ENDPOINT_HANDLE); */
3872 IOCTL_NAME(WS_SIO_RCVALL);
3873 IOCTL_NAME(WS_SIO_RCVALL_IGMPMCAST);
3874 IOCTL_NAME(WS_SIO_RCVALL_MCAST);
3875 /* IOCTL_NAME(WS_SIO_RELEASE_PORT_RESERVATION); */
3876 IOCTL_NAME(WS_SIO_ROUTING_INTERFACE_CHANGE);
3877 IOCTL_NAME(WS_SIO_ROUTING_INTERFACE_QUERY);
3878 IOCTL_NAME(WS_SIO_SET_COMPATIBILITY_MODE);
3879 IOCTL_NAME(WS_SIO_SET_GROUP_QOS);
3880 IOCTL_NAME(WS_SIO_SET_QOS);
3881 IOCTL_NAME(WS_SIO_TRANSLATE_HANDLE);
3882 IOCTL_NAME(WS_SIO_UDP_CONNRESET);
3884 #undef IOCTL_NAME
3886 if (name)
3887 return name + 3;
3889 /* If this is not a known code split its bits */
3890 switch(code & 0x18000000)
3892 case WS_IOC_WS2:
3893 family = "IOC_WS2";
3894 break;
3895 case WS_IOC_PROTOCOL:
3896 family = "IOC_PROTOCOL";
3897 break;
3898 case WS_IOC_VENDOR:
3899 family = "IOC_VENDOR";
3900 break;
3901 default: /* WS_IOC_UNIX */
3903 BYTE size = (code >> 16) & WS_IOCPARM_MASK;
3904 char x = (code & 0xff00) >> 8;
3905 BYTE y = code & 0xff;
3906 char args[14];
3908 switch (code & (WS_IOC_VOID|WS_IOC_INOUT))
3910 case WS_IOC_VOID:
3911 buf_type = "_IO";
3912 sprintf(args, "%d, %d", x, y);
3913 break;
3914 case WS_IOC_IN:
3915 buf_type = "_IOW";
3916 sprintf(args, "'%c', %d, %d", x, y, size);
3917 break;
3918 case WS_IOC_OUT:
3919 buf_type = "_IOR";
3920 sprintf(args, "'%c', %d, %d", x, y, size);
3921 break;
3922 default:
3923 buf_type = "?";
3924 sprintf(args, "'%c', %d, %d", x, y, size);
3925 break;
3927 return wine_dbg_sprintf("%s(%s)", buf_type, args);
3931 /* We are different from WS_IOC_UNIX. */
3932 switch (code & (WS_IOC_VOID|WS_IOC_INOUT))
3934 case WS_IOC_VOID:
3935 buf_type = "_WSAIO";
3936 break;
3937 case WS_IOC_INOUT:
3938 buf_type = "_WSAIORW";
3939 break;
3940 case WS_IOC_IN:
3941 buf_type = "_WSAIOW";
3942 break;
3943 case WS_IOC_OUT:
3944 buf_type = "_WSAIOR";
3945 break;
3946 default:
3947 buf_type = "?";
3948 break;
3951 return wine_dbg_sprintf("%s(%s, %d)", buf_type, family,
3952 (USHORT)(code & 0xffff));
3955 /* do an ioctl call through the server */
3956 static DWORD server_ioctl_sock( SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size,
3957 LPVOID out_buff, DWORD out_size, LPDWORD ret_size,
3958 LPWSAOVERLAPPED overlapped,
3959 LPWSAOVERLAPPED_COMPLETION_ROUTINE completion )
3961 HANDLE event = overlapped ? overlapped->hEvent : 0;
3962 HANDLE handle = SOCKET2HANDLE( s );
3963 struct ws2_async *wsa = NULL;
3964 IO_STATUS_BLOCK *io = (PIO_STATUS_BLOCK)overlapped, iosb;
3965 void *cvalue = NULL;
3966 NTSTATUS status;
3968 if (completion)
3970 if (!(wsa = (struct ws2_async *)alloc_async_io( sizeof(*wsa), NULL )))
3971 return WSA_NOT_ENOUGH_MEMORY;
3972 wsa->hSocket = handle;
3973 wsa->user_overlapped = overlapped;
3974 wsa->completion_func = completion;
3975 if (!io) io = &wsa->local_iosb;
3976 cvalue = wsa;
3978 else if (!io)
3979 io = &iosb;
3980 else if (!((ULONG_PTR)overlapped->hEvent & 1))
3981 cvalue = overlapped;
3983 status = NtDeviceIoControlFile( handle, event, wsa ? ws2_async_apc : NULL, cvalue, io, code,
3984 in_buff, in_size, out_buff, out_size );
3985 if (status == STATUS_NOT_SUPPORTED)
3987 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
3988 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
3990 else if (status == STATUS_SUCCESS)
3991 *ret_size = io->Information; /* "Information" is the size written to the output buffer */
3993 if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, wsa );
3995 return NtStatusToWSAError( status );
3998 static DWORD get_interface_list(SOCKET s, void *out_buff, DWORD out_size, DWORD *ret_size, DWORD *total_bytes)
4000 DWORD size, interface_count = 0, ret;
4001 INTERFACE_INFO *info = out_buff;
4002 PMIB_IPADDRTABLE table = NULL;
4003 struct if_nameindex *if_ni;
4004 DWORD status = 0;
4005 int fd;
4007 if (!out_buff || !ret_size)
4008 return WSAEFAULT;
4010 if ((fd = get_sock_fd(s, 0, NULL)) == -1)
4011 return SOCKET_ERROR;
4013 if ((ret = GetIpAddrTable(NULL, &size, TRUE)) != ERROR_INSUFFICIENT_BUFFER)
4015 if (ret != ERROR_NO_DATA)
4017 ERR("Unable to get ip address table.\n");
4018 status = WSAEINVAL;
4020 goto done;
4022 if (!(table = heap_alloc(size)))
4024 ERR("No memory.\n");
4025 status = WSAEINVAL;
4026 goto done;
4028 if (GetIpAddrTable(table, &size, TRUE) != NO_ERROR)
4030 ERR("Unable to get interface table.\n");
4031 status = WSAEINVAL;
4032 goto done;
4034 if (table->dwNumEntries * sizeof(INTERFACE_INFO) > out_size)
4036 WARN("Buffer too small, dwNumEntries %u, out_size = %u.\n", table->dwNumEntries, out_size);
4037 *ret_size = 0;
4038 status = WSAEFAULT;
4039 goto done;
4042 if (!(if_ni = if_nameindex()))
4044 ERR("Unable to get interface name index.\n");
4045 status = WSAEINVAL;
4046 goto done;
4049 for (; interface_count < table->dwNumEntries; ++interface_count, ++info)
4051 unsigned int addr, mask;
4052 struct ifreq if_info;
4053 unsigned int i;
4055 memset(info, 0, sizeof(*info));
4057 for (i = 0; if_ni[i].if_index || if_ni[i].if_name; ++i)
4058 if (if_ni[i].if_index == table->table[interface_count].dwIndex)
4059 break;
4061 if (!if_ni[i].if_name)
4063 ERR("Error obtaining interface name for ifindex %u.\n", table->table[interface_count].dwIndex);
4064 status = WSAEINVAL;
4065 break;
4068 lstrcpynA(if_info.ifr_name, if_ni[i].if_name, IFNAMSIZ);
4069 if (ioctl(fd, SIOCGIFFLAGS, &if_info) < 0)
4071 ERR("Error obtaining status flags for socket.\n");
4072 status = WSAEINVAL;
4073 break;
4076 if (if_info.ifr_flags & IFF_BROADCAST)
4077 info->iiFlags |= WS_IFF_BROADCAST;
4078 #ifdef IFF_POINTOPOINT
4079 if (if_info.ifr_flags & IFF_POINTOPOINT)
4080 info->iiFlags |= WS_IFF_POINTTOPOINT;
4081 #endif
4082 if (if_info.ifr_flags & IFF_LOOPBACK)
4083 info->iiFlags |= WS_IFF_LOOPBACK;
4084 if (if_info.ifr_flags & IFF_UP)
4085 info->iiFlags |= WS_IFF_UP;
4086 if (if_info.ifr_flags & IFF_MULTICAST)
4087 info->iiFlags |= WS_IFF_MULTICAST;
4089 addr = table->table[interface_count].dwAddr;
4090 mask = table->table[interface_count].dwMask;
4092 info->iiAddress.AddressIn.sin_family = WS_AF_INET;
4093 info->iiAddress.AddressIn.sin_port = 0;
4094 info->iiAddress.AddressIn.sin_addr.WS_s_addr = addr;
4096 info->iiNetmask.AddressIn.sin_family = WS_AF_INET;
4097 info->iiNetmask.AddressIn.sin_port = 0;
4098 info->iiNetmask.AddressIn.sin_addr.WS_s_addr = mask;
4100 if (if_info.ifr_flags & IFF_BROADCAST)
4102 info->iiBroadcastAddress.AddressIn.sin_family = WS_AF_INET;
4103 info->iiBroadcastAddress.AddressIn.sin_port = 0;
4104 info->iiBroadcastAddress.AddressIn.sin_addr.WS_s_addr = addr | ~mask;
4107 if_freenameindex(if_ni);
4108 done:
4109 heap_free(table);
4110 *total_bytes = sizeof(INTERFACE_INFO) * interface_count;
4111 release_sock_fd(s, fd);
4112 return status;
4115 /**********************************************************************
4116 * WSAIoctl (WS2_32.50)
4119 INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID out_buff,
4120 DWORD out_size, LPDWORD ret_size, LPWSAOVERLAPPED overlapped,
4121 LPWSAOVERLAPPED_COMPLETION_ROUTINE completion )
4123 int fd;
4124 DWORD status = 0, total = 0;
4126 TRACE("%04lx, %s, %p, %d, %p, %d, %p, %p, %p\n",
4127 s, debugstr_wsaioctl(code), in_buff, in_size, out_buff, out_size, ret_size, overlapped, completion);
4129 switch (code)
4131 case WS_FIONBIO:
4132 if (in_size != sizeof(WS_u_long) || IS_INTRESOURCE(in_buff))
4134 SetLastError(WSAEFAULT);
4135 return SOCKET_ERROR;
4137 TRACE("-> FIONBIO (%x)\n", *(WS_u_long*)in_buff);
4138 if (_get_sock_mask(s))
4140 /* AsyncSelect()'ed sockets are always nonblocking */
4141 if (!*(WS_u_long *)in_buff) status = WSAEINVAL;
4142 break;
4144 if (*(WS_u_long *)in_buff)
4145 _enable_event(SOCKET2HANDLE(s), 0, FD_WINE_NONBLOCKING, 0);
4146 else
4147 _enable_event(SOCKET2HANDLE(s), 0, 0, FD_WINE_NONBLOCKING);
4148 break;
4150 case WS_FIONREAD:
4152 #if defined(linux)
4153 int listening = 0;
4154 socklen_t len = sizeof(listening);
4155 #endif
4156 if (out_size != sizeof(WS_u_long) || IS_INTRESOURCE(out_buff))
4158 SetLastError(WSAEFAULT);
4159 return SOCKET_ERROR;
4161 if ((fd = get_sock_fd( s, 0, NULL )) == -1) return SOCKET_ERROR;
4163 #if defined(linux)
4164 /* On Linux, FIONREAD on listening socket always fails (see tcp(7)).
4165 However, it succeeds on native. */
4166 if (!getsockopt( fd, SOL_SOCKET, SO_ACCEPTCONN, &listening, &len ) && listening)
4167 (*(WS_u_long *) out_buff) = 0;
4168 else
4169 #endif
4170 if (ioctl(fd, FIONREAD, out_buff ) == -1)
4171 status = wsaErrno();
4172 release_sock_fd( s, fd );
4173 break;
4176 case WS_SIOCATMARK:
4178 unsigned int oob = 0, atmark = 0;
4179 socklen_t oobsize = sizeof(int);
4180 if (out_size != sizeof(WS_u_long) || IS_INTRESOURCE(out_buff))
4182 SetLastError(WSAEFAULT);
4183 return SOCKET_ERROR;
4185 if ((fd = get_sock_fd( s, 0, NULL )) == -1) return SOCKET_ERROR;
4186 /* SO_OOBINLINE sockets must always return TRUE to SIOCATMARK */
4187 if ((getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &oob, &oobsize ) == -1)
4188 || (!oob && ioctl(fd, SIOCATMARK, &atmark ) == -1))
4189 status = wsaErrno();
4190 else
4192 /* The SIOCATMARK value read from ioctl() is reversed
4193 * because BSD returns TRUE if it's in the OOB mark
4194 * while Windows returns TRUE if there are NO OOB bytes.
4196 (*(WS_u_long *) out_buff) = oob || !atmark;
4199 release_sock_fd( s, fd );
4200 break;
4203 case WS_FIOASYNC:
4204 WARN("Warning: WS1.1 shouldn't be using async I/O\n");
4205 SetLastError(WSAEINVAL);
4206 return SOCKET_ERROR;
4208 case WS_SIO_GET_INTERFACE_LIST:
4210 TRACE("-> SIO_GET_INTERFACE_LIST request\n");
4212 status = get_interface_list(s, out_buff, out_size, ret_size, &total);
4213 break;
4216 case WS_SIO_ADDRESS_LIST_QUERY:
4218 DWORD size;
4220 TRACE("-> SIO_ADDRESS_LIST_QUERY request\n");
4222 if (!ret_size)
4224 SetLastError(WSAEFAULT);
4225 return SOCKET_ERROR;
4228 if (out_size && out_size < FIELD_OFFSET(SOCKET_ADDRESS_LIST, Address[0]))
4230 *ret_size = 0;
4231 SetLastError(WSAEINVAL);
4232 return SOCKET_ERROR;
4235 if (GetAdaptersInfo(NULL, &size) == ERROR_BUFFER_OVERFLOW)
4237 IP_ADAPTER_INFO *p, *table = HeapAlloc(GetProcessHeap(), 0, size);
4238 SOCKET_ADDRESS_LIST *sa_list;
4239 SOCKADDR_IN *sockaddr;
4240 SOCKET_ADDRESS *sa;
4241 unsigned int i;
4242 DWORD num;
4244 if (!table || GetAdaptersInfo(table, &size))
4246 HeapFree(GetProcessHeap(), 0, table);
4247 status = WSAEINVAL;
4248 break;
4251 for (p = table, num = 0; p; p = p->Next)
4252 if (p->IpAddressList.IpAddress.String[0]) num++;
4254 total = FIELD_OFFSET(SOCKET_ADDRESS_LIST, Address[num]) + num * sizeof(*sockaddr);
4255 if (total > out_size || !out_buff)
4257 *ret_size = total;
4258 HeapFree(GetProcessHeap(), 0, table);
4259 status = WSAEFAULT;
4260 break;
4263 sa_list = out_buff;
4264 sa = sa_list->Address;
4265 sockaddr = (SOCKADDR_IN *)&sa[num];
4266 sa_list->iAddressCount = num;
4268 for (p = table, i = 0; p; p = p->Next)
4270 if (!p->IpAddressList.IpAddress.String[0]) continue;
4272 sa[i].lpSockaddr = (SOCKADDR *)&sockaddr[i];
4273 sa[i].iSockaddrLength = sizeof(SOCKADDR);
4275 sockaddr[i].sin_family = WS_AF_INET;
4276 sockaddr[i].sin_port = 0;
4277 sockaddr[i].sin_addr.WS_s_addr = inet_addr(p->IpAddressList.IpAddress.String);
4278 i++;
4281 HeapFree(GetProcessHeap(), 0, table);
4283 else
4285 WARN("unable to get IP address list\n");
4286 status = WSAEINVAL;
4288 break;
4291 case WS_SIO_FLUSH:
4292 FIXME("SIO_FLUSH: stub.\n");
4293 break;
4295 case WS_SIO_GET_EXTENSION_FUNCTION_POINTER:
4297 #define EXTENSION_FUNCTION(x, y) { x, y, #y },
4298 static const struct
4300 GUID guid;
4301 void *func_ptr;
4302 const char *name;
4303 } guid_funcs[] = {
4304 EXTENSION_FUNCTION(WSAID_CONNECTEX, WS2_ConnectEx)
4305 EXTENSION_FUNCTION(WSAID_DISCONNECTEX, WS2_DisconnectEx)
4306 EXTENSION_FUNCTION(WSAID_ACCEPTEX, WS2_AcceptEx)
4307 EXTENSION_FUNCTION(WSAID_GETACCEPTEXSOCKADDRS, WS2_GetAcceptExSockaddrs)
4308 EXTENSION_FUNCTION(WSAID_TRANSMITFILE, WS2_TransmitFile)
4309 /* EXTENSION_FUNCTION(WSAID_TRANSMITPACKETS, WS2_TransmitPackets) */
4310 EXTENSION_FUNCTION(WSAID_WSARECVMSG, WS2_WSARecvMsg)
4311 EXTENSION_FUNCTION(WSAID_WSASENDMSG, WSASendMsg)
4313 #undef EXTENSION_FUNCTION
4314 BOOL found = FALSE;
4315 unsigned int i;
4317 for (i = 0; i < ARRAY_SIZE(guid_funcs); i++)
4319 if (IsEqualGUID(&guid_funcs[i].guid, in_buff))
4321 found = TRUE;
4322 break;
4326 if (found)
4328 TRACE("-> got %s\n", guid_funcs[i].name);
4329 *(void **)out_buff = guid_funcs[i].func_ptr;
4330 total = sizeof(void *);
4331 break;
4334 FIXME("SIO_GET_EXTENSION_FUNCTION_POINTER %s: stub\n", debugstr_guid(in_buff));
4335 status = WSAEOPNOTSUPP;
4336 break;
4338 case WS_SIO_KEEPALIVE_VALS:
4340 struct tcp_keepalive *k;
4341 int keepalive, keepidle, keepintvl;
4343 if (!in_buff || in_size < sizeof(struct tcp_keepalive))
4345 SetLastError(WSAEFAULT);
4346 return SOCKET_ERROR;
4349 k = in_buff;
4350 keepalive = k->onoff ? 1 : 0;
4351 keepidle = max( 1, (k->keepalivetime + 500) / 1000 );
4352 keepintvl = max( 1, (k->keepaliveinterval + 500) / 1000 );
4354 TRACE("onoff: %d, keepalivetime: %d, keepaliveinterval: %d\n", keepalive, keepidle, keepintvl);
4356 fd = get_sock_fd(s, 0, NULL);
4357 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(int)) == -1)
4358 status = WSAEINVAL;
4359 #if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL)
4360 /* these values need to be set only if SO_KEEPALIVE is enabled */
4361 else if(keepalive)
4363 #ifndef TCP_KEEPIDLE
4364 FIXME("ignoring keepalive timeout\n");
4365 #else
4366 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle, sizeof(int)) == -1)
4367 status = WSAEINVAL;
4368 else
4369 #endif
4370 #ifdef TCP_KEEPINTVL
4371 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepintvl, sizeof(int)) == -1)
4372 status = WSAEINVAL;
4373 #else
4374 FIXME("ignoring keepalive interval\n");
4375 #endif
4377 #else
4378 else
4379 FIXME("ignoring keepalive interval and timeout\n");
4380 #endif
4381 release_sock_fd(s, fd);
4382 break;
4384 case WS_SIO_ROUTING_INTERFACE_QUERY:
4386 struct WS_sockaddr *daddr = (struct WS_sockaddr *)in_buff;
4387 struct WS_sockaddr_in *daddr_in = (struct WS_sockaddr_in *)daddr;
4388 struct WS_sockaddr_in *saddr_in = out_buff;
4389 MIB_IPFORWARDROW row;
4390 PMIB_IPADDRTABLE ipAddrTable = NULL;
4391 DWORD size, i, found_index;
4393 TRACE("-> WS_SIO_ROUTING_INTERFACE_QUERY request\n");
4395 if (!in_buff || in_size < sizeof(struct WS_sockaddr) ||
4396 !out_buff || out_size < sizeof(struct WS_sockaddr_in) || !ret_size)
4398 SetLastError(WSAEFAULT);
4399 return SOCKET_ERROR;
4401 if (daddr->sa_family != WS_AF_INET)
4403 FIXME("unsupported address family %d\n", daddr->sa_family);
4404 status = WSAEAFNOSUPPORT;
4405 break;
4407 if (GetBestRoute(daddr_in->sin_addr.S_un.S_addr, 0, &row) != NOERROR ||
4408 GetIpAddrTable(NULL, &size, FALSE) != ERROR_INSUFFICIENT_BUFFER)
4410 status = WSAEFAULT;
4411 break;
4413 ipAddrTable = HeapAlloc(GetProcessHeap(), 0, size);
4414 if (GetIpAddrTable(ipAddrTable, &size, FALSE))
4416 HeapFree(GetProcessHeap(), 0, ipAddrTable);
4417 status = WSAEFAULT;
4418 break;
4420 for (i = 0, found_index = ipAddrTable->dwNumEntries;
4421 i < ipAddrTable->dwNumEntries; i++)
4423 if (ipAddrTable->table[i].dwIndex == row.dwForwardIfIndex)
4424 found_index = i;
4426 if (found_index == ipAddrTable->dwNumEntries)
4428 ERR("no matching IP address for interface %d\n",
4429 row.dwForwardIfIndex);
4430 HeapFree(GetProcessHeap(), 0, ipAddrTable);
4431 status = WSAEFAULT;
4432 break;
4434 saddr_in->sin_family = WS_AF_INET;
4435 saddr_in->sin_addr.S_un.S_addr = ipAddrTable->table[found_index].dwAddr;
4436 saddr_in->sin_port = 0;
4437 total = sizeof(struct WS_sockaddr_in);
4438 HeapFree(GetProcessHeap(), 0, ipAddrTable);
4439 break;
4441 case WS_SIO_SET_COMPATIBILITY_MODE:
4442 TRACE("WS_SIO_SET_COMPATIBILITY_MODE ignored\n");
4443 status = WSAEOPNOTSUPP;
4444 break;
4445 case WS_SIO_UDP_CONNRESET:
4446 FIXME("WS_SIO_UDP_CONNRESET stub\n");
4447 break;
4448 case 0x667e: /* Netscape tries hard to use bogus ioctl 0x667e */
4449 SetLastError(WSAEOPNOTSUPP);
4450 return SOCKET_ERROR;
4451 case WS_SIO_ADDRESS_LIST_CHANGE:
4452 code = IOCTL_AFD_WINE_ADDRESS_LIST_CHANGE;
4453 status = WSAEOPNOTSUPP;
4454 break;
4455 default:
4456 status = WSAEOPNOTSUPP;
4457 break;
4460 if (status == WSAEOPNOTSUPP)
4462 status = server_ioctl_sock(s, code, in_buff, in_size, out_buff, out_size, &total,
4463 overlapped, completion);
4464 if (status != WSAEOPNOTSUPP)
4466 if (status == 0 || status == WSA_IO_PENDING || status == WSAEWOULDBLOCK)
4467 TRACE("-> %s request\n", debugstr_wsaioctl(code));
4468 else
4469 ERR("-> %s request failed with status 0x%x\n", debugstr_wsaioctl(code), status);
4471 /* overlapped and completion operations will be handled by the server */
4472 completion = NULL;
4473 overlapped = NULL;
4475 else
4476 FIXME("unsupported WS_IOCTL cmd (%s)\n", debugstr_wsaioctl(code));
4479 if (completion)
4481 FIXME( "completion routine %p not supported\n", completion );
4483 else if (overlapped)
4485 ULONG_PTR cvalue = (overlapped && ((ULONG_PTR)overlapped->hEvent & 1) == 0) ? (ULONG_PTR)overlapped : 0;
4486 overlapped->Internal = sock_error_to_ntstatus( status );
4487 overlapped->InternalHigh = total;
4488 if (cvalue) WS_AddCompletion( HANDLE2SOCKET(s), cvalue, overlapped->Internal, total, FALSE );
4489 if (overlapped->hEvent) NtSetEvent( overlapped->hEvent, NULL );
4492 if (!status)
4494 if (ret_size) *ret_size = total;
4495 return 0;
4497 SetLastError( status );
4498 return SOCKET_ERROR;
4502 /***********************************************************************
4503 * ioctlsocket (WS2_32.10)
4505 int WINAPI WS_ioctlsocket(SOCKET s, LONG cmd, WS_u_long *argp)
4507 DWORD ret_size;
4508 return WSAIoctl( s, cmd, argp, sizeof(WS_u_long), argp, sizeof(WS_u_long), &ret_size, NULL, NULL );
4512 /***********************************************************************
4513 * listen (ws2_32.13)
4515 int WINAPI WS_listen( SOCKET s, int backlog )
4517 struct afd_listen_params params = {.backlog = backlog};
4518 IO_STATUS_BLOCK io;
4519 NTSTATUS status;
4520 int fd, bound;
4522 TRACE( "socket %#lx, backlog %d\n", s, backlog );
4524 if ((fd = get_sock_fd( s, FILE_READ_DATA, NULL )) == -1)
4525 return -1;
4526 bound = is_fd_bound( fd, NULL, NULL );
4527 release_sock_fd( s, fd );
4528 if (bound <= 0)
4530 SetLastError( bound ? wsaErrno() : WSAEINVAL );
4531 return -1;
4534 status = NtDeviceIoControlFile( SOCKET2HANDLE(s), NULL, NULL, NULL, &io,
4535 IOCTL_AFD_LISTEN, &params, sizeof(params), NULL, 0 );
4536 SetLastError( NtStatusToWSAError( status ) );
4537 return status ? -1 : 0;
4541 /***********************************************************************
4542 * recv (WS2_32.16)
4544 int WINAPI WS_recv(SOCKET s, char *buf, int len, int flags)
4546 DWORD n, dwFlags = flags;
4547 WSABUF wsabuf;
4549 wsabuf.len = len;
4550 wsabuf.buf = buf;
4552 if ( WS2_recv_base(s, &wsabuf, 1, &n, &dwFlags, NULL, NULL, NULL, NULL, NULL) == SOCKET_ERROR )
4553 return SOCKET_ERROR;
4554 else
4555 return n;
4558 /***********************************************************************
4559 * recvfrom (WS2_32.17)
4561 int WINAPI WS_recvfrom(SOCKET s, char *buf, INT len, int flags,
4562 struct WS_sockaddr *from, int *fromlen)
4564 DWORD n, dwFlags = flags;
4565 WSABUF wsabuf;
4567 wsabuf.len = len;
4568 wsabuf.buf = buf;
4570 if ( WS2_recv_base(s, &wsabuf, 1, &n, &dwFlags, from, fromlen, NULL, NULL, NULL) == SOCKET_ERROR )
4571 return SOCKET_ERROR;
4572 else
4573 return n;
4576 /* allocate a poll array for the corresponding fd sets */
4577 static struct pollfd *fd_sets_to_poll( const WS_fd_set *readfds, const WS_fd_set *writefds,
4578 const WS_fd_set *exceptfds, int *count_ptr )
4580 unsigned int i, j = 0, count = 0;
4581 struct pollfd *fds;
4582 struct per_thread_data *ptb = get_per_thread_data();
4584 if (readfds) count += readfds->fd_count;
4585 if (writefds) count += writefds->fd_count;
4586 if (exceptfds) count += exceptfds->fd_count;
4587 *count_ptr = count;
4588 if (!count)
4590 SetLastError(WSAEINVAL);
4591 return NULL;
4594 /* check if the cache can hold all descriptors, if not do the resizing */
4595 if (ptb->fd_count < count)
4597 if (!(fds = HeapAlloc(GetProcessHeap(), 0, count * sizeof(fds[0]))))
4599 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
4600 return NULL;
4602 HeapFree(GetProcessHeap(), 0, ptb->fd_cache);
4603 ptb->fd_cache = fds;
4604 ptb->fd_count = count;
4606 else
4607 fds = ptb->fd_cache;
4609 if (readfds)
4610 for (i = 0; i < readfds->fd_count; i++, j++)
4612 fds[j].fd = get_sock_fd( readfds->fd_array[i], FILE_READ_DATA, NULL );
4613 if (fds[j].fd == -1) goto failed;
4614 fds[j].revents = 0;
4615 if (is_fd_bound(fds[j].fd, NULL, NULL) == 1)
4617 fds[j].events = POLLIN;
4619 else
4621 release_sock_fd( readfds->fd_array[i], fds[j].fd );
4622 fds[j].fd = -1;
4623 fds[j].events = 0;
4626 if (writefds)
4627 for (i = 0; i < writefds->fd_count; i++, j++)
4629 fds[j].fd = get_sock_fd( writefds->fd_array[i], FILE_WRITE_DATA, NULL );
4630 if (fds[j].fd == -1) goto failed;
4631 fds[j].revents = 0;
4632 if (is_fd_bound(fds[j].fd, NULL, NULL) == 1 ||
4633 _get_fd_type(fds[j].fd) == SOCK_DGRAM)
4635 fds[j].events = POLLOUT;
4637 else
4639 release_sock_fd( writefds->fd_array[i], fds[j].fd );
4640 fds[j].fd = -1;
4641 fds[j].events = 0;
4644 if (exceptfds)
4645 for (i = 0; i < exceptfds->fd_count; i++, j++)
4647 fds[j].fd = get_sock_fd( exceptfds->fd_array[i], 0, NULL );
4648 if (fds[j].fd == -1) goto failed;
4649 fds[j].revents = 0;
4650 if (is_fd_bound(fds[j].fd, NULL, NULL) == 1)
4652 int oob_inlined = 0;
4653 socklen_t olen = sizeof(oob_inlined);
4655 fds[j].events = POLLHUP;
4657 /* Check if we need to test for urgent data or not */
4658 getsockopt(fds[j].fd, SOL_SOCKET, SO_OOBINLINE, (char*) &oob_inlined, &olen);
4659 if (!oob_inlined)
4660 fds[j].events |= POLLPRI;
4662 else
4664 release_sock_fd( exceptfds->fd_array[i], fds[j].fd );
4665 fds[j].fd = -1;
4666 fds[j].events = 0;
4669 return fds;
4671 failed:
4672 count = j;
4673 j = 0;
4674 if (readfds)
4675 for (i = 0; i < readfds->fd_count && j < count; i++, j++)
4676 if (fds[j].fd != -1) release_sock_fd( readfds->fd_array[i], fds[j].fd );
4677 if (writefds)
4678 for (i = 0; i < writefds->fd_count && j < count; i++, j++)
4679 if (fds[j].fd != -1) release_sock_fd( writefds->fd_array[i], fds[j].fd );
4680 if (exceptfds)
4681 for (i = 0; i < exceptfds->fd_count && j < count; i++, j++)
4682 if (fds[j].fd != -1) release_sock_fd( exceptfds->fd_array[i], fds[j].fd );
4683 return NULL;
4686 /* release the file descriptor obtained in fd_sets_to_poll */
4687 /* must be called with the original fd_set arrays, before calling get_poll_results */
4688 static void release_poll_fds( const WS_fd_set *readfds, const WS_fd_set *writefds,
4689 const WS_fd_set *exceptfds, struct pollfd *fds )
4691 unsigned int i, j = 0;
4693 if (readfds)
4695 for (i = 0; i < readfds->fd_count; i++, j++)
4696 if (fds[j].fd != -1) release_sock_fd( readfds->fd_array[i], fds[j].fd );
4698 if (writefds)
4700 for (i = 0; i < writefds->fd_count; i++, j++)
4701 if (fds[j].fd != -1) release_sock_fd( writefds->fd_array[i], fds[j].fd );
4703 if (exceptfds)
4705 for (i = 0; i < exceptfds->fd_count; i++, j++)
4707 if (fds[j].fd == -1) continue;
4708 release_sock_fd( exceptfds->fd_array[i], fds[j].fd );
4709 if (fds[j].revents & POLLHUP)
4711 int fd = get_sock_fd( exceptfds->fd_array[i], 0, NULL );
4712 if (fd != -1)
4713 release_sock_fd( exceptfds->fd_array[i], fd );
4714 else
4715 fds[j].revents = 0;
4721 static int do_poll(struct pollfd *pollfds, int count, int timeout)
4723 struct timeval tv1, tv2;
4724 int ret, torig = timeout;
4726 if (timeout > 0) gettimeofday( &tv1, 0 );
4728 while ((ret = poll( pollfds, count, timeout )) < 0)
4730 if (errno != EINTR) break;
4731 if (timeout < 0) continue;
4732 if (timeout == 0) return 0;
4734 gettimeofday( &tv2, 0 );
4736 tv2.tv_sec -= tv1.tv_sec;
4737 tv2.tv_usec -= tv1.tv_usec;
4738 if (tv2.tv_usec < 0)
4740 tv2.tv_usec += 1000000;
4741 tv2.tv_sec -= 1;
4744 timeout = torig - (tv2.tv_sec * 1000) - (tv2.tv_usec + 999) / 1000;
4745 if (timeout <= 0) return 0;
4747 return ret;
4750 /* map the poll results back into the Windows fd sets */
4751 static int get_poll_results( WS_fd_set *readfds, WS_fd_set *writefds, WS_fd_set *exceptfds,
4752 const struct pollfd *fds )
4754 const struct pollfd *poll_writefds = fds + (readfds ? readfds->fd_count : 0);
4755 const struct pollfd *poll_exceptfds = poll_writefds + (writefds ? writefds->fd_count : 0);
4756 unsigned int i, k, total = 0;
4758 if (readfds)
4760 for (i = k = 0; i < readfds->fd_count; i++)
4762 if (fds[i].revents ||
4763 (readfds == writefds && (poll_writefds[i].revents & POLLOUT) && !(poll_writefds[i].revents & POLLHUP)) ||
4764 (readfds == exceptfds && poll_exceptfds[i].revents))
4765 readfds->fd_array[k++] = readfds->fd_array[i];
4767 readfds->fd_count = k;
4768 total += k;
4770 if (writefds && writefds != readfds)
4772 for (i = k = 0; i < writefds->fd_count; i++)
4774 if (((poll_writefds[i].revents & POLLOUT) && !(poll_writefds[i].revents & POLLHUP)) ||
4775 (writefds == exceptfds && poll_exceptfds[i].revents))
4776 writefds->fd_array[k++] = writefds->fd_array[i];
4778 writefds->fd_count = k;
4779 total += k;
4781 if (exceptfds && exceptfds != readfds && exceptfds != writefds)
4783 for (i = k = 0; i < exceptfds->fd_count; i++)
4784 if (poll_exceptfds[i].revents) exceptfds->fd_array[k++] = exceptfds->fd_array[i];
4785 exceptfds->fd_count = k;
4786 total += k;
4788 return total;
4791 /***********************************************************************
4792 * select (WS2_32.18)
4794 int WINAPI WS_select(int nfds, WS_fd_set *ws_readfds,
4795 WS_fd_set *ws_writefds, WS_fd_set *ws_exceptfds,
4796 const struct WS_timeval* ws_timeout)
4798 struct pollfd *pollfds;
4799 int count, ret, timeout = -1;
4801 TRACE("read %p, write %p, excp %p timeout %p\n",
4802 ws_readfds, ws_writefds, ws_exceptfds, ws_timeout);
4804 if (!(pollfds = fd_sets_to_poll( ws_readfds, ws_writefds, ws_exceptfds, &count )))
4805 return SOCKET_ERROR;
4807 if (ws_timeout)
4808 timeout = (ws_timeout->tv_sec * 1000) + (ws_timeout->tv_usec + 999) / 1000;
4810 ret = do_poll(pollfds, count, timeout);
4811 release_poll_fds( ws_readfds, ws_writefds, ws_exceptfds, pollfds );
4813 if (ret == -1) SetLastError(wsaErrno());
4814 else ret = get_poll_results( ws_readfds, ws_writefds, ws_exceptfds, pollfds );
4815 return ret;
4818 /***********************************************************************
4819 * WSAPoll
4821 int WINAPI WSAPoll(WSAPOLLFD *wfds, ULONG count, int timeout)
4823 int i, ret;
4824 struct pollfd *ufds;
4826 if (!count)
4828 SetLastError(WSAEINVAL);
4829 return SOCKET_ERROR;
4831 if (!wfds)
4833 SetLastError(WSAEFAULT);
4834 return SOCKET_ERROR;
4837 if (!(ufds = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ufds[0]))))
4839 SetLastError(WSAENOBUFS);
4840 return SOCKET_ERROR;
4843 for (i = 0; i < count; i++)
4845 ufds[i].fd = get_sock_fd(wfds[i].fd, 0, NULL);
4846 ufds[i].events = convert_poll_w2u(wfds[i].events);
4847 ufds[i].revents = 0;
4850 ret = do_poll(ufds, count, timeout);
4852 for (i = 0; i < count; i++)
4854 if (ufds[i].fd != -1)
4856 release_sock_fd(wfds[i].fd, ufds[i].fd);
4857 if (ufds[i].revents & POLLHUP)
4859 /* Check if the socket still exists */
4860 int fd = get_sock_fd(wfds[i].fd, 0, NULL);
4861 if (fd != -1)
4863 wfds[i].revents = WS_POLLHUP;
4864 release_sock_fd(wfds[i].fd, fd);
4866 else
4867 wfds[i].revents = WS_POLLNVAL;
4869 else
4870 wfds[i].revents = convert_poll_u2w(ufds[i].revents);
4872 else
4873 wfds[i].revents = WS_POLLNVAL;
4876 HeapFree(GetProcessHeap(), 0, ufds);
4877 return ret;
4880 /* helper to send completion messages for client-only i/o operation case */
4881 static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS CompletionStatus,
4882 ULONG Information, BOOL async )
4884 SERVER_START_REQ( add_fd_completion )
4886 req->handle = wine_server_obj_handle( SOCKET2HANDLE(sock) );
4887 req->cvalue = CompletionValue;
4888 req->status = CompletionStatus;
4889 req->information = Information;
4890 req->async = async;
4891 wine_server_call( req );
4893 SERVER_END_REQ;
4897 /***********************************************************************
4898 * send (WS2_32.19)
4900 int WINAPI WS_send(SOCKET s, const char *buf, int len, int flags)
4902 DWORD n;
4903 WSABUF wsabuf;
4905 wsabuf.len = len;
4906 wsabuf.buf = (char*) buf;
4908 if ( WS2_sendto( s, &wsabuf, 1, &n, flags, NULL, 0, NULL, NULL) == SOCKET_ERROR )
4909 return SOCKET_ERROR;
4910 else
4911 return n;
4914 /***********************************************************************
4915 * WSASend (WS2_32.72)
4917 INT WINAPI WSASend( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
4918 LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
4919 LPWSAOVERLAPPED lpOverlapped,
4920 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
4922 return WS2_sendto( s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags,
4923 NULL, 0, lpOverlapped, lpCompletionRoutine );
4926 /***********************************************************************
4927 * WSASendDisconnect (WS2_32.73)
4929 INT WINAPI WSASendDisconnect( SOCKET s, LPWSABUF lpBuffers )
4931 return WS_shutdown( s, SD_SEND );
4935 static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
4936 LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
4937 const struct WS_sockaddr *to, int tolen,
4938 LPWSAOVERLAPPED lpOverlapped,
4939 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
4941 unsigned int i, options;
4942 int n, fd, err, overlapped, flags;
4943 struct ws2_async *wsa = NULL, localwsa;
4944 int totalLength = 0;
4945 DWORD bytes_sent;
4946 BOOL is_blocking;
4948 TRACE("socket %04lx, wsabuf %p, nbufs %d, flags %d, to %p, tolen %d, ovl %p, func %p\n",
4949 s, lpBuffers, dwBufferCount, dwFlags,
4950 to, tolen, lpOverlapped, lpCompletionRoutine);
4952 fd = get_sock_fd( s, FILE_WRITE_DATA, &options );
4953 TRACE( "fd=%d, options=%x\n", fd, options );
4955 if ( fd == -1 ) return SOCKET_ERROR;
4957 if (!lpOverlapped && !lpNumberOfBytesSent)
4959 err = WSAEFAULT;
4960 goto error;
4963 overlapped = (lpOverlapped || lpCompletionRoutine) &&
4964 !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
4965 if (overlapped || dwBufferCount > 1)
4967 if (!(wsa = (struct ws2_async *)alloc_async_io( offsetof(struct ws2_async, iovec[dwBufferCount]),
4968 WS2_async_send )))
4970 err = WSAEFAULT;
4971 goto error;
4974 else
4975 wsa = &localwsa;
4977 wsa->hSocket = SOCKET2HANDLE(s);
4978 wsa->addr = (struct WS_sockaddr *)to;
4979 wsa->addrlen.val = tolen;
4980 wsa->flags = dwFlags;
4981 wsa->lpFlags = &wsa->flags;
4982 wsa->control = NULL;
4983 wsa->n_iovecs = dwBufferCount;
4984 wsa->first_iovec = 0;
4985 for ( i = 0; i < dwBufferCount; i++ )
4987 wsa->iovec[i].iov_base = lpBuffers[i].buf;
4988 wsa->iovec[i].iov_len = lpBuffers[i].len;
4989 totalLength += lpBuffers[i].len;
4992 flags = convert_flags(dwFlags);
4993 n = WS2_send( fd, wsa, flags );
4994 if (n == -1 && errno != EAGAIN)
4996 err = wsaErrno();
4997 goto error;
5000 if (overlapped)
5002 IO_STATUS_BLOCK *iosb = lpOverlapped ? (IO_STATUS_BLOCK *)lpOverlapped : &wsa->local_iosb;
5003 ULONG_PTR cvalue = (lpOverlapped && ((ULONG_PTR)lpOverlapped->hEvent & 1) == 0) ? (ULONG_PTR)lpOverlapped : 0;
5005 wsa->user_overlapped = lpOverlapped;
5006 wsa->completion_func = lpCompletionRoutine;
5007 release_sock_fd( s, fd );
5009 if (n == -1 || n < totalLength)
5011 iosb->u.Status = STATUS_PENDING;
5012 iosb->Information = n == -1 ? 0 : n;
5014 if (wsa->completion_func)
5015 err = register_async( ASYNC_TYPE_WRITE, wsa->hSocket, &wsa->io, NULL,
5016 ws2_async_apc, wsa, iosb );
5017 else
5018 err = register_async( ASYNC_TYPE_WRITE, wsa->hSocket, &wsa->io, lpOverlapped->hEvent,
5019 NULL, (void *)cvalue, iosb );
5021 /* Enable the event only after starting the async. The server will deliver it as soon as
5022 the async is done. */
5023 _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
5025 if (err != STATUS_PENDING) HeapFree( GetProcessHeap(), 0, wsa );
5026 SetLastError(NtStatusToWSAError( err ));
5027 return SOCKET_ERROR;
5030 iosb->u.Status = STATUS_SUCCESS;
5031 iosb->Information = n;
5032 if (lpNumberOfBytesSent) *lpNumberOfBytesSent = n;
5033 if (!wsa->completion_func)
5035 if (cvalue) WS_AddCompletion( s, cvalue, STATUS_SUCCESS, n, FALSE );
5036 if (lpOverlapped->hEvent) SetEvent( lpOverlapped->hEvent );
5037 HeapFree( GetProcessHeap(), 0, wsa );
5039 else NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)ws2_async_apc,
5040 (ULONG_PTR)wsa, (ULONG_PTR)iosb, 0 );
5041 SetLastError(ERROR_SUCCESS);
5042 return 0;
5045 if ((err = sock_is_blocking( s, &is_blocking ))) goto error;
5047 if ( is_blocking )
5049 /* On a blocking non-overlapped stream socket,
5050 * sending blocks until the entire buffer is sent. */
5051 DWORD timeout_start = GetTickCount();
5053 bytes_sent = n == -1 ? 0 : n;
5055 while (wsa->first_iovec < wsa->n_iovecs)
5057 struct pollfd pfd;
5058 int poll_timeout = -1;
5059 INT64 timeout = get_rcvsnd_timeo(fd, FALSE);
5061 if (timeout)
5063 timeout -= GetTickCount() - timeout_start;
5064 if (timeout < 0) poll_timeout = 0;
5065 else poll_timeout = timeout <= INT_MAX ? timeout : INT_MAX;
5068 pfd.fd = fd;
5069 pfd.events = POLLOUT;
5071 if (!poll_timeout || !poll( &pfd, 1, poll_timeout ))
5073 err = WSAETIMEDOUT;
5074 goto error; /* msdn says a timeout in send is fatal */
5077 n = WS2_send( fd, wsa, flags );
5078 if (n == -1 && errno != EAGAIN)
5080 err = wsaErrno();
5081 goto error;
5084 if (n >= 0)
5085 bytes_sent += n;
5088 else /* non-blocking */
5090 if (n < totalLength)
5091 _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
5092 if (n == -1)
5094 err = WSAEWOULDBLOCK;
5095 goto error;
5097 bytes_sent = n;
5100 TRACE(" -> %i bytes\n", bytes_sent);
5102 if (lpNumberOfBytesSent) *lpNumberOfBytesSent = bytes_sent;
5103 if (wsa != &localwsa) HeapFree( GetProcessHeap(), 0, wsa );
5104 release_sock_fd( s, fd );
5105 SetLastError(ERROR_SUCCESS);
5106 return 0;
5108 error:
5109 if (wsa != &localwsa) HeapFree( GetProcessHeap(), 0, wsa );
5110 release_sock_fd( s, fd );
5111 WARN(" -> ERROR %d\n", err);
5112 SetLastError(err);
5113 return SOCKET_ERROR;
5116 /***********************************************************************
5117 * WSASendTo (WS2_32.74)
5119 INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
5120 LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
5121 const struct WS_sockaddr *to, int tolen,
5122 LPWSAOVERLAPPED lpOverlapped,
5123 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
5125 return WS2_sendto( s, lpBuffers, dwBufferCount,
5126 lpNumberOfBytesSent, dwFlags,
5127 to, tolen,
5128 lpOverlapped, lpCompletionRoutine );
5131 /***********************************************************************
5132 * sendto (WS2_32.20)
5134 int WINAPI WS_sendto(SOCKET s, const char *buf, int len, int flags,
5135 const struct WS_sockaddr *to, int tolen)
5137 DWORD n;
5138 WSABUF wsabuf;
5140 wsabuf.len = len;
5141 wsabuf.buf = (char*) buf;
5143 if ( WS2_sendto(s, &wsabuf, 1, &n, flags, to, tolen, NULL, NULL) == SOCKET_ERROR )
5144 return SOCKET_ERROR;
5145 else
5146 return n;
5149 /***********************************************************************
5150 * setsockopt (WS2_32.21)
5152 int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
5153 const char *optval, int optlen)
5155 int fd;
5156 int woptval;
5157 struct linger linger;
5158 struct timeval tval;
5159 struct ip_mreq_source mreq_source;
5161 TRACE("(socket %04lx, %s, optval %s, optlen %d)\n", s,
5162 debugstr_sockopt(level, optname), debugstr_optval(optval, optlen),
5163 optlen);
5165 /* some broken apps pass the value directly instead of a pointer to it */
5166 if(optlen && IS_INTRESOURCE(optval))
5168 SetLastError(WSAEFAULT);
5169 return SOCKET_ERROR;
5172 switch(level)
5174 case WS_SOL_SOCKET:
5175 switch(optname)
5177 /* Some options need some conversion before they can be sent to
5178 * setsockopt. The conversions are done here, then they will fall through
5179 * to the general case. Special options that are not passed to
5180 * setsockopt follow below that.*/
5182 case WS_SO_DONTLINGER:
5183 if (!optval)
5185 SetLastError(WSAEFAULT);
5186 return SOCKET_ERROR;
5188 linger.l_onoff = *(const int*)optval == 0;
5189 linger.l_linger = 0;
5190 level = SOL_SOCKET;
5191 optname = SO_LINGER;
5192 optval = (char*)&linger;
5193 optlen = sizeof(struct linger);
5194 break;
5196 case WS_SO_LINGER:
5197 if (!optval)
5199 SetLastError(WSAEFAULT);
5200 return SOCKET_ERROR;
5202 linger.l_onoff = ((LINGER*)optval)->l_onoff;
5203 linger.l_linger = ((LINGER*)optval)->l_linger;
5204 level = SOL_SOCKET;
5205 optname = SO_LINGER;
5206 optval = (char*)&linger;
5207 optlen = sizeof(struct linger);
5208 break;
5210 case WS_SO_SNDBUF:
5211 if (!*(const int *)optval)
5213 FIXME("SO_SNDBUF ignoring request to disable send buffering\n");
5214 #ifdef __APPLE__
5215 return 0;
5216 #endif
5218 convert_sockopt(&level, &optname);
5219 break;
5221 case WS_SO_RCVBUF:
5222 if (*(const int*)optval < 2048)
5224 WARN("SO_RCVBF for %d bytes is too small: ignored\n", *(const int*)optval );
5225 return 0;
5227 /* Fall through */
5229 /* The options listed here don't need any special handling. Thanks to
5230 * the conversion happening above, options from there will fall through
5231 * to this, too.*/
5232 case WS_SO_ACCEPTCONN:
5233 case WS_SO_BROADCAST:
5234 case WS_SO_ERROR:
5235 case WS_SO_KEEPALIVE:
5236 case WS_SO_OOBINLINE:
5237 /* BSD socket SO_REUSEADDR is not 100% compatible to winsock semantics.
5238 * however, using it the BSD way fixes bug 8513 and seems to be what
5239 * most programmers assume, anyway */
5240 case WS_SO_REUSEADDR:
5241 case WS_SO_TYPE:
5242 convert_sockopt(&level, &optname);
5243 break;
5245 /* SO_DEBUG is a privileged operation, ignore it. */
5246 case WS_SO_DEBUG:
5247 TRACE("Ignoring SO_DEBUG\n");
5248 return 0;
5250 /* For some reason the game GrandPrixLegends does set SO_DONTROUTE on its
5251 * socket. According to MSDN, this option is silently ignored.*/
5252 case WS_SO_DONTROUTE:
5253 TRACE("Ignoring SO_DONTROUTE\n");
5254 return 0;
5256 /* Stops two sockets from being bound to the same port. Always happens
5257 * on unix systems, so just drop it. */
5258 case WS_SO_EXCLUSIVEADDRUSE:
5259 TRACE("Ignoring SO_EXCLUSIVEADDRUSE, is always set.\n");
5260 return 0;
5262 /* After a ConnectEx call succeeds, the socket can't be used with half of the
5263 * normal winsock functions on windows. We don't have that problem. */
5264 case WS_SO_UPDATE_CONNECT_CONTEXT:
5265 TRACE("Ignoring SO_UPDATE_CONNECT_CONTEXT, since our sockets are normal\n");
5266 return 0;
5268 /* After a AcceptEx call succeeds, the socket can't be used with half of the
5269 * normal winsock functions on windows. We don't have that problem. */
5270 case WS_SO_UPDATE_ACCEPT_CONTEXT:
5271 TRACE("Ignoring SO_UPDATE_ACCEPT_CONTEXT, since our sockets are normal\n");
5272 return 0;
5274 /* SO_OPENTYPE does not require a valid socket handle. */
5275 case WS_SO_OPENTYPE:
5276 if (!optlen || optlen < sizeof(int) || !optval)
5278 SetLastError(WSAEFAULT);
5279 return SOCKET_ERROR;
5281 get_per_thread_data()->opentype = *(const int *)optval;
5282 TRACE("setting global SO_OPENTYPE = 0x%x\n", *((const int*)optval) );
5283 return 0;
5285 #ifdef SO_RCVTIMEO
5286 case WS_SO_RCVTIMEO:
5287 #endif
5288 #ifdef SO_SNDTIMEO
5289 case WS_SO_SNDTIMEO:
5290 #endif
5291 #if defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)
5292 if (optval && optlen == sizeof(UINT32)) {
5293 /* WinSock passes milliseconds instead of struct timeval */
5294 tval.tv_usec = (*(const UINT32*)optval % 1000) * 1000;
5295 tval.tv_sec = *(const UINT32*)optval / 1000;
5296 /* min of 500 milliseconds */
5297 if (tval.tv_sec == 0 && tval.tv_usec && tval.tv_usec < 500000)
5298 tval.tv_usec = 500000;
5299 optlen = sizeof(struct timeval);
5300 optval = (char*)&tval;
5301 } else if (optlen == sizeof(struct timeval)) {
5302 WARN("SO_SND/RCVTIMEO for %d bytes: assuming unixism\n", optlen);
5303 } else {
5304 WARN("SO_SND/RCVTIMEO for %d bytes is weird: ignored\n", optlen);
5305 return 0;
5307 convert_sockopt(&level, &optname);
5308 break;
5309 #endif
5311 case WS_SO_RANDOMIZE_PORT:
5312 FIXME("Ignoring WS_SO_RANDOMIZE_PORT\n");
5313 return 0;
5315 case WS_SO_PORT_SCALABILITY:
5316 FIXME("Ignoring WS_SO_PORT_SCALABILITY\n");
5317 return 0;
5319 case WS_SO_REUSE_UNICASTPORT:
5320 FIXME("Ignoring WS_SO_REUSE_UNICASTPORT\n");
5321 return 0;
5323 case WS_SO_REUSE_MULTICASTPORT:
5324 FIXME("Ignoring WS_SO_REUSE_MULTICASTPORT\n");
5325 return 0;
5327 default:
5328 TRACE("Unknown SOL_SOCKET optname: 0x%08x\n", optname);
5329 SetLastError(WSAENOPROTOOPT);
5330 return SOCKET_ERROR;
5332 break; /* case WS_SOL_SOCKET */
5334 #ifdef HAS_IPX
5335 case WS_NSPROTO_IPX:
5336 switch(optname)
5338 case WS_IPX_PTYPE:
5339 return set_ipx_packettype(s, *(int*)optval);
5341 case WS_IPX_FILTERPTYPE:
5342 /* Sets the receive filter packet type, at the moment we don't support it */
5343 FIXME("IPX_FILTERPTYPE: %x\n", *optval);
5344 /* Returning 0 is better for now than returning a SOCKET_ERROR */
5345 return 0;
5347 default:
5348 FIXME("opt_name:%x\n", optname);
5349 return SOCKET_ERROR;
5351 break; /* case WS_NSPROTO_IPX */
5352 #endif
5354 /* Levels WS_IPPROTO_TCP and WS_IPPROTO_IP convert directly */
5355 case WS_IPPROTO_TCP:
5356 switch(optname)
5358 case WS_TCP_NODELAY:
5359 convert_sockopt(&level, &optname);
5360 break;
5361 default:
5362 FIXME("Unknown IPPROTO_TCP optname 0x%08x\n", optname);
5363 return SOCKET_ERROR;
5365 break;
5367 case WS_IPPROTO_IP:
5368 switch(optname)
5370 case WS_IP_ADD_SOURCE_MEMBERSHIP:
5371 case WS_IP_DROP_SOURCE_MEMBERSHIP:
5372 case WS_IP_BLOCK_SOURCE:
5373 case WS_IP_UNBLOCK_SOURCE:
5375 WS_IP_MREQ_SOURCE* val = (void*)optval;
5376 mreq_source.imr_interface.s_addr = val->imr_interface.S_un.S_addr;
5377 mreq_source.imr_multiaddr.s_addr = val->imr_multiaddr.S_un.S_addr;
5378 mreq_source.imr_sourceaddr.s_addr = val->imr_sourceaddr.S_un.S_addr;
5380 optval = (char*)&mreq_source;
5381 optlen = sizeof(mreq_source);
5383 convert_sockopt(&level, &optname);
5384 break;
5386 case WS_IP_ADD_MEMBERSHIP:
5387 case WS_IP_DROP_MEMBERSHIP:
5388 #ifdef IP_HDRINCL
5389 case WS_IP_HDRINCL:
5390 #endif
5391 case WS_IP_MULTICAST_IF:
5392 case WS_IP_MULTICAST_LOOP:
5393 case WS_IP_MULTICAST_TTL:
5394 case WS_IP_OPTIONS:
5395 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
5396 case WS_IP_PKTINFO:
5397 #endif
5398 case WS_IP_TOS:
5399 case WS_IP_TTL:
5400 #ifdef IP_UNICAST_IF
5401 case WS_IP_UNICAST_IF:
5402 #endif
5403 convert_sockopt(&level, &optname);
5404 break;
5405 case WS_IP_DONTFRAGMENT:
5406 return set_dont_fragment(s, IPPROTO_IP, *(BOOL *)optval) ? 0 : SOCKET_ERROR;
5407 default:
5408 FIXME("Unknown IPPROTO_IP optname 0x%08x\n", optname);
5409 return SOCKET_ERROR;
5411 break;
5413 case WS_IPPROTO_IPV6:
5414 switch(optname)
5416 #ifdef IPV6_ADD_MEMBERSHIP
5417 case WS_IPV6_ADD_MEMBERSHIP:
5418 #endif
5419 #ifdef IPV6_DROP_MEMBERSHIP
5420 case WS_IPV6_DROP_MEMBERSHIP:
5421 #endif
5422 case WS_IPV6_MULTICAST_IF:
5423 case WS_IPV6_MULTICAST_HOPS:
5424 case WS_IPV6_MULTICAST_LOOP:
5425 case WS_IPV6_UNICAST_HOPS:
5426 #ifdef IPV6_UNICAST_IF
5427 case WS_IPV6_UNICAST_IF:
5428 #endif
5429 convert_sockopt(&level, &optname);
5430 break;
5431 case WS_IPV6_DONTFRAG:
5432 return set_dont_fragment(s, IPPROTO_IPV6, *(BOOL *)optval) ? 0 : SOCKET_ERROR;
5433 case WS_IPV6_PROTECTION_LEVEL:
5434 FIXME("IPV6_PROTECTION_LEVEL is ignored!\n");
5435 return 0;
5436 case WS_IPV6_V6ONLY:
5438 union generic_unix_sockaddr uaddr;
5439 socklen_t uaddrlen;
5440 int bound;
5442 fd = get_sock_fd( s, 0, NULL );
5443 if (fd == -1) return SOCKET_ERROR;
5445 bound = is_fd_bound(fd, &uaddr, &uaddrlen);
5446 release_sock_fd( s, fd );
5447 if (bound == 0 && uaddr.addr.sa_family == AF_INET)
5449 /* Changing IPV6_V6ONLY succeeds on AF_INET (IPv4) socket
5450 * on Windows (with IPv6 support) if the socket is unbound.
5451 * It is essentially a noop, though Windows does store the value
5453 WARN("Silently ignoring IPPROTO_IPV6+IPV6_V6ONLY on AF_INET socket\n");
5454 return 0;
5456 level = IPPROTO_IPV6;
5457 optname = IPV6_V6ONLY;
5458 break;
5460 default:
5461 FIXME("Unknown IPPROTO_IPV6 optname 0x%08x\n", optname);
5462 return SOCKET_ERROR;
5464 break;
5466 default:
5467 WARN("Unknown level: 0x%08x\n", level);
5468 SetLastError(WSAEINVAL);
5469 return SOCKET_ERROR;
5470 } /* end switch(level) */
5472 /* avoid endianness issues if argument is a 16-bit int */
5473 if (optval && optlen < sizeof(int))
5475 woptval= *((const INT16 *) optval);
5476 optval= (char*) &woptval;
5477 woptval&= (1 << optlen * 8) - 1;
5478 optlen=sizeof(int);
5480 fd = get_sock_fd( s, 0, NULL );
5481 if (fd == -1) return SOCKET_ERROR;
5483 if (setsockopt(fd, level, optname, optval, optlen) == 0)
5485 #ifdef __APPLE__
5486 if (level == SOL_SOCKET && optname == SO_REUSEADDR &&
5487 setsockopt(fd, level, SO_REUSEPORT, optval, optlen) != 0)
5489 SetLastError(wsaErrno());
5490 release_sock_fd( s, fd );
5491 return SOCKET_ERROR;
5493 #endif
5494 release_sock_fd( s, fd );
5495 return 0;
5497 TRACE("Setting socket error, %d\n", wsaErrno());
5498 SetLastError(wsaErrno());
5499 release_sock_fd( s, fd );
5501 return SOCKET_ERROR;
5504 /***********************************************************************
5505 * shutdown (WS2_32.22)
5507 int WINAPI WS_shutdown(SOCKET s, int how)
5509 int fd, err = WSAENOTSOCK;
5510 unsigned int options = 0, clear_flags = 0;
5512 fd = get_sock_fd( s, 0, &options );
5513 TRACE("socket %04lx, how 0x%x, options 0x%x\n", s, how, options );
5515 if (fd == -1)
5516 return SOCKET_ERROR;
5518 switch( how )
5520 case SD_RECEIVE: /* drop receives */
5521 clear_flags |= FD_READ;
5522 break;
5523 case SD_SEND: /* drop sends */
5524 clear_flags |= FD_WRITE;
5525 break;
5526 case SD_BOTH: /* drop all */
5527 clear_flags |= FD_READ|FD_WRITE;
5528 /*fall through */
5529 default:
5530 clear_flags |= FD_WINE_LISTENING;
5533 if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
5535 switch ( how )
5537 case SD_RECEIVE:
5538 err = WS2_register_async_shutdown( s, ASYNC_TYPE_READ );
5539 break;
5540 case SD_SEND:
5541 err = WS2_register_async_shutdown( s, ASYNC_TYPE_WRITE );
5542 break;
5543 case SD_BOTH:
5544 default:
5545 err = WS2_register_async_shutdown( s, ASYNC_TYPE_READ );
5546 if (!err) err = WS2_register_async_shutdown( s, ASYNC_TYPE_WRITE );
5547 break;
5549 if (err) goto error;
5551 else /* non-overlapped mode */
5553 if ( shutdown( fd, how ) )
5555 err = wsaErrno();
5556 goto error;
5560 release_sock_fd( s, fd );
5561 _enable_event( SOCKET2HANDLE(s), 0, 0, clear_flags );
5562 if ( how > 1) WSAAsyncSelect( s, 0, 0, 0 );
5563 return 0;
5565 error:
5566 release_sock_fd( s, fd );
5567 _enable_event( SOCKET2HANDLE(s), 0, 0, clear_flags );
5568 SetLastError( err );
5569 return SOCKET_ERROR;
5572 /***********************************************************************
5573 * socket (WS2_32.23)
5575 SOCKET WINAPI WS_socket(int af, int type, int protocol)
5577 TRACE("af=%d type=%d protocol=%d\n", af, type, protocol);
5579 return WSASocketW( af, type, protocol, NULL, 0,
5580 get_per_thread_data()->opentype ? 0 : WSA_FLAG_OVERLAPPED );
5584 /***********************************************************************
5585 * WSAEnumNetworkEvents (WS2_32.36)
5587 int WINAPI WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEvent, LPWSANETWORKEVENTS lpEvent)
5589 int ret;
5590 int i;
5591 int errors[FD_MAX_EVENTS];
5593 TRACE("%04lx, hEvent %p, lpEvent %p\n", s, hEvent, lpEvent );
5595 SERVER_START_REQ( get_socket_event )
5597 req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) );
5598 req->service = TRUE;
5599 req->c_event = wine_server_obj_handle( hEvent );
5600 wine_server_set_reply( req, errors, sizeof(errors) );
5601 if (!(ret = wine_server_call(req))) lpEvent->lNetworkEvents = reply->pmask & reply->mask;
5603 SERVER_END_REQ;
5604 if (!ret)
5606 for (i = 0; i < FD_MAX_EVENTS; i++)
5608 if (lpEvent->lNetworkEvents & (1 << i))
5609 lpEvent->iErrorCode[i] = errors[i];
5611 return 0;
5613 SetLastError(WSAEINVAL);
5614 return SOCKET_ERROR;
5617 /***********************************************************************
5618 * WSAEventSelect (WS2_32.39)
5620 int WINAPI WSAEventSelect(SOCKET s, WSAEVENT hEvent, LONG lEvent)
5622 int ret;
5624 TRACE("%04lx, hEvent %p, event %08x\n", s, hEvent, lEvent);
5626 SERVER_START_REQ( set_socket_event )
5628 req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) );
5629 req->mask = lEvent;
5630 req->event = wine_server_obj_handle( hEvent );
5631 req->window = 0;
5632 req->msg = 0;
5633 ret = wine_server_call( req );
5635 SERVER_END_REQ;
5636 if (!ret) return 0;
5637 SetLastError(WSAEINVAL);
5638 return SOCKET_ERROR;
5641 /**********************************************************************
5642 * WSAGetOverlappedResult (WS2_32.40)
5644 BOOL WINAPI WSAGetOverlappedResult( SOCKET s, LPWSAOVERLAPPED lpOverlapped,
5645 LPDWORD lpcbTransfer, BOOL fWait,
5646 LPDWORD lpdwFlags )
5648 NTSTATUS status;
5650 TRACE( "socket %04lx ovl %p trans %p, wait %d flags %p\n",
5651 s, lpOverlapped, lpcbTransfer, fWait, lpdwFlags );
5653 if ( lpOverlapped == NULL )
5655 ERR( "Invalid pointer\n" );
5656 SetLastError(WSA_INVALID_PARAMETER);
5657 return FALSE;
5660 status = lpOverlapped->Internal;
5661 if (status == STATUS_PENDING)
5663 if (!fWait)
5665 SetLastError( WSA_IO_INCOMPLETE );
5666 return FALSE;
5669 if (WaitForSingleObject( lpOverlapped->hEvent ? lpOverlapped->hEvent : SOCKET2HANDLE(s),
5670 INFINITE ) == WAIT_FAILED)
5671 return FALSE;
5672 status = lpOverlapped->Internal;
5675 if ( lpcbTransfer )
5676 *lpcbTransfer = lpOverlapped->InternalHigh;
5678 if ( lpdwFlags )
5679 *lpdwFlags = lpOverlapped->u.s.Offset;
5681 SetLastError( NtStatusToWSAError(status) );
5682 return NT_SUCCESS( status );
5686 /***********************************************************************
5687 * WSAAsyncSelect (WS2_32.101)
5689 INT WINAPI WSAAsyncSelect(SOCKET s, HWND hWnd, UINT uMsg, LONG lEvent)
5691 int ret;
5693 TRACE("%04lx, hWnd %p, uMsg %08x, event %08x\n", s, hWnd, uMsg, lEvent);
5695 SERVER_START_REQ( set_socket_event )
5697 req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) );
5698 req->mask = lEvent;
5699 req->event = 0;
5700 req->window = wine_server_user_handle( hWnd );
5701 req->msg = uMsg;
5702 ret = wine_server_call( req );
5704 SERVER_END_REQ;
5705 if (!ret) return 0;
5706 SetLastError(WSAEINVAL);
5707 return SOCKET_ERROR;
5710 /***********************************************************************
5711 * WSACreateEvent (WS2_32.31)
5714 WSAEVENT WINAPI WSACreateEvent(void)
5716 /* Create a manual-reset event, with initial state: unsignaled */
5717 TRACE("\n");
5719 return CreateEventW(NULL, TRUE, FALSE, NULL);
5722 /***********************************************************************
5723 * WSACloseEvent (WS2_32.29)
5726 BOOL WINAPI WSACloseEvent(WSAEVENT event)
5728 TRACE ("event=%p\n", event);
5730 return CloseHandle(event);
5733 /***********************************************************************
5734 * WSASocketA (WS2_32.78)
5737 SOCKET WINAPI WSASocketA(int af, int type, int protocol,
5738 LPWSAPROTOCOL_INFOA lpProtocolInfo,
5739 GROUP g, DWORD dwFlags)
5741 INT len;
5742 WSAPROTOCOL_INFOW info;
5744 TRACE("af=%d type=%d protocol=%d protocol_info=%p group=%d flags=0x%x\n",
5745 af, type, protocol, lpProtocolInfo, g, dwFlags);
5747 if (!lpProtocolInfo) return WSASocketW(af, type, protocol, NULL, g, dwFlags);
5749 memcpy(&info, lpProtocolInfo, FIELD_OFFSET(WSAPROTOCOL_INFOW, szProtocol));
5750 len = MultiByteToWideChar(CP_ACP, 0, lpProtocolInfo->szProtocol, -1,
5751 info.szProtocol, WSAPROTOCOL_LEN + 1);
5753 if (!len)
5755 SetLastError(WSAEINVAL);
5756 return SOCKET_ERROR;
5759 return WSASocketW(af, type, protocol, &info, g, dwFlags);
5762 /***********************************************************************
5763 * WSASocketW (WS2_32.79)
5766 SOCKET WINAPI WSASocketW(int af, int type, int protocol,
5767 LPWSAPROTOCOL_INFOW lpProtocolInfo,
5768 GROUP g, DWORD flags)
5770 static const WCHAR afdW[] = {'\\','D','e','v','i','c','e','\\','A','f','d',0};
5771 struct afd_create_params create_params;
5772 OBJECT_ATTRIBUTES attr;
5773 UNICODE_STRING string;
5774 IO_STATUS_BLOCK io;
5775 NTSTATUS status;
5776 HANDLE handle;
5777 SOCKET ret;
5778 DWORD err;
5781 FIXME: The "advanced" parameters of WSASocketW (lpProtocolInfo,
5782 g, dwFlags except WSA_FLAG_OVERLAPPED) are ignored.
5785 TRACE("af=%d type=%d protocol=%d protocol_info=%p group=%d flags=0x%x\n",
5786 af, type, protocol, lpProtocolInfo, g, flags );
5788 if (!num_startup)
5790 err = WSANOTINITIALISED;
5791 goto done;
5794 /* hack for WSADuplicateSocket */
5795 if (lpProtocolInfo && lpProtocolInfo->dwServiceFlags4 == 0xff00ff00)
5797 ret = lpProtocolInfo->dwServiceFlags3;
5798 TRACE("\tgot duplicate %04lx\n", ret);
5799 if (!socket_list_add(ret))
5801 CloseHandle(SOCKET2HANDLE(ret));
5802 return INVALID_SOCKET;
5804 return ret;
5807 if (lpProtocolInfo)
5809 if (af == FROM_PROTOCOL_INFO || !af)
5810 af = lpProtocolInfo->iAddressFamily;
5811 if (type == FROM_PROTOCOL_INFO || !type)
5812 type = lpProtocolInfo->iSocketType;
5813 if (protocol == FROM_PROTOCOL_INFO || !protocol)
5814 protocol = lpProtocolInfo->iProtocol;
5817 if (!af && !protocol)
5819 WSASetLastError(WSAEINVAL);
5820 return INVALID_SOCKET;
5823 if (!af && lpProtocolInfo)
5825 WSASetLastError(WSAEAFNOSUPPORT);
5826 return INVALID_SOCKET;
5829 if (!af || !type || !protocol)
5831 unsigned int i;
5833 for (i = 0; i < ARRAY_SIZE(supported_protocols); ++i)
5835 const WSAPROTOCOL_INFOW *info = &supported_protocols[i];
5837 if (af && af != info->iAddressFamily) continue;
5838 if (type && type != info->iSocketType) continue;
5839 if (protocol && (protocol < info->iProtocol ||
5840 protocol > info->iProtocol + info->iProtocolMaxOffset)) continue;
5841 if (!protocol && !(info->dwProviderFlags & PFL_MATCHES_PROTOCOL_ZERO)) continue;
5843 if (!af) af = supported_protocols[i].iAddressFamily;
5844 if (!type) type = supported_protocols[i].iSocketType;
5845 if (!protocol) protocol = supported_protocols[i].iProtocol;
5846 break;
5850 RtlInitUnicodeString(&string, afdW);
5851 InitializeObjectAttributes(&attr, &string, (flags & WSA_FLAG_NO_HANDLE_INHERIT) ? 0 : OBJ_INHERIT, NULL, NULL);
5852 if ((status = NtOpenFile(&handle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &attr,
5853 &io, 0, (flags & WSA_FLAG_OVERLAPPED) ? 0 : FILE_SYNCHRONOUS_IO_NONALERT)))
5855 WARN("Failed to create socket, status %#x.\n", status);
5856 WSASetLastError(NtStatusToWSAError(status));
5857 return INVALID_SOCKET;
5860 create_params.family = af;
5861 create_params.type = type;
5862 create_params.protocol = protocol;
5863 create_params.flags = flags & ~(WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
5864 if ((status = NtDeviceIoControlFile(handle, NULL, NULL, NULL, &io,
5865 IOCTL_AFD_WINE_CREATE, &create_params, sizeof(create_params), NULL, 0)))
5867 WARN("Failed to initialize socket, status %#x.\n", status);
5868 err = RtlNtStatusToDosError( status );
5869 if (err == WSAEACCES) /* raw socket denied */
5871 if (type == SOCK_RAW)
5872 ERR_(winediag)("Failed to create a socket of type SOCK_RAW, this requires special permissions.\n");
5873 else
5874 ERR_(winediag)("Failed to create socket, this requires special permissions.\n");
5876 WSASetLastError(err);
5877 NtClose(handle);
5878 return INVALID_SOCKET;
5881 ret = HANDLE2SOCKET(handle);
5882 TRACE("\tcreated %04lx\n", ret );
5884 if (!socket_list_add(ret))
5886 CloseHandle(handle);
5887 return INVALID_SOCKET;
5889 return ret;
5891 done:
5892 WARN("\t\tfailed, error %d!\n", err);
5893 SetLastError(err);
5894 return INVALID_SOCKET;
5897 /***********************************************************************
5898 * WSAJoinLeaf (WS2_32.58)
5901 SOCKET WINAPI WSAJoinLeaf(
5902 SOCKET s,
5903 const struct WS_sockaddr *addr,
5904 int addrlen,
5905 LPWSABUF lpCallerData,
5906 LPWSABUF lpCalleeData,
5907 LPQOS lpSQOS,
5908 LPQOS lpGQOS,
5909 DWORD dwFlags)
5911 FIXME("stub.\n");
5912 return INVALID_SOCKET;
5915 /***********************************************************************
5916 * __WSAFDIsSet (WS2_32.151)
5918 int WINAPI __WSAFDIsSet(SOCKET s, WS_fd_set *set)
5920 int i = set->fd_count, ret = 0;
5922 while (i--)
5923 if (set->fd_array[i] == s)
5925 ret = 1;
5926 break;
5929 TRACE("(socket %04lx, fd_set %p, count %i) <- %d\n", s, set, set->fd_count, ret);
5930 return ret;
5933 /***********************************************************************
5934 * WSAIsBlocking (WS2_32.114)
5936 BOOL WINAPI WSAIsBlocking(void)
5938 /* By default WinSock should set all its sockets to non-blocking mode
5939 * and poll in PeekMessage loop when processing "blocking" ones. This
5940 * function is supposed to tell if the program is in this loop. Our
5941 * blocking calls are truly blocking so we always return FALSE.
5943 * Note: It is allowed to call this function without prior WSAStartup().
5946 TRACE("\n");
5947 return FALSE;
5950 /***********************************************************************
5951 * WSACancelBlockingCall (WS2_32.113)
5953 INT WINAPI WSACancelBlockingCall(void)
5955 TRACE("\n");
5956 return 0;
5959 static INT WINAPI WSA_DefaultBlockingHook( FARPROC x )
5961 FIXME("How was this called?\n");
5962 return x();
5966 /***********************************************************************
5967 * WSASetBlockingHook (WS2_32.109)
5969 FARPROC WINAPI WSASetBlockingHook(FARPROC lpBlockFunc)
5971 FARPROC prev = blocking_hook;
5972 blocking_hook = lpBlockFunc;
5973 TRACE("hook %p\n", lpBlockFunc);
5974 return prev;
5978 /***********************************************************************
5979 * WSAUnhookBlockingHook (WS2_32.110)
5981 INT WINAPI WSAUnhookBlockingHook(void)
5983 blocking_hook = (FARPROC)WSA_DefaultBlockingHook;
5984 return 0;
5988 /***********************************************************************
5989 * WSARecv (WS2_32.67)
5991 int WINAPI WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
5992 LPDWORD NumberOfBytesReceived, LPDWORD lpFlags,
5993 LPWSAOVERLAPPED lpOverlapped,
5994 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
5996 return WS2_recv_base(s, lpBuffers, dwBufferCount, NumberOfBytesReceived, lpFlags,
5997 NULL, NULL, lpOverlapped, lpCompletionRoutine, NULL);
6000 static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
6001 LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,
6002 struct WS_sockaddr *lpFrom,
6003 LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
6004 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
6005 LPWSABUF lpControlBuffer )
6007 unsigned int i, options;
6008 int n, fd, err, overlapped, flags;
6009 struct ws2_async *wsa = NULL, localwsa;
6010 BOOL is_blocking;
6011 DWORD timeout_start = GetTickCount();
6012 ULONG_PTR cvalue = (lpOverlapped && ((ULONG_PTR)lpOverlapped->hEvent & 1) == 0) ? (ULONG_PTR)lpOverlapped : 0;
6014 TRACE("socket %04lx, wsabuf %p, nbufs %d, flags %d, from %p, fromlen %d, ovl %p, func %p\n",
6015 s, lpBuffers, dwBufferCount, *lpFlags, lpFrom,
6016 (lpFromlen ? *lpFromlen : -1),
6017 lpOverlapped, lpCompletionRoutine);
6019 fd = get_sock_fd( s, FILE_READ_DATA, &options );
6020 TRACE( "fd=%d, options=%x\n", fd, options );
6022 if (fd == -1) return SOCKET_ERROR;
6024 if (*lpFlags & WS_MSG_OOB)
6026 /* It's invalid to receive OOB data from an OOBINLINED socket
6027 * as OOB data is turned into normal data. */
6028 socklen_t len = sizeof(n);
6029 if (!getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*) &n, &len) && n)
6031 err = WSAEINVAL;
6032 goto error;
6036 overlapped = (lpOverlapped || lpCompletionRoutine) &&
6037 !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
6038 if (overlapped || dwBufferCount > 1)
6040 if (!(wsa = (struct ws2_async *)alloc_async_io( offsetof(struct ws2_async, iovec[dwBufferCount]),
6041 WS2_async_recv )))
6043 err = WSAEFAULT;
6044 goto error;
6047 else
6048 wsa = &localwsa;
6050 wsa->hSocket = SOCKET2HANDLE(s);
6051 wsa->flags = *lpFlags;
6052 wsa->lpFlags = lpFlags;
6053 wsa->addr = lpFrom;
6054 wsa->addrlen.ptr = lpFromlen;
6055 wsa->control = lpControlBuffer;
6056 wsa->n_iovecs = dwBufferCount;
6057 wsa->first_iovec = 0;
6058 for (i = 0; i < dwBufferCount; i++)
6060 /* check buffer first to trigger write watches */
6061 if (IsBadWritePtr( lpBuffers[i].buf, lpBuffers[i].len ))
6063 err = WSAEFAULT;
6064 goto error;
6066 wsa->iovec[i].iov_base = lpBuffers[i].buf;
6067 wsa->iovec[i].iov_len = lpBuffers[i].len;
6070 flags = convert_flags(wsa->flags);
6071 for (;;)
6073 n = WS2_recv( fd, wsa, flags );
6074 if (n == -1)
6076 /* Unix-like systems return EINVAL when attempting to read OOB data from
6077 * an empty socket buffer, convert that to a Windows expected return. */
6078 if ((flags & MSG_OOB) && errno == EINVAL)
6079 errno = EWOULDBLOCK;
6081 if (errno != EAGAIN)
6083 err = wsaErrno();
6084 goto error;
6087 else if (lpNumberOfBytesRecvd) *lpNumberOfBytesRecvd = n;
6089 if (overlapped)
6091 IO_STATUS_BLOCK *iosb = lpOverlapped ? (IO_STATUS_BLOCK *)lpOverlapped : &wsa->local_iosb;
6093 wsa->user_overlapped = lpOverlapped;
6094 wsa->completion_func = lpCompletionRoutine;
6095 release_sock_fd( s, fd );
6097 if (n == -1)
6099 iosb->u.Status = STATUS_PENDING;
6100 iosb->Information = 0;
6102 if (wsa->completion_func)
6103 err = register_async( ASYNC_TYPE_READ, wsa->hSocket, &wsa->io, NULL,
6104 ws2_async_apc, wsa, iosb );
6105 else
6106 err = register_async( ASYNC_TYPE_READ, wsa->hSocket, &wsa->io, lpOverlapped->hEvent,
6107 NULL, (void *)cvalue, iosb );
6109 if (err != STATUS_PENDING) HeapFree( GetProcessHeap(), 0, wsa );
6110 SetLastError(NtStatusToWSAError( err ));
6111 return SOCKET_ERROR;
6114 iosb->u.Status = STATUS_SUCCESS;
6115 iosb->Information = n;
6116 if (!wsa->completion_func)
6118 if (cvalue) WS_AddCompletion( s, cvalue, STATUS_SUCCESS, n, FALSE );
6119 if (lpOverlapped->hEvent) SetEvent( lpOverlapped->hEvent );
6120 HeapFree( GetProcessHeap(), 0, wsa );
6122 else NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)ws2_async_apc,
6123 (ULONG_PTR)wsa, (ULONG_PTR)iosb, 0 );
6124 _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0);
6125 return 0;
6128 if (n != -1) break;
6130 if ((err = sock_is_blocking( s, &is_blocking ))) goto error;
6132 if ( is_blocking )
6134 struct pollfd pfd;
6135 int poll_timeout = -1;
6136 INT64 timeout = get_rcvsnd_timeo(fd, TRUE);
6138 if (timeout)
6140 timeout -= GetTickCount() - timeout_start;
6141 if (timeout < 0) poll_timeout = 0;
6142 else poll_timeout = timeout <= INT_MAX ? timeout : INT_MAX;
6145 pfd.fd = fd;
6146 pfd.events = POLLIN;
6147 if (*lpFlags & WS_MSG_OOB) pfd.events |= POLLPRI;
6149 if (!poll_timeout || !poll( &pfd, 1, poll_timeout ))
6151 err = WSAETIMEDOUT;
6152 /* a timeout is not fatal */
6153 _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0);
6154 goto error;
6157 else
6159 _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0);
6160 err = WSAEWOULDBLOCK;
6161 goto error;
6165 TRACE(" -> %i bytes\n", n);
6166 if (wsa != &localwsa) HeapFree( GetProcessHeap(), 0, wsa );
6167 release_sock_fd( s, fd );
6168 _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0);
6169 SetLastError(ERROR_SUCCESS);
6171 return 0;
6173 error:
6174 if (wsa != &localwsa) HeapFree( GetProcessHeap(), 0, wsa );
6175 release_sock_fd( s, fd );
6176 WARN(" -> ERROR %d\n", err);
6177 SetLastError( err );
6178 return SOCKET_ERROR;
6181 /***********************************************************************
6182 * WSARecvFrom (WS2_32.69)
6184 INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
6185 LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct WS_sockaddr *lpFrom,
6186 LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
6187 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
6190 return WS2_recv_base( s, lpBuffers, dwBufferCount,
6191 lpNumberOfBytesRecvd, lpFlags,
6192 lpFrom, lpFromlen,
6193 lpOverlapped, lpCompletionRoutine, NULL );
6197 /***********************************************************************
6198 * WSAAccept (WS2_32.26)
6200 SOCKET WINAPI WSAAccept( SOCKET s, struct WS_sockaddr *addr, LPINT addrlen,
6201 LPCONDITIONPROC lpfnCondition, DWORD_PTR dwCallbackData)
6204 int ret = 0, size;
6205 WSABUF CallerId, CallerData, CalleeId, CalleeData;
6206 /* QOS SQOS, GQOS; */
6207 GROUP g;
6208 SOCKET cs;
6209 SOCKADDR src_addr, dst_addr;
6211 TRACE("socket %04lx, sockaddr %p, addrlen %p, fnCondition %p, dwCallbackData %ld\n",
6212 s, addr, addrlen, lpfnCondition, dwCallbackData);
6214 cs = WS_accept(s, addr, addrlen);
6215 if (cs == SOCKET_ERROR) return SOCKET_ERROR;
6216 if (!lpfnCondition) return cs;
6218 if (addr && addrlen)
6220 CallerId.buf = (char *)addr;
6221 CallerId.len = *addrlen;
6223 else
6225 size = sizeof(src_addr);
6226 WS_getpeername(cs, &src_addr, &size);
6227 CallerId.buf = (char *)&src_addr;
6228 CallerId.len = size;
6230 CallerData.buf = NULL;
6231 CallerData.len = 0;
6233 size = sizeof(dst_addr);
6234 WS_getsockname(cs, &dst_addr, &size);
6236 CalleeId.buf = (char *)&dst_addr;
6237 CalleeId.len = sizeof(dst_addr);
6239 ret = (*lpfnCondition)(&CallerId, &CallerData, NULL, NULL,
6240 &CalleeId, &CalleeData, &g, dwCallbackData);
6242 switch (ret)
6244 case CF_ACCEPT:
6245 return cs;
6246 case CF_DEFER:
6247 SERVER_START_REQ( set_socket_deferred )
6249 req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) );
6250 req->deferred = wine_server_obj_handle( SOCKET2HANDLE(cs) );
6251 if ( !wine_server_call_err ( req ) )
6253 SetLastError( WSATRY_AGAIN );
6254 WS_closesocket( cs );
6257 SERVER_END_REQ;
6258 return SOCKET_ERROR;
6259 case CF_REJECT:
6260 WS_closesocket(cs);
6261 SetLastError(WSAECONNREFUSED);
6262 return SOCKET_ERROR;
6263 default:
6264 FIXME("Unknown return type from Condition function\n");
6265 SetLastError(WSAENOTSOCK);
6266 return SOCKET_ERROR;
6270 /***********************************************************************
6271 * WSADuplicateSocketA (WS2_32.32)
6273 int WINAPI WSADuplicateSocketA( SOCKET s, DWORD dwProcessId, LPWSAPROTOCOL_INFOA lpProtocolInfo )
6275 return WS_DuplicateSocket(FALSE, s, dwProcessId, (LPWSAPROTOCOL_INFOW) lpProtocolInfo);
6278 /***********************************************************************
6279 * WSADuplicateSocketW (WS2_32.33)
6281 int WINAPI WSADuplicateSocketW( SOCKET s, DWORD dwProcessId, LPWSAPROTOCOL_INFOW lpProtocolInfo )
6283 return WS_DuplicateSocket(TRUE, s, dwProcessId, lpProtocolInfo);
6287 /***********************************************************************
6288 * WSAGetQOSByName (WS2_32.41)
6290 BOOL WINAPI WSAGetQOSByName( SOCKET s, LPWSABUF lpQOSName, LPQOS lpQOS )
6292 FIXME( "(0x%04lx %p %p) Stub!\n", s, lpQOSName, lpQOS );
6293 return FALSE;
6297 /***********************************************************************
6298 * WSARecvDisconnect (WS2_32.68)
6300 INT WINAPI WSARecvDisconnect( SOCKET s, LPWSABUF disconnectdata )
6302 TRACE( "(%04lx %p)\n", s, disconnectdata );
6304 return WS_shutdown( s, SD_RECEIVE );
6308 static BOOL protocol_matches_filter( const int *filter, int protocol )
6310 if (!filter) return TRUE;
6311 while (*filter)
6313 if (protocol == *filter++) return TRUE;
6315 return FALSE;
6318 /*****************************************************************************
6319 * WSAEnumProtocolsA [WS2_32.@]
6321 * see function WSAEnumProtocolsW
6323 int WINAPI WSAEnumProtocolsA( int *filter, WSAPROTOCOL_INFOA *protocols, DWORD *size )
6325 DWORD i, count = 0;
6327 TRACE("filter %p, protocols %p, size %p\n", filter, protocols, size);
6329 for (i = 0; i < ARRAY_SIZE(supported_protocols); ++i)
6331 if (protocol_matches_filter( filter, supported_protocols[i].iProtocol ))
6332 ++count;
6335 if (!protocols || *size < count * sizeof(WSAPROTOCOL_INFOA))
6337 *size = count * sizeof(WSAPROTOCOL_INFOA);
6338 WSASetLastError( WSAENOBUFS );
6339 return SOCKET_ERROR;
6342 count = 0;
6343 for (i = 0; i < ARRAY_SIZE(supported_protocols); ++i)
6345 if (protocol_matches_filter( filter, supported_protocols[i].iProtocol ))
6347 memcpy( &protocols[count], &supported_protocols[i], offsetof( WSAPROTOCOL_INFOW, szProtocol ) );
6348 WideCharToMultiByte( CP_ACP, 0, supported_protocols[i].szProtocol, -1,
6349 protocols[count].szProtocol, sizeof(protocols[count].szProtocol), NULL, NULL );
6350 ++count;
6353 return count;
6356 /*****************************************************************************
6357 * WSAEnumProtocolsW [WS2_32.@]
6359 * Retrieves information about specified set of active network protocols.
6361 * PARAMS
6362 * protocols [I] Pointer to null-terminated array of protocol id's. NULL
6363 * retrieves information on all available protocols.
6364 * buffer [I] Pointer to a buffer to be filled with WSAPROTOCOL_INFO
6365 * structures.
6366 * len [I/O] Pointer to a variable specifying buffer size. On output
6367 * the variable holds the number of bytes needed when the
6368 * specified size is too small.
6370 * RETURNS
6371 * Success: number of WSAPROTOCOL_INFO structures in buffer.
6372 * Failure: SOCKET_ERROR
6374 * NOTES
6375 * NT4SP5 does not return SPX if protocols == NULL
6377 * BUGS
6378 * - NT4SP5 returns in addition these list of NETBIOS protocols
6379 * (address family 17), each entry two times one for socket type 2 and 5
6381 * iProtocol szProtocol
6382 * 0x80000000 \Device\NwlnkNb
6383 * 0xfffffffa \Device\NetBT_CBENT7
6384 * 0xfffffffb \Device\Nbf_CBENT7
6385 * 0xfffffffc \Device\NetBT_NdisWan5
6386 * 0xfffffffd \Device\NetBT_El9202
6387 * 0xfffffffe \Device\Nbf_El9202
6388 * 0xffffffff \Device\Nbf_NdisWan4
6390 * - there is no check that the operating system supports the returned
6391 * protocols
6393 int WINAPI WSAEnumProtocolsW( int *filter, WSAPROTOCOL_INFOW *protocols, DWORD *size )
6395 DWORD i, count = 0;
6397 TRACE("filter %p, protocols %p, size %p\n", filter, protocols, size);
6399 for (i = 0; i < ARRAY_SIZE(supported_protocols); ++i)
6401 if (protocol_matches_filter( filter, supported_protocols[i].iProtocol ))
6402 ++count;
6405 if (!protocols || *size < count * sizeof(WSAPROTOCOL_INFOW))
6407 *size = count * sizeof(WSAPROTOCOL_INFOW);
6408 WSASetLastError( WSAENOBUFS );
6409 return SOCKET_ERROR;
6412 count = 0;
6413 for (i = 0; i < ARRAY_SIZE(supported_protocols); ++i)
6415 if (protocol_matches_filter( filter, supported_protocols[i].iProtocol ))
6416 protocols[count++] = supported_protocols[i];
6418 return count;