ws2_32: Move the setsockopt(TCP_NODELAY) implementation to ntdll.
[wine.git] / dlls / ntdll / unix / socket.c
blob0e52db178d860c8e02d9ab92cdcdc8e13914b8ed
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 #include <errno.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #ifdef HAVE_IFADDRS_H
30 # include <ifaddrs.h>
31 #endif
32 #ifdef HAVE_NET_IF_H
33 # include <net/if.h>
34 #endif
35 #ifdef HAVE_SYS_IOCTL_H
36 # include <sys/ioctl.h>
37 #endif
38 #ifdef HAVE_SYS_SOCKET_H
39 #include <sys/socket.h>
40 #endif
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
44 #ifdef HAVE_NETINET_TCP_H
45 # include <netinet/tcp.h>
46 #endif
48 #ifdef HAVE_NETIPX_IPX_H
49 # include <netipx/ipx.h>
50 #elif defined(HAVE_LINUX_IPX_H)
51 # ifdef HAVE_ASM_TYPES_H
52 # include <asm/types.h>
53 # endif
54 # ifdef HAVE_LINUX_TYPES_H
55 # include <linux/types.h>
56 # endif
57 # include <linux/ipx.h>
58 #endif
59 #if defined(SOL_IPX) || defined(SO_DEFAULT_HEADERS)
60 # define HAS_IPX
61 #endif
63 #ifdef HAVE_LINUX_IRDA_H
64 # ifdef HAVE_LINUX_TYPES_H
65 # include <linux/types.h>
66 # endif
67 # include <linux/irda.h>
68 # define HAS_IRDA
69 #endif
71 #include "ntstatus.h"
72 #define WIN32_NO_STATUS
73 #include "windef.h"
74 #include "winioctl.h"
75 #define USE_WS_PREFIX
76 #include "winsock2.h"
77 #include "mswsock.h"
78 #include "mstcpip.h"
79 #include "ws2tcpip.h"
80 #include "wsipx.h"
81 #include "af_irda.h"
82 #include "wine/afd.h"
84 #include "unix_private.h"
86 #if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE)
87 /* TCP_KEEPALIVE is the Mac OS name for TCP_KEEPIDLE */
88 #define TCP_KEEPIDLE TCP_KEEPALIVE
89 #endif
91 #if defined(linux) && !defined(IP_UNICAST_IF)
92 #define IP_UNICAST_IF 50
93 #endif
95 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
97 #define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
99 static async_data_t server_async( HANDLE handle, struct async_fileio *user, HANDLE event,
100 PIO_APC_ROUTINE apc, void *apc_context, IO_STATUS_BLOCK *io )
102 async_data_t async;
103 async.handle = wine_server_obj_handle( handle );
104 async.user = wine_server_client_ptr( user );
105 async.iosb = wine_server_client_ptr( io );
106 async.event = wine_server_obj_handle( event );
107 async.apc = wine_server_client_ptr( apc );
108 async.apc_context = wine_server_client_ptr( apc_context );
109 return async;
112 static NTSTATUS wait_async( HANDLE handle, BOOL alertable )
114 return NtWaitForSingleObject( handle, alertable, NULL );
117 union unix_sockaddr
119 struct sockaddr addr;
120 struct sockaddr_in in;
121 struct sockaddr_in6 in6;
122 #ifdef HAS_IPX
123 struct sockaddr_ipx ipx;
124 #endif
125 #ifdef HAS_IRDA
126 struct sockaddr_irda irda;
127 #endif
130 struct async_recv_ioctl
132 struct async_fileio io;
133 WSABUF *control;
134 struct WS_sockaddr *addr;
135 int *addr_len;
136 DWORD *ret_flags;
137 int unix_flags;
138 unsigned int count;
139 struct iovec iov[1];
142 struct async_send_ioctl
144 struct async_fileio io;
145 const struct WS_sockaddr *addr;
146 int addr_len;
147 int unix_flags;
148 unsigned int sent_len;
149 unsigned int count;
150 unsigned int iov_cursor;
151 struct iovec iov[1];
154 struct async_transmit_ioctl
156 struct async_fileio io;
157 HANDLE file;
158 char *buffer;
159 unsigned int buffer_size; /* allocated size of buffer */
160 unsigned int read_len; /* amount of valid data currently in the buffer */
161 unsigned int head_cursor; /* amount of header data already sent */
162 unsigned int file_cursor; /* amount of file data already sent */
163 unsigned int buffer_cursor; /* amount of data currently in the buffer already sent */
164 unsigned int tail_cursor; /* amount of tail data already sent */
165 unsigned int file_len; /* total file length to send */
166 DWORD flags;
167 TRANSMIT_FILE_BUFFERS buffers;
168 LARGE_INTEGER offset;
171 static NTSTATUS sock_errno_to_status( int err )
173 switch (err)
175 case EBADF: return STATUS_INVALID_HANDLE;
176 case EBUSY: return STATUS_DEVICE_BUSY;
177 case EPERM:
178 case EACCES: return STATUS_ACCESS_DENIED;
179 case EFAULT: return STATUS_ACCESS_VIOLATION;
180 case EINVAL: return STATUS_INVALID_PARAMETER;
181 case ENFILE:
182 case EMFILE: return STATUS_TOO_MANY_OPENED_FILES;
183 case EINPROGRESS:
184 case EWOULDBLOCK: return STATUS_DEVICE_NOT_READY;
185 case EALREADY: return STATUS_NETWORK_BUSY;
186 case ENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH;
187 case EDESTADDRREQ: return STATUS_INVALID_PARAMETER;
188 case EMSGSIZE: return STATUS_BUFFER_OVERFLOW;
189 case EPROTONOSUPPORT:
190 case ESOCKTNOSUPPORT:
191 case EPFNOSUPPORT:
192 case EAFNOSUPPORT:
193 case EPROTOTYPE: return STATUS_NOT_SUPPORTED;
194 case ENOPROTOOPT: return STATUS_INVALID_PARAMETER;
195 case EOPNOTSUPP: return STATUS_NOT_SUPPORTED;
196 case EADDRINUSE: return STATUS_SHARING_VIOLATION;
197 case EADDRNOTAVAIL: return STATUS_INVALID_PARAMETER;
198 case ECONNREFUSED: return STATUS_CONNECTION_REFUSED;
199 case ESHUTDOWN: return STATUS_PIPE_DISCONNECTED;
200 case ENOTCONN: return STATUS_INVALID_CONNECTION;
201 case ETIMEDOUT: return STATUS_IO_TIMEOUT;
202 case ENETUNREACH: return STATUS_NETWORK_UNREACHABLE;
203 case EHOSTUNREACH: return STATUS_HOST_UNREACHABLE;
204 case ENETDOWN: return STATUS_NETWORK_BUSY;
205 case EPIPE:
206 case ECONNRESET: return STATUS_CONNECTION_RESET;
207 case ECONNABORTED: return STATUS_CONNECTION_ABORTED;
208 case EISCONN: return STATUS_CONNECTION_ACTIVE;
210 case 0: return STATUS_SUCCESS;
211 default:
212 FIXME( "unknown errno %d\n", err );
213 return STATUS_UNSUCCESSFUL;
217 static socklen_t sockaddr_to_unix( const struct WS_sockaddr *wsaddr, int wsaddrlen, union unix_sockaddr *uaddr )
219 memset( uaddr, 0, sizeof(*uaddr) );
221 switch (wsaddr->sa_family)
223 case WS_AF_INET:
225 struct WS_sockaddr_in win = {0};
227 if (wsaddrlen < sizeof(win)) return 0;
228 memcpy( &win, wsaddr, sizeof(win) );
229 uaddr->in.sin_family = AF_INET;
230 uaddr->in.sin_port = win.sin_port;
231 memcpy( &uaddr->in.sin_addr, &win.sin_addr, sizeof(win.sin_addr) );
232 return sizeof(uaddr->in);
235 case WS_AF_INET6:
237 struct WS_sockaddr_in6 win = {0};
239 if (wsaddrlen < sizeof(win)) return 0;
240 memcpy( &win, wsaddr, sizeof(win) );
241 uaddr->in6.sin6_family = AF_INET6;
242 uaddr->in6.sin6_port = win.sin6_port;
243 uaddr->in6.sin6_flowinfo = win.sin6_flowinfo;
244 memcpy( &uaddr->in6.sin6_addr, &win.sin6_addr, sizeof(win.sin6_addr) );
245 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
246 uaddr->in6.sin6_scope_id = win.sin6_scope_id;
247 #endif
248 return sizeof(uaddr->in6);
251 #ifdef HAS_IPX
252 case WS_AF_IPX:
254 struct WS_sockaddr_ipx win = {0};
256 if (wsaddrlen < sizeof(win)) return 0;
257 memcpy( &win, wsaddr, sizeof(win) );
258 uaddr->ipx.sipx_family = AF_IPX;
259 memcpy( &uaddr->ipx.sipx_network, win.sa_netnum, sizeof(win.sa_netnum) );
260 memcpy( &uaddr->ipx.sipx_node, win.sa_nodenum, sizeof(win.sa_nodenum) );
261 uaddr->ipx.sipx_port = win.sa_socket;
262 return sizeof(uaddr->ipx);
264 #endif
266 #ifdef HAS_IRDA
267 case WS_AF_IRDA:
269 SOCKADDR_IRDA win = {0};
270 unsigned int lsap_sel;
272 if (wsaddrlen < sizeof(win)) return 0;
273 memcpy( &win, wsaddr, sizeof(win) );
274 uaddr->irda.sir_family = AF_IRDA;
275 if (sscanf( win.irdaServiceName, "LSAP-SEL%u", &lsap_sel ) == 1)
276 uaddr->irda.sir_lsap_sel = lsap_sel;
277 else
279 uaddr->irda.sir_lsap_sel = LSAP_ANY;
280 memcpy( uaddr->irda.sir_name, win.irdaServiceName, sizeof(win.irdaServiceName) );
282 memcpy( &uaddr->irda.sir_addr, win.irdaDeviceID, sizeof(win.irdaDeviceID) );
283 return sizeof(uaddr->irda);
285 #endif
287 case WS_AF_UNSPEC:
288 switch (wsaddrlen)
290 default: /* likely an ipv4 address */
291 case sizeof(struct WS_sockaddr_in):
292 return sizeof(uaddr->in);
294 #ifdef HAS_IPX
295 case sizeof(struct WS_sockaddr_ipx):
296 return sizeof(uaddr->ipx);
297 #endif
299 #ifdef HAS_IRDA
300 case sizeof(SOCKADDR_IRDA):
301 return sizeof(uaddr->irda);
302 #endif
304 case sizeof(struct WS_sockaddr_in6):
305 return sizeof(uaddr->in6);
308 default:
309 FIXME( "unknown address family %u\n", wsaddr->sa_family );
310 return 0;
314 static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_sockaddr *wsaddr, socklen_t wsaddrlen )
316 memset( wsaddr, 0, wsaddrlen );
318 switch (uaddr->addr.sa_family)
320 case AF_INET:
322 struct WS_sockaddr_in win = {0};
324 if (wsaddrlen < sizeof(win)) return -1;
325 win.sin_family = WS_AF_INET;
326 win.sin_port = uaddr->in.sin_port;
327 memcpy( &win.sin_addr, &uaddr->in.sin_addr, sizeof(win.sin_addr) );
328 memcpy( wsaddr, &win, sizeof(win) );
329 return sizeof(win);
332 case AF_INET6:
334 struct WS_sockaddr_in6 win = {0};
336 if (wsaddrlen < sizeof(win)) return -1;
337 win.sin6_family = WS_AF_INET6;
338 win.sin6_port = uaddr->in6.sin6_port;
339 win.sin6_flowinfo = uaddr->in6.sin6_flowinfo;
340 memcpy( &win.sin6_addr, &uaddr->in6.sin6_addr, sizeof(win.sin6_addr) );
341 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
342 win.sin6_scope_id = uaddr->in6.sin6_scope_id;
343 #endif
344 memcpy( wsaddr, &win, sizeof(win) );
345 return sizeof(win);
348 #ifdef HAS_IPX
349 case AF_IPX:
351 struct WS_sockaddr_ipx win = {0};
353 if (wsaddrlen < sizeof(win)) return -1;
354 win.sa_family = WS_AF_IPX;
355 memcpy( win.sa_netnum, &uaddr->ipx.sipx_network, sizeof(win.sa_netnum) );
356 memcpy( win.sa_nodenum, &uaddr->ipx.sipx_node, sizeof(win.sa_nodenum) );
357 win.sa_socket = uaddr->ipx.sipx_port;
358 memcpy( wsaddr, &win, sizeof(win) );
359 return sizeof(win);
361 #endif
363 #ifdef HAS_IRDA
364 case AF_IRDA:
366 SOCKADDR_IRDA win;
368 if (wsaddrlen < sizeof(win)) return -1;
369 win.irdaAddressFamily = WS_AF_IRDA;
370 memcpy( win.irdaDeviceID, &uaddr->irda.sir_addr, sizeof(win.irdaDeviceID) );
371 if (uaddr->irda.sir_lsap_sel != LSAP_ANY)
372 snprintf( win.irdaServiceName, sizeof(win.irdaServiceName), "LSAP-SEL%u", uaddr->irda.sir_lsap_sel );
373 else
374 memcpy( win.irdaServiceName, uaddr->irda.sir_name, sizeof(win.irdaServiceName) );
375 memcpy( wsaddr, &win, sizeof(win) );
376 return sizeof(win);
378 #endif
380 case AF_UNSPEC:
381 return 0;
383 default:
384 FIXME( "unknown address family %d\n", uaddr->addr.sa_family );
385 return -1;
389 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
390 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
391 static WSACMSGHDR *fill_control_message( int level, int type, WSACMSGHDR *current, ULONG *maxsize, void *data, int len )
393 ULONG msgsize = sizeof(WSACMSGHDR) + WSA_CMSG_ALIGN(len);
394 char *ptr = (char *) current + sizeof(WSACMSGHDR);
396 if (msgsize > *maxsize)
397 return NULL;
398 *maxsize -= msgsize;
399 current->cmsg_len = sizeof(WSACMSGHDR) + len;
400 current->cmsg_level = level;
401 current->cmsg_type = type;
402 memcpy(ptr, data, len);
403 return (WSACMSGHDR *)(ptr + WSA_CMSG_ALIGN(len));
405 #endif /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
407 static int convert_control_headers(struct msghdr *hdr, WSABUF *control)
409 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
410 WSACMSGHDR *cmsg_win = (WSACMSGHDR *)control->buf, *ptr;
411 ULONG ctlsize = control->len;
412 struct cmsghdr *cmsg_unix;
414 ptr = cmsg_win;
415 for (cmsg_unix = CMSG_FIRSTHDR(hdr); cmsg_unix != NULL; cmsg_unix = CMSG_NXTHDR(hdr, cmsg_unix))
417 switch (cmsg_unix->cmsg_level)
419 case IPPROTO_IP:
420 switch (cmsg_unix->cmsg_type)
422 #if defined(IP_PKTINFO)
423 case IP_PKTINFO:
425 const struct in_pktinfo *data_unix = (struct in_pktinfo *)CMSG_DATA(cmsg_unix);
426 struct WS_in_pktinfo data_win;
428 memcpy( &data_win.ipi_addr, &data_unix->ipi_addr.s_addr, 4 ); /* 4 bytes = 32 address bits */
429 data_win.ipi_ifindex = data_unix->ipi_ifindex;
430 ptr = fill_control_message( WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize,
431 (void *)&data_win, sizeof(data_win) );
432 if (!ptr) goto error;
433 break;
435 #elif defined(IP_RECVDSTADDR)
436 case IP_RECVDSTADDR:
438 const struct in_addr *addr_unix = (struct in_addr *)CMSG_DATA(cmsg_unix);
439 struct WS_in_pktinfo data_win;
441 memcpy( &data_win.ipi_addr, &addr_unix->s_addr, 4 ); /* 4 bytes = 32 address bits */
442 data_win.ipi_ifindex = 0; /* FIXME */
443 ptr = fill_control_message( WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize,
444 (void *)&data_win, sizeof(data_win) );
445 if (!ptr) goto error;
446 break;
448 #endif /* IP_PKTINFO */
449 default:
450 FIXME("Unhandled IPPROTO_IP message header type %d\n", cmsg_unix->cmsg_type);
451 break;
453 break;
455 default:
456 FIXME("Unhandled message header level %d\n", cmsg_unix->cmsg_level);
457 break;
461 control->len = (char *)ptr - (char *)cmsg_win;
462 return 1;
464 error:
465 control->len = 0;
466 return 0;
467 #else /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
468 control->len = 0;
469 return 1;
470 #endif /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
472 #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */
474 static NTSTATUS try_recv( int fd, struct async_recv_ioctl *async, ULONG_PTR *size )
476 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
477 char control_buffer[512];
478 #endif
479 union unix_sockaddr unix_addr;
480 struct msghdr hdr;
481 NTSTATUS status;
482 ssize_t ret;
484 memset( &hdr, 0, sizeof(hdr) );
485 if (async->addr)
487 hdr.msg_name = &unix_addr.addr;
488 hdr.msg_namelen = sizeof(unix_addr);
490 hdr.msg_iov = async->iov;
491 hdr.msg_iovlen = async->count;
492 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
493 hdr.msg_control = control_buffer;
494 hdr.msg_controllen = sizeof(control_buffer);
495 #endif
496 while ((ret = virtual_locked_recvmsg( fd, &hdr, async->unix_flags )) < 0 && errno == EINTR);
498 if (ret < 0)
500 /* Unix-like systems return EINVAL when attempting to read OOB data from
501 * an empty socket buffer; Windows returns WSAEWOULDBLOCK. */
502 if ((async->unix_flags & MSG_OOB) && errno == EINVAL)
503 errno = EWOULDBLOCK;
505 if (errno != EWOULDBLOCK) WARN( "recvmsg: %s\n", strerror( errno ) );
506 return sock_errno_to_status( errno );
509 status = (hdr.msg_flags & MSG_TRUNC) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
511 #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
512 if (async->control)
514 ERR( "Message control headers cannot be properly supported on this system.\n" );
515 async->control->len = 0;
517 #else
518 if (async->control && !convert_control_headers( &hdr, async->control ))
520 WARN( "Application passed insufficient room for control headers.\n" );
521 *async->ret_flags |= WS_MSG_CTRUNC;
522 status = STATUS_BUFFER_OVERFLOW;
524 #endif
526 /* If this socket is connected, Linux doesn't give us msg_name and
527 * msg_namelen from recvmsg, but it does set msg_namelen to zero.
529 * MSDN says that the address is ignored for connection-oriented sockets, so
530 * don't try to translate it.
532 if (async->addr && hdr.msg_namelen)
533 *async->addr_len = sockaddr_from_unix( &unix_addr, async->addr, *async->addr_len );
535 *size = ret;
536 return status;
539 static NTSTATUS async_recv_proc( void *user, ULONG_PTR *info, NTSTATUS status )
541 struct async_recv_ioctl *async = user;
542 ULONG_PTR information = 0;
543 int fd, needs_close;
545 TRACE( "%#x\n", status );
547 if (status == STATUS_ALERTED)
549 if ((status = server_get_unix_fd( async->io.handle, 0, &fd, &needs_close, NULL, NULL )))
550 return status;
552 status = try_recv( fd, async, &information );
553 TRACE( "got status %#x, %#lx bytes read\n", status, information );
555 if (status == STATUS_DEVICE_NOT_READY)
556 status = STATUS_PENDING;
558 if (needs_close) close( fd );
560 if (status != STATUS_PENDING)
562 *info = information;
563 release_fileio( &async->io );
565 return status;
568 static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io,
569 int fd, const WSABUF *buffers, unsigned int count, WSABUF *control,
570 struct WS_sockaddr *addr, int *addr_len, DWORD *ret_flags, int unix_flags, int force_async )
572 struct async_recv_ioctl *async;
573 ULONG_PTR information;
574 HANDLE wait_handle;
575 DWORD async_size;
576 NTSTATUS status;
577 unsigned int i;
578 ULONG options;
580 if (unix_flags & MSG_OOB)
582 int oobinline;
583 socklen_t len = sizeof(oobinline);
584 if (!getsockopt( fd, SOL_SOCKET, SO_OOBINLINE, (char *)&oobinline, &len ) && oobinline)
585 return STATUS_INVALID_PARAMETER;
588 for (i = 0; i < count; ++i)
590 if (!virtual_check_buffer_for_write( buffers[i].buf, buffers[i].len ))
591 return STATUS_ACCESS_VIOLATION;
594 async_size = offsetof( struct async_recv_ioctl, iov[count] );
596 if (!(async = (struct async_recv_ioctl *)alloc_fileio( async_size, async_recv_proc, handle )))
597 return STATUS_NO_MEMORY;
599 async->count = count;
600 for (i = 0; i < count; ++i)
602 async->iov[i].iov_base = buffers[i].buf;
603 async->iov[i].iov_len = buffers[i].len;
605 async->unix_flags = unix_flags;
606 async->control = control;
607 async->addr = addr;
608 async->addr_len = addr_len;
609 async->ret_flags = ret_flags;
611 status = try_recv( fd, async, &information );
613 if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW && status != STATUS_DEVICE_NOT_READY)
615 release_fileio( &async->io );
616 return status;
619 if (status == STATUS_DEVICE_NOT_READY && force_async)
620 status = STATUS_PENDING;
622 SERVER_START_REQ( recv_socket )
624 req->status = status;
625 req->total = information;
626 req->async = server_async( handle, &async->io, event, apc, apc_user, io );
627 req->oob = !!(unix_flags & MSG_OOB);
628 status = wine_server_call( req );
629 wait_handle = wine_server_ptr_handle( reply->wait );
630 options = reply->options;
631 if ((!NT_ERROR(status) || wait_handle) && status != STATUS_PENDING)
633 io->Status = status;
634 io->Information = information;
637 SERVER_END_REQ;
639 if (status != STATUS_PENDING) release_fileio( &async->io );
641 if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
642 return status;
646 struct async_poll_ioctl
648 struct async_fileio io;
649 unsigned int count;
650 struct afd_poll_params *input, *output;
651 struct poll_socket_output sockets[1];
654 static ULONG_PTR fill_poll_output( struct async_poll_ioctl *async, NTSTATUS status )
656 struct afd_poll_params *input = async->input, *output = async->output;
657 unsigned int i, count = 0;
659 memcpy( output, input, offsetof( struct afd_poll_params, sockets[0] ) );
661 if (!status)
663 for (i = 0; i < async->count; ++i)
665 if (async->sockets[i].flags)
667 output->sockets[count].socket = input->sockets[i].socket;
668 output->sockets[count].flags = async->sockets[i].flags;
669 output->sockets[count].status = async->sockets[i].status;
670 ++count;
674 output->count = count;
675 return offsetof( struct afd_poll_params, sockets[count] );
678 static NTSTATUS async_poll_proc( void *user, ULONG_PTR *info, NTSTATUS status )
680 struct async_poll_ioctl *async = user;
681 ULONG_PTR information = 0;
683 if (status == STATUS_ALERTED)
685 SERVER_START_REQ( get_async_result )
687 req->user_arg = wine_server_client_ptr( async );
688 wine_server_set_reply( req, async->sockets, async->count * sizeof(async->sockets[0]) );
689 status = wine_server_call( req );
691 SERVER_END_REQ;
693 information = fill_poll_output( async, status );
696 if (status != STATUS_PENDING)
698 *info = information;
699 free( async->input );
700 release_fileio( &async->io );
702 return status;
706 /* we could handle this ioctl entirely on the server side, but the differing
707 * structure size makes it painful */
708 static NTSTATUS sock_poll( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io,
709 void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size )
711 const struct afd_poll_params *params = in_buffer;
712 struct poll_socket_input *input;
713 struct async_poll_ioctl *async;
714 HANDLE wait_handle;
715 DWORD async_size;
716 NTSTATUS status;
717 unsigned int i;
718 ULONG options;
720 if (in_size < sizeof(*params) || out_size < in_size || !params->count
721 || in_size < offsetof( struct afd_poll_params, sockets[params->count] ))
722 return STATUS_INVALID_PARAMETER;
724 TRACE( "timeout %s, count %u, unknown %#x, padding (%#x, %#x, %#x), sockets[0] {%04lx, %#x}\n",
725 wine_dbgstr_longlong(params->timeout), params->count, params->unknown,
726 params->padding[0], params->padding[1], params->padding[2],
727 params->sockets[0].socket, params->sockets[0].flags );
729 if (params->unknown) FIXME( "unknown boolean is %#x\n", params->unknown );
730 if (params->padding[0]) FIXME( "padding[0] is %#x\n", params->padding[0] );
731 if (params->padding[1]) FIXME( "padding[1] is %#x\n", params->padding[1] );
732 if (params->padding[2]) FIXME( "padding[2] is %#x\n", params->padding[2] );
733 for (i = 0; i < params->count; ++i)
735 if (params->sockets[i].flags & ~0x1ff)
736 FIXME( "unknown socket flags %#x\n", params->sockets[i].flags );
739 if (!(input = malloc( params->count * sizeof(*input) )))
740 return STATUS_NO_MEMORY;
742 async_size = offsetof( struct async_poll_ioctl, sockets[params->count] );
744 if (!(async = (struct async_poll_ioctl *)alloc_fileio( async_size, async_poll_proc, handle )))
746 free( input );
747 return STATUS_NO_MEMORY;
750 if (!(async->input = malloc( in_size )))
752 release_fileio( &async->io );
753 free( input );
754 return STATUS_NO_MEMORY;
756 memcpy( async->input, in_buffer, in_size );
758 async->count = params->count;
759 async->output = out_buffer;
761 for (i = 0; i < params->count; ++i)
763 input[i].socket = params->sockets[i].socket;
764 input[i].flags = params->sockets[i].flags;
767 SERVER_START_REQ( poll_socket )
769 req->async = server_async( handle, &async->io, event, apc, apc_user, io );
770 req->timeout = params->timeout;
771 wine_server_add_data( req, input, params->count * sizeof(*input) );
772 wine_server_set_reply( req, async->sockets, params->count * sizeof(async->sockets[0]) );
773 status = wine_server_call( req );
774 wait_handle = wine_server_ptr_handle( reply->wait );
775 options = reply->options;
776 if (wait_handle && status != STATUS_PENDING)
778 io->Status = status;
779 io->Information = fill_poll_output( async, status );
782 SERVER_END_REQ;
784 free( input );
786 if (status != STATUS_PENDING)
788 free( async->input );
789 release_fileio( &async->io );
792 if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT) );
793 return status;
796 static NTSTATUS try_send( int fd, struct async_send_ioctl *async )
798 union unix_sockaddr unix_addr;
799 struct msghdr hdr;
800 ssize_t ret;
802 memset( &hdr, 0, sizeof(hdr) );
803 if (async->addr)
805 hdr.msg_name = &unix_addr;
806 hdr.msg_namelen = sockaddr_to_unix( async->addr, async->addr_len, &unix_addr );
807 if (!hdr.msg_namelen)
809 ERR( "failed to convert address\n" );
810 return STATUS_ACCESS_VIOLATION;
813 #if defined(HAS_IPX) && defined(SOL_IPX)
814 if (async->addr->sa_family == WS_AF_IPX)
816 int type;
817 socklen_t len = sizeof(type);
819 /* The packet type is stored at the IPX socket level. At least the
820 * linux kernel seems to do something with it in case hdr.msg_name
821 * is NULL. Nonetheless we can use it to store the packet type, and
822 * then we can retrieve it using getsockopt. After that we can set
823 * the IPX type in the sockaddr_ipx structure with the stored value.
825 if (getsockopt(fd, SOL_IPX, IPX_TYPE, &type, &len) >= 0)
826 unix_addr.ipx.sipx_type = type;
828 #endif
831 hdr.msg_iov = async->iov + async->iov_cursor;
832 hdr.msg_iovlen = async->count - async->iov_cursor;
834 while ((ret = sendmsg( fd, &hdr, async->unix_flags )) == -1)
836 if (errno == EISCONN)
838 hdr.msg_name = NULL;
839 hdr.msg_namelen = 0;
841 else if (errno != EINTR)
843 if (errno != EWOULDBLOCK) WARN( "sendmsg: %s\n", strerror( errno ) );
844 return sock_errno_to_status( errno );
848 async->sent_len += ret;
850 while (async->iov_cursor < async->count && ret >= async->iov[async->iov_cursor].iov_len)
851 ret -= async->iov[async->iov_cursor++].iov_len;
852 if (async->iov_cursor < async->count)
854 async->iov[async->iov_cursor].iov_base = (char *)async->iov[async->iov_cursor].iov_base + ret;
855 async->iov[async->iov_cursor].iov_len -= ret;
856 return STATUS_DEVICE_NOT_READY;
858 return STATUS_SUCCESS;
861 static NTSTATUS async_send_proc( void *user, ULONG_PTR *info, NTSTATUS status )
863 struct async_send_ioctl *async = user;
864 int fd, needs_close;
866 TRACE( "%#x\n", status );
868 if (status == STATUS_ALERTED)
870 if ((status = server_get_unix_fd( async->io.handle, 0, &fd, &needs_close, NULL, NULL )))
871 return status;
873 status = try_send( fd, async );
874 TRACE( "got status %#x\n", status );
876 if (status == STATUS_DEVICE_NOT_READY)
877 status = STATUS_PENDING;
879 if (needs_close) close( fd );
881 if (status != STATUS_PENDING)
883 *info = async->sent_len;
884 release_fileio( &async->io );
886 return status;
889 static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
890 IO_STATUS_BLOCK *io, int fd, const WSABUF *buffers, unsigned int count,
891 const struct WS_sockaddr *addr, unsigned int addr_len, int unix_flags, int force_async )
893 struct async_send_ioctl *async;
894 HANDLE wait_handle;
895 DWORD async_size;
896 NTSTATUS status;
897 unsigned int i;
898 ULONG options;
900 async_size = offsetof( struct async_send_ioctl, iov[count] );
902 if (!(async = (struct async_send_ioctl *)alloc_fileio( async_size, async_send_proc, handle )))
903 return STATUS_NO_MEMORY;
905 async->count = count;
906 for (i = 0; i < count; ++i)
908 async->iov[i].iov_base = buffers[i].buf;
909 async->iov[i].iov_len = buffers[i].len;
911 async->unix_flags = unix_flags;
912 async->addr = addr;
913 async->addr_len = addr_len;
914 async->iov_cursor = 0;
915 async->sent_len = 0;
917 status = try_send( fd, async );
919 if (status != STATUS_SUCCESS && status != STATUS_DEVICE_NOT_READY)
921 release_fileio( &async->io );
922 return status;
925 if (status == STATUS_DEVICE_NOT_READY && force_async)
926 status = STATUS_PENDING;
928 SERVER_START_REQ( send_socket )
930 req->status = status;
931 req->total = async->sent_len;
932 req->async = server_async( handle, &async->io, event, apc, apc_user, io );
933 status = wine_server_call( req );
934 wait_handle = wine_server_ptr_handle( reply->wait );
935 options = reply->options;
936 if ((!NT_ERROR(status) || wait_handle) && status != STATUS_PENDING)
938 io->Status = status;
939 io->Information = async->sent_len;
942 SERVER_END_REQ;
944 if (status != STATUS_PENDING) release_fileio( &async->io );
946 if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
947 return status;
950 static ssize_t do_send( int fd, const void *buffer, size_t len, int flags )
952 ssize_t ret;
953 while ((ret = send( fd, buffer, len, flags )) < 0 && errno == EINTR);
954 if (ret < 0 && errno != EWOULDBLOCK) WARN( "send: %s\n", strerror( errno ) );
955 return ret;
958 static NTSTATUS try_transmit( int sock_fd, int file_fd, struct async_transmit_ioctl *async )
960 ssize_t ret;
962 while (async->head_cursor < async->buffers.HeadLength)
964 TRACE( "sending %u bytes of header data\n", async->buffers.HeadLength - async->head_cursor );
965 ret = do_send( sock_fd, (char *)async->buffers.Head + async->head_cursor,
966 async->buffers.HeadLength - async->head_cursor, 0 );
967 if (ret < 0) return sock_errno_to_status( errno );
968 TRACE( "send returned %zd\n", ret );
969 async->head_cursor += ret;
972 while (async->buffer_cursor < async->read_len)
974 TRACE( "sending %u bytes of file data\n", async->read_len - async->buffer_cursor );
975 ret = do_send( sock_fd, async->buffer + async->buffer_cursor,
976 async->read_len - async->buffer_cursor, 0 );
977 if (ret < 0) return sock_errno_to_status( errno );
978 TRACE( "send returned %zd\n", ret );
979 async->buffer_cursor += ret;
980 async->file_cursor += ret;
983 if (async->file && async->buffer_cursor == async->read_len)
985 unsigned int read_size = async->buffer_size;
987 if (async->file_len)
988 read_size = min( read_size, async->file_len - async->file_cursor );
990 TRACE( "reading %u bytes of file data\n", read_size );
993 if (async->offset.QuadPart == FILE_USE_FILE_POINTER_POSITION)
994 ret = read( file_fd, async->buffer, read_size );
995 else
996 ret = pread( file_fd, async->buffer, read_size, async->offset.QuadPart );
997 } while (ret < 0 && errno == EINTR);
998 if (ret < 0) return errno_to_status( errno );
999 TRACE( "read returned %zd\n", ret );
1001 async->read_len = ret;
1002 async->buffer_cursor = 0;
1003 if (async->offset.QuadPart != FILE_USE_FILE_POINTER_POSITION)
1004 async->offset.QuadPart += ret;
1006 if (ret < read_size || (async->file_len && async->file_cursor == async->file_len))
1007 async->file = NULL;
1008 return STATUS_PENDING; /* still more data to send */
1011 while (async->tail_cursor < async->buffers.TailLength)
1013 TRACE( "sending %u bytes of tail data\n", async->buffers.TailLength - async->tail_cursor );
1014 ret = do_send( sock_fd, (char *)async->buffers.Tail + async->tail_cursor,
1015 async->buffers.TailLength - async->tail_cursor, 0 );
1016 if (ret < 0) return sock_errno_to_status( errno );
1017 TRACE( "send returned %zd\n", ret );
1018 async->tail_cursor += ret;
1021 return STATUS_SUCCESS;
1024 static NTSTATUS async_transmit_proc( void *user, ULONG_PTR *info, NTSTATUS status )
1026 int sock_fd, file_fd = -1, sock_needs_close = FALSE, file_needs_close = FALSE;
1027 struct async_transmit_ioctl *async = user;
1029 TRACE( "%#x\n", status );
1031 if (status == STATUS_ALERTED)
1033 if ((status = server_get_unix_fd( async->io.handle, 0, &sock_fd, &sock_needs_close, NULL, NULL )))
1034 return status;
1036 if (async->file && (status = server_get_unix_fd( async->file, 0, &file_fd, &file_needs_close, NULL, NULL )))
1038 if (sock_needs_close) close( sock_fd );
1039 return status;
1042 status = try_transmit( sock_fd, file_fd, async );
1043 TRACE( "got status %#x\n", status );
1045 if (status == STATUS_DEVICE_NOT_READY)
1046 status = STATUS_PENDING;
1048 if (sock_needs_close) close( sock_fd );
1049 if (file_needs_close) close( file_fd );
1051 if (status != STATUS_PENDING)
1053 *info = async->head_cursor + async->file_cursor + async->tail_cursor;
1054 release_fileio( &async->io );
1056 return status;
1059 static NTSTATUS sock_transmit( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1060 IO_STATUS_BLOCK *io, int fd, const struct afd_transmit_params *params )
1062 int file_fd, file_needs_close = FALSE;
1063 struct async_transmit_ioctl *async;
1064 enum server_fd_type file_type;
1065 union unix_sockaddr addr;
1066 socklen_t addr_len;
1067 HANDLE wait_handle;
1068 NTSTATUS status;
1069 ULONG options;
1071 addr_len = sizeof(addr);
1072 if (getpeername( fd, &addr.addr, &addr_len ) != 0)
1073 return STATUS_INVALID_CONNECTION;
1075 if (params->file)
1077 if ((status = server_get_unix_fd( params->file, 0, &file_fd, &file_needs_close, &file_type, NULL )))
1078 return status;
1079 if (file_needs_close) close( file_fd );
1081 if (file_type != FD_TYPE_FILE)
1083 FIXME( "unsupported file type %#x\n", file_type );
1084 return STATUS_NOT_IMPLEMENTED;
1088 if (!(async = (struct async_transmit_ioctl *)alloc_fileio( sizeof(*async), async_transmit_proc, handle )))
1089 return STATUS_NO_MEMORY;
1091 async->file = params->file;
1092 async->buffer_size = params->buffer_size ? params->buffer_size : 65536;
1093 if (!(async->buffer = malloc( async->buffer_size )))
1095 release_fileio( &async->io );
1096 return STATUS_NO_MEMORY;
1098 async->read_len = 0;
1099 async->head_cursor = 0;
1100 async->file_cursor = 0;
1101 async->buffer_cursor = 0;
1102 async->tail_cursor = 0;
1103 async->file_len = params->file_len;
1104 async->flags = params->flags;
1105 async->buffers = params->buffers;
1106 async->offset = params->offset;
1108 SERVER_START_REQ( send_socket )
1110 req->status = STATUS_PENDING;
1111 req->total = 0;
1112 req->async = server_async( handle, &async->io, event, apc, apc_user, io );
1113 status = wine_server_call( req );
1114 wait_handle = wine_server_ptr_handle( reply->wait );
1115 options = reply->options;
1116 /* In theory we'd fill the iosb here, as above in sock_send(), but it's
1117 * actually currently impossible to get STATUS_SUCCESS. The server will
1118 * either return STATUS_PENDING or an error code, and in neither case
1119 * should the iosb be filled. */
1121 SERVER_END_REQ;
1123 if (status != STATUS_PENDING) release_fileio( &async->io );
1125 if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
1126 return status;
1129 static void complete_async( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
1130 IO_STATUS_BLOCK *io, NTSTATUS status, ULONG_PTR information )
1132 io->Status = status;
1133 io->Information = information;
1134 if (event) NtSetEvent( event, NULL );
1135 if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc, (ULONG_PTR)apc_user, (ULONG_PTR)io, 0 );
1136 if (apc_user) add_completion( handle, (ULONG_PTR)apc_user, status, information, FALSE );
1140 static NTSTATUS do_getsockopt( HANDLE handle, IO_STATUS_BLOCK *io, int level,
1141 int option, void *out_buffer, ULONG out_size )
1143 int fd, needs_close = FALSE;
1144 socklen_t len = out_size;
1145 NTSTATUS status;
1146 int ret;
1148 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1149 return status;
1151 ret = getsockopt( fd, level, option, out_buffer, &len );
1152 if (needs_close) close( fd );
1153 if (ret) return sock_errno_to_status( errno );
1154 io->Information = len;
1155 return STATUS_SUCCESS;
1159 static NTSTATUS do_setsockopt( HANDLE handle, IO_STATUS_BLOCK *io, int level,
1160 int option, const void *optval, socklen_t optlen )
1162 int fd, needs_close = FALSE;
1163 NTSTATUS status;
1164 int ret;
1166 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1167 return status;
1169 ret = setsockopt( fd, level, option, optval, optlen );
1170 if (needs_close) close( fd );
1171 return ret ? sock_errno_to_status( errno ) : STATUS_SUCCESS;
1175 NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io,
1176 ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size )
1178 int fd, needs_close = FALSE;
1179 NTSTATUS status;
1181 TRACE( "handle %p, code %#x, in_buffer %p, in_size %u, out_buffer %p, out_size %u\n",
1182 handle, code, in_buffer, in_size, out_buffer, out_size );
1184 switch (code)
1186 case IOCTL_AFD_BIND:
1188 const struct afd_bind_params *params = in_buffer;
1190 if (params->unknown) FIXME( "bind: got unknown %#x\n", params->unknown );
1192 status = STATUS_BAD_DEVICE_TYPE;
1193 break;
1196 case IOCTL_AFD_GETSOCKNAME:
1197 if (in_size) FIXME( "unexpected input size %u\n", in_size );
1199 status = STATUS_BAD_DEVICE_TYPE;
1200 break;
1202 case IOCTL_AFD_LISTEN:
1204 const struct afd_listen_params *params = in_buffer;
1206 TRACE( "backlog %u\n", params->backlog );
1207 if (out_size) FIXME( "unexpected output size %u\n", out_size );
1208 if (params->unknown1) FIXME( "listen: got unknown1 %#x\n", params->unknown1 );
1209 if (params->unknown2) FIXME( "listen: got unknown2 %#x\n", params->unknown2 );
1211 status = STATUS_BAD_DEVICE_TYPE;
1212 break;
1215 case IOCTL_AFD_EVENT_SELECT:
1217 const struct afd_event_select_params *params = in_buffer;
1219 TRACE( "event %p, mask %#x\n", params->event, params->mask );
1220 if (out_size) FIXME( "unexpected output size %u\n", out_size );
1222 status = STATUS_BAD_DEVICE_TYPE;
1223 break;
1226 case IOCTL_AFD_GET_EVENTS:
1227 if (in_size) FIXME( "unexpected input size %u\n", in_size );
1229 status = STATUS_BAD_DEVICE_TYPE;
1230 break;
1232 case IOCTL_AFD_RECV:
1234 const struct afd_recv_params *params = in_buffer;
1235 int unix_flags = 0;
1237 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1238 return status;
1240 if (out_size) FIXME( "unexpected output size %u\n", out_size );
1242 if (in_size < sizeof(struct afd_recv_params))
1244 status = STATUS_INVALID_PARAMETER;
1245 break;
1248 if ((params->msg_flags & (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) == 0 ||
1249 (params->msg_flags & (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) == (AFD_MSG_NOT_OOB | AFD_MSG_OOB))
1251 status = STATUS_INVALID_PARAMETER;
1252 break;
1255 if (params->msg_flags & ~(AFD_MSG_NOT_OOB | AFD_MSG_OOB | AFD_MSG_PEEK | AFD_MSG_WAITALL))
1256 FIXME( "unknown msg_flags %#x\n", params->msg_flags );
1257 if (params->recv_flags & ~AFD_RECV_FORCE_ASYNC)
1258 FIXME( "unknown recv_flags %#x\n", params->recv_flags );
1260 if (params->msg_flags & AFD_MSG_OOB)
1261 unix_flags |= MSG_OOB;
1262 if (params->msg_flags & AFD_MSG_PEEK)
1263 unix_flags |= MSG_PEEK;
1264 if (params->msg_flags & AFD_MSG_WAITALL)
1265 FIXME( "MSG_WAITALL is not supported\n" );
1267 status = sock_recv( handle, event, apc, apc_user, io, fd, params->buffers, params->count, NULL,
1268 NULL, NULL, NULL, unix_flags, !!(params->recv_flags & AFD_RECV_FORCE_ASYNC) );
1269 break;
1272 case IOCTL_AFD_WINE_RECVMSG:
1274 struct afd_recvmsg_params *params = in_buffer;
1275 int unix_flags = 0;
1277 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1278 return status;
1280 if (in_size < sizeof(*params))
1282 status = STATUS_BUFFER_TOO_SMALL;
1283 break;
1286 if (*params->ws_flags & WS_MSG_OOB)
1287 unix_flags |= MSG_OOB;
1288 if (*params->ws_flags & WS_MSG_PEEK)
1289 unix_flags |= MSG_PEEK;
1290 if (*params->ws_flags & WS_MSG_WAITALL)
1291 FIXME( "MSG_WAITALL is not supported\n" );
1293 status = sock_recv( handle, event, apc, apc_user, io, fd, params->buffers, params->count, params->control,
1294 params->addr, params->addr_len, params->ws_flags, unix_flags, params->force_async );
1295 break;
1298 case IOCTL_AFD_WINE_SENDMSG:
1300 const struct afd_sendmsg_params *params = in_buffer;
1301 int unix_flags = 0;
1303 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1304 return status;
1306 if (in_size < sizeof(*params))
1308 status = STATUS_BUFFER_TOO_SMALL;
1309 break;
1312 if (params->ws_flags & WS_MSG_OOB)
1313 unix_flags |= MSG_OOB;
1314 if (params->ws_flags & WS_MSG_PARTIAL)
1315 WARN( "ignoring MSG_PARTIAL\n" );
1316 if (params->ws_flags & ~(WS_MSG_OOB | WS_MSG_PARTIAL))
1317 FIXME( "unknown flags %#x\n", params->ws_flags );
1319 status = sock_send( handle, event, apc, apc_user, io, fd, params->buffers, params->count,
1320 params->addr, params->addr_len, unix_flags, params->force_async );
1321 break;
1324 case IOCTL_AFD_WINE_TRANSMIT:
1326 const struct afd_transmit_params *params = in_buffer;
1328 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1329 return status;
1331 if (in_size < sizeof(*params))
1333 status = STATUS_BUFFER_TOO_SMALL;
1334 break;
1337 status = sock_transmit( handle, event, apc, apc_user, io, fd, params );
1338 break;
1341 case IOCTL_AFD_WINE_COMPLETE_ASYNC:
1343 if (in_size != sizeof(NTSTATUS))
1344 return STATUS_BUFFER_TOO_SMALL;
1346 status = *(NTSTATUS *)in_buffer;
1347 complete_async( handle, event, apc, apc_user, io, status, 0 );
1348 break;
1351 case IOCTL_AFD_POLL:
1352 status = sock_poll( handle, event, apc, apc_user, io, in_buffer, in_size, out_buffer, out_size );
1353 break;
1355 case IOCTL_AFD_WINE_FIONREAD:
1357 int value, ret;
1359 if (out_size < sizeof(int))
1361 status = STATUS_BUFFER_TOO_SMALL;
1362 break;
1365 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1366 return status;
1368 #ifdef linux
1370 socklen_t len = sizeof(value);
1372 /* FIONREAD on a listening socket always fails (see tcp(7)). */
1373 if (!getsockopt( fd, SOL_SOCKET, SO_ACCEPTCONN, &value, &len ) && value)
1375 *(int *)out_buffer = 0;
1376 status = STATUS_SUCCESS;
1377 complete_async( handle, event, apc, apc_user, io, status, 0 );
1378 break;
1381 #endif
1383 if ((ret = ioctl( fd, FIONREAD, &value )) < 0)
1385 status = sock_errno_to_status( errno );
1386 break;
1388 *(int *)out_buffer = value;
1389 status = STATUS_SUCCESS;
1390 complete_async( handle, event, apc, apc_user, io, status, 0 );
1391 break;
1394 case IOCTL_AFD_WINE_SIOCATMARK:
1396 int value, ret;
1397 socklen_t len = sizeof(value);
1399 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1400 return status;
1402 if (out_size < sizeof(int))
1404 status = STATUS_BUFFER_TOO_SMALL;
1405 break;
1408 if (getsockopt( fd, SOL_SOCKET, SO_OOBINLINE, &value, &len ) < 0)
1410 status = sock_errno_to_status( errno );
1411 break;
1414 if (value)
1416 *(int *)out_buffer = TRUE;
1418 else
1420 if ((ret = ioctl( fd, SIOCATMARK, &value )) < 0)
1422 status = sock_errno_to_status( errno );
1423 break;
1425 /* windows is reversed with respect to unix */
1426 *(int *)out_buffer = !value;
1428 status = STATUS_SUCCESS;
1429 complete_async( handle, event, apc, apc_user, io, status, 0 );
1430 break;
1433 case IOCTL_AFD_WINE_GET_INTERFACE_LIST:
1435 #ifdef HAVE_GETIFADDRS
1436 INTERFACE_INFO *info = out_buffer;
1437 struct ifaddrs *ifaddrs, *ifaddr;
1438 unsigned int count = 0;
1439 ULONG ret_size;
1441 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1442 return status;
1444 if (getifaddrs( &ifaddrs ) < 0)
1446 status = sock_errno_to_status( errno );
1447 break;
1450 for (ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next)
1452 if (ifaddr->ifa_addr && ifaddr->ifa_addr->sa_family == AF_INET) ++count;
1455 ret_size = count * sizeof(*info);
1456 if (out_size < ret_size)
1458 status = STATUS_PENDING;
1459 complete_async( handle, event, apc, apc_user, io, STATUS_BUFFER_TOO_SMALL, 0 );
1460 freeifaddrs( ifaddrs );
1461 break;
1464 memset( out_buffer, 0, ret_size );
1466 count = 0;
1467 for (ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next)
1469 in_addr_t addr, mask;
1471 if (!ifaddr->ifa_addr || ifaddr->ifa_addr->sa_family != AF_INET)
1472 continue;
1474 addr = ((const struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr;
1475 mask = ((const struct sockaddr_in *)ifaddr->ifa_netmask)->sin_addr.s_addr;
1477 info[count].iiFlags = 0;
1478 if (ifaddr->ifa_flags & IFF_BROADCAST)
1479 info[count].iiFlags |= WS_IFF_BROADCAST;
1480 if (ifaddr->ifa_flags & IFF_LOOPBACK)
1481 info[count].iiFlags |= WS_IFF_LOOPBACK;
1482 if (ifaddr->ifa_flags & IFF_MULTICAST)
1483 info[count].iiFlags |= WS_IFF_MULTICAST;
1484 #ifdef IFF_POINTTOPOINT
1485 if (ifaddr->ifa_flags & IFF_POINTTOPOINT)
1486 info[count].iiFlags |= WS_IFF_POINTTOPOINT;
1487 #endif
1488 if (ifaddr->ifa_flags & IFF_UP)
1489 info[count].iiFlags |= WS_IFF_UP;
1491 info[count].iiAddress.AddressIn.sin_family = WS_AF_INET;
1492 info[count].iiAddress.AddressIn.sin_port = 0;
1493 info[count].iiAddress.AddressIn.sin_addr.WS_s_addr = addr;
1495 info[count].iiNetmask.AddressIn.sin_family = WS_AF_INET;
1496 info[count].iiNetmask.AddressIn.sin_port = 0;
1497 info[count].iiNetmask.AddressIn.sin_addr.WS_s_addr = mask;
1499 if (ifaddr->ifa_flags & IFF_BROADCAST)
1501 info[count].iiBroadcastAddress.AddressIn.sin_family = WS_AF_INET;
1502 info[count].iiBroadcastAddress.AddressIn.sin_port = 0;
1503 info[count].iiBroadcastAddress.AddressIn.sin_addr.WS_s_addr = addr | ~mask;
1506 ++count;
1509 freeifaddrs( ifaddrs );
1510 status = STATUS_PENDING;
1511 complete_async( handle, event, apc, apc_user, io, STATUS_SUCCESS, ret_size );
1512 #else
1513 FIXME( "Interface list queries are currently not supported on this platform.\n" );
1514 status = STATUS_NOT_SUPPORTED;
1515 #endif
1516 break;
1519 case IOCTL_AFD_WINE_KEEPALIVE_VALS:
1521 struct tcp_keepalive *k = in_buffer;
1522 int keepalive;
1524 if (!in_buffer || in_size < sizeof(struct tcp_keepalive))
1525 return STATUS_BUFFER_TOO_SMALL;
1526 keepalive = !!k->onoff;
1528 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1529 return status;
1531 if (setsockopt( fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(int) ) < 0)
1533 status = STATUS_INVALID_PARAMETER;
1534 break;
1537 if (keepalive)
1539 #ifdef TCP_KEEPIDLE
1540 int idle = max( 1, (k->keepalivetime + 500) / 1000 );
1542 if (setsockopt( fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(int) ) < 0)
1544 status = STATUS_INVALID_PARAMETER;
1545 break;
1547 #else
1548 FIXME("ignoring keepalive timeout\n");
1549 #endif
1552 if (keepalive)
1554 #ifdef TCP_KEEPINTVL
1555 int interval = max( 1, (k->keepaliveinterval + 500) / 1000 );
1557 if (setsockopt( fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(int) ) < 0)
1558 status = STATUS_INVALID_PARAMETER;
1559 #else
1560 FIXME("ignoring keepalive interval\n");
1561 #endif
1564 status = STATUS_SUCCESS;
1565 complete_async( handle, event, apc, apc_user, io, status, 0 );
1566 break;
1569 case IOCTL_AFD_WINE_GETPEERNAME:
1571 union unix_sockaddr unix_addr;
1572 socklen_t unix_len = sizeof(unix_addr);
1573 int len;
1575 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1576 return status;
1578 if (getpeername( fd, &unix_addr.addr, &unix_len ) < 0)
1580 status = sock_errno_to_status( errno );
1581 break;
1584 len = sockaddr_from_unix( &unix_addr, out_buffer, out_size );
1585 if (out_size < len)
1587 status = STATUS_BUFFER_TOO_SMALL;
1588 break;
1590 io->Information = len;
1591 status = STATUS_SUCCESS;
1592 break;
1595 case IOCTL_AFD_WINE_GET_SO_BROADCAST:
1596 return do_getsockopt( handle, io, SOL_SOCKET, SO_BROADCAST, out_buffer, out_size );
1598 case IOCTL_AFD_WINE_SET_SO_BROADCAST:
1599 return do_setsockopt( handle, io, SOL_SOCKET, SO_BROADCAST, in_buffer, in_size );
1601 case IOCTL_AFD_WINE_GET_SO_KEEPALIVE:
1602 return do_getsockopt( handle, io, SOL_SOCKET, SO_KEEPALIVE, out_buffer, out_size );
1604 case IOCTL_AFD_WINE_SET_SO_KEEPALIVE:
1605 return do_setsockopt( handle, io, SOL_SOCKET, SO_KEEPALIVE, in_buffer, in_size );
1607 case IOCTL_AFD_WINE_GET_SO_LINGER:
1609 struct WS_linger *ws_linger = out_buffer;
1610 struct linger unix_linger;
1611 socklen_t len = sizeof(unix_linger);
1612 int ret;
1614 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1615 return status;
1617 ret = getsockopt( fd, SOL_SOCKET, SO_LINGER, &unix_linger, &len );
1618 if (needs_close) close( fd );
1619 if (!ret)
1621 ws_linger->l_onoff = unix_linger.l_onoff;
1622 ws_linger->l_linger = unix_linger.l_linger;
1623 io->Information = sizeof(*ws_linger);
1626 return ret ? sock_errno_to_status( errno ) : STATUS_SUCCESS;
1629 case IOCTL_AFD_WINE_SET_SO_LINGER:
1631 const struct WS_linger *ws_linger = in_buffer;
1632 struct linger unix_linger;
1634 unix_linger.l_onoff = ws_linger->l_onoff;
1635 unix_linger.l_linger = ws_linger->l_linger;
1637 return do_setsockopt( handle, io, SOL_SOCKET, SO_LINGER, &unix_linger, sizeof(unix_linger) );
1640 case IOCTL_AFD_WINE_GET_SO_OOBINLINE:
1641 return do_getsockopt( handle, io, SOL_SOCKET, SO_OOBINLINE, out_buffer, out_size );
1643 case IOCTL_AFD_WINE_SET_SO_OOBINLINE:
1644 return do_setsockopt( handle, io, SOL_SOCKET, SO_OOBINLINE, in_buffer, in_size );
1646 case IOCTL_AFD_WINE_GET_SO_REUSEADDR:
1647 return do_getsockopt( handle, io, SOL_SOCKET, SO_REUSEADDR, out_buffer, out_size );
1649 /* BSD socket SO_REUSEADDR is not 100% compatible to winsock semantics;
1650 * however, using it the BSD way fixes bug 8513 and seems to be what
1651 * most programmers assume, anyway */
1652 case IOCTL_AFD_WINE_SET_SO_REUSEADDR:
1654 int fd, needs_close = FALSE;
1655 NTSTATUS status;
1656 int ret;
1658 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1659 return status;
1661 ret = setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, in_buffer, in_size );
1662 #ifdef __APPLE__
1663 if (!ret) ret = setsockopt( fd, SOL_SOCKET, SO_REUSEPORT, in_buffer, in_size );
1664 #endif
1665 if (needs_close) close( fd );
1666 return ret ? sock_errno_to_status( errno ) : STATUS_SUCCESS;
1669 case IOCTL_AFD_WINE_SET_IP_ADD_MEMBERSHIP:
1670 return do_setsockopt( handle, io, IPPROTO_IP, IP_ADD_MEMBERSHIP, in_buffer, in_size );
1672 case IOCTL_AFD_WINE_SET_IP_ADD_SOURCE_MEMBERSHIP:
1673 return do_setsockopt( handle, io, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, in_buffer, in_size );
1675 case IOCTL_AFD_WINE_SET_IP_BLOCK_SOURCE:
1676 return do_setsockopt( handle, io, IPPROTO_IP, IP_BLOCK_SOURCE, in_buffer, in_size );
1678 case IOCTL_AFD_WINE_GET_IP_DONTFRAGMENT:
1680 socklen_t len = out_size;
1681 int ret;
1683 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1684 return status;
1686 #ifdef IP_DONTFRAG
1687 ret = getsockopt( fd, IPPROTO_IP, IP_DONTFRAG, out_buffer, &len );
1688 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1690 int value;
1692 len = sizeof(value);
1693 ret = getsockopt( fd, IPPROTO_IP, IP_MTU_DISCOVER, &value, &len );
1694 if (!ret) *(DWORD *)out_buffer = (value != IP_PMTUDISC_DONT);
1696 #else
1698 static int once;
1700 if (!once++)
1701 FIXME( "IP_DONTFRAGMENT is not supported on this platform\n" );
1702 ret = 0; /* fake success */
1704 #endif
1705 if (needs_close) close( fd );
1706 if (ret) return sock_errno_to_status( errno );
1707 io->Information = len;
1708 return STATUS_SUCCESS;
1711 case IOCTL_AFD_WINE_SET_IP_DONTFRAGMENT:
1712 #ifdef IP_DONTFRAG
1713 return do_setsockopt( handle, io, IPPROTO_IP, IP_DONTFRAG, in_buffer, in_size );
1714 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) && defined(IP_PMTUDISC_DONT)
1716 int value = *(DWORD *)in_buffer ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
1718 return do_setsockopt( handle, io, IPPROTO_IP, IP_MTU_DISCOVER, &value, sizeof(value) );
1720 #else
1722 static int once;
1724 if (!once++)
1725 FIXME( "IP_DONTFRAGMENT is not supported on this platform\n" );
1726 return STATUS_SUCCESS; /* fake success */
1728 #endif
1730 case IOCTL_AFD_WINE_SET_IP_DROP_MEMBERSHIP:
1731 return do_setsockopt( handle, io, IPPROTO_IP, IP_DROP_MEMBERSHIP, in_buffer, in_size );
1733 case IOCTL_AFD_WINE_SET_IP_DROP_SOURCE_MEMBERSHIP:
1734 return do_setsockopt( handle, io, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, in_buffer, in_size );
1736 #ifdef IP_HDRINCL
1737 case IOCTL_AFD_WINE_GET_IP_HDRINCL:
1738 return do_getsockopt( handle, io, IPPROTO_IP, IP_HDRINCL, out_buffer, out_size );
1740 case IOCTL_AFD_WINE_SET_IP_HDRINCL:
1741 return do_setsockopt( handle, io, IPPROTO_IP, IP_HDRINCL, in_buffer, in_size );
1742 #endif
1744 case IOCTL_AFD_WINE_GET_IP_MULTICAST_IF:
1745 return do_getsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_IF, out_buffer, out_size );
1747 case IOCTL_AFD_WINE_SET_IP_MULTICAST_IF:
1748 return do_setsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_IF, in_buffer, in_size );
1750 case IOCTL_AFD_WINE_GET_IP_MULTICAST_LOOP:
1751 return do_getsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_LOOP, out_buffer, out_size );
1753 case IOCTL_AFD_WINE_SET_IP_MULTICAST_LOOP:
1754 return do_setsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_LOOP, in_buffer, in_size );
1756 case IOCTL_AFD_WINE_GET_IP_MULTICAST_TTL:
1757 return do_getsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_TTL, out_buffer, out_size );
1759 case IOCTL_AFD_WINE_SET_IP_MULTICAST_TTL:
1760 return do_setsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_TTL, in_buffer, in_size );
1762 case IOCTL_AFD_WINE_GET_IP_OPTIONS:
1763 return do_getsockopt( handle, io, IPPROTO_IP, IP_OPTIONS, out_buffer, out_size );
1765 case IOCTL_AFD_WINE_SET_IP_OPTIONS:
1766 return do_setsockopt( handle, io, IPPROTO_IP, IP_OPTIONS, in_buffer, in_size );
1768 #ifdef IP_PKTINFO
1769 case IOCTL_AFD_WINE_GET_IP_PKTINFO:
1770 return do_getsockopt( handle, io, IPPROTO_IP, IP_PKTINFO, out_buffer, out_size );
1772 case IOCTL_AFD_WINE_SET_IP_PKTINFO:
1773 return do_setsockopt( handle, io, IPPROTO_IP, IP_PKTINFO, in_buffer, in_size );
1774 #elif defined(IP_RECVDSTADDR)
1775 case IOCTL_AFD_WINE_GET_IP_PKTINFO:
1776 return do_getsockopt( handle, io, IPPROTO_IP, IP_RECVDSTADDR, out_buffer, out_size );
1778 case IOCTL_AFD_WINE_SET_IP_PKTINFO:
1779 return do_setsockopt( handle, io, IPPROTO_IP, IP_RECVDSTADDR, in_buffer, in_size );
1780 #endif
1782 case IOCTL_AFD_WINE_GET_IP_TOS:
1783 return do_getsockopt( handle, io, IPPROTO_IP, IP_TOS, out_buffer, out_size );
1785 case IOCTL_AFD_WINE_SET_IP_TOS:
1786 return do_setsockopt( handle, io, IPPROTO_IP, IP_TOS, in_buffer, in_size );
1788 case IOCTL_AFD_WINE_GET_IP_TTL:
1789 return do_getsockopt( handle, io, IPPROTO_IP, IP_TTL, out_buffer, out_size );
1791 case IOCTL_AFD_WINE_SET_IP_TTL:
1792 return do_setsockopt( handle, io, IPPROTO_IP, IP_TTL, in_buffer, in_size );
1794 case IOCTL_AFD_WINE_SET_IP_UNBLOCK_SOURCE:
1795 return do_setsockopt( handle, io, IPPROTO_IP, IP_UNBLOCK_SOURCE, in_buffer, in_size );
1797 #ifdef IP_UNICAST_IF
1798 case IOCTL_AFD_WINE_GET_IP_UNICAST_IF:
1799 return do_getsockopt( handle, io, IPPROTO_IP, IP_UNICAST_IF, out_buffer, out_size );
1801 case IOCTL_AFD_WINE_SET_IP_UNICAST_IF:
1802 return do_setsockopt( handle, io, IPPROTO_IP, IP_UNICAST_IF, in_buffer, in_size );
1803 #endif
1805 #ifdef IPV6_ADD_MEMBERSHIP
1806 case IOCTL_AFD_WINE_SET_IPV6_ADD_MEMBERSHIP:
1807 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, in_buffer, in_size );
1808 #endif
1810 case IOCTL_AFD_WINE_GET_IPV6_DONTFRAG:
1812 socklen_t len = out_size;
1813 int ret;
1815 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1816 return status;
1818 #ifdef IPV6_DONTFRAG
1819 ret = getsockopt( fd, IPPROTO_IPV6, IPV6_DONTFRAG, out_buffer, &len );
1820 #elif defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT)
1822 int value;
1824 len = sizeof(value);
1825 ret = getsockopt( fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &value, &len );
1826 if (!ret) *(DWORD *)out_buffer = (value != IPV6_PMTUDISC_DONT);
1828 #else
1830 static int once;
1832 if (!once++)
1833 FIXME( "IPV6_DONTFRAGMENT is not supported on this platform\n" );
1834 ret = 0; /* fake success */
1836 #endif
1837 if (needs_close) close( fd );
1838 if (ret) return sock_errno_to_status( errno );
1839 io->Information = len;
1840 return STATUS_SUCCESS;
1843 case IOCTL_AFD_WINE_SET_IPV6_DONTFRAG:
1844 #ifdef IPV6_DONTFRAG
1845 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_DONTFRAG, in_buffer, in_size );
1846 #elif defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) && defined(IPV6_PMTUDISC_DONT)
1848 int value = *(DWORD *)in_buffer ? IPV6_PMTUDISC_DO : IPV6_PMTUDISC_DONT;
1850 return do_setsockopt( handle, io, IPPROTO_IP, IPV6_MTU_DISCOVER, &value, sizeof(value) );
1852 #else
1854 static int once;
1856 if (!once++)
1857 FIXME( "IPV6_DONTFRAGMENT is not supported on this platform\n" );
1858 return STATUS_SUCCESS; /* fake success */
1860 #endif
1862 #ifdef IPV6_DROP_MEMBERSHIP
1863 case IOCTL_AFD_WINE_SET_IPV6_DROP_MEMBERSHIP:
1864 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, in_buffer, in_size );
1865 #endif
1867 case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_HOPS:
1868 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, out_buffer, out_size );
1870 case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_HOPS:
1871 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, in_buffer, in_size );
1873 case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_IF:
1874 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_IF, out_buffer, out_size );
1876 case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_IF:
1877 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_IF, in_buffer, in_size );
1879 case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_LOOP:
1880 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, out_buffer, out_size );
1882 case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_LOOP:
1883 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, in_buffer, in_size );
1885 case IOCTL_AFD_WINE_GET_IPV6_UNICAST_HOPS:
1886 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_UNICAST_HOPS, out_buffer, out_size );
1888 case IOCTL_AFD_WINE_SET_IPV6_UNICAST_HOPS:
1889 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_UNICAST_HOPS, in_buffer, in_size );
1891 #ifdef IPV6_UNICAST_IF
1892 case IOCTL_AFD_WINE_GET_IPV6_UNICAST_IF:
1893 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_UNICAST_IF, out_buffer, out_size );
1895 case IOCTL_AFD_WINE_SET_IPV6_UNICAST_IF:
1896 return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_UNICAST_IF, in_buffer, in_size );
1897 #endif
1899 case IOCTL_AFD_WINE_GET_IPV6_V6ONLY:
1900 return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_V6ONLY, out_buffer, out_size );
1902 case IOCTL_AFD_WINE_SET_IPV6_V6ONLY:
1904 int fd, needs_close = FALSE;
1905 union unix_sockaddr addr;
1906 socklen_t len = sizeof(addr);
1907 NTSTATUS status;
1908 int ret;
1910 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1911 return status;
1913 if (!getsockname( fd, &addr.addr, &len ) && addr.addr.sa_family == AF_INET && !addr.in.sin_port)
1915 /* changing IPV6_V6ONLY succeeds on an unbound IPv4 socket */
1916 WARN( "ignoring IPV6_V6ONLY on an unbound IPv4 socket\n" );
1917 return STATUS_SUCCESS;
1920 ret = setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, in_buffer, in_size );
1921 if (needs_close) close( fd );
1922 return ret ? sock_errno_to_status( errno ) : STATUS_SUCCESS;
1925 #ifdef SOL_IPX
1926 case IOCTL_AFD_WINE_GET_IPX_PTYPE:
1927 return do_getsockopt( handle, io, SOL_IPX, IPX_TYPE, out_buffer, out_size );
1929 case IOCTL_AFD_WINE_SET_IPX_PTYPE:
1930 return do_setsockopt( handle, io, SOL_IPX, IPX_TYPE, in_buffer, in_size );
1931 #elif defined(SO_DEFAULT_HEADERS)
1932 case IOCTL_AFD_WINE_GET_IPX_PTYPE:
1934 int fd, needs_close = FALSE;
1935 struct ipx value;
1936 socklen_t len = sizeof(value);
1937 int ret;
1939 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1940 return status;
1942 ret = getsockopt( fd, 0, SO_DEFAULT_HEADERS, &value, &len );
1943 if (needs_close) close( fd );
1944 if (ret) return sock_errno_to_status( errno );
1945 *(DWORD *)out_buffer = value.ipx_pt;
1946 return STATUS_SUCCESS;
1949 case IOCTL_AFD_WINE_SET_IPX_PTYPE:
1951 struct ipx value = {0};
1953 /* FIXME: should we retrieve SO_DEFAULT_HEADERS first and modify it? */
1954 value.ipx_pt = *(DWORD *)in_buffer;
1955 return do_setsockopt( handle, io, 0, SO_DEFAULT_HEADERS, &value, sizeof(value) );
1957 #endif
1959 #ifdef HAS_IRDA
1960 #define MAX_IRDA_DEVICES 10
1961 case IOCTL_AFD_WINE_GET_IRLMP_ENUMDEVICES:
1963 char buffer[offsetof( struct irda_device_list, dev[MAX_IRDA_DEVICES] )];
1964 struct irda_device_list *unix_list = (struct irda_device_list *)buffer;
1965 socklen_t len = sizeof(buffer);
1966 DEVICELIST *ws_list = out_buffer;
1967 int fd, needs_close = FALSE;
1968 NTSTATUS status;
1969 unsigned int i;
1970 int ret;
1972 if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
1973 return status;
1975 ret = getsockopt( fd, SOL_IRLMP, IRLMP_ENUMDEVICES, buffer, &len );
1976 if (needs_close) close( fd );
1977 if (ret) return sock_errno_to_status( errno );
1979 io->Information = offsetof( DEVICELIST, unix_list->len );
1980 if (out_size < io->Information)
1981 return STATUS_BUFFER_TOO_SMALL;
1983 TRACE( "IRLMP_ENUMDEVICES: got %u devices:\n", unix_list->len );
1984 ws_list->numDevice = unix_list->len;
1985 for (i = 0; i < unix_list->len; ++i)
1987 const struct irda_device_info *unix_dev = &unix_list->dev[i];
1988 IRDA_DEVICE_INFO *ws_dev = &ws_list->Device[i];
1990 TRACE( "saddr %#08x, daddr %#08x, info %s, hints 0x%02x%02x\n",
1991 unix_dev->saddr, unix_dev->daddr, unix_dev->info, unix_dev->hints[0], unix_dev->hints[1] );
1992 memcpy( ws_dev->irdaDeviceID, &unix_dev->daddr, sizeof(unix_dev->daddr) );
1993 memcpy( ws_dev->irdaDeviceName, unix_dev->info, sizeof(unix_dev->info) );
1994 ws_dev->irdaDeviceHints1 = unix_dev->hints[0];
1995 ws_dev->irdaDeviceHints2 = unix_dev->hints[1];
1996 ws_dev->irdaCharSet = unix_dev->charset;
1998 return STATUS_SUCCESS;
2000 #endif
2002 case IOCTL_AFD_WINE_GET_TCP_NODELAY:
2003 return do_getsockopt( handle, io, IPPROTO_TCP, TCP_NODELAY, out_buffer, out_size );
2005 case IOCTL_AFD_WINE_SET_TCP_NODELAY:
2006 return do_setsockopt( handle, io, IPPROTO_TCP, TCP_NODELAY, in_buffer, in_size );
2008 default:
2010 if ((code >> 16) == FILE_DEVICE_NETWORK)
2012 /* Wine-internal ioctl */
2013 status = STATUS_BAD_DEVICE_TYPE;
2015 else
2017 FIXME( "Unknown ioctl %#x (device %#x, access %#x, function %#x, method %#x)\n",
2018 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3 );
2019 status = STATUS_INVALID_DEVICE_REQUEST;
2021 break;
2025 if (needs_close) close( fd );
2026 return status;