ws2_32: Drop support for getting the IP_HDRINCL socket option.
[wine.git] / dlls / ntdll / unix / socket.c
blob1ac4365c01295d4eaad2d274b908db6dd32dce1f
1 /*
2 * Windows sockets
4 * Copyright 2021 Zebediah Figura for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
26 #define _GNU_SOURCE /* for struct in6_pktinfo */
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #ifdef HAVE_IFADDRS_H
31 # include <ifaddrs.h>
32 #endif
33 #ifdef HAVE_NET_IF_H
34 # include <net/if.h>
35 #endif
36 #ifdef HAVE_SYS_IOCTL_H
37 # include <sys/ioctl.h>
38 #endif
39 #ifdef HAVE_SYS_SOCKET_H
40 #include <sys/socket.h>
41 #endif
42 #ifdef HAVE_NETINET_IN_H
43 # define __APPLE_USE_RFC_3542
44 # include <netinet/in.h>
45 #endif
46 #ifdef HAVE_NETINET_TCP_H
47 # include <netinet/tcp.h>
48 #endif
50 #ifdef HAVE_NETIPX_IPX_H
51 # include <netipx/ipx.h>
52 #elif defined(HAVE_LINUX_IPX_H)
53 # ifdef HAVE_ASM_TYPES_H
54 # include <asm/types.h>
55 # endif
56 # ifdef HAVE_LINUX_TYPES_H
57 # include <linux/types.h>
58 # endif
59 # include <linux/ipx.h>
60 #endif
61 #if defined(SOL_IPX) || defined(SO_DEFAULT_HEADERS)
62 # define HAS_IPX
63 #endif
65 #ifdef HAVE_LINUX_IRDA_H
66 # ifdef HAVE_LINUX_TYPES_H
67 # include <linux/types.h>
68 # endif
69 # include <linux/irda.h>
70 # define HAS_IRDA
71 #endif
73 #include "ntstatus.h"
74 #define WIN32_NO_STATUS
75 #include "windef.h"
76 #include "winioctl.h"
77 #define USE_WS_PREFIX
78 #include "winsock2.h"
79 #include "mswsock.h"
80 #include "mstcpip.h"
81 #include "ws2tcpip.h"
82 #include "wsipx.h"
83 #include "af_irda.h"
84 #include "wine/afd.h"
86 #include "unix_private.h"
88 #if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE)
89 /* TCP_KEEPALIVE is the Mac OS name for TCP_KEEPIDLE */
90 #define TCP_KEEPIDLE TCP_KEEPALIVE
91 #endif
93 #if defined(linux) && !defined(IP_UNICAST_IF)
94 #define IP_UNICAST_IF 50
95 #endif
97 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
99 union unix_sockaddr
101 struct sockaddr addr;
102 struct sockaddr_in in;
103 struct sockaddr_in6 in6;
104 #ifdef HAS_IPX
105 struct sockaddr_ipx ipx;
106 #endif
107 #ifdef HAS_IRDA
108 struct sockaddr_irda irda;
109 #endif
112 struct async_recv_ioctl
114 struct async_fileio io;
115 WSABUF *control;
116 struct WS_sockaddr *addr;
117 int *addr_len;
118 DWORD *ret_flags;
119 int unix_flags;
120 unsigned int count;
121 struct iovec iov[1];
124 struct async_send_ioctl
126 struct async_fileio io;
127 const struct WS_sockaddr *addr;
128 int addr_len;
129 int unix_flags;
130 unsigned int sent_len;
131 unsigned int count;
132 unsigned int iov_cursor;
133 struct iovec iov[1];
136 struct async_transmit_ioctl
138 struct async_fileio io;
139 HANDLE file;
140 char *buffer;
141 unsigned int buffer_size; /* allocated size of buffer */
142 unsigned int read_len; /* amount of valid data currently in the buffer */
143 unsigned int head_cursor; /* amount of header data already sent */
144 unsigned int file_cursor; /* amount of file data already sent */
145 unsigned int buffer_cursor; /* amount of data currently in the buffer already sent */
146 unsigned int tail_cursor; /* amount of tail data already sent */
147 unsigned int file_len; /* total file length to send */
148 DWORD flags;
149 TRANSMIT_FILE_BUFFERS buffers;
150 LARGE_INTEGER offset;
153 static NTSTATUS sock_errno_to_status( int err )
155 switch (err)
157 case EBADF: return STATUS_INVALID_HANDLE;
158 case EBUSY: return STATUS_DEVICE_BUSY;
159 case EPERM:
160 case EACCES: return STATUS_ACCESS_DENIED;
161 case EFAULT: return STATUS_ACCESS_VIOLATION;
162 case EINVAL: return STATUS_INVALID_PARAMETER;
163 case ENFILE:
164 case EMFILE: return STATUS_TOO_MANY_OPENED_FILES;
165 case EINPROGRESS:
166 case EWOULDBLOCK: return STATUS_DEVICE_NOT_READY;
167 case EALREADY: return STATUS_NETWORK_BUSY;
168 case ENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH;
169 case EDESTADDRREQ: return STATUS_INVALID_PARAMETER;
170 case EMSGSIZE: return STATUS_BUFFER_OVERFLOW;
171 case EPROTONOSUPPORT:
172 case ESOCKTNOSUPPORT:
173 case EPFNOSUPPORT:
174 case EAFNOSUPPORT:
175 case EPROTOTYPE: return STATUS_NOT_SUPPORTED;
176 case ENOPROTOOPT: return STATUS_INVALID_PARAMETER;
177 case EOPNOTSUPP: return STATUS_NOT_SUPPORTED;
178 case EADDRINUSE: return STATUS_SHARING_VIOLATION;
179 case EADDRNOTAVAIL: return STATUS_INVALID_PARAMETER;
180 case ECONNREFUSED: return STATUS_CONNECTION_REFUSED;
181 case ESHUTDOWN: return STATUS_PIPE_DISCONNECTED;
182 case ENOTCONN: return STATUS_INVALID_CONNECTION;
183 case ETIMEDOUT: return STATUS_IO_TIMEOUT;
184 case ENETUNREACH: return STATUS_NETWORK_UNREACHABLE;
185 case EHOSTUNREACH: return STATUS_HOST_UNREACHABLE;
186 case ENETDOWN: return STATUS_NETWORK_BUSY;
187 case EPIPE:
188 case ECONNRESET: return STATUS_CONNECTION_RESET;
189 case ECONNABORTED: return STATUS_CONNECTION_ABORTED;
190 case EISCONN: return STATUS_CONNECTION_ACTIVE;
192 case 0: return STATUS_SUCCESS;
193 default:
194 FIXME( "unknown errno %d\n", err );
195 return STATUS_UNSUCCESSFUL;
199 static socklen_t sockaddr_to_unix( const struct WS_sockaddr *wsaddr, int wsaddrlen, union unix_sockaddr *uaddr )
201 memset( uaddr, 0, sizeof(*uaddr) );
203 switch (wsaddr->sa_family)
205 case WS_AF_INET:
207 struct WS_sockaddr_in win = {0};
209 if (wsaddrlen < sizeof(win)) return 0;
210 memcpy( &win, wsaddr, sizeof(win) );
211 uaddr->in.sin_family = AF_INET;
212 uaddr->in.sin_port = win.sin_port;
213 memcpy( &uaddr->in.sin_addr, &win.sin_addr, sizeof(win.sin_addr) );
214 return sizeof(uaddr->in);
217 case WS_AF_INET6:
219 struct WS_sockaddr_in6 win = {0};
221 if (wsaddrlen < sizeof(win)) return 0;
222 memcpy( &win, wsaddr, sizeof(win) );
223 uaddr->in6.sin6_family = AF_INET6;
224 uaddr->in6.sin6_port = win.sin6_port;
225 uaddr->in6.sin6_flowinfo = win.sin6_flowinfo;
226 memcpy( &uaddr->in6.sin6_addr, &win.sin6_addr, sizeof(win.sin6_addr) );
227 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
228 uaddr->in6.sin6_scope_id = win.sin6_scope_id;
229 #endif
230 return sizeof(uaddr->in6);
233 #ifdef HAS_IPX
234 case WS_AF_IPX:
236 struct WS_sockaddr_ipx win = {0};
238 if (wsaddrlen < sizeof(win)) return 0;
239 memcpy( &win, wsaddr, sizeof(win) );
240 uaddr->ipx.sipx_family = AF_IPX;
241 memcpy( &uaddr->ipx.sipx_network, win.sa_netnum, sizeof(win.sa_netnum) );
242 memcpy( &uaddr->ipx.sipx_node, win.sa_nodenum, sizeof(win.sa_nodenum) );
243 uaddr->ipx.sipx_port = win.sa_socket;
244 return sizeof(uaddr->ipx);
246 #endif
248 #ifdef HAS_IRDA
249 case WS_AF_IRDA:
251 SOCKADDR_IRDA win = {0};
252 unsigned int lsap_sel;
254 if (wsaddrlen < sizeof(win)) return 0;
255 memcpy( &win, wsaddr, sizeof(win) );
256 uaddr->irda.sir_family = AF_IRDA;
257 if (sscanf( win.irdaServiceName, "LSAP-SEL%u", &lsap_sel ) == 1)
258 uaddr->irda.sir_lsap_sel = lsap_sel;
259 else
261 uaddr->irda.sir_lsap_sel = LSAP_ANY;
262 memcpy( uaddr->irda.sir_name, win.irdaServiceName, sizeof(win.irdaServiceName) );
264 memcpy( &uaddr->irda.sir_addr, win.irdaDeviceID, sizeof(win.irdaDeviceID) );
265 return sizeof(uaddr->irda);
267 #endif
269 case WS_AF_UNSPEC:
270 switch (wsaddrlen)
272 default: /* likely an ipv4 address */
273 case sizeof(struct WS_sockaddr_in):
274 return sizeof(uaddr->in);
276 #ifdef HAS_IPX
277 case sizeof(struct WS_sockaddr_ipx):
278 return sizeof(uaddr->ipx);
279 #endif
281 #ifdef HAS_IRDA
282 case sizeof(SOCKADDR_IRDA):
283 return sizeof(uaddr->irda);
284 #endif
286 case sizeof(struct WS_sockaddr_in6):
287 return sizeof(uaddr->in6);
290 default:
291 FIXME( "unknown address family %u\n", wsaddr->sa_family );
292 return 0;
296 static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_sockaddr *wsaddr, socklen_t wsaddrlen )
298 memset( wsaddr, 0, wsaddrlen );
300 switch (uaddr->addr.sa_family)
302 case AF_INET:
304 struct WS_sockaddr_in win = {0};
306 if (wsaddrlen < sizeof(win)) return -1;
307 win.sin_family = WS_AF_INET;
308 win.sin_port = uaddr->in.sin_port;
309 memcpy( &win.sin_addr, &uaddr->in.sin_addr, sizeof(win.sin_addr) );
310 memcpy( wsaddr, &win, sizeof(win) );
311 return sizeof(win);
314 case AF_INET6:
316 struct WS_sockaddr_in6 win = {0};
318 if (wsaddrlen < sizeof(win)) return -1;
319 win.sin6_family = WS_AF_INET6;
320 win.sin6_port = uaddr->in6.sin6_port;
321 win.sin6_flowinfo = uaddr->in6.sin6_flowinfo;
322 memcpy( &win.sin6_addr, &uaddr->in6.sin6_addr, sizeof(win.sin6_addr) );
323 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
324 win.sin6_scope_id = uaddr->in6.sin6_scope_id;
325 #endif
326 memcpy( wsaddr, &win, sizeof(win) );
327 return sizeof(win);
330 #ifdef HAS_IPX
331 case AF_IPX:
333 struct WS_sockaddr_ipx win = {0};
335 if (wsaddrlen < sizeof(win)) return -1;
336 win.sa_family = WS_AF_IPX;
337 memcpy( win.sa_netnum, &uaddr->ipx.sipx_network, sizeof(win.sa_netnum) );
338 memcpy( win.sa_nodenum, &uaddr->ipx.sipx_node, sizeof(win.sa_nodenum) );
339 win.sa_socket = uaddr->ipx.sipx_port;
340 memcpy( wsaddr, &win, sizeof(win) );
341 return sizeof(win);
343 #endif
345 #ifdef HAS_IRDA
346 case AF_IRDA:
348 SOCKADDR_IRDA win;
350 if (wsaddrlen < sizeof(win)) return -1;
351 win.irdaAddressFamily = WS_AF_IRDA;
352 memcpy( win.irdaDeviceID, &uaddr->irda.sir_addr, sizeof(win.irdaDeviceID) );
353 if (uaddr->irda.sir_lsap_sel != LSAP_ANY)
354 snprintf( win.irdaServiceName, sizeof(win.irdaServiceName), "LSAP-SEL%u", uaddr->irda.sir_lsap_sel );
355 else
356 memcpy( win.irdaServiceName, uaddr->irda.sir_name, sizeof(win.irdaServiceName) );
357 memcpy( wsaddr, &win, sizeof(win) );
358 return sizeof(win);
360 #endif
362 case AF_UNSPEC:
363 return 0;
365 default:
366 FIXME( "unknown address family %d\n", uaddr->addr.sa_family );
367 return -1;
371 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
372 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
373 static WSACMSGHDR *fill_control_message( int level, int type, WSACMSGHDR *current, ULONG *maxsize, void *data, int len )
375 ULONG msgsize = sizeof(WSACMSGHDR) + WSA_CMSG_ALIGN(len);
376 char *ptr = (char *) current + sizeof(WSACMSGHDR);
378 if (msgsize > *maxsize)
379 return NULL;
380 *maxsize -= msgsize;
381 current->cmsg_len = sizeof(WSACMSGHDR) + len;
382 current->cmsg_level = level;
383 current->cmsg_type = type;
384 memcpy(ptr, data, len);
385 return (WSACMSGHDR *)(ptr + WSA_CMSG_ALIGN(len));
387 #endif /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
389 static int convert_control_headers(struct msghdr *hdr, WSABUF *control)
391 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
392 WSACMSGHDR *cmsg_win = (WSACMSGHDR *)control->buf, *ptr;
393 ULONG ctlsize = control->len;
394 struct cmsghdr *cmsg_unix;
396 ptr = cmsg_win;
397 for (cmsg_unix = CMSG_FIRSTHDR(hdr); cmsg_unix != NULL; cmsg_unix = CMSG_NXTHDR(hdr, cmsg_unix))
399 switch (cmsg_unix->cmsg_level)
401 case IPPROTO_IP:
402 switch (cmsg_unix->cmsg_type)
404 #if defined(IP_PKTINFO)
405 case IP_PKTINFO:
407 const struct in_pktinfo *data_unix = (struct in_pktinfo *)CMSG_DATA(cmsg_unix);
408 struct WS_in_pktinfo data_win;
410 memcpy( &data_win.ipi_addr, &data_unix->ipi_addr.s_addr, 4 ); /* 4 bytes = 32 address bits */
411 data_win.ipi_ifindex = data_unix->ipi_ifindex;
412 ptr = fill_control_message( WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize,
413 (void *)&data_win, sizeof(data_win) );
414 if (!ptr) goto error;
415 break;
417 #elif defined(IP_RECVDSTADDR)
418 case IP_RECVDSTADDR:
420 const struct in_addr *addr_unix = (struct in_addr *)CMSG_DATA(cmsg_unix);
421 struct WS_in_pktinfo data_win;
423 memcpy( &data_win.ipi_addr, &addr_unix->s_addr, 4 ); /* 4 bytes = 32 address bits */
424 data_win.ipi_ifindex = 0; /* FIXME */
425 ptr = fill_control_message( WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize,
426 (void *)&data_win, sizeof(data_win) );
427 if (!ptr) goto error;
428 break;
430 #endif /* IP_PKTINFO */
431 default:
432 FIXME("Unhandled IPPROTO_IP message header type %d\n", cmsg_unix->cmsg_type);
433 break;
435 break;
437 case IPPROTO_IPV6:
438 switch (cmsg_unix->cmsg_type)
440 #if defined(IPV6_HOPLIMIT)
441 case IPV6_HOPLIMIT:
443 ptr = fill_control_message( WS_IPPROTO_IPV6, WS_IPV6_HOPLIMIT, ptr, &ctlsize,
444 CMSG_DATA(cmsg_unix), sizeof(INT) );
445 if (!ptr) goto error;
446 break;
448 #endif /* IPV6_HOPLIMIT */
450 #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO_IPI6_ADDR)
451 case IPV6_PKTINFO:
453 struct in6_pktinfo *data_unix = (struct in6_pktinfo *)CMSG_DATA(cmsg_unix);
454 struct WS_in6_pktinfo data_win;
456 memcpy(&data_win.ipi6_addr, &data_unix->ipi6_addr.s6_addr, 16);
457 data_win.ipi6_ifindex = data_unix->ipi6_ifindex;
458 ptr = fill_control_message( WS_IPPROTO_IPV6, WS_IPV6_PKTINFO, ptr, &ctlsize,
459 (void *)&data_win, sizeof(data_win) );
460 if (!ptr) goto error;
461 break;
463 #endif /* IPV6_PKTINFO */
465 #if defined(IPV6_TCLASS)
466 case IPV6_TCLASS:
468 ptr = fill_control_message( WS_IPPROTO_IPV6, WS_IPV6_TCLASS, ptr, &ctlsize,
469 CMSG_DATA(cmsg_unix), sizeof(INT) );
470 if (!ptr) goto error;
471 break;
473 #endif /* IPV6_TCLASS */
475 default:
476 FIXME("Unhandled IPPROTO_IPV6 message header type %d\n", cmsg_unix->cmsg_type);
477 break;
479 break;
481 default:
482 FIXME("Unhandled message header level %d\n", cmsg_unix->cmsg_level);
483 break;
487 control->len = (char *)ptr - (char *)cmsg_win;
488 return 1;
490 error:
491 control->len = 0;
492 return 0;
493 #else /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
494 control->len = 0;
495 return 1;
496 #endif /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
498 #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */
500 static NTSTATUS try_recv( int fd, struct async_recv_ioctl *async, ULONG_PTR *size )
502 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
503 char control_buffer[512];
504 #endif
505 union unix_sockaddr unix_addr;
506 struct msghdr hdr;
507 NTSTATUS status;
508 ssize_t ret;
510 memset( &hdr, 0, sizeof(hdr) );
511 if (async->addr)
513 hdr.msg_name = &unix_addr.addr;
514 hdr.msg_namelen = sizeof(unix_addr);
516 hdr.msg_iov = async->iov;
517 hdr.msg_iovlen = async->count;
518 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
519 hdr.msg_control = control_buffer;
520 hdr.msg_controllen = sizeof(control_buffer);
521 #endif
522 while ((ret = virtual_locked_recvmsg( fd, &hdr, async->unix_flags )) < 0 && errno == EINTR);
524 if (ret < 0)
526 /* Unix-like systems return EINVAL when attempting to read OOB data from
527 * an empty socket buffer; Windows returns WSAEWOULDBLOCK. */
528 if ((async->unix_flags & MSG_OOB) && errno == EINVAL)
529 errno = EWOULDBLOCK;
531 if (errno != EWOULDBLOCK) WARN( "recvmsg: %s\n", strerror( errno ) );
532 return sock_errno_to_status( errno );
535 status = (hdr.msg_flags & MSG_TRUNC) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
537 #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
538 if (async->control)
540 ERR( "Message control headers cannot be properly supported on this system.\n" );
541 async->control->len = 0;
543 #else
544 if (async->control && !convert_control_headers( &hdr, async->control ))
546 WARN( "Application passed insufficient room for control headers.\n" );
547 *async->ret_flags |= WS_MSG_CTRUNC;
548 status = STATUS_BUFFER_OVERFLOW;
550 #endif
552 /* If this socket is connected, Linux doesn't give us msg_name and
553 * msg_namelen from recvmsg, but it does set msg_namelen to zero.
555 * MSDN says that the address is ignored for connection-oriented sockets, so
556 * don't try to translate it.
558 if (async->addr && hdr.msg_namelen)
559 *async->addr_len = sockaddr_from_unix( &unix_addr, async->addr, *async->addr_len );
561 *size = ret;
562 return status;
565 static NTSTATUS async_recv_proc( void *user, ULONG_PTR *info, NTSTATUS status )
567 struct async_recv_ioctl *async = user;
568 ULONG_PTR information = 0;
569 int fd, needs_close;
571 TRACE( "%#x\n", status );
573 if (status == STATUS_ALERTED)
575 if ((status = server_get_unix_fd( async->io.handle, 0, &fd, &needs_close, NULL, NULL )))
576 return status;
578 status = try_recv( fd, async, &information );
579 TRACE( "got status %#x, %#lx bytes read\n", status, information );
581 if (status == STATUS_DEVICE_NOT_READY)
582 status = STATUS_PENDING;
584 if (needs_close) close( fd );
586 if (status != STATUS_PENDING)
588 *info = information;
589 release_fileio( &async->io );
591 return status;
594 static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io,
595 int fd, const WSABUF *buffers, unsigned int count, WSABUF *control,
596 struct WS_sockaddr *addr, int *addr_len, DWORD *ret_flags, int unix_flags, int force_async )
598 struct async_recv_ioctl *async;
599 ULONG_PTR information;
600 HANDLE wait_handle;
601 DWORD async_size;
602 NTSTATUS status;
603 unsigned int i;
604 ULONG options;
606 if (unix_flags & MSG_OOB)
608 int oobinline;
609 socklen_t len = sizeof(oobinline);
610 if (!getsockopt( fd, SOL_SOCKET, SO_OOBINLINE, (char *)&oobinline, &len ) && oobinline)
611 return STATUS_INVALID_PARAMETER;
614 for (i = 0; i < count; ++i)
616 if (!virtual_check_buffer_for_write( buffers[i].buf, buffers[i].len ))
617 return STATUS_ACCESS_VIOLATION;
620 async_size = offsetof( struct async_recv_ioctl, iov[count] );
622 if (!(async = (struct async_recv_ioctl *)alloc_fileio( async_size, async_recv_proc, handle )))
623 return STATUS_NO_MEMORY;
625 async->count = count;
626 for (i = 0; i < count; ++i)
628 async->iov[i].iov_base = buffers[i].buf;
629 async->iov[i].iov_len = buffers[i].len;
631 async->unix_flags = unix_flags;
632 async->control = control;
633 async->addr = addr;
634 async->addr_len = addr_len;
635 async->ret_flags = ret_flags;
637 status = try_recv( fd, async, &information );
639 if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW && status != STATUS_DEVICE_NOT_READY)
641 release_fileio( &async->io );
642 return status;
645 if (status == STATUS_DEVICE_NOT_READY && force_async)
646 status = STATUS_PENDING;
648 SERVER_START_REQ( recv_socket )
650 req->status = status;
651 req->total = information;
652 req->async = server_async( handle, &async->io, event, apc, apc_user, iosb_client_ptr(io) );
653 req->oob = !!(unix_flags & MSG_OOB);
654 status = wine_server_call( req );
655 wait_handle = wine_server_ptr_handle( reply->wait );
656 options = reply->options;
657 if ((!NT_ERROR(status) || wait_handle) && status != STATUS_PENDING)
659 io->Status = status;
660 io->Information = information;
663 SERVER_END_REQ;
665 if (status != STATUS_PENDING) release_fileio( &async->io );
667 if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
668 return status;
672 struct async_poll_ioctl
674 struct async_fileio io;
675 unsigned int count;
676 struct afd_poll_params *input, *output;
677 struct poll_socket_output sockets[1];
680 static ULONG_PTR fill_poll_output( struct async_poll_ioctl *async, NTSTATUS status )
682 struct afd_poll_params *input = async->input, *output = async->output;
683 unsigned int i, count = 0;
685 memcpy( output, input, offsetof( struct afd_poll_params, sockets[0] ) );
687 if (!status)
689 for (i = 0; i < async->count; ++i)
691 if (async->sockets[i].flags)
693 output->sockets[count].socket = input->sockets[i].socket;
694 output->sockets[count].flags = async->sockets[i].flags;
695 output->sockets[count].status = async->sockets[i].status;
696 ++count;
700 output->count = count;
701 return offsetof( struct afd_poll_params, sockets[count] );
704 static NTSTATUS async_poll_proc( void *user, ULONG_PTR *info, NTSTATUS status )
706 struct async_poll_ioctl *async = user;
707 ULONG_PTR information = 0;
709 if (status == STATUS_ALERTED)
711 SERVER_START_REQ( get_async_result )
713 req->user_arg = wine_server_client_ptr( async );
714 wine_server_set_reply( req, async->sockets, async->count * sizeof(async->sockets[0]) );
715 status = wine_server_call( req );
717 SERVER_END_REQ;
719 information = fill_poll_output( async, status );
722 if (status != STATUS_PENDING)
724 *info = information;
725 free( async->input );
726 release_fileio( &async->io );
728 return status;
732 /* we could handle this ioctl entirely on the server side, but the differing
733 * structure size makes it painful */
734 static NTSTATUS sock_poll( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io,
735 void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size )
737 const struct afd_poll_params *params = in_buffer;
738 struct poll_socket_input *input;
739 struct async_poll_ioctl *async;
740 HANDLE wait_handle;
741 DWORD async_size;
742 NTSTATUS status;
743 unsigned int i;
744 ULONG options;
746 if (in_size < sizeof(*params) || out_size < in_size || !params->count
747 || in_size < offsetof( struct afd_poll_params, sockets[params->count] ))
748 return STATUS_INVALID_PARAMETER;
750 TRACE( "timeout %s, count %u, unknown %#x, padding (%#x, %#x, %#x), sockets[0] {%04lx, %#x}\n",
751 wine_dbgstr_longlong(params->timeout), params->count, params->unknown,
752 params->padding[0], params->padding[1], params->padding[2],
753 params->sockets[0].socket, params->sockets[0].flags );
755 if (params->unknown) FIXME( "unknown boolean is %#x\n", params->unknown );
756 if (params->padding[0]) FIXME( "padding[0] is %#x\n", params->padding[0] );
757 if (params->padding[1]) FIXME( "padding[1] is %#x\n", params->padding[1] );
758 if (params->padding[2]) FIXME( "padding[2] is %#x\n", params->padding[2] );
759 for (i = 0; i < params->count; ++i)
761 if (params->sockets[i].flags & ~0x1ff)
762 FIXME( "unknown socket flags %#x\n", params->sockets[i].flags );
765 if (!(input = malloc( params->count * sizeof(*input) )))
766 return STATUS_NO_MEMORY;
768 async_size = offsetof( struct async_poll_ioctl, sockets[params->count] );
770 if (!(async = (struct async_poll_ioctl *)alloc_fileio( async_size, async_poll_proc, handle )))
772 free( input );
773 return STATUS_NO_MEMORY;
776 if (!(async->input = malloc( in_size )))
778 release_fileio( &async->io );
779 free( input );
780 return STATUS_NO_MEMORY;
782 memcpy( async->input, in_buffer, in_size );
784 async->count = params->count;
785 async->output = out_buffer;
787 for (i = 0; i < params->count; ++i)
789 input[i].socket = params->sockets[i].socket;
790 input[i].flags = params->sockets[i].flags;
793 SERVER_START_REQ( poll_socket )
795 req->async = server_async( handle, &async->io, event, apc, apc_user, iosb_client_ptr(io) );
796 req->timeout = params->timeout;
797 wine_server_add_data( req, input, params->count * sizeof(*input) );
798 wine_server_set_reply( req, async->sockets, params->count * sizeof(async->sockets[0]) );
799 status = wine_server_call( req );
800 wait_handle = wine_server_ptr_handle( reply->wait );
801 options = reply->options;
802 if (wait_handle && status != STATUS_PENDING)
804 io->Status = status;
805 io->Information = fill_poll_output( async, status );
808 SERVER_END_REQ;
810 free( input );
812 if (status != STATUS_PENDING)
814 free( async->input );
815 release_fileio( &async->io );
818 if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT) );
819 return status;
822 static NTSTATUS try_send( int fd, struct async_send_ioctl *async )
824 union unix_sockaddr unix_addr;
825 struct msghdr hdr;
826 ssize_t ret;
828 memset( &hdr, 0, sizeof(hdr) );
829 if (async->addr)
831 hdr.msg_name = &unix_addr;
832 hdr.msg_namelen = sockaddr_to_unix( async->addr, async->addr_len, &unix_addr );
833 if (!hdr.msg_namelen)
835 ERR( "failed to convert address\n" );
836 return STATUS_ACCESS_VIOLATION;
839 #if defined(HAS_IPX) && defined(SOL_IPX)
840 if (async->addr->sa_family == WS_AF_IPX)
842 int type;
843 socklen_t len = sizeof(type);
845 /* The packet type is stored at the IPX socket level. At least the
846 * linux kernel seems to do something with it in case hdr.msg_name
847 * is NULL. Nonetheless we can use it to store the packet type, and
848 * then we can retrieve it using getsockopt. After that we can set
849 * the IPX type in the sockaddr_ipx structure with the stored value.
851 if (getsockopt(fd, SOL_IPX, IPX_TYPE, &type, &len) >= 0)
852 unix_addr.ipx.sipx_type = type;
854 #endif
857 hdr.msg_iov = async->iov + async->iov_cursor;
858 hdr.msg_iovlen = async->count - async->iov_cursor;
860 while ((ret = sendmsg( fd, &hdr, async->unix_flags )) == -1)
862 if (errno == EISCONN)
864 hdr.msg_name = NULL;
865 hdr.msg_namelen = 0;
867 else if (errno != EINTR)
869 if (errno != EWOULDBLOCK) WARN( "sendmsg: %s\n", strerror( errno ) );
870 return sock_errno_to_status( errno );
874 async->sent_len += ret;
876 while (async->iov_cursor < async->count && ret >= async->iov[async->iov_cursor].iov_len)
877 ret -= async->iov[async->iov_cursor++].iov_len;
878 if (async->iov_cursor < async->count)
880 async->iov[async->iov_cursor].iov_base = (char *)async->iov[async->iov_cursor].iov_base + ret;
881 async->iov[async->iov_cursor].iov_len -= ret;
882 return STATUS_DEVICE_NOT_READY;
884 return STATUS_SUCCESS;
887 static NTSTATUS async_send_proc( void *user, ULONG_PTR *info, NTSTATUS status )
889 struct async_send_ioctl *async = user;
890 int fd, needs_close;
892 TRACE( "%#x\n", status );
894 if (status == STATUS_ALERTED)
896 if ((status = server_get_unix_fd( async->io.handle, 0, &fd, &needs_close, NULL, NULL )))
897 return status;
899 status = try_send( fd, async );
900 TRACE( "got status %#x\n", status );
902 if (status == STATUS_DEVICE_NOT_READY)
903 status = STATUS_PENDING;
905 if (needs_close) close( fd );
907 if (status != STATUS_PENDING)
909 *info = async->sent_len;
910 release_fileio( &async->io );
912 return status;
915 static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
916 IO_STATUS_BLOCK *io, int fd, const WSABUF *buffers, unsigned int count,
917 const struct WS_sockaddr *addr, unsigned int addr_len, int unix_flags, int force_async )
919 struct async_send_ioctl *async;
920 HANDLE wait_handle;
921 DWORD async_size;
922 NTSTATUS status;
923 unsigned int i;
924 ULONG options;
926 async_size = offsetof( struct async_send_ioctl, iov[count] );
928 if (!(async = (struct async_send_ioctl *)alloc_fileio( async_size, async_send_proc, handle )))
929 return STATUS_NO_MEMORY;
931 async->count = count;
932 for (i = 0; i < count; ++i)
934 async->iov[i].iov_base = buffers[i].buf;
935 async->iov[i].iov_len = buffers[i].len;
937 async->unix_flags = unix_flags;
938 async->addr = addr;
939 async->addr_len = addr_len;
940 async->iov_cursor = 0;
941 async->sent_len = 0;
943 status = try_send( fd, async );
945 if (status != STATUS_SUCCESS && status != STATUS_DEVICE_NOT_READY)
947 release_fileio( &async->io );
948 return status;
951 if (status == STATUS_DEVICE_NOT_READY && force_async)
952 status = STATUS_PENDING;
954 SERVER_START_REQ( send_socket )
956 req->status = status;
957 req->total = async->sent_len;
958 req->async = server_async( handle, &async->io, event, apc, apc_user, iosb_client_ptr(io) );
959 status = wine_server_call( req );
960 wait_handle = wine_server_ptr_handle( reply->wait );
961 options = reply->options;
962 if ((!NT_ERROR(status) || wait_handle) && status != STATUS_PENDING)
964 io->Status = status;
965 io->Information = async->sent_len;
968 SERVER_END_REQ;
970 if (status != STATUS_PENDING) release_fileio( &async->io );
972 if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
973 return status;
976 static ssize_t do_send( int fd, const void *buffer, size_t len, int flags )
978 ssize_t ret;
979 while ((ret = send( fd, buffer, len, flags )) < 0 && errno == EINTR);
980 if (ret < 0 && errno != EWOULDBLOCK) WARN( "send: %s\n", strerror( errno ) );
981 return ret;
984 static NTSTATUS try_transmit( int sock_fd, int file_fd, struct async_transmit_ioctl *async )
986 ssize_t ret;
988 while (async->head_cursor < async->buffers.HeadLength)
990 TRACE( "sending %u bytes of header data\n", async->buffers.HeadLength - async->head_cursor );
991 ret = do_send( sock_fd, (char *)async->buffers.Head + async->head_cursor,
992 async->buffers.HeadLength - async->head_cursor, 0 );
993 if (ret < 0) return sock_errno_to_status( errno );
994 TRACE( "send returned %zd\n", ret );
995 async->head_cursor += ret;
998 while (async->buffer_cursor < async->read_len)
1000 TRACE( "sending %u bytes of file data\n", async->read_len - async->buffer_cursor );
1001 ret = do_send( sock_fd, async->buffer + async->buffer_cursor,
1002 async->read_len - async->buffer_cursor, 0 );
1003 if (ret < 0) return sock_errno_to_status( errno );
1004 TRACE( "send returned %zd\n", ret );
1005 async->buffer_cursor += ret;
1006 async->file_cursor += ret;
1009 if (async->file && async->buffer_cursor == async->read_len)
1011 unsigned int read_size = async->buffer_size;
1013 if (async->file_len)
1014 read_size = min( read_size, async->file_len - async->file_cursor );
1016 TRACE( "reading %u bytes of file data\n", read_size );
1019 if (async->offset.QuadPart == FILE_USE_FILE_POINTER_POSITION)
1020 ret = read( file_fd, async->buffer, read_size );
1021 else
1022 ret = pread( file_fd, async->buffer, read_size, async->offset.QuadPart );
1023 } while (ret < 0 && errno == EINTR);
1024 if (ret < 0) return errno_to_status( errno );
1025 TRACE( "read returned %zd\n", ret );
1027 async->read_len = ret;
1028 async->buffer_cursor = 0;
1029 if (async->offset.QuadPart != FILE_USE_FILE_POINTER_POSITION)
1030 async->offset.QuadPart += ret;
1032 if (ret < read_size || (async->file_len && async->file_cursor == async->file_len))
1033 async->file = NULL;
1034 return STATUS_PENDING; /* still more data to send */
1037 while (async->tail_cursor < async->buffers.TailLength)
1039 TRACE( "sending %u bytes of tail data\n", async->buffers.TailLength - async->tail_cursor );
1040 ret = do_send( sock_fd, (char *)async->buffers.Tail + async->tail_cursor,
1041 async->buffers.TailLength - async->tail_cursor, 0 );
1042 if (ret < 0) return sock_errno_to_status( errno );
1043 TRACE( "send returned %zd\n", ret );
1044 async->tail_cursor += ret;
1047 return STATUS_SUCCESS;
1050 static NTSTATUS async_transmit_proc( void *user, ULONG_PTR *info, NTSTATUS status )
1052 int sock_fd, file_fd = -1, sock_needs_close = FALSE, file_needs_close = FALSE;
1053 struct async_transmit_ioctl *async = user;
1055 TRACE( "%#x\n", status );
1057 if (status == STATUS_ALERTED)
1059 if ((status = server_get_unix_fd( async->io.handle, 0, &sock_fd, &sock_needs_close, NULL, NULL )))
1060 return status;
1062 if (async->file && (status = server_get_unix_fd( async->file, 0, &file_fd, &file_needs_close, NULL, NULL )))
1064 if (sock_needs_close) close( sock_fd );
1065 return status;
1068 status = try_transmit( sock_fd, file_fd, async );
1069 TRACE( "got status %#x\n", status );
1071 if (status == STATUS_DEVICE_NOT_READY)
1072 status = STATUS_PENDING;
1074 if (sock_needs_close) close( sock_fd );
1075 if (file_needs_close) close( file_fd );
1077 if (status != STATUS_PENDING)
1079 *info = async->head_cursor + async->file_cursor + async->tail_cursor;
1080 release_fileio( &async->io );
1082 return status;
1085 static NTSTATUS sock_transmit( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1086 IO_STATUS_BLOCK *io, int fd, const struct afd_transmit_params *params )
1088 int file_fd, file_needs_close = FALSE;
1089 struct async_transmit_ioctl *async;
1090 enum server_fd_type file_type;
1091 union unix_sockaddr addr;
1092 socklen_t addr_len;
1093 HANDLE wait_handle;
1094 NTSTATUS status;
1095 ULONG options;
1097 addr_len = sizeof(addr);
1098 if (getpeername( fd, &addr.addr, &addr_len ) != 0)
1099 return STATUS_INVALID_CONNECTION;
1101 if (params->file)
1103 if ((status = server_get_unix_fd( params->file, 0, &file_fd, &file_needs_close, &file_type, NULL )))
1104 return status;
1105 if (file_needs_close) close( file_fd );
1107 if (file_type != FD_TYPE_FILE)
1109 FIXME( "unsupported file type %#x\n", file_type );
1110 return STATUS_NOT_IMPLEMENTED;
1114 if (!(async = (struct async_transmit_ioctl *)alloc_fileio( sizeof(*async), async_transmit_proc, handle )))
1115 return STATUS_NO_MEMORY;
1117 async->file = params->file;
1118 async->buffer_size = params->buffer_size ? params->buffer_size : 65536;
1119 if (!(async->buffer = malloc( async->buffer_size )))
1121 release_fileio( &async->io );
1122 return STATUS_NO_MEMORY;
1124 async->read_len = 0;
1125 async->head_cursor = 0;
1126 async->file_cursor = 0;
1127 async->buffer_cursor = 0;
1128 async->tail_cursor = 0;
1129 async->file_len = params->file_len;
1130 async->flags = params->flags;
1131 async->buffers = params->buffers;
1132 async->offset = params->offset;
1134 SERVER_START_REQ( send_socket )
1136 req->status = STATUS_PENDING;
1137 req->total = 0;
1138 req->async = server_async( handle, &async->io, event, apc, apc_user, iosb_client_ptr(io) );
1139 status = wine_server_call( req );
1140 wait_handle = wine_server_ptr_handle( reply->wait );
1141 options = reply->options;
1142 /* In theory we'd fill the iosb here, as above in sock_send(), but it's
1143 * actually currently impossible to get STATUS_SUCCESS. The server will
1144 * either return STATUS_PENDING or an error code, and in neither case
1145 * should the iosb be filled. */
1147 SERVER_END_REQ;
1149 if (status != STATUS_PENDING) release_fileio( &async->io );
1151 if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
1152 return status;
1155 static void complete_async( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1156 IO_STATUS_BLOCK *io, NTSTATUS status, ULONG_PTR information )
1158 ULONG_PTR iosb_ptr = iosb_client_ptr(io);
1160 io->Status = status;
1161 io->Information = information;
1162 if (event) NtSetEvent( event, NULL );
1163 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc, (ULONG_PTR)apc_user, iosb_ptr, 0 );
1164 if (apc_user) add_completion( handle, (ULONG_PTR)apc_user, status, information, FALSE );
1168 static NTSTATUS do_getsockopt( HANDLE handle, IO_STATUS_BLOCK *io, int level,
1169 int option, void *out_buffer, ULONG out_size )
1171 int fd, needs_close = FALSE;
1172 socklen_t len = out_size;
1173 NTSTATUS status;
1174 int ret;
1176 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1177 return status;
1179 ret = getsockopt( fd, level, option, out_buffer, &len );
1180 if (needs_close) close( fd );
1181 if (ret) return sock_errno_to_status( errno );
1182 io->Information = len;
1183 return STATUS_SUCCESS;
1187 static NTSTATUS do_setsockopt( HANDLE handle, IO_STATUS_BLOCK *io, int level,
1188 int option, const void *optval, socklen_t optlen )
1190 int fd, needs_close = FALSE;
1191 NTSTATUS status;
1192 int ret;
1194 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1195 return status;
1197 ret = setsockopt( fd, level, option, optval, optlen );
1198 if (needs_close) close( fd );
1199 return ret ? sock_errno_to_status( errno ) : STATUS_SUCCESS;
1203 NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io,
1204 ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size )
1206 int fd, needs_close = FALSE;
1207 NTSTATUS status;
1209 TRACE( "handle %p, code %#x, in_buffer %p, in_size %u, out_buffer %p, out_size %u\n",
1210 handle, code, in_buffer, in_size, out_buffer, out_size );
1212 switch (code)
1214 case IOCTL_AFD_BIND:
1216 const struct afd_bind_params *params = in_buffer;
1218 if (params->unknown) FIXME( "bind: got unknown %#x\n", params->unknown );
1220 status = STATUS_BAD_DEVICE_TYPE;
1221 break;
1224 case IOCTL_AFD_GETSOCKNAME:
1225 if (in_size) FIXME( "unexpected input size %u\n", in_size );
1227 status = STATUS_BAD_DEVICE_TYPE;
1228 break;
1230 case IOCTL_AFD_LISTEN:
1232 const struct afd_listen_params *params = in_buffer;
1234 TRACE( "backlog %u\n", params->backlog );
1235 if (out_size) FIXME( "unexpected output size %u\n", out_size );
1236 if (params->unknown1) FIXME( "listen: got unknown1 %#x\n", params->unknown1 );
1237 if (params->unknown2) FIXME( "listen: got unknown2 %#x\n", params->unknown2 );
1239 status = STATUS_BAD_DEVICE_TYPE;
1240 break;
1243 case IOCTL_AFD_EVENT_SELECT:
1245 const struct afd_event_select_params *params = in_buffer;
1247 TRACE( "event %p, mask %#x\n", params->event, params->mask );
1248 if (out_size) FIXME( "unexpected output size %u\n", out_size );
1250 status = STATUS_BAD_DEVICE_TYPE;
1251 break;
1254 case IOCTL_AFD_GET_EVENTS:
1255 if (in_size) FIXME( "unexpected input size %u\n", in_size );
1257 status = STATUS_BAD_DEVICE_TYPE;
1258 break;
1260 case IOCTL_AFD_RECV:
1262 const struct afd_recv_params *params = in_buffer;
1263 int unix_flags = 0;
1265 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1266 return status;
1268 if (out_size) FIXME( "unexpected output size %u\n", out_size );
1270 if (in_size < sizeof(struct afd_recv_params))
1272 status = STATUS_INVALID_PARAMETER;
1273 break;
1276 if ((params->msg_flags & (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) == 0 ||
1277 (params->msg_flags & (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) == (AFD_MSG_NOT_OOB | AFD_MSG_OOB))
1279 status = STATUS_INVALID_PARAMETER;
1280 break;
1283 if (params->msg_flags & ~(AFD_MSG_NOT_OOB | AFD_MSG_OOB | AFD_MSG_PEEK | AFD_MSG_WAITALL))
1284 FIXME( "unknown msg_flags %#x\n", params->msg_flags );
1285 if (params->recv_flags & ~AFD_RECV_FORCE_ASYNC)
1286 FIXME( "unknown recv_flags %#x\n", params->recv_flags );
1288 if (params->msg_flags & AFD_MSG_OOB)
1289 unix_flags |= MSG_OOB;
1290 if (params->msg_flags & AFD_MSG_PEEK)
1291 unix_flags |= MSG_PEEK;
1292 if (params->msg_flags & AFD_MSG_WAITALL)
1293 FIXME( "MSG_WAITALL is not supported\n" );
1295 status = sock_recv( handle, event, apc, apc_user, io, fd, params->buffers, params->count, NULL,
1296 NULL, NULL, NULL, unix_flags, !!(params->recv_flags & AFD_RECV_FORCE_ASYNC) );
1297 break;
1300 case IOCTL_AFD_WINE_RECVMSG:
1302 struct afd_recvmsg_params *params = in_buffer;
1303 int unix_flags = 0;
1305 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1306 return status;
1308 if (in_size < sizeof(*params))
1310 status = STATUS_BUFFER_TOO_SMALL;
1311 break;
1314 if (*params->ws_flags & WS_MSG_OOB)
1315 unix_flags |= MSG_OOB;
1316 if (*params->ws_flags & WS_MSG_PEEK)
1317 unix_flags |= MSG_PEEK;
1318 if (*params->ws_flags & WS_MSG_WAITALL)
1319 FIXME( "MSG_WAITALL is not supported\n" );
1321 status = sock_recv( handle, event, apc, apc_user, io, fd, params->buffers, params->count, params->control,
1322 params->addr, params->addr_len, params->ws_flags, unix_flags, params->force_async );
1323 break;
1326 case IOCTL_AFD_WINE_SENDMSG:
1328 const struct afd_sendmsg_params *params = in_buffer;
1329 int unix_flags = 0;
1331 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1332 return status;
1334 if (in_size < sizeof(*params))
1336 status = STATUS_BUFFER_TOO_SMALL;
1337 break;
1340 if (params->ws_flags & WS_MSG_OOB)
1341 unix_flags |= MSG_OOB;
1342 if (params->ws_flags & WS_MSG_PARTIAL)
1343 WARN( "ignoring MSG_PARTIAL\n" );
1344 if (params->ws_flags & ~(WS_MSG_OOB | WS_MSG_PARTIAL))
1345 FIXME( "unknown flags %#x\n", params->ws_flags );
1347 status = sock_send( handle, event, apc, apc_user, io, fd, params->buffers, params->count,
1348 params->addr, params->addr_len, unix_flags, params->force_async );
1349 break;
1352 case IOCTL_AFD_WINE_TRANSMIT:
1354 const struct afd_transmit_params *params = in_buffer;
1356 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1357 return status;
1359 if (in_size < sizeof(*params))
1361 status = STATUS_BUFFER_TOO_SMALL;
1362 break;
1365 status = sock_transmit( handle, event, apc, apc_user, io, fd, params );
1366 break;
1369 case IOCTL_AFD_WINE_COMPLETE_ASYNC:
1371 if (in_size != sizeof(NTSTATUS))
1372 return STATUS_BUFFER_TOO_SMALL;
1374 status = *(NTSTATUS *)in_buffer;
1375 complete_async( handle, event, apc, apc_user, io, status, 0 );
1376 break;
1379 case IOCTL_AFD_POLL:
1380 status = sock_poll( handle, event, apc, apc_user, io, in_buffer, in_size, out_buffer, out_size );
1381 break;
1383 case IOCTL_AFD_WINE_FIONREAD:
1385 int value, ret;
1387 if (out_size < sizeof(int))
1389 status = STATUS_BUFFER_TOO_SMALL;
1390 break;
1393 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1394 return status;
1396 #ifdef linux
1398 socklen_t len = sizeof(value);
1400 /* FIONREAD on a listening socket always fails (see tcp(7)). */
1401 if (!getsockopt( fd, SOL_SOCKET, SO_ACCEPTCONN, &value, &len ) && value)
1403 *(int *)out_buffer = 0;
1404 status = STATUS_SUCCESS;
1405 complete_async( handle, event, apc, apc_user, io, status, 0 );
1406 break;
1409 #endif
1411 if ((ret = ioctl( fd, FIONREAD, &value )) < 0)
1413 status = sock_errno_to_status( errno );
1414 break;
1416 *(int *)out_buffer = value;
1417 status = STATUS_SUCCESS;
1418 complete_async( handle, event, apc, apc_user, io, status, 0 );
1419 break;
1422 case IOCTL_AFD_WINE_SIOCATMARK:
1424 int value, ret;
1425 socklen_t len = sizeof(value);
1427 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1428 return status;
1430 if (out_size < sizeof(int))
1432 status = STATUS_BUFFER_TOO_SMALL;
1433 break;
1436 if (getsockopt( fd, SOL_SOCKET, SO_OOBINLINE, &value, &len ) < 0)
1438 status = sock_errno_to_status( errno );
1439 break;
1442 if (value)
1444 *(int *)out_buffer = TRUE;
1446 else
1448 if ((ret = ioctl( fd, SIOCATMARK, &value )) < 0)
1450 status = sock_errno_to_status( errno );
1451 break;
1453 /* windows is reversed with respect to unix */
1454 *(int *)out_buffer = !value;
1456 status = STATUS_SUCCESS;
1457 complete_async( handle, event, apc, apc_user, io, status, 0 );
1458 break;
1461 case IOCTL_AFD_WINE_GET_INTERFACE_LIST:
1463 #ifdef HAVE_GETIFADDRS
1464 INTERFACE_INFO *info = out_buffer;
1465 struct ifaddrs *ifaddrs, *ifaddr;
1466 unsigned int count = 0;
1467 ULONG ret_size;
1469 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1470 return status;
1472 if (getifaddrs( &ifaddrs ) < 0)
1474 status = sock_errno_to_status( errno );
1475 break;
1478 for (ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next)
1480 if (ifaddr->ifa_addr && ifaddr->ifa_addr->sa_family == AF_INET) ++count;
1483 ret_size = count * sizeof(*info);
1484 if (out_size < ret_size)
1486 status = STATUS_PENDING;
1487 complete_async( handle, event, apc, apc_user, io, STATUS_BUFFER_TOO_SMALL, 0 );
1488 freeifaddrs( ifaddrs );
1489 break;
1492 memset( out_buffer, 0, ret_size );
1494 count = 0;
1495 for (ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next)
1497 in_addr_t addr, mask;
1499 if (!ifaddr->ifa_addr || ifaddr->ifa_addr->sa_family != AF_INET)
1500 continue;
1502 addr = ((const struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr;
1503 mask = ((const struct sockaddr_in *)ifaddr->ifa_netmask)->sin_addr.s_addr;
1505 info[count].iiFlags = 0;
1506 if (ifaddr->ifa_flags & IFF_BROADCAST)
1507 info[count].iiFlags |= WS_IFF_BROADCAST;
1508 if (ifaddr->ifa_flags & IFF_LOOPBACK)
1509 info[count].iiFlags |= WS_IFF_LOOPBACK;
1510 if (ifaddr->ifa_flags & IFF_MULTICAST)
1511 info[count].iiFlags |= WS_IFF_MULTICAST;
1512 #ifdef IFF_POINTTOPOINT
1513 if (ifaddr->ifa_flags & IFF_POINTTOPOINT)
1514 info[count].iiFlags |= WS_IFF_POINTTOPOINT;
1515 #endif
1516 if (ifaddr->ifa_flags & IFF_UP)
1517 info[count].iiFlags |= WS_IFF_UP;
1519 info[count].iiAddress.AddressIn.sin_family = WS_AF_INET;
1520 info[count].iiAddress.AddressIn.sin_port = 0;
1521 info[count].iiAddress.AddressIn.sin_addr.WS_s_addr = addr;
1523 info[count].iiNetmask.AddressIn.sin_family = WS_AF_INET;
1524 info[count].iiNetmask.AddressIn.sin_port = 0;
1525 info[count].iiNetmask.AddressIn.sin_addr.WS_s_addr = mask;
1527 if (ifaddr->ifa_flags & IFF_BROADCAST)
1529 info[count].iiBroadcastAddress.AddressIn.sin_family = WS_AF_INET;
1530 info[count].iiBroadcastAddress.AddressIn.sin_port = 0;
1531 info[count].iiBroadcastAddress.AddressIn.sin_addr.WS_s_addr = addr | ~mask;
1534 ++count;
1537 freeifaddrs( ifaddrs );
1538 status = STATUS_PENDING;
1539 complete_async( handle, event, apc, apc_user, io, STATUS_SUCCESS, ret_size );
1540 #else
1541 FIXME( "Interface list queries are currently not supported on this platform.\n" );
1542 status = STATUS_NOT_SUPPORTED;
1543 #endif
1544 break;
1547 case IOCTL_AFD_WINE_KEEPALIVE_VALS:
1549 struct tcp_keepalive *k = in_buffer;
1550 int keepalive;
1552 if (!in_buffer || in_size < sizeof(struct tcp_keepalive))
1553 return STATUS_BUFFER_TOO_SMALL;
1554 keepalive = !!k->onoff;
1556 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1557 return status;
1559 if (setsockopt( fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(int) ) < 0)
1561 status = STATUS_INVALID_PARAMETER;
1562 break;
1565 if (keepalive)
1567 #ifdef TCP_KEEPIDLE
1568 int idle = max( 1, (k->keepalivetime + 500) / 1000 );
1570 if (setsockopt( fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(int) ) < 0)
1572 status = STATUS_INVALID_PARAMETER;
1573 break;
1575 #else
1576 FIXME("ignoring keepalive timeout\n");
1577 #endif
1580 if (keepalive)
1582 #ifdef TCP_KEEPINTVL
1583 int interval = max( 1, (k->keepaliveinterval + 500) / 1000 );
1585 if (setsockopt( fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(int) ) < 0)
1586 status = STATUS_INVALID_PARAMETER;
1587 #else
1588 FIXME("ignoring keepalive interval\n");
1589 #endif
1592 status = STATUS_SUCCESS;
1593 complete_async( handle, event, apc, apc_user, io, status, 0 );
1594 break;
1597 case IOCTL_AFD_WINE_GETPEERNAME:
1599 union unix_sockaddr unix_addr;
1600 socklen_t unix_len = sizeof(unix_addr);
1601 int len;
1603 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1604 return status;
1606 if (getpeername( fd, &unix_addr.addr, &unix_len ) < 0)
1608 status = sock_errno_to_status( errno );
1609 break;
1612 len = sockaddr_from_unix( &unix_addr, out_buffer, out_size );
1613 if (out_size < len)
1615 status = STATUS_BUFFER_TOO_SMALL;
1616 break;
1618 io->Information = len;
1619 status = STATUS_SUCCESS;
1620 break;
1623 case IOCTL_AFD_WINE_GET_SO_BROADCAST:
1624 return do_getsockopt( handle, io, SOL_SOCKET, SO_BROADCAST, out_buffer, out_size );
1626 case IOCTL_AFD_WINE_SET_SO_BROADCAST:
1627 return do_setsockopt( handle, io, SOL_SOCKET, SO_BROADCAST, in_buffer, in_size );
1629 case IOCTL_AFD_WINE_GET_SO_KEEPALIVE:
1630 return do_getsockopt( handle, io, SOL_SOCKET, SO_KEEPALIVE, out_buffer, out_size );
1632 case IOCTL_AFD_WINE_SET_SO_KEEPALIVE:
1633 return do_setsockopt( handle, io, SOL_SOCKET, SO_KEEPALIVE, in_buffer, in_size );
1635 case IOCTL_AFD_WINE_GET_SO_LINGER:
1637 struct WS_linger *ws_linger = out_buffer;
1638 struct linger unix_linger;
1639 socklen_t len = sizeof(unix_linger);
1640 int ret;
1642 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1643 return status;
1645 ret = getsockopt( fd, SOL_SOCKET, SO_LINGER, &unix_linger, &len );
1646 if (needs_close) close( fd );
1647 if (!ret)
1649 ws_linger->l_onoff = unix_linger.l_onoff;
1650 ws_linger->l_linger = unix_linger.l_linger;
1651 io->Information = sizeof(*ws_linger);
1654 return ret ? sock_errno_to_status( errno ) : STATUS_SUCCESS;
1657 case IOCTL_AFD_WINE_SET_SO_LINGER:
1659 const struct WS_linger *ws_linger = in_buffer;
1660 struct linger unix_linger;
1662 unix_linger.l_onoff = ws_linger->l_onoff;
1663 unix_linger.l_linger = ws_linger->l_linger;
1665 return do_setsockopt( handle, io, SOL_SOCKET, SO_LINGER, &unix_linger, sizeof(unix_linger) );
1668 case IOCTL_AFD_WINE_GET_SO_OOBINLINE:
1669 return do_getsockopt( handle, io, SOL_SOCKET, SO_OOBINLINE, out_buffer, out_size );
1671 case IOCTL_AFD_WINE_SET_SO_OOBINLINE:
1672 return do_setsockopt( handle, io, SOL_SOCKET, SO_OOBINLINE, in_buffer, in_size );
1674 case IOCTL_AFD_WINE_GET_SO_REUSEADDR:
1675 return do_getsockopt( handle, io, SOL_SOCKET, SO_REUSEADDR, out_buffer, out_size );
1677 /* BSD socket SO_REUSEADDR is not 100% compatible to winsock semantics;
1678 * however, using it the BSD way fixes bug 8513 and seems to be what
1679 * most programmers assume, anyway */
1680 case IOCTL_AFD_WINE_SET_SO_REUSEADDR:
1682 int fd, needs_close = FALSE;
1683 NTSTATUS status;
1684 int ret;
1686 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1687 return status;
1689 ret = setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, in_buffer, in_size );
1690 #ifdef __APPLE__
1691 if (!ret) ret = setsockopt( fd, SOL_SOCKET, SO_REUSEPORT, in_buffer, in_size );
1692 #endif
1693 if (needs_close) close( fd );
1694 return ret ? sock_errno_to_status( errno ) : STATUS_SUCCESS;
1697 case IOCTL_AFD_WINE_SET_IP_ADD_MEMBERSHIP:
1698 return do_setsockopt( handle, io, IPPROTO_IP, IP_ADD_MEMBERSHIP, in_buffer, in_size );
1700 case IOCTL_AFD_WINE_SET_IP_ADD_SOURCE_MEMBERSHIP:
1701 return do_setsockopt( handle, io, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, in_buffer, in_size );
1703 case IOCTL_AFD_WINE_SET_IP_BLOCK_SOURCE:
1704 return do_setsockopt( handle, io, IPPROTO_IP, IP_BLOCK_SOURCE, in_buffer, in_size );
1706 case IOCTL_AFD_WINE_GET_IP_DONTFRAGMENT:
1708 socklen_t len = out_size;
1709 int ret;
1711 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1712 return status;
1714 #ifdef IP_DONTFRAG
1715 ret = getsockopt( fd, IPPROTO_IP, IP_DONTFRAG, out_buffer, &len );
1716 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1718 int value;
1720 len = sizeof(value);
1721 ret = getsockopt( fd, IPPROTO_IP, IP_MTU_DISCOVER, &value, &len );
1722 if (!ret) *(DWORD *)out_buffer = (value != IP_PMTUDISC_DONT);
1724 #else
1726 static int once;
1728 if (!once++)
1729 FIXME( "IP_DONTFRAGMENT is not supported on this platform\n" );
1730 ret = 0; /* fake success */
1732 #endif
1733 if (needs_close) close( fd );
1734 if (ret) return sock_errno_to_status( errno );
1735 io->Information = len;
1736 return STATUS_SUCCESS;
1739 case IOCTL_AFD_WINE_SET_IP_DONTFRAGMENT:
1740 #ifdef IP_DONTFRAG
1741 return do_setsockopt( handle, io, IPPROTO_IP, IP_DONTFRAG, in_buffer, in_size );
1742 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) && defined(IP_PMTUDISC_DONT)
1744 int value = *(DWORD *)in_buffer ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
1746 return do_setsockopt( handle, io, IPPROTO_IP, IP_MTU_DISCOVER, &value, sizeof(value) );
1748 #else
1750 static int once;
1752 if (!once++)
1753 FIXME( "IP_DONTFRAGMENT is not supported on this platform\n" );
1754 return STATUS_SUCCESS; /* fake success */
1756 #endif
1758 case IOCTL_AFD_WINE_SET_IP_DROP_MEMBERSHIP:
1759 return do_setsockopt( handle, io, IPPROTO_IP, IP_DROP_MEMBERSHIP, in_buffer, in_size );
1761 case IOCTL_AFD_WINE_SET_IP_DROP_SOURCE_MEMBERSHIP:
1762 return do_setsockopt( handle, io, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, in_buffer, in_size );
1764 #ifdef IP_HDRINCL
1765 case IOCTL_AFD_WINE_SET_IP_HDRINCL:
1766 return do_setsockopt( handle, io, IPPROTO_IP, IP_HDRINCL, in_buffer, in_size );
1767 #endif
1769 case IOCTL_AFD_WINE_GET_IP_MULTICAST_IF:
1770 return do_getsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_IF, out_buffer, out_size );
1772 case IOCTL_AFD_WINE_SET_IP_MULTICAST_IF:
1773 return do_setsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_IF, in_buffer, in_size );
1775 case IOCTL_AFD_WINE_GET_IP_MULTICAST_LOOP:
1776 return do_getsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_LOOP, out_buffer, out_size );
1778 case IOCTL_AFD_WINE_SET_IP_MULTICAST_LOOP:
1779 return do_setsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_LOOP, in_buffer, in_size );
1781 case IOCTL_AFD_WINE_GET_IP_MULTICAST_TTL:
1782 return do_getsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_TTL, out_buffer, out_size );
1784 case IOCTL_AFD_WINE_SET_IP_MULTICAST_TTL:
1785 return do_setsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_TTL, in_buffer, in_size );
1787 case IOCTL_AFD_WINE_GET_IP_OPTIONS:
1788 return do_getsockopt( handle, io, IPPROTO_IP, IP_OPTIONS, out_buffer, out_size );
1790 case IOCTL_AFD_WINE_SET_IP_OPTIONS:
1791 return do_setsockopt( handle, io, IPPROTO_IP, IP_OPTIONS, in_buffer, in_size );
1793 #ifdef IP_PKTINFO
1794 case IOCTL_AFD_WINE_GET_IP_PKTINFO:
1795 return do_getsockopt( handle, io, IPPROTO_IP, IP_PKTINFO, out_buffer, out_size );
1797 case IOCTL_AFD_WINE_SET_IP_PKTINFO:
1798 return do_setsockopt( handle, io, IPPROTO_IP, IP_PKTINFO, in_buffer, in_size );
1799 #elif defined(IP_RECVDSTADDR)
1800 case IOCTL_AFD_WINE_GET_IP_PKTINFO:
1801 return do_getsockopt( handle, io, IPPROTO_IP, IP_RECVDSTADDR, out_buffer, out_size );
1803 case IOCTL_AFD_WINE_SET_IP_PKTINFO:
1804 return do_setsockopt( handle, io, IPPROTO_IP, IP_RECVDSTADDR, in_buffer, in_size );
1805 #endif
1807 case IOCTL_AFD_WINE_GET_IP_TOS:
1808 return do_getsockopt( handle, io, IPPROTO_IP, IP_TOS, out_buffer, out_size );
1810 case IOCTL_AFD_WINE_SET_IP_TOS:
1811 return do_setsockopt( handle, io, IPPROTO_IP, IP_TOS, in_buffer, in_size );
1813 case IOCTL_AFD_WINE_GET_IP_TTL:
1814 return do_getsockopt( handle, io, IPPROTO_IP, IP_TTL, out_buffer, out_size );
1816 case IOCTL_AFD_WINE_SET_IP_TTL:
1817 return do_setsockopt( handle, io, IPPROTO_IP, IP_TTL, in_buffer, in_size );
1819 case IOCTL_AFD_WINE_SET_IP_UNBLOCK_SOURCE:
1820 return do_setsockopt( handle, io, IPPROTO_IP, IP_UNBLOCK_SOURCE, in_buffer, in_size );
1822 #ifdef IP_UNICAST_IF
1823 case IOCTL_AFD_WINE_GET_IP_UNICAST_IF:
1824 return do_getsockopt( handle, io, IPPROTO_IP, IP_UNICAST_IF, out_buffer, out_size );
1826 case IOCTL_AFD_WINE_SET_IP_UNICAST_IF:
1827 return do_setsockopt( handle, io, IPPROTO_IP, IP_UNICAST_IF, in_buffer, in_size );
1828 #endif
1830 #ifdef IPV6_ADD_MEMBERSHIP
1831 case IOCTL_AFD_WINE_SET_IPV6_ADD_MEMBERSHIP:
1832 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, in_buffer, in_size );
1833 #endif
1835 case IOCTL_AFD_WINE_GET_IPV6_DONTFRAG:
1837 socklen_t len = out_size;
1838 int ret;
1840 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1841 return status;
1843 #ifdef IPV6_DONTFRAG
1844 ret = getsockopt( fd, IPPROTO_IPV6, IPV6_DONTFRAG, out_buffer, &len );
1845 #elif defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT)
1847 int value;
1849 len = sizeof(value);
1850 ret = getsockopt( fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &value, &len );
1851 if (!ret) *(DWORD *)out_buffer = (value != IPV6_PMTUDISC_DONT);
1853 #else
1855 static int once;
1857 if (!once++)
1858 FIXME( "IPV6_DONTFRAGMENT is not supported on this platform\n" );
1859 ret = 0; /* fake success */
1861 #endif
1862 if (needs_close) close( fd );
1863 if (ret) return sock_errno_to_status( errno );
1864 io->Information = len;
1865 return STATUS_SUCCESS;
1868 case IOCTL_AFD_WINE_SET_IPV6_DONTFRAG:
1869 #ifdef IPV6_DONTFRAG
1870 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_DONTFRAG, in_buffer, in_size );
1871 #elif defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) && defined(IPV6_PMTUDISC_DONT)
1873 int value = *(DWORD *)in_buffer ? IPV6_PMTUDISC_DO : IPV6_PMTUDISC_DONT;
1875 return do_setsockopt( handle, io, IPPROTO_IP, IPV6_MTU_DISCOVER, &value, sizeof(value) );
1877 #else
1879 static int once;
1881 if (!once++)
1882 FIXME( "IPV6_DONTFRAGMENT is not supported on this platform\n" );
1883 return STATUS_SUCCESS; /* fake success */
1885 #endif
1887 #ifdef IPV6_DROP_MEMBERSHIP
1888 case IOCTL_AFD_WINE_SET_IPV6_DROP_MEMBERSHIP:
1889 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, in_buffer, in_size );
1890 #endif
1892 case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_HOPS:
1893 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, out_buffer, out_size );
1895 case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_HOPS:
1896 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, in_buffer, in_size );
1898 case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_IF:
1899 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_IF, out_buffer, out_size );
1901 case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_IF:
1902 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_IF, in_buffer, in_size );
1904 case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_LOOP:
1905 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, out_buffer, out_size );
1907 case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_LOOP:
1908 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, in_buffer, in_size );
1910 #ifdef IPV6_RECVHOPLIMIT
1911 case IOCTL_AFD_WINE_GET_IPV6_RECVHOPLIMIT:
1912 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, out_buffer, out_size );
1914 case IOCTL_AFD_WINE_SET_IPV6_RECVHOPLIMIT:
1915 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, in_buffer, in_size );
1916 #endif
1918 #ifdef IPV6_RECVPKTINFO
1919 case IOCTL_AFD_WINE_GET_IPV6_RECVPKTINFO:
1920 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVPKTINFO, out_buffer, out_size );
1922 case IOCTL_AFD_WINE_SET_IPV6_RECVPKTINFO:
1923 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVPKTINFO, in_buffer, in_size );
1924 #endif
1926 #ifdef IPV6_RECVTCLASS
1927 case IOCTL_AFD_WINE_GET_IPV6_RECVTCLASS:
1928 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVTCLASS, out_buffer, out_size );
1930 case IOCTL_AFD_WINE_SET_IPV6_RECVTCLASS:
1931 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVTCLASS, in_buffer, in_size );
1932 #endif
1934 case IOCTL_AFD_WINE_GET_IPV6_UNICAST_HOPS:
1935 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_UNICAST_HOPS, out_buffer, out_size );
1937 case IOCTL_AFD_WINE_SET_IPV6_UNICAST_HOPS:
1938 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_UNICAST_HOPS, in_buffer, in_size );
1940 #ifdef IPV6_UNICAST_IF
1941 case IOCTL_AFD_WINE_GET_IPV6_UNICAST_IF:
1942 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_UNICAST_IF, out_buffer, out_size );
1944 case IOCTL_AFD_WINE_SET_IPV6_UNICAST_IF:
1945 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_UNICAST_IF, in_buffer, in_size );
1946 #endif
1948 case IOCTL_AFD_WINE_GET_IPV6_V6ONLY:
1949 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_V6ONLY, out_buffer, out_size );
1951 case IOCTL_AFD_WINE_SET_IPV6_V6ONLY:
1953 int fd, needs_close = FALSE;
1954 union unix_sockaddr addr;
1955 socklen_t len = sizeof(addr);
1956 NTSTATUS status;
1957 int ret;
1959 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1960 return status;
1962 if (!getsockname( fd, &addr.addr, &len ) && addr.addr.sa_family == AF_INET && !addr.in.sin_port)
1964 /* changing IPV6_V6ONLY succeeds on an unbound IPv4 socket */
1965 WARN( "ignoring IPV6_V6ONLY on an unbound IPv4 socket\n" );
1966 return STATUS_SUCCESS;
1969 ret = setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, in_buffer, in_size );
1970 if (needs_close) close( fd );
1971 return ret ? sock_errno_to_status( errno ) : STATUS_SUCCESS;
1974 #ifdef SOL_IPX
1975 case IOCTL_AFD_WINE_GET_IPX_PTYPE:
1976 return do_getsockopt( handle, io, SOL_IPX, IPX_TYPE, out_buffer, out_size );
1978 case IOCTL_AFD_WINE_SET_IPX_PTYPE:
1979 return do_setsockopt( handle, io, SOL_IPX, IPX_TYPE, in_buffer, in_size );
1980 #elif defined(SO_DEFAULT_HEADERS)
1981 case IOCTL_AFD_WINE_GET_IPX_PTYPE:
1983 int fd, needs_close = FALSE;
1984 struct ipx value;
1985 socklen_t len = sizeof(value);
1986 int ret;
1988 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1989 return status;
1991 ret = getsockopt( fd, 0, SO_DEFAULT_HEADERS, &value, &len );
1992 if (needs_close) close( fd );
1993 if (ret) return sock_errno_to_status( errno );
1994 *(DWORD *)out_buffer = value.ipx_pt;
1995 return STATUS_SUCCESS;
1998 case IOCTL_AFD_WINE_SET_IPX_PTYPE:
2000 struct ipx value = {0};
2002 /* FIXME: should we retrieve SO_DEFAULT_HEADERS first and modify it? */
2003 value.ipx_pt = *(DWORD *)in_buffer;
2004 return do_setsockopt( handle, io, 0, SO_DEFAULT_HEADERS, &value, sizeof(value) );
2006 #endif
2008 #ifdef HAS_IRDA
2009 #define MAX_IRDA_DEVICES 10
2010 case IOCTL_AFD_WINE_GET_IRLMP_ENUMDEVICES:
2012 char buffer[offsetof( struct irda_device_list, dev[MAX_IRDA_DEVICES] )];
2013 struct irda_device_list *unix_list = (struct irda_device_list *)buffer;
2014 socklen_t len = sizeof(buffer);
2015 DEVICELIST *ws_list = out_buffer;
2016 int fd, needs_close = FALSE;
2017 NTSTATUS status;
2018 unsigned int i;
2019 int ret;
2021 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
2022 return status;
2024 ret = getsockopt( fd, SOL_IRLMP, IRLMP_ENUMDEVICES, buffer, &len );
2025 if (needs_close) close( fd );
2026 if (ret) return sock_errno_to_status( errno );
2028 io->Information = offsetof( DEVICELIST, Device[unix_list->len] );
2029 if (out_size < io->Information)
2030 return STATUS_BUFFER_TOO_SMALL;
2032 TRACE( "IRLMP_ENUMDEVICES: got %u devices:\n", unix_list->len );
2033 ws_list->numDevice = unix_list->len;
2034 for (i = 0; i < unix_list->len; ++i)
2036 const struct irda_device_info *unix_dev = &unix_list->dev[i];
2037 IRDA_DEVICE_INFO *ws_dev = &ws_list->Device[i];
2039 TRACE( "saddr %#08x, daddr %#08x, info %s, hints 0x%02x%02x\n",
2040 unix_dev->saddr, unix_dev->daddr, unix_dev->info, unix_dev->hints[0], unix_dev->hints[1] );
2041 memcpy( ws_dev->irdaDeviceID, &unix_dev->daddr, sizeof(unix_dev->daddr) );
2042 memcpy( ws_dev->irdaDeviceName, unix_dev->info, sizeof(unix_dev->info) );
2043 ws_dev->irdaDeviceHints1 = unix_dev->hints[0];
2044 ws_dev->irdaDeviceHints2 = unix_dev->hints[1];
2045 ws_dev->irdaCharSet = unix_dev->charset;
2047 return STATUS_SUCCESS;
2049 #endif
2051 case IOCTL_AFD_WINE_GET_TCP_NODELAY:
2052 return do_getsockopt( handle, io, IPPROTO_TCP, TCP_NODELAY, out_buffer, out_size );
2054 case IOCTL_AFD_WINE_SET_TCP_NODELAY:
2055 return do_setsockopt( handle, io, IPPROTO_TCP, TCP_NODELAY, in_buffer, in_size );
2057 default:
2059 if ((code >> 16) == FILE_DEVICE_NETWORK)
2061 /* Wine-internal ioctl */
2062 status = STATUS_BAD_DEVICE_TYPE;
2064 else
2066 FIXME( "Unknown ioctl %#x (device %#x, access %#x, function %#x, method %#x)\n",
2067 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3 );
2068 status = STATUS_INVALID_DEVICE_REQUEST;
2070 break;
2074 if (needs_close) close( fd );
2075 return status;