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
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
38 #ifdef HAVE_NETINET_IN_H
39 # define __APPLE_USE_RFC_3542
40 # include <netinet/in.h>
42 #ifdef HAVE_NETINET_TCP_H
43 # include <netinet/tcp.h>
46 #ifdef HAVE_NETIPX_IPX_H
47 # include <netipx/ipx.h>
48 #elif defined(HAVE_LINUX_IPX_H)
49 # ifdef HAVE_ASM_TYPES_H
50 # include <asm/types.h>
52 # ifdef HAVE_LINUX_TYPES_H
53 # include <linux/types.h>
55 # include <linux/ipx.h>
57 #if defined(SOL_IPX) || defined(SO_DEFAULT_HEADERS)
61 #ifdef HAVE_LINUX_IRDA_H
62 # ifdef HAVE_LINUX_TYPES_H
63 # include <linux/types.h>
65 # include <linux/irda.h>
70 #define WIN32_NO_STATUS
82 #include "unix_private.h"
84 #if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE)
85 /* TCP_KEEPALIVE is the Mac OS name for TCP_KEEPIDLE */
86 #define TCP_KEEPIDLE TCP_KEEPALIVE
89 #if defined(linux) && !defined(IP_UNICAST_IF)
90 #define IP_UNICAST_IF 50
93 WINE_DEFAULT_DEBUG_CHANNEL(winsock
);
95 #define u64_to_user_ptr(u) ((void *)(uintptr_t)(u))
100 struct sockaddr_in in
;
101 struct sockaddr_in6 in6
;
103 struct sockaddr_ipx ipx
;
106 struct sockaddr_irda irda
;
110 struct async_recv_ioctl
112 struct async_fileio io
;
114 struct WS_sockaddr
*addr
;
116 unsigned int *ret_flags
;
119 BOOL icmp_over_dgram
;
123 struct async_send_ioctl
125 struct async_fileio io
;
126 const struct WS_sockaddr
*addr
;
129 unsigned int sent_len
;
131 unsigned int iov_cursor
;
135 struct async_transmit_ioctl
137 struct async_fileio io
;
140 unsigned int buffer_size
; /* allocated size of buffer */
141 unsigned int read_len
; /* amount of valid data currently in the buffer */
142 unsigned int head_cursor
; /* amount of header data already sent */
143 unsigned int file_cursor
; /* amount of file data already sent */
144 unsigned int buffer_cursor
; /* amount of data currently in the buffer already sent */
145 unsigned int tail_cursor
; /* amount of tail data already sent */
146 unsigned int file_len
; /* total file length to send */
150 unsigned int head_len
;
151 unsigned int tail_len
;
152 LARGE_INTEGER offset
;
155 static NTSTATUS
sock_errno_to_status( int err
)
159 case EBADF
: return STATUS_INVALID_HANDLE
;
160 case EBUSY
: return STATUS_DEVICE_BUSY
;
162 case EACCES
: return STATUS_ACCESS_DENIED
;
163 case EFAULT
: return STATUS_ACCESS_VIOLATION
;
164 case EINVAL
: return STATUS_INVALID_PARAMETER
;
166 case EMFILE
: return STATUS_TOO_MANY_OPENED_FILES
;
168 case EWOULDBLOCK
: return STATUS_DEVICE_NOT_READY
;
169 case EALREADY
: return STATUS_NETWORK_BUSY
;
170 case ENOTSOCK
: return STATUS_OBJECT_TYPE_MISMATCH
;
171 case EDESTADDRREQ
: return STATUS_INVALID_PARAMETER
;
172 case EMSGSIZE
: return STATUS_BUFFER_OVERFLOW
;
173 case EPROTONOSUPPORT
:
174 case ESOCKTNOSUPPORT
:
177 case EPROTOTYPE
: return STATUS_NOT_SUPPORTED
;
178 case ENOPROTOOPT
: return STATUS_INVALID_PARAMETER
;
179 case EOPNOTSUPP
: return STATUS_NOT_SUPPORTED
;
180 case EADDRINUSE
: return STATUS_SHARING_VIOLATION
;
181 case EADDRNOTAVAIL
: return STATUS_INVALID_PARAMETER
;
182 case ECONNREFUSED
: return STATUS_CONNECTION_REFUSED
;
183 case ESHUTDOWN
: return STATUS_PIPE_DISCONNECTED
;
184 case ENOTCONN
: return STATUS_INVALID_CONNECTION
;
185 case ETIMEDOUT
: return STATUS_IO_TIMEOUT
;
186 case ENETUNREACH
: return STATUS_NETWORK_UNREACHABLE
;
187 case EHOSTUNREACH
: return STATUS_HOST_UNREACHABLE
;
188 case ENETDOWN
: return STATUS_NETWORK_BUSY
;
190 case ECONNRESET
: return STATUS_CONNECTION_RESET
;
191 case ECONNABORTED
: return STATUS_CONNECTION_ABORTED
;
192 case EISCONN
: return STATUS_CONNECTION_ACTIVE
;
194 case 0: return STATUS_SUCCESS
;
196 FIXME( "unknown errno %d\n", err
);
197 return STATUS_UNSUCCESSFUL
;
201 static socklen_t
sockaddr_to_unix( const struct WS_sockaddr
*wsaddr
, int wsaddrlen
, union unix_sockaddr
*uaddr
)
203 memset( uaddr
, 0, sizeof(*uaddr
) );
205 switch (wsaddr
->sa_family
)
209 struct WS_sockaddr_in win
= {0};
211 if (wsaddrlen
< sizeof(win
)) return 0;
212 memcpy( &win
, wsaddr
, sizeof(win
) );
213 uaddr
->in
.sin_family
= AF_INET
;
214 uaddr
->in
.sin_port
= win
.sin_port
;
215 memcpy( &uaddr
->in
.sin_addr
, &win
.sin_addr
, sizeof(win
.sin_addr
) );
216 return sizeof(uaddr
->in
);
221 struct WS_sockaddr_in6 win
= {0};
223 if (wsaddrlen
< sizeof(win
)) return 0;
224 memcpy( &win
, wsaddr
, sizeof(win
) );
225 uaddr
->in6
.sin6_family
= AF_INET6
;
226 uaddr
->in6
.sin6_port
= win
.sin6_port
;
227 uaddr
->in6
.sin6_flowinfo
= win
.sin6_flowinfo
;
228 memcpy( &uaddr
->in6
.sin6_addr
, &win
.sin6_addr
, sizeof(win
.sin6_addr
) );
229 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
230 uaddr
->in6
.sin6_scope_id
= win
.sin6_scope_id
;
232 return sizeof(uaddr
->in6
);
238 struct WS_sockaddr_ipx win
= {0};
240 if (wsaddrlen
< sizeof(win
)) return 0;
241 memcpy( &win
, wsaddr
, sizeof(win
) );
242 uaddr
->ipx
.sipx_family
= AF_IPX
;
243 memcpy( &uaddr
->ipx
.sipx_network
, win
.sa_netnum
, sizeof(win
.sa_netnum
) );
244 memcpy( &uaddr
->ipx
.sipx_node
, win
.sa_nodenum
, sizeof(win
.sa_nodenum
) );
245 uaddr
->ipx
.sipx_port
= win
.sa_socket
;
246 return sizeof(uaddr
->ipx
);
253 SOCKADDR_IRDA win
= {0};
254 unsigned int lsap_sel
;
256 if (wsaddrlen
< sizeof(win
)) return 0;
257 memcpy( &win
, wsaddr
, sizeof(win
) );
258 uaddr
->irda
.sir_family
= AF_IRDA
;
259 if (sscanf( win
.irdaServiceName
, "LSAP-SEL%u", &lsap_sel
) == 1)
260 uaddr
->irda
.sir_lsap_sel
= lsap_sel
;
263 uaddr
->irda
.sir_lsap_sel
= LSAP_ANY
;
264 memcpy( uaddr
->irda
.sir_name
, win
.irdaServiceName
, sizeof(win
.irdaServiceName
) );
266 memcpy( &uaddr
->irda
.sir_addr
, win
.irdaDeviceID
, sizeof(win
.irdaDeviceID
) );
267 return sizeof(uaddr
->irda
);
274 default: /* likely an ipv4 address */
275 case sizeof(struct WS_sockaddr_in
):
276 return sizeof(uaddr
->in
);
279 case sizeof(struct WS_sockaddr_ipx
):
280 return sizeof(uaddr
->ipx
);
284 case sizeof(SOCKADDR_IRDA
):
285 return sizeof(uaddr
->irda
);
288 case sizeof(struct WS_sockaddr_in6
):
289 return sizeof(uaddr
->in6
);
293 FIXME( "unknown address family %u\n", wsaddr
->sa_family
);
298 static int sockaddr_from_unix( const union unix_sockaddr
*uaddr
, struct WS_sockaddr
*wsaddr
, socklen_t wsaddrlen
)
300 memset( wsaddr
, 0, wsaddrlen
);
302 switch (uaddr
->addr
.sa_family
)
306 struct WS_sockaddr_in win
= {0};
308 if (wsaddrlen
< sizeof(win
)) return -1;
309 win
.sin_family
= WS_AF_INET
;
310 win
.sin_port
= uaddr
->in
.sin_port
;
311 memcpy( &win
.sin_addr
, &uaddr
->in
.sin_addr
, sizeof(win
.sin_addr
) );
312 memcpy( wsaddr
, &win
, sizeof(win
) );
318 struct WS_sockaddr_in6 win
= {0};
320 if (wsaddrlen
< sizeof(win
)) return -1;
321 win
.sin6_family
= WS_AF_INET6
;
322 win
.sin6_port
= uaddr
->in6
.sin6_port
;
323 win
.sin6_flowinfo
= uaddr
->in6
.sin6_flowinfo
;
324 memcpy( &win
.sin6_addr
, &uaddr
->in6
.sin6_addr
, sizeof(win
.sin6_addr
) );
325 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
326 win
.sin6_scope_id
= uaddr
->in6
.sin6_scope_id
;
328 memcpy( wsaddr
, &win
, sizeof(win
) );
335 struct WS_sockaddr_ipx win
= {0};
337 if (wsaddrlen
< sizeof(win
)) return -1;
338 win
.sa_family
= WS_AF_IPX
;
339 memcpy( win
.sa_netnum
, &uaddr
->ipx
.sipx_network
, sizeof(win
.sa_netnum
) );
340 memcpy( win
.sa_nodenum
, &uaddr
->ipx
.sipx_node
, sizeof(win
.sa_nodenum
) );
341 win
.sa_socket
= uaddr
->ipx
.sipx_port
;
342 memcpy( wsaddr
, &win
, sizeof(win
) );
352 if (wsaddrlen
< sizeof(win
)) return -1;
353 win
.irdaAddressFamily
= WS_AF_IRDA
;
354 memcpy( win
.irdaDeviceID
, &uaddr
->irda
.sir_addr
, sizeof(win
.irdaDeviceID
) );
355 if (uaddr
->irda
.sir_lsap_sel
!= LSAP_ANY
)
356 snprintf( win
.irdaServiceName
, sizeof(win
.irdaServiceName
), "LSAP-SEL%u", uaddr
->irda
.sir_lsap_sel
);
358 memcpy( win
.irdaServiceName
, uaddr
->irda
.sir_name
, sizeof(win
.irdaServiceName
) );
359 memcpy( wsaddr
, &win
, sizeof(win
) );
368 FIXME( "unknown address family %d\n", uaddr
->addr
.sa_family
);
373 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
374 static WSACMSGHDR
*fill_control_message( int level
, int type
, WSACMSGHDR
*current
, ULONG
*maxsize
, void *data
, int len
)
376 ULONG msgsize
= sizeof(WSACMSGHDR
) + WSA_CMSG_ALIGN(len
);
377 char *ptr
= (char *) current
+ sizeof(WSACMSGHDR
);
379 if (msgsize
> *maxsize
)
382 current
->cmsg_len
= sizeof(WSACMSGHDR
) + len
;
383 current
->cmsg_level
= level
;
384 current
->cmsg_type
= type
;
385 memcpy(ptr
, data
, len
);
386 return (WSACMSGHDR
*)(ptr
+ WSA_CMSG_ALIGN(len
));
389 static int convert_control_headers(struct msghdr
*hdr
, WSABUF
*control
)
391 WSACMSGHDR
*cmsg_win
= (WSACMSGHDR
*)control
->buf
, *ptr
;
392 ULONG ctlsize
= control
->len
;
393 struct cmsghdr
*cmsg_unix
;
396 for (cmsg_unix
= CMSG_FIRSTHDR(hdr
); cmsg_unix
!= NULL
; cmsg_unix
= CMSG_NXTHDR(hdr
, cmsg_unix
))
398 switch (cmsg_unix
->cmsg_level
)
401 switch (cmsg_unix
->cmsg_type
)
403 #if defined(IP_PKTINFO)
406 const struct in_pktinfo
*data_unix
= (struct in_pktinfo
*)CMSG_DATA(cmsg_unix
);
407 struct WS_in_pktinfo data_win
;
409 memcpy( &data_win
.ipi_addr
, &data_unix
->ipi_addr
.s_addr
, 4 ); /* 4 bytes = 32 address bits */
410 data_win
.ipi_ifindex
= data_unix
->ipi_ifindex
;
411 ptr
= fill_control_message( WS_IPPROTO_IP
, WS_IP_PKTINFO
, ptr
, &ctlsize
,
412 (void *)&data_win
, sizeof(data_win
) );
413 if (!ptr
) goto error
;
416 #elif defined(IP_RECVDSTADDR)
419 const struct in_addr
*addr_unix
= (struct in_addr
*)CMSG_DATA(cmsg_unix
);
420 struct WS_in_pktinfo data_win
;
422 memcpy( &data_win
.ipi_addr
, &addr_unix
->s_addr
, 4 ); /* 4 bytes = 32 address bits */
423 data_win
.ipi_ifindex
= 0; /* FIXME */
424 ptr
= fill_control_message( WS_IPPROTO_IP
, WS_IP_PKTINFO
, ptr
, &ctlsize
,
425 (void *)&data_win
, sizeof(data_win
) );
426 if (!ptr
) goto error
;
429 #endif /* IP_PKTINFO */
434 INT tos
= *(unsigned char *)CMSG_DATA(cmsg_unix
);
435 ptr
= fill_control_message( WS_IPPROTO_IP
, WS_IP_TOS
, ptr
, &ctlsize
,
437 if (!ptr
) goto error
;
445 ptr
= fill_control_message( WS_IPPROTO_IP
, WS_IP_TTL
, ptr
, &ctlsize
,
446 CMSG_DATA(cmsg_unix
), sizeof(INT
) );
447 if (!ptr
) goto error
;
453 FIXME("Unhandled IPPROTO_IP message header type %d\n", cmsg_unix
->cmsg_type
);
459 switch (cmsg_unix
->cmsg_type
)
461 #if defined(IPV6_HOPLIMIT)
464 ptr
= fill_control_message( WS_IPPROTO_IPV6
, WS_IPV6_HOPLIMIT
, ptr
, &ctlsize
,
465 CMSG_DATA(cmsg_unix
), sizeof(INT
) );
466 if (!ptr
) goto error
;
469 #endif /* IPV6_HOPLIMIT */
471 #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO_IPI6_ADDR)
474 struct in6_pktinfo
*data_unix
= (struct in6_pktinfo
*)CMSG_DATA(cmsg_unix
);
475 struct WS_in6_pktinfo data_win
;
477 memcpy(&data_win
.ipi6_addr
, &data_unix
->ipi6_addr
.s6_addr
, 16);
478 data_win
.ipi6_ifindex
= data_unix
->ipi6_ifindex
;
479 ptr
= fill_control_message( WS_IPPROTO_IPV6
, WS_IPV6_PKTINFO
, ptr
, &ctlsize
,
480 (void *)&data_win
, sizeof(data_win
) );
481 if (!ptr
) goto error
;
484 #endif /* IPV6_PKTINFO */
486 #if defined(IPV6_TCLASS)
489 ptr
= fill_control_message( WS_IPPROTO_IPV6
, WS_IPV6_TCLASS
, ptr
, &ctlsize
,
490 CMSG_DATA(cmsg_unix
), sizeof(INT
) );
491 if (!ptr
) goto error
;
494 #endif /* IPV6_TCLASS */
497 FIXME("Unhandled IPPROTO_IPV6 message header type %d\n", cmsg_unix
->cmsg_type
);
503 FIXME("Unhandled message header level %d\n", cmsg_unix
->cmsg_level
);
508 control
->len
= (char *)ptr
- (char *)cmsg_win
;
516 static int convert_control_headers(struct msghdr
*hdr
, WSABUF
*control
)
518 ERR( "Message control headers cannot be properly supported on this system.\n" );
522 #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */
529 /* UCHAR cmsg_data[]; */
532 static size_t cmsg_align_32( size_t len
)
534 return (len
+ sizeof(ULONG
) - 1) & ~(sizeof(ULONG
) - 1);
537 /* we assume that cmsg_data does not require translation, which is currently
538 * true for all messages */
539 static int wow64_translate_control( const WSABUF
*control64
, struct afd_wsabuf_32
*control32
)
541 char *const buf32
= ULongToPtr(control32
->buf
);
542 const ULONG max_len
= control32
->len
;
543 const char *ptr64
= control64
->buf
;
546 while (ptr64
< control64
->buf
+ control64
->len
)
548 struct cmsghdr_32
*cmsg32
= (struct cmsghdr_32
*)ptr32
;
549 const WSACMSGHDR
*cmsg64
= (const WSACMSGHDR
*)ptr64
;
551 if (ptr32
+ sizeof(*cmsg32
) + cmsg_align_32( cmsg64
->cmsg_len
) > buf32
+ max_len
)
557 cmsg32
->cmsg_len
= cmsg64
->cmsg_len
- sizeof(*cmsg64
) + sizeof(*cmsg32
);
558 cmsg32
->cmsg_level
= cmsg64
->cmsg_level
;
559 cmsg32
->cmsg_type
= cmsg64
->cmsg_type
;
560 memcpy( cmsg32
+ 1, cmsg64
+ 1, cmsg64
->cmsg_len
);
562 ptr64
+= WSA_CMSG_ALIGN( cmsg64
->cmsg_len
);
563 ptr32
+= cmsg_align_32( cmsg32
->cmsg_len
);
566 control32
->len
= ptr32
- buf32
;
567 FIXME("-> %d\n", control32
->len
);
573 BYTE v_hl
; /* version << 4 | hdr_len */
600 /* rfc 1071 checksum */
601 static unsigned short chksum(BYTE
*data
, unsigned int count
)
603 unsigned int sum
= 0, carry
= 0;
604 unsigned short check
, s
;
608 s
= *(unsigned short *)data
;
615 sum
+= carry
; /* This won't produce another carry */
616 sum
= (sum
& 0xffff) + (sum
>> 16);
618 if (count
) sum
+= *data
; /* LE-only */
620 sum
= (sum
& 0xffff) + (sum
>> 16);
621 /* fold in any carry */
622 sum
= (sum
& 0xffff) + (sum
>> 16);
628 static ssize_t
fixup_icmp_over_dgram( struct msghdr
*hdr
, union unix_sockaddr
*unix_addr
,
629 HANDLE handle
, ssize_t recv_len
, NTSTATUS
*status
)
631 unsigned int tot_len
= sizeof(struct ip_hdr
) + recv_len
;
632 struct icmp_hdr
*icmp_h
= NULL
;
633 unsigned int fixup_status
;
634 struct cmsghdr
*cmsg
;
639 if (hdr
->msg_iovlen
!= 1)
641 FIXME( "Buffer count %zu is not supported for ICMP fixup.\n", (size_t)hdr
->msg_iovlen
);
645 buf
= hdr
->msg_iov
[0].iov_base
;
646 buf_len
= hdr
->msg_iov
[0].iov_len
;
648 if (recv_len
+ sizeof(ip_h
) > buf_len
)
649 *status
= STATUS_BUFFER_OVERFLOW
;
651 if (buf_len
< sizeof(ip_h
))
657 recv_len
= min( recv_len
, buf_len
- sizeof(ip_h
) );
658 memmove( buf
+ sizeof(ip_h
), buf
, recv_len
);
659 if (recv_len
>= sizeof(struct icmp_hdr
))
660 icmp_h
= (struct icmp_hdr
*)(buf
+ sizeof(ip_h
));
661 recv_len
+= sizeof(ip_h
);
663 memset( &ip_h
, 0, sizeof(ip_h
) );
664 ip_h
.v_hl
= (4 << 4) | (sizeof(ip_h
) >> 2);
665 ip_h
.tot_len
= htons( tot_len
);
667 ip_h
.saddr
= unix_addr
->in
.sin_addr
.s_addr
;
669 for (cmsg
= CMSG_FIRSTHDR( hdr
); cmsg
; cmsg
= CMSG_NXTHDR( hdr
, cmsg
))
671 if (cmsg
->cmsg_level
!= IPPROTO_IP
) continue;
672 switch (cmsg
->cmsg_type
)
676 ip_h
.ttl
= *(BYTE
*)CMSG_DATA( cmsg
);
681 ip_h
.tos
= *(BYTE
*)CMSG_DATA( cmsg
);
684 #if defined(IP_PKTINFO)
687 struct in_pktinfo
*info
;
689 info
= (struct in_pktinfo
*)CMSG_DATA( cmsg
);
690 ip_h
.daddr
= info
->ipi_addr
.s_addr
;
698 SERVER_START_REQ( socket_get_icmp_id
)
700 req
->handle
= wine_server_obj_handle( handle
);
701 req
->icmp_seq
= icmp_h
->un
.echo
.sequence
;
702 if (!(fixup_status
= wine_server_call( req
)))
703 icmp_h
->un
.echo
.id
= reply
->icmp_id
;
705 WARN( "socket_get_fixup_data returned %#x.\n", fixup_status
);
711 icmp_h
->checksum
= 0;
712 icmp_h
->checksum
= chksum( (BYTE
*)icmp_h
, recv_len
- sizeof(ip_h
) );
715 ip_h
.checksum
= chksum( (BYTE
*)&ip_h
, sizeof(ip_h
) );
716 memcpy( buf
, &ip_h
, min( sizeof(ip_h
), buf_len
));
721 static NTSTATUS
try_recv( int fd
, struct async_recv_ioctl
*async
, ULONG_PTR
*size
)
723 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
724 char control_buffer
[512];
726 union unix_sockaddr unix_addr
;
731 memset( &hdr
, 0, sizeof(hdr
) );
732 if (async
->addr
|| async
->icmp_over_dgram
)
734 hdr
.msg_name
= &unix_addr
.addr
;
735 hdr
.msg_namelen
= sizeof(unix_addr
);
737 hdr
.msg_iov
= async
->iov
;
738 hdr
.msg_iovlen
= async
->count
;
739 #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
740 hdr
.msg_control
= control_buffer
;
741 hdr
.msg_controllen
= sizeof(control_buffer
);
743 while ((ret
= virtual_locked_recvmsg( fd
, &hdr
, async
->unix_flags
)) < 0 && errno
== EINTR
);
747 /* Unix-like systems return EINVAL when attempting to read OOB data from
748 * an empty socket buffer; Windows returns WSAEWOULDBLOCK. */
749 if ((async
->unix_flags
& MSG_OOB
) && errno
== EINVAL
)
752 if (errno
!= EWOULDBLOCK
) WARN( "recvmsg: %s\n", strerror( errno
) );
753 return sock_errno_to_status( errno
);
756 status
= (hdr
.msg_flags
& MSG_TRUNC
) ? STATUS_BUFFER_OVERFLOW
: STATUS_SUCCESS
;
757 if (async
->icmp_over_dgram
)
758 ret
= fixup_icmp_over_dgram( &hdr
, &unix_addr
, async
->io
.handle
, ret
, &status
);
762 if (async
->icmp_over_dgram
)
763 FIXME( "May return extra control headers.\n" );
767 char control_buffer64
[512];
770 wsabuf
.len
= sizeof(control_buffer64
);
771 wsabuf
.buf
= control_buffer64
;
772 if (convert_control_headers( &hdr
, &wsabuf
))
774 if (!wow64_translate_control( &wsabuf
, async
->control
))
776 WARN( "Application passed insufficient room for control headers.\n" );
777 *async
->ret_flags
|= WS_MSG_CTRUNC
;
778 status
= STATUS_BUFFER_OVERFLOW
;
783 FIXME( "control buffer is too small\n" );
784 *async
->ret_flags
|= WS_MSG_CTRUNC
;
785 status
= STATUS_BUFFER_OVERFLOW
;
790 if (!convert_control_headers( &hdr
, async
->control
))
792 WARN( "Application passed insufficient room for control headers.\n" );
793 *async
->ret_flags
|= WS_MSG_CTRUNC
;
794 status
= STATUS_BUFFER_OVERFLOW
;
799 /* If this socket is connected, Linux doesn't give us msg_name and
800 * msg_namelen from recvmsg, but it does set msg_namelen to zero.
802 * MSDN says that the address is ignored for connection-oriented sockets, so
803 * don't try to translate it.
805 if (async
->addr
&& hdr
.msg_namelen
)
806 *async
->addr_len
= sockaddr_from_unix( &unix_addr
, async
->addr
, *async
->addr_len
);
812 static BOOL
async_recv_proc( void *user
, ULONG_PTR
*info
, unsigned int *status
)
814 struct async_recv_ioctl
*async
= user
;
817 TRACE( "%#x\n", *status
);
819 if (*status
== STATUS_ALERTED
)
821 if ((*status
= server_get_unix_fd( async
->io
.handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
824 *status
= try_recv( fd
, async
, info
);
825 TRACE( "got status %#x, %#lx bytes read\n", *status
, *info
);
826 if (needs_close
) close( fd
);
828 if (*status
== STATUS_DEVICE_NOT_READY
)
831 release_fileio( &async
->io
);
835 static BOOL
is_icmp_over_dgram( int fd
)
842 if (getsockopt( fd
, SOL_SOCKET
, SO_PROTOCOL
, (char *)&val
, &len
) || val
!= IPPROTO_ICMP
)
846 return !getsockopt( fd
, SOL_SOCKET
, SO_TYPE
, (char *)&val
, &len
) && val
== SOCK_DGRAM
;
852 static NTSTATUS
sock_recv( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc
, void *apc_user
, IO_STATUS_BLOCK
*io
,
853 int fd
, struct async_recv_ioctl
*async
, int force_async
)
857 unsigned int i
, status
;
860 for (i
= 0; i
< async
->count
; ++i
)
862 if (!virtual_check_buffer_for_write( async
->iov
[i
].iov_base
, async
->iov
[i
].iov_len
))
864 release_fileio( &async
->io
);
865 return STATUS_ACCESS_VIOLATION
;
869 SERVER_START_REQ( recv_socket
)
871 req
->force_async
= force_async
;
872 req
->async
= server_async( handle
, &async
->io
, event
, apc
, apc_user
, iosb_client_ptr(io
) );
873 req
->oob
= !!(async
->unix_flags
& MSG_OOB
);
874 status
= wine_server_call( req
);
875 wait_handle
= wine_server_ptr_handle( reply
->wait
);
876 options
= reply
->options
;
877 nonblocking
= reply
->nonblocking
;
881 /* the server currently will never succeed immediately */
882 assert(status
== STATUS_ALERTED
|| status
== STATUS_PENDING
|| NT_ERROR(status
));
884 if (status
== STATUS_ALERTED
)
886 ULONG_PTR information
;
888 status
= try_recv( fd
, async
, &information
);
889 if (status
== STATUS_DEVICE_NOT_READY
&& (force_async
|| !nonblocking
))
890 status
= STATUS_PENDING
;
891 if (!NT_ERROR(status
) && status
!= STATUS_PENDING
)
894 io
->Information
= information
;
896 set_async_direct_result( &wait_handle
, status
, information
, FALSE
);
899 if (status
!= STATUS_PENDING
)
900 release_fileio( &async
->io
);
902 if (wait_handle
) status
= wait_async( wait_handle
, options
& FILE_SYNCHRONOUS_IO_ALERT
);
907 static NTSTATUS
sock_ioctl_recv( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc
, void *apc_user
, IO_STATUS_BLOCK
*io
,
908 int fd
, const void *buffers_ptr
, unsigned int count
, WSABUF
*control
,
909 struct WS_sockaddr
*addr
, int *addr_len
, unsigned int *ret_flags
, int unix_flags
, int force_async
)
911 struct async_recv_ioctl
*async
;
915 if (unix_flags
& MSG_OOB
)
918 socklen_t len
= sizeof(oobinline
);
919 if (!getsockopt( fd
, SOL_SOCKET
, SO_OOBINLINE
, (char *)&oobinline
, &len
) && oobinline
)
920 return STATUS_INVALID_PARAMETER
;
923 async_size
= offsetof( struct async_recv_ioctl
, iov
[count
] );
925 if (!(async
= (struct async_recv_ioctl
*)alloc_fileio( async_size
, async_recv_proc
, handle
)))
926 return STATUS_NO_MEMORY
;
928 async
->count
= count
;
931 const struct afd_wsabuf_32
*buffers
= buffers_ptr
;
933 for (i
= 0; i
< count
; ++i
)
935 async
->iov
[i
].iov_base
= ULongToPtr( buffers
[i
].buf
);
936 async
->iov
[i
].iov_len
= buffers
[i
].len
;
941 const WSABUF
*buffers
= buffers_ptr
;
943 for (i
= 0; i
< count
; ++i
)
945 async
->iov
[i
].iov_base
= buffers
[i
].buf
;
946 async
->iov
[i
].iov_len
= buffers
[i
].len
;
949 async
->unix_flags
= unix_flags
;
950 async
->control
= control
;
952 async
->addr_len
= addr_len
;
953 async
->ret_flags
= ret_flags
;
954 async
->icmp_over_dgram
= is_icmp_over_dgram( fd
);
956 return sock_recv( handle
, event
, apc
, apc_user
, io
, fd
, async
, force_async
);
960 NTSTATUS
sock_read( HANDLE handle
, int fd
, HANDLE event
, PIO_APC_ROUTINE apc
,
961 void *apc_user
, IO_STATUS_BLOCK
*io
, void *buffer
, ULONG length
)
963 static const DWORD async_size
= offsetof( struct async_recv_ioctl
, iov
[1] );
964 struct async_recv_ioctl
*async
;
966 if (!(async
= (struct async_recv_ioctl
*)alloc_fileio( async_size
, async_recv_proc
, handle
)))
967 return STATUS_NO_MEMORY
;
970 async
->iov
[0].iov_base
= buffer
;
971 async
->iov
[0].iov_len
= length
;
972 async
->unix_flags
= 0;
973 async
->control
= NULL
;
975 async
->addr_len
= NULL
;
976 async
->ret_flags
= NULL
;
977 async
->icmp_over_dgram
= is_icmp_over_dgram( fd
);
979 return sock_recv( handle
, event
, apc
, apc_user
, io
, fd
, async
, 1 );
983 static NTSTATUS
try_send( int fd
, struct async_send_ioctl
*async
)
985 union unix_sockaddr unix_addr
;
989 memset( &hdr
, 0, sizeof(hdr
) );
992 hdr
.msg_name
= &unix_addr
;
993 hdr
.msg_namelen
= sockaddr_to_unix( async
->addr
, async
->addr_len
, &unix_addr
);
994 if (!hdr
.msg_namelen
)
996 ERR( "failed to convert address\n" );
997 return STATUS_ACCESS_VIOLATION
;
1000 #if defined(HAS_IPX) && defined(SOL_IPX)
1001 if (async
->addr
->sa_family
== WS_AF_IPX
)
1004 socklen_t len
= sizeof(type
);
1006 /* The packet type is stored at the IPX socket level. At least the
1007 * linux kernel seems to do something with it in case hdr.msg_name
1008 * is NULL. Nonetheless we can use it to store the packet type, and
1009 * then we can retrieve it using getsockopt. After that we can set
1010 * the IPX type in the sockaddr_ipx structure with the stored value.
1012 if (getsockopt(fd
, SOL_IPX
, IPX_TYPE
, &type
, &len
) >= 0)
1013 unix_addr
.ipx
.sipx_type
= type
;
1018 hdr
.msg_iov
= async
->iov
+ async
->iov_cursor
;
1019 hdr
.msg_iovlen
= async
->count
- async
->iov_cursor
;
1021 while ((ret
= sendmsg( fd
, &hdr
, async
->unix_flags
)) == -1)
1023 if (errno
== EISCONN
)
1025 hdr
.msg_name
= NULL
;
1026 hdr
.msg_namelen
= 0;
1028 else if (errno
!= EINTR
)
1030 if (errno
!= EWOULDBLOCK
) WARN( "sendmsg: %s\n", strerror( errno
) );
1031 return sock_errno_to_status( errno
);
1035 async
->sent_len
+= ret
;
1037 while (async
->iov_cursor
< async
->count
&& ret
>= async
->iov
[async
->iov_cursor
].iov_len
)
1038 ret
-= async
->iov
[async
->iov_cursor
++].iov_len
;
1039 if (async
->iov_cursor
< async
->count
)
1041 async
->iov
[async
->iov_cursor
].iov_base
= (char *)async
->iov
[async
->iov_cursor
].iov_base
+ ret
;
1042 async
->iov
[async
->iov_cursor
].iov_len
-= ret
;
1043 return STATUS_DEVICE_NOT_READY
;
1045 return STATUS_SUCCESS
;
1048 static BOOL
async_send_proc( void *user
, ULONG_PTR
*info
, unsigned int *status
)
1050 struct async_send_ioctl
*async
= user
;
1051 int fd
, needs_close
;
1053 TRACE( "%#x\n", *status
);
1055 if (*status
== STATUS_ALERTED
)
1057 if ((*status
= server_get_unix_fd( async
->io
.handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1060 *status
= try_send( fd
, async
);
1061 TRACE( "got status %#x\n", *status
);
1063 if (needs_close
) close( fd
);
1065 if (*status
== STATUS_DEVICE_NOT_READY
)
1068 *info
= async
->sent_len
;
1069 release_fileio( &async
->io
);
1073 static void sock_save_icmp_id( struct async_send_ioctl
*async
)
1075 unsigned short id
, seq
;
1078 if (async
->count
!= 1 || async
->iov
[0].iov_len
< sizeof(*h
))
1080 FIXME( "ICMP over DGRAM fixup is not supported for count %u, len %zu.\n", async
->count
, async
->iov
[0].iov_len
);
1084 h
= async
->iov
[0].iov_base
;
1086 seq
= h
->un
.echo
.sequence
;
1087 SERVER_START_REQ( socket_send_icmp_id
)
1089 req
->handle
= wine_server_obj_handle( async
->io
.handle
);
1091 req
->icmp_seq
= seq
;
1092 if (wine_server_call( req
))
1093 WARN( "socket_fixup_send_data failed.\n" );
1098 static NTSTATUS
sock_send( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc
, void *apc_user
,
1099 IO_STATUS_BLOCK
*io
, int fd
, struct async_send_ioctl
*async
, int force_async
)
1103 unsigned int status
;
1106 SERVER_START_REQ( send_socket
)
1108 req
->force_async
= force_async
;
1109 req
->async
= server_async( handle
, &async
->io
, event
, apc
, apc_user
, iosb_client_ptr(io
) );
1110 status
= wine_server_call( req
);
1111 wait_handle
= wine_server_ptr_handle( reply
->wait
);
1112 options
= reply
->options
;
1113 nonblocking
= reply
->nonblocking
;
1117 /* the server currently will never succeed immediately */
1118 assert(status
== STATUS_ALERTED
|| status
== STATUS_PENDING
|| NT_ERROR(status
));
1120 if (!NT_ERROR(status
) && is_icmp_over_dgram( fd
))
1121 sock_save_icmp_id( async
);
1123 if (status
== STATUS_ALERTED
)
1125 ULONG_PTR information
;
1127 status
= try_send( fd
, async
);
1128 if (status
== STATUS_DEVICE_NOT_READY
&& (force_async
|| !nonblocking
))
1129 status
= STATUS_PENDING
;
1131 /* If we had a short write and the socket is nonblocking (and we are
1132 * not trying to force the operation to be asynchronous), return
1133 * success. Windows actually refuses to send any data in this case,
1134 * and returns EWOULDBLOCK, but we have no way of doing that. */
1135 if (status
== STATUS_DEVICE_NOT_READY
&& async
->sent_len
)
1136 status
= STATUS_SUCCESS
;
1138 information
= async
->sent_len
;
1139 if (!NT_ERROR(status
) && status
!= STATUS_PENDING
)
1141 io
->Status
= status
;
1142 io
->Information
= information
;
1145 set_async_direct_result( &wait_handle
, status
, information
, FALSE
);
1148 if (status
!= STATUS_PENDING
)
1149 release_fileio( &async
->io
);
1151 if (wait_handle
) status
= wait_async( wait_handle
, options
& FILE_SYNCHRONOUS_IO_ALERT
);
1155 static NTSTATUS
sock_ioctl_send( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc
, void *apc_user
,
1156 IO_STATUS_BLOCK
*io
, int fd
, const void *buffers_ptr
, unsigned int count
,
1157 const struct WS_sockaddr
*addr
, unsigned int addr_len
, int unix_flags
, int force_async
)
1159 struct async_send_ioctl
*async
;
1163 async_size
= offsetof( struct async_send_ioctl
, iov
[count
] );
1165 if (!(async
= (struct async_send_ioctl
*)alloc_fileio( async_size
, async_send_proc
, handle
)))
1166 return STATUS_NO_MEMORY
;
1168 async
->count
= count
;
1169 if (in_wow64_call())
1171 const struct afd_wsabuf_32
*buffers
= buffers_ptr
;
1173 for (i
= 0; i
< count
; ++i
)
1175 async
->iov
[i
].iov_base
= ULongToPtr( buffers
[i
].buf
);
1176 async
->iov
[i
].iov_len
= buffers
[i
].len
;
1181 const WSABUF
*buffers
= buffers_ptr
;
1183 for (i
= 0; i
< count
; ++i
)
1185 async
->iov
[i
].iov_base
= buffers
[i
].buf
;
1186 async
->iov
[i
].iov_len
= buffers
[i
].len
;
1189 async
->unix_flags
= unix_flags
;
1191 async
->addr_len
= addr_len
;
1192 async
->iov_cursor
= 0;
1193 async
->sent_len
= 0;
1195 return sock_send( handle
, event
, apc
, apc_user
, io
, fd
, async
, force_async
);
1199 NTSTATUS
sock_write( HANDLE handle
, int fd
, HANDLE event
, PIO_APC_ROUTINE apc
,
1200 void *apc_user
, IO_STATUS_BLOCK
*io
, const void *buffer
, ULONG length
)
1202 static const DWORD async_size
= offsetof( struct async_send_ioctl
, iov
[1] );
1203 struct async_send_ioctl
*async
;
1205 if (!(async
= (struct async_send_ioctl
*)alloc_fileio( async_size
, async_recv_proc
, handle
)))
1206 return STATUS_NO_MEMORY
;
1209 async
->iov
[0].iov_base
= (void *)buffer
;
1210 async
->iov
[0].iov_len
= length
;
1211 async
->unix_flags
= 0;
1213 async
->addr_len
= 0;
1214 async
->iov_cursor
= 0;
1215 async
->sent_len
= 0;
1217 return sock_send( handle
, event
, apc
, apc_user
, io
, fd
, async
, 1 );
1221 static ssize_t
do_send( int fd
, const void *buffer
, size_t len
, int flags
)
1224 while ((ret
= send( fd
, buffer
, len
, flags
)) < 0 && errno
== EINTR
);
1225 if (ret
< 0 && errno
!= EWOULDBLOCK
) WARN( "send: %s\n", strerror( errno
) );
1229 static NTSTATUS
try_transmit( int sock_fd
, int file_fd
, struct async_transmit_ioctl
*async
)
1233 while (async
->head_cursor
< async
->head_len
)
1235 TRACE( "sending %u bytes of header data\n", async
->head_len
- async
->head_cursor
);
1236 ret
= do_send( sock_fd
, async
->head
+ async
->head_cursor
,
1237 async
->head_len
- async
->head_cursor
, 0 );
1238 if (ret
< 0) return sock_errno_to_status( errno
);
1239 TRACE( "send returned %zd\n", ret
);
1240 async
->head_cursor
+= ret
;
1243 while (async
->buffer_cursor
< async
->read_len
)
1245 TRACE( "sending %u bytes of file data\n", async
->read_len
- async
->buffer_cursor
);
1246 ret
= do_send( sock_fd
, async
->buffer
+ async
->buffer_cursor
,
1247 async
->read_len
- async
->buffer_cursor
, 0 );
1248 if (ret
< 0) return sock_errno_to_status( errno
);
1249 TRACE( "send returned %zd\n", ret
);
1250 async
->buffer_cursor
+= ret
;
1251 async
->file_cursor
+= ret
;
1254 if (async
->file
&& async
->buffer_cursor
== async
->read_len
)
1256 unsigned int read_size
= async
->buffer_size
;
1258 if (async
->file_len
)
1259 read_size
= min( read_size
, async
->file_len
- async
->file_cursor
);
1261 TRACE( "reading %u bytes of file data\n", read_size
);
1264 if (async
->offset
.QuadPart
== FILE_USE_FILE_POINTER_POSITION
)
1265 ret
= read( file_fd
, async
->buffer
, read_size
);
1267 ret
= pread( file_fd
, async
->buffer
, read_size
, async
->offset
.QuadPart
);
1268 } while (ret
< 0 && errno
== EINTR
);
1269 if (ret
< 0) return errno_to_status( errno
);
1270 TRACE( "read returned %zd\n", ret
);
1272 async
->read_len
= ret
;
1273 async
->buffer_cursor
= 0;
1274 if (async
->offset
.QuadPart
!= FILE_USE_FILE_POINTER_POSITION
)
1275 async
->offset
.QuadPart
+= ret
;
1277 if (ret
< read_size
|| (async
->file_len
&& async
->file_cursor
== async
->file_len
))
1279 return STATUS_DEVICE_NOT_READY
; /* still more data to send */
1282 while (async
->tail_cursor
< async
->tail_len
)
1284 TRACE( "sending %u bytes of tail data\n", async
->tail_len
- async
->tail_cursor
);
1285 ret
= do_send( sock_fd
, async
->tail
+ async
->tail_cursor
,
1286 async
->tail_len
- async
->tail_cursor
, 0 );
1287 if (ret
< 0) return sock_errno_to_status( errno
);
1288 TRACE( "send returned %zd\n", ret
);
1289 async
->tail_cursor
+= ret
;
1292 return STATUS_SUCCESS
;
1295 static BOOL
async_transmit_proc( void *user
, ULONG_PTR
*info
, unsigned int *status
)
1297 int sock_fd
, file_fd
= -1, sock_needs_close
= FALSE
, file_needs_close
= FALSE
;
1298 struct async_transmit_ioctl
*async
= user
;
1300 TRACE( "%#x\n", *status
);
1302 if (*status
== STATUS_ALERTED
)
1304 if ((*status
= server_get_unix_fd( async
->io
.handle
, 0, &sock_fd
, &sock_needs_close
, NULL
, NULL
)))
1307 if (async
->file
&& (*status
= server_get_unix_fd( async
->file
, 0, &file_fd
, &file_needs_close
, NULL
, NULL
)))
1309 if (sock_needs_close
) close( sock_fd
);
1313 *status
= try_transmit( sock_fd
, file_fd
, async
);
1314 TRACE( "got status %#x\n", *status
);
1316 if (sock_needs_close
) close( sock_fd
);
1317 if (file_needs_close
) close( file_fd
);
1319 if (*status
== STATUS_DEVICE_NOT_READY
)
1322 *info
= async
->head_cursor
+ async
->file_cursor
+ async
->tail_cursor
;
1323 release_fileio( &async
->io
);
1327 static NTSTATUS
sock_transmit( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc
, void *apc_user
,
1328 IO_STATUS_BLOCK
*io
, int fd
, const struct afd_transmit_params
*params
)
1330 int file_fd
, file_needs_close
= FALSE
;
1331 struct async_transmit_ioctl
*async
;
1332 enum server_fd_type file_type
;
1333 union unix_sockaddr addr
;
1336 unsigned int status
;
1339 addr_len
= sizeof(addr
);
1340 if (getpeername( fd
, &addr
.addr
, &addr_len
) != 0)
1341 return STATUS_INVALID_CONNECTION
;
1345 if ((status
= server_get_unix_fd( ULongToHandle( params
->file
), 0, &file_fd
, &file_needs_close
, &file_type
, NULL
)))
1347 if (file_needs_close
) close( file_fd
);
1349 if (file_type
!= FD_TYPE_FILE
)
1351 FIXME( "unsupported file type %#x\n", file_type
);
1352 return STATUS_NOT_IMPLEMENTED
;
1356 if (!(async
= (struct async_transmit_ioctl
*)alloc_fileio( sizeof(*async
), async_transmit_proc
, handle
)))
1357 return STATUS_NO_MEMORY
;
1359 async
->file
= ULongToHandle( params
->file
);
1360 async
->buffer_size
= params
->buffer_size
? params
->buffer_size
: 65536;
1361 if (!(async
->buffer
= malloc( async
->buffer_size
)))
1363 release_fileio( &async
->io
);
1364 return STATUS_NO_MEMORY
;
1366 async
->read_len
= 0;
1367 async
->head_cursor
= 0;
1368 async
->file_cursor
= 0;
1369 async
->buffer_cursor
= 0;
1370 async
->tail_cursor
= 0;
1371 async
->file_len
= params
->file_len
;
1372 async
->flags
= params
->flags
;
1373 async
->head
= u64_to_user_ptr(params
->head_ptr
);
1374 async
->head_len
= params
->head_len
;
1375 async
->tail
= u64_to_user_ptr(params
->tail_ptr
);
1376 async
->tail_len
= params
->tail_len
;
1377 async
->offset
= params
->offset
;
1379 SERVER_START_REQ( send_socket
)
1381 req
->force_async
= 1;
1382 req
->async
= server_async( handle
, &async
->io
, event
, apc
, apc_user
, iosb_client_ptr(io
) );
1383 status
= wine_server_call( req
);
1384 wait_handle
= wine_server_ptr_handle( reply
->wait
);
1385 options
= reply
->options
;
1389 /* the server currently will never succeed immediately */
1390 assert(status
== STATUS_ALERTED
|| status
== STATUS_PENDING
|| NT_ERROR(status
));
1392 if (status
== STATUS_ALERTED
)
1394 ULONG_PTR information
;
1396 status
= try_transmit( fd
, file_fd
, async
);
1397 if (status
== STATUS_DEVICE_NOT_READY
)
1398 status
= STATUS_PENDING
;
1400 information
= async
->head_cursor
+ async
->file_cursor
+ async
->tail_cursor
;
1401 if (!NT_ERROR(status
) && status
!= STATUS_PENDING
)
1403 io
->Status
= status
;
1404 io
->Information
= information
;
1407 set_async_direct_result( &wait_handle
, status
, information
, TRUE
);
1410 if (status
!= STATUS_PENDING
)
1411 release_fileio( &async
->io
);
1413 if (!status
&& !(options
& (FILE_SYNCHRONOUS_IO_ALERT
| FILE_SYNCHRONOUS_IO_NONALERT
)))
1415 /* Pretend we always do async I/O. The client can always retrieve
1416 * the actual I/O status via the IO_STATUS_BLOCK.
1418 status
= STATUS_PENDING
;
1421 if (wait_handle
) status
= wait_async( wait_handle
, options
& FILE_SYNCHRONOUS_IO_ALERT
);
1425 static void complete_async( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc
, void *apc_user
,
1426 IO_STATUS_BLOCK
*io
, NTSTATUS status
, ULONG_PTR information
)
1428 ULONG_PTR iosb_ptr
= iosb_client_ptr(io
);
1430 io
->Status
= status
;
1431 io
->Information
= information
;
1432 if (event
) NtSetEvent( event
, NULL
);
1433 if (apc
) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC
)apc
, (ULONG_PTR
)apc_user
, iosb_ptr
, 0 );
1434 if (apc_user
) add_completion( handle
, (ULONG_PTR
)apc_user
, status
, information
, FALSE
);
1438 static NTSTATUS
do_getsockopt( HANDLE handle
, IO_STATUS_BLOCK
*io
, int level
,
1439 int option
, void *out_buffer
, ULONG out_size
)
1441 int fd
, needs_close
= FALSE
;
1442 socklen_t len
= out_size
;
1446 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1449 ret
= getsockopt( fd
, level
, option
, out_buffer
, &len
);
1450 if (needs_close
) close( fd
);
1451 if (ret
) return sock_errno_to_status( errno
);
1454 io
->Status
= STATUS_SUCCESS
;
1455 io
->Information
= len
;
1457 return STATUS_SUCCESS
;
1461 static NTSTATUS
do_setsockopt( HANDLE handle
, IO_STATUS_BLOCK
*io
, int level
,
1462 int option
, const void *optval
, socklen_t optlen
)
1464 int fd
, needs_close
= FALSE
;
1468 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1471 ret
= setsockopt( fd
, level
, option
, optval
, optlen
);
1472 if (needs_close
) close( fd
);
1473 if (ret
) return sock_errno_to_status( errno
);
1474 if (io
) io
->Status
= STATUS_SUCCESS
;
1475 return STATUS_SUCCESS
;
1479 static int get_sock_type( HANDLE handle
)
1482 if (do_getsockopt( handle
, NULL
, SOL_SOCKET
, SO_TYPE
, &sock_type
, sizeof(sock_type
) ) != STATUS_SUCCESS
)
1488 NTSTATUS
sock_ioctl( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc
, void *apc_user
, IO_STATUS_BLOCK
*io
,
1489 UINT code
, void *in_buffer
, UINT in_size
, void *out_buffer
, UINT out_size
)
1491 int fd
, needs_close
= FALSE
;
1494 TRACE( "handle %p, code %#x, in_buffer %p, in_size %u, out_buffer %p, out_size %u\n",
1495 handle
, code
, in_buffer
, in_size
, out_buffer
, out_size
);
1499 case IOCTL_AFD_BIND
:
1501 const struct afd_bind_params
*params
= in_buffer
;
1503 if (params
->unknown
) FIXME( "bind: got unknown %#x\n", params
->unknown
);
1505 status
= STATUS_BAD_DEVICE_TYPE
;
1509 case IOCTL_AFD_GETSOCKNAME
:
1510 if (in_size
) FIXME( "unexpected input size %u\n", in_size
);
1512 status
= STATUS_BAD_DEVICE_TYPE
;
1515 case IOCTL_AFD_LISTEN
:
1517 const struct afd_listen_params
*params
= in_buffer
;
1519 TRACE( "backlog %u\n", params
->backlog
);
1520 if (out_size
) FIXME( "unexpected output size %u\n", out_size
);
1521 if (params
->unknown1
) FIXME( "listen: got unknown1 %#x\n", params
->unknown1
);
1522 if (params
->unknown2
) FIXME( "listen: got unknown2 %#x\n", params
->unknown2
);
1524 status
= STATUS_BAD_DEVICE_TYPE
;
1528 case IOCTL_AFD_EVENT_SELECT
:
1530 const struct afd_event_select_params
*params
= in_buffer
;
1532 TRACE( "event %p, mask %#x\n", params
->event
, params
->mask
);
1533 if (out_size
) FIXME( "unexpected output size %u\n", out_size
);
1535 status
= STATUS_BAD_DEVICE_TYPE
;
1539 case IOCTL_AFD_GET_EVENTS
:
1540 if (in_size
) FIXME( "unexpected input size %u\n", in_size
);
1542 status
= STATUS_BAD_DEVICE_TYPE
;
1545 case IOCTL_AFD_POLL
:
1546 status
= STATUS_BAD_DEVICE_TYPE
;
1549 case IOCTL_AFD_RECV
:
1551 struct afd_recv_params params
;
1554 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1557 if (out_size
) FIXME( "unexpected output size %u\n", out_size
);
1559 if (in_wow64_call())
1561 const struct afd_recv_params_32
*params32
= in_buffer
;
1563 if (in_size
< sizeof(struct afd_recv_params_32
))
1565 status
= STATUS_INVALID_PARAMETER
;
1569 params
.recv_flags
= params32
->recv_flags
;
1570 params
.msg_flags
= params32
->msg_flags
;
1571 params
.buffers
= ULongToPtr( params32
->buffers
);
1572 params
.count
= params32
->count
;
1576 if (in_size
< sizeof(struct afd_recv_params
))
1578 status
= STATUS_INVALID_PARAMETER
;
1582 memcpy( ¶ms
, in_buffer
, sizeof(params
) );
1585 if ((params
.msg_flags
& (AFD_MSG_NOT_OOB
| AFD_MSG_OOB
)) == 0 ||
1586 (params
.msg_flags
& (AFD_MSG_NOT_OOB
| AFD_MSG_OOB
)) == (AFD_MSG_NOT_OOB
| AFD_MSG_OOB
))
1588 status
= STATUS_INVALID_PARAMETER
;
1592 if (params
.msg_flags
& ~(AFD_MSG_NOT_OOB
| AFD_MSG_OOB
| AFD_MSG_PEEK
| AFD_MSG_WAITALL
))
1593 FIXME( "unknown msg_flags %#x\n", params
.msg_flags
);
1594 if (params
.recv_flags
& ~AFD_RECV_FORCE_ASYNC
)
1595 FIXME( "unknown recv_flags %#x\n", params
.recv_flags
);
1597 if (params
.msg_flags
& AFD_MSG_OOB
)
1598 unix_flags
|= MSG_OOB
;
1599 if (params
.msg_flags
& AFD_MSG_PEEK
)
1600 unix_flags
|= MSG_PEEK
;
1601 if (params
.msg_flags
& AFD_MSG_WAITALL
)
1602 FIXME( "MSG_WAITALL is not supported\n" );
1603 status
= sock_ioctl_recv( handle
, event
, apc
, apc_user
, io
, fd
, params
.buffers
, params
.count
, NULL
,
1604 NULL
, NULL
, NULL
, unix_flags
, !!(params
.recv_flags
& AFD_RECV_FORCE_ASYNC
) );
1605 if (needs_close
) close( fd
);
1609 case IOCTL_AFD_WINE_RECVMSG
:
1611 struct afd_recvmsg_params
*params
= in_buffer
;
1612 unsigned int *ws_flags
= u64_to_user_ptr(params
->ws_flags_ptr
);
1615 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1618 if (in_size
< sizeof(*params
))
1620 status
= STATUS_BUFFER_TOO_SMALL
;
1624 if (*ws_flags
& WS_MSG_OOB
)
1625 unix_flags
|= MSG_OOB
;
1626 if (*ws_flags
& WS_MSG_PEEK
)
1627 unix_flags
|= MSG_PEEK
;
1628 if (*ws_flags
& WS_MSG_WAITALL
)
1629 FIXME( "MSG_WAITALL is not supported\n" );
1630 status
= sock_ioctl_recv( handle
, event
, apc
, apc_user
, io
, fd
, u64_to_user_ptr(params
->buffers_ptr
),
1631 params
->count
, u64_to_user_ptr(params
->control_ptr
),
1632 u64_to_user_ptr(params
->addr_ptr
), u64_to_user_ptr(params
->addr_len_ptr
),
1633 ws_flags
, unix_flags
, params
->force_async
);
1634 if (needs_close
) close( fd
);
1638 case IOCTL_AFD_WINE_SENDMSG
:
1640 const struct afd_sendmsg_params
*params
= in_buffer
;
1643 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1646 if (in_size
< sizeof(*params
))
1648 status
= STATUS_BUFFER_TOO_SMALL
;
1652 if (params
->ws_flags
& WS_MSG_OOB
)
1653 unix_flags
|= MSG_OOB
;
1654 if (params
->ws_flags
& WS_MSG_PARTIAL
)
1655 WARN( "ignoring MSG_PARTIAL\n" );
1656 if (params
->ws_flags
& ~(WS_MSG_OOB
| WS_MSG_PARTIAL
))
1657 FIXME( "unknown flags %#x\n", params
->ws_flags
);
1658 status
= sock_ioctl_send( handle
, event
, apc
, apc_user
, io
, fd
, u64_to_user_ptr( params
->buffers_ptr
),
1659 params
->count
, u64_to_user_ptr( params
->addr_ptr
), params
->addr_len
,
1660 unix_flags
, params
->force_async
);
1661 if (needs_close
) close( fd
);
1665 case IOCTL_AFD_WINE_TRANSMIT
:
1667 const struct afd_transmit_params
*params
= in_buffer
;
1669 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1672 if (in_size
< sizeof(*params
))
1674 status
= STATUS_BUFFER_TOO_SMALL
;
1677 status
= sock_transmit( handle
, event
, apc
, apc_user
, io
, fd
, params
);
1678 if (needs_close
) close( fd
);
1682 case IOCTL_AFD_WINE_COMPLETE_ASYNC
:
1684 if (in_size
!= sizeof(NTSTATUS
))
1685 return STATUS_BUFFER_TOO_SMALL
;
1687 status
= *(NTSTATUS
*)in_buffer
;
1688 complete_async( handle
, event
, apc
, apc_user
, io
, status
, 0 );
1692 case IOCTL_AFD_WINE_FIONREAD
:
1696 if (out_size
< sizeof(int))
1698 status
= STATUS_BUFFER_TOO_SMALL
;
1702 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1707 socklen_t len
= sizeof(value
);
1709 /* FIONREAD on a listening socket always fails (see tcp(7)). */
1710 if (!getsockopt( fd
, SOL_SOCKET
, SO_ACCEPTCONN
, &value
, &len
) && value
)
1712 *(int *)out_buffer
= 0;
1713 if (needs_close
) close( fd
);
1714 complete_async( handle
, event
, apc
, apc_user
, io
, STATUS_SUCCESS
, 0 );
1715 return STATUS_SUCCESS
;
1720 if ((ret
= ioctl( fd
, FIONREAD
, &value
)) < 0)
1722 status
= sock_errno_to_status( errno
);
1725 *(int *)out_buffer
= value
;
1726 if (needs_close
) close( fd
);
1727 complete_async( handle
, event
, apc
, apc_user
, io
, STATUS_SUCCESS
, 0 );
1728 return STATUS_SUCCESS
;
1731 case IOCTL_AFD_WINE_SIOCATMARK
:
1734 socklen_t len
= sizeof(value
);
1736 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1739 if (out_size
< sizeof(int))
1741 status
= STATUS_BUFFER_TOO_SMALL
;
1745 if (getsockopt( fd
, SOL_SOCKET
, SO_OOBINLINE
, &value
, &len
) < 0)
1747 status
= sock_errno_to_status( errno
);
1753 *(int *)out_buffer
= TRUE
;
1757 if ((ret
= ioctl( fd
, SIOCATMARK
, &value
)) < 0)
1759 status
= sock_errno_to_status( errno
);
1762 /* windows is reversed with respect to unix */
1763 *(int *)out_buffer
= !value
;
1765 if (needs_close
) close( fd
);
1766 complete_async( handle
, event
, apc
, apc_user
, io
, STATUS_SUCCESS
, 0 );
1767 return STATUS_SUCCESS
;
1770 case IOCTL_AFD_WINE_GET_INTERFACE_LIST
:
1772 #ifdef HAVE_GETIFADDRS
1773 INTERFACE_INFO
*info
= out_buffer
;
1774 struct ifaddrs
*ifaddrs
, *ifaddr
;
1775 unsigned int count
= 0;
1778 if (getifaddrs( &ifaddrs
) < 0)
1780 status
= sock_errno_to_status( errno
);
1784 for (ifaddr
= ifaddrs
; ifaddr
!= NULL
; ifaddr
= ifaddr
->ifa_next
)
1786 if (ifaddr
->ifa_addr
&& ifaddr
->ifa_addr
->sa_family
== AF_INET
) ++count
;
1789 ret_size
= count
* sizeof(*info
);
1790 if (out_size
< ret_size
)
1792 freeifaddrs( ifaddrs
);
1793 complete_async( handle
, event
, apc
, apc_user
, io
, STATUS_BUFFER_TOO_SMALL
, 0 );
1794 return STATUS_PENDING
;
1797 memset( out_buffer
, 0, ret_size
);
1800 for (ifaddr
= ifaddrs
; ifaddr
!= NULL
; ifaddr
= ifaddr
->ifa_next
)
1802 in_addr_t addr
, mask
;
1804 if (!ifaddr
->ifa_addr
|| ifaddr
->ifa_addr
->sa_family
!= AF_INET
)
1807 addr
= ((const struct sockaddr_in
*)ifaddr
->ifa_addr
)->sin_addr
.s_addr
;
1808 mask
= ((const struct sockaddr_in
*)ifaddr
->ifa_netmask
)->sin_addr
.s_addr
;
1810 info
[count
].iiFlags
= 0;
1811 if (ifaddr
->ifa_flags
& IFF_BROADCAST
)
1812 info
[count
].iiFlags
|= WS_IFF_BROADCAST
;
1813 if (ifaddr
->ifa_flags
& IFF_LOOPBACK
)
1814 info
[count
].iiFlags
|= WS_IFF_LOOPBACK
;
1815 if (ifaddr
->ifa_flags
& IFF_MULTICAST
)
1816 info
[count
].iiFlags
|= WS_IFF_MULTICAST
;
1817 #ifdef IFF_POINTTOPOINT
1818 if (ifaddr
->ifa_flags
& IFF_POINTTOPOINT
)
1819 info
[count
].iiFlags
|= WS_IFF_POINTTOPOINT
;
1821 if (ifaddr
->ifa_flags
& IFF_UP
)
1822 info
[count
].iiFlags
|= WS_IFF_UP
;
1824 info
[count
].iiAddress
.AddressIn
.sin_family
= WS_AF_INET
;
1825 info
[count
].iiAddress
.AddressIn
.sin_port
= 0;
1826 info
[count
].iiAddress
.AddressIn
.sin_addr
.WS_s_addr
= addr
;
1828 info
[count
].iiNetmask
.AddressIn
.sin_family
= WS_AF_INET
;
1829 info
[count
].iiNetmask
.AddressIn
.sin_port
= 0;
1830 info
[count
].iiNetmask
.AddressIn
.sin_addr
.WS_s_addr
= mask
;
1832 if (ifaddr
->ifa_flags
& IFF_BROADCAST
)
1834 info
[count
].iiBroadcastAddress
.AddressIn
.sin_family
= WS_AF_INET
;
1835 info
[count
].iiBroadcastAddress
.AddressIn
.sin_port
= 0;
1836 info
[count
].iiBroadcastAddress
.AddressIn
.sin_addr
.WS_s_addr
= addr
| ~mask
;
1842 freeifaddrs( ifaddrs
);
1843 complete_async( handle
, event
, apc
, apc_user
, io
, STATUS_SUCCESS
, ret_size
);
1844 return STATUS_PENDING
;
1846 FIXME( "Interface list queries are currently not supported on this platform.\n" );
1847 status
= STATUS_NOT_SUPPORTED
;
1852 case IOCTL_AFD_WINE_KEEPALIVE_VALS
:
1854 struct tcp_keepalive
*k
= in_buffer
;
1857 if (!in_buffer
|| in_size
< sizeof(struct tcp_keepalive
))
1858 return STATUS_BUFFER_TOO_SMALL
;
1859 keepalive
= !!k
->onoff
;
1861 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1864 if (setsockopt( fd
, SOL_SOCKET
, SO_KEEPALIVE
, &keepalive
, sizeof(int) ) < 0)
1866 status
= STATUS_INVALID_PARAMETER
;
1873 int idle
= max( 1, (k
->keepalivetime
+ 500) / 1000 );
1875 if (setsockopt( fd
, IPPROTO_TCP
, TCP_KEEPIDLE
, &idle
, sizeof(int) ) < 0)
1877 status
= STATUS_INVALID_PARAMETER
;
1881 FIXME("ignoring keepalive timeout\n");
1887 #ifdef TCP_KEEPINTVL
1888 int interval
= max( 1, (k
->keepaliveinterval
+ 500) / 1000 );
1890 if (setsockopt( fd
, IPPROTO_TCP
, TCP_KEEPINTVL
, &interval
, sizeof(int) ) < 0)
1891 status
= STATUS_INVALID_PARAMETER
;
1893 FIXME("ignoring keepalive interval\n");
1897 if (needs_close
) close( fd
);
1898 complete_async( handle
, event
, apc
, apc_user
, io
, STATUS_SUCCESS
, 0 );
1899 return STATUS_SUCCESS
;
1902 case IOCTL_AFD_WINE_GETPEERNAME
:
1904 union unix_sockaddr unix_addr
;
1905 socklen_t unix_len
= sizeof(unix_addr
);
1908 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1911 if (getpeername( fd
, &unix_addr
.addr
, &unix_len
) < 0)
1913 status
= sock_errno_to_status( errno
);
1917 len
= sockaddr_from_unix( &unix_addr
, out_buffer
, out_size
);
1920 status
= STATUS_BUFFER_TOO_SMALL
;
1923 io
->Information
= len
;
1924 status
= STATUS_SUCCESS
;
1928 case IOCTL_AFD_WINE_GET_SO_BROADCAST
:
1929 return do_getsockopt( handle
, io
, SOL_SOCKET
, SO_BROADCAST
, out_buffer
, out_size
);
1931 case IOCTL_AFD_WINE_SET_SO_BROADCAST
:
1932 return do_setsockopt( handle
, io
, SOL_SOCKET
, SO_BROADCAST
, in_buffer
, in_size
);
1934 case IOCTL_AFD_WINE_GET_SO_KEEPALIVE
:
1935 return do_getsockopt( handle
, io
, SOL_SOCKET
, SO_KEEPALIVE
, out_buffer
, out_size
);
1937 case IOCTL_AFD_WINE_SET_SO_KEEPALIVE
:
1938 return do_setsockopt( handle
, io
, SOL_SOCKET
, SO_KEEPALIVE
, in_buffer
, in_size
);
1940 case IOCTL_AFD_WINE_GET_SO_LINGER
:
1942 struct WS_linger
*ws_linger
= out_buffer
;
1943 struct linger unix_linger
;
1944 socklen_t len
= sizeof(unix_linger
);
1947 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1950 ret
= getsockopt( fd
, SOL_SOCKET
, SO_LINGER
, &unix_linger
, &len
);
1953 ws_linger
->l_onoff
= unix_linger
.l_onoff
;
1954 ws_linger
->l_linger
= unix_linger
.l_linger
;
1955 io
->Information
= sizeof(*ws_linger
);
1958 status
= ret
? sock_errno_to_status( errno
) : STATUS_SUCCESS
;
1962 case IOCTL_AFD_WINE_SET_SO_LINGER
:
1964 const struct WS_linger
*ws_linger
= in_buffer
;
1965 struct linger unix_linger
;
1967 unix_linger
.l_onoff
= ws_linger
->l_onoff
;
1968 unix_linger
.l_linger
= ws_linger
->l_linger
;
1970 return do_setsockopt( handle
, io
, SOL_SOCKET
, SO_LINGER
, &unix_linger
, sizeof(unix_linger
) );
1973 case IOCTL_AFD_WINE_GET_SO_OOBINLINE
:
1974 return do_getsockopt( handle
, io
, SOL_SOCKET
, SO_OOBINLINE
, out_buffer
, out_size
);
1976 case IOCTL_AFD_WINE_SET_SO_OOBINLINE
:
1977 return do_setsockopt( handle
, io
, SOL_SOCKET
, SO_OOBINLINE
, in_buffer
, in_size
);
1979 case IOCTL_AFD_WINE_SET_IP_ADD_MEMBERSHIP
:
1980 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, in_buffer
, in_size
);
1982 case IOCTL_AFD_WINE_SET_IP_ADD_SOURCE_MEMBERSHIP
:
1983 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_ADD_SOURCE_MEMBERSHIP
, in_buffer
, in_size
);
1985 case IOCTL_AFD_WINE_SET_IP_BLOCK_SOURCE
:
1986 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_BLOCK_SOURCE
, in_buffer
, in_size
);
1988 case IOCTL_AFD_WINE_GET_IP_DONTFRAGMENT
:
1990 socklen_t len
= out_size
;
1993 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
1997 ret
= getsockopt( fd
, IPPROTO_IP
, IP_DONTFRAG
, out_buffer
, &len
);
1998 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2002 len
= sizeof(value
);
2003 ret
= getsockopt( fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &value
, &len
);
2004 if (!ret
) *(DWORD
*)out_buffer
= (value
!= IP_PMTUDISC_DONT
);
2011 FIXME( "IP_DONTFRAGMENT is not supported on this platform\n" );
2012 ret
= 0; /* fake success */
2017 status
= sock_errno_to_status( errno
);
2021 io
->Information
= len
;
2022 status
= STATUS_SUCCESS
;
2027 case IOCTL_AFD_WINE_SET_IP_DONTFRAGMENT
:
2029 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_DONTFRAG
, in_buffer
, in_size
);
2030 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) && defined(IP_PMTUDISC_DONT)
2032 int value
= *(DWORD
*)in_buffer
? IP_PMTUDISC_DO
: IP_PMTUDISC_DONT
;
2034 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_MTU_DISCOVER
, &value
, sizeof(value
) );
2041 FIXME( "IP_DONTFRAGMENT is not supported on this platform\n" );
2042 status
= STATUS_SUCCESS
; /* fake success */
2047 case IOCTL_AFD_WINE_SET_IP_DROP_MEMBERSHIP
:
2048 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, in_buffer
, in_size
);
2050 case IOCTL_AFD_WINE_SET_IP_DROP_SOURCE_MEMBERSHIP
:
2051 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_DROP_SOURCE_MEMBERSHIP
, in_buffer
, in_size
);
2054 case IOCTL_AFD_WINE_GET_IP_HDRINCL
:
2055 if (get_sock_type( handle
) != SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2056 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_HDRINCL
, out_buffer
, out_size
);
2058 case IOCTL_AFD_WINE_SET_IP_HDRINCL
:
2059 if (get_sock_type( handle
) != SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2060 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_HDRINCL
, in_buffer
, in_size
);
2063 case IOCTL_AFD_WINE_GET_IP_MULTICAST_IF
:
2065 int sock_type
= get_sock_type( handle
);
2066 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2067 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_MULTICAST_IF
, out_buffer
, out_size
);
2070 case IOCTL_AFD_WINE_SET_IP_MULTICAST_IF
:
2072 int sock_type
= get_sock_type( handle
);
2073 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2074 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_MULTICAST_IF
, in_buffer
, in_size
);
2077 case IOCTL_AFD_WINE_GET_IP_MULTICAST_LOOP
:
2079 int sock_type
= get_sock_type( handle
);
2080 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2081 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_MULTICAST_LOOP
, out_buffer
, out_size
);
2084 case IOCTL_AFD_WINE_SET_IP_MULTICAST_LOOP
:
2086 int sock_type
= get_sock_type( handle
);
2087 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2088 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_MULTICAST_LOOP
, in_buffer
, in_size
);
2091 case IOCTL_AFD_WINE_GET_IP_MULTICAST_TTL
:
2093 int sock_type
= get_sock_type( handle
);
2094 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2095 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_MULTICAST_TTL
, out_buffer
, out_size
);
2098 case IOCTL_AFD_WINE_SET_IP_MULTICAST_TTL
:
2100 int sock_type
= get_sock_type( handle
);
2101 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2102 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_MULTICAST_TTL
, in_buffer
, in_size
);
2105 case IOCTL_AFD_WINE_GET_IP_OPTIONS
:
2106 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_OPTIONS
, out_buffer
, out_size
);
2108 case IOCTL_AFD_WINE_SET_IP_OPTIONS
:
2109 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_OPTIONS
, in_buffer
, in_size
);
2112 case IOCTL_AFD_WINE_GET_IP_PKTINFO
:
2114 int sock_type
= get_sock_type( handle
);
2115 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2116 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_PKTINFO
, out_buffer
, out_size
);
2119 case IOCTL_AFD_WINE_SET_IP_PKTINFO
:
2121 int sock_type
= get_sock_type( handle
);
2122 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2123 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_PKTINFO
, in_buffer
, in_size
);
2125 #elif defined(IP_RECVDSTADDR)
2126 case IOCTL_AFD_WINE_GET_IP_PKTINFO
:
2128 int sock_type
= get_sock_type( handle
);
2129 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2130 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_RECVDSTADDR
, out_buffer
, out_size
);
2133 case IOCTL_AFD_WINE_SET_IP_PKTINFO
:
2135 int sock_type
= get_sock_type( handle
);
2136 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2137 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_RECVDSTADDR
, in_buffer
, in_size
);
2142 case IOCTL_AFD_WINE_GET_IP_RECVTOS
:
2144 int sock_type
= get_sock_type( handle
);
2145 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2146 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_RECVTOS
, out_buffer
, out_size
);
2149 case IOCTL_AFD_WINE_SET_IP_RECVTOS
:
2151 int sock_type
= get_sock_type( handle
);
2152 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2153 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_RECVTOS
, in_buffer
, in_size
);
2158 case IOCTL_AFD_WINE_GET_IP_RECVTTL
:
2160 int sock_type
= get_sock_type( handle
);
2161 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2162 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_RECVTTL
, out_buffer
, out_size
);
2165 case IOCTL_AFD_WINE_SET_IP_RECVTTL
:
2167 int sock_type
= get_sock_type( handle
);
2168 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2169 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_RECVTTL
, in_buffer
, in_size
);
2173 case IOCTL_AFD_WINE_GET_IP_TOS
:
2174 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_TOS
, out_buffer
, out_size
);
2176 case IOCTL_AFD_WINE_SET_IP_TOS
:
2177 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_TOS
, in_buffer
, in_size
);
2179 case IOCTL_AFD_WINE_GET_IP_TTL
:
2180 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_TTL
, out_buffer
, out_size
);
2182 case IOCTL_AFD_WINE_SET_IP_TTL
:
2183 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_TTL
, in_buffer
, in_size
);
2185 case IOCTL_AFD_WINE_SET_IP_UNBLOCK_SOURCE
:
2186 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_UNBLOCK_SOURCE
, in_buffer
, in_size
);
2188 #ifdef IP_UNICAST_IF
2189 case IOCTL_AFD_WINE_GET_IP_UNICAST_IF
:
2190 return do_getsockopt( handle
, io
, IPPROTO_IP
, IP_UNICAST_IF
, out_buffer
, out_size
);
2192 case IOCTL_AFD_WINE_SET_IP_UNICAST_IF
:
2193 return do_setsockopt( handle
, io
, IPPROTO_IP
, IP_UNICAST_IF
, in_buffer
, in_size
);
2196 #ifdef IPV6_ADD_MEMBERSHIP
2197 case IOCTL_AFD_WINE_SET_IPV6_ADD_MEMBERSHIP
:
2198 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, in_buffer
, in_size
);
2201 case IOCTL_AFD_WINE_GET_IPV6_DONTFRAG
:
2203 socklen_t len
= out_size
;
2206 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
2209 #ifdef IPV6_DONTFRAG
2210 ret
= getsockopt( fd
, IPPROTO_IPV6
, IPV6_DONTFRAG
, out_buffer
, &len
);
2211 #elif defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT)
2215 len
= sizeof(value
);
2216 ret
= getsockopt( fd
, IPPROTO_IPV6
, IPV6_MTU_DISCOVER
, &value
, &len
);
2217 if (!ret
) *(DWORD
*)out_buffer
= (value
!= IPV6_PMTUDISC_DONT
);
2224 FIXME( "IPV6_DONTFRAGMENT is not supported on this platform\n" );
2225 ret
= 0; /* fake success */
2230 status
= sock_errno_to_status( errno
);
2234 io
->Information
= len
;
2235 status
= STATUS_SUCCESS
;
2240 case IOCTL_AFD_WINE_SET_IPV6_DONTFRAG
:
2241 #ifdef IPV6_DONTFRAG
2242 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_DONTFRAG
, in_buffer
, in_size
);
2243 #elif defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) && defined(IPV6_PMTUDISC_DONT)
2245 int value
= *(DWORD
*)in_buffer
? IPV6_PMTUDISC_DO
: IPV6_PMTUDISC_DONT
;
2247 return do_setsockopt( handle
, io
, IPPROTO_IP
, IPV6_MTU_DISCOVER
, &value
, sizeof(value
) );
2254 FIXME( "IPV6_DONTFRAGMENT is not supported on this platform\n" );
2255 return STATUS_SUCCESS
; /* fake success */
2259 #ifdef IPV6_DROP_MEMBERSHIP
2260 case IOCTL_AFD_WINE_SET_IPV6_DROP_MEMBERSHIP
:
2261 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_DROP_MEMBERSHIP
, in_buffer
, in_size
);
2264 case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_HOPS
:
2266 int sock_type
= get_sock_type( handle
);
2267 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2268 return do_getsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, out_buffer
, out_size
);
2271 case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_HOPS
:
2273 int sock_type
= get_sock_type( handle
);
2274 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2275 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, in_buffer
, in_size
);
2278 case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_IF
:
2280 int sock_type
= get_sock_type( handle
);
2281 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2282 return do_getsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, out_buffer
, out_size
);
2285 case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_IF
:
2287 int sock_type
= get_sock_type( handle
);
2288 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2289 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, in_buffer
, in_size
);
2292 case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_LOOP
:
2294 int sock_type
= get_sock_type( handle
);
2295 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2296 return do_getsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, out_buffer
, out_size
);
2299 case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_LOOP
:
2301 int sock_type
= get_sock_type( handle
);
2302 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2303 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, in_buffer
, in_size
);
2306 #ifdef IPV6_RECVHOPLIMIT
2307 case IOCTL_AFD_WINE_GET_IPV6_RECVHOPLIMIT
:
2309 int sock_type
= get_sock_type( handle
);
2310 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2311 return do_getsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, out_buffer
, out_size
);
2314 case IOCTL_AFD_WINE_SET_IPV6_RECVHOPLIMIT
:
2316 int sock_type
= get_sock_type( handle
);
2317 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2318 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, in_buffer
, in_size
);
2322 #ifdef IPV6_RECVPKTINFO
2323 case IOCTL_AFD_WINE_GET_IPV6_RECVPKTINFO
:
2325 int sock_type
= get_sock_type( handle
);
2326 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2327 return do_getsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, out_buffer
, out_size
);
2330 case IOCTL_AFD_WINE_SET_IPV6_RECVPKTINFO
:
2332 int sock_type
= get_sock_type( handle
);
2333 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2334 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, in_buffer
, in_size
);
2338 #ifdef IPV6_RECVTCLASS
2339 case IOCTL_AFD_WINE_GET_IPV6_RECVTCLASS
:
2341 int sock_type
= get_sock_type( handle
);
2342 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2343 return do_getsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_RECVTCLASS
, out_buffer
, out_size
);
2346 case IOCTL_AFD_WINE_SET_IPV6_RECVTCLASS
:
2348 int sock_type
= get_sock_type( handle
);
2349 if (sock_type
!= SOCK_DGRAM
&& sock_type
!= SOCK_RAW
) return STATUS_INVALID_PARAMETER
;
2350 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_RECVTCLASS
, in_buffer
, in_size
);
2354 case IOCTL_AFD_WINE_GET_IPV6_UNICAST_HOPS
:
2355 return do_getsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, out_buffer
, out_size
);
2357 case IOCTL_AFD_WINE_SET_IPV6_UNICAST_HOPS
:
2358 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, in_buffer
, in_size
);
2360 #ifdef IPV6_UNICAST_IF
2361 case IOCTL_AFD_WINE_GET_IPV6_UNICAST_IF
:
2362 return do_getsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_UNICAST_IF
, out_buffer
, out_size
);
2364 case IOCTL_AFD_WINE_SET_IPV6_UNICAST_IF
:
2365 return do_setsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_UNICAST_IF
, in_buffer
, in_size
);
2368 case IOCTL_AFD_WINE_GET_IPV6_V6ONLY
:
2369 return do_getsockopt( handle
, io
, IPPROTO_IPV6
, IPV6_V6ONLY
, out_buffer
, out_size
);
2371 case IOCTL_AFD_WINE_SET_IPV6_V6ONLY
:
2373 union unix_sockaddr addr
;
2374 socklen_t len
= sizeof(addr
);
2377 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
2380 if (!getsockname( fd
, &addr
.addr
, &len
) && addr
.addr
.sa_family
== AF_INET
&& !addr
.in
.sin_port
)
2382 /* changing IPV6_V6ONLY succeeds on an unbound IPv4 socket */
2383 WARN( "ignoring IPV6_V6ONLY on an unbound IPv4 socket\n" );
2384 status
= STATUS_SUCCESS
;
2388 ret
= setsockopt( fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, in_buffer
, in_size
);
2389 status
= ret
? sock_errno_to_status( errno
) : STATUS_SUCCESS
;
2394 case IOCTL_AFD_WINE_GET_IPX_PTYPE
:
2395 return do_getsockopt( handle
, io
, SOL_IPX
, IPX_TYPE
, out_buffer
, out_size
);
2397 case IOCTL_AFD_WINE_SET_IPX_PTYPE
:
2398 return do_setsockopt( handle
, io
, SOL_IPX
, IPX_TYPE
, in_buffer
, in_size
);
2399 #elif defined(SO_DEFAULT_HEADERS)
2400 case IOCTL_AFD_WINE_GET_IPX_PTYPE
:
2403 socklen_t len
= sizeof(value
);
2406 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
2409 ret
= getsockopt( fd
, 0, SO_DEFAULT_HEADERS
, &value
, &len
);
2412 status
= sock_errno_to_status( errno
);
2416 *(DWORD
*)out_buffer
= value
.ipx_pt
;
2417 status
= STATUS_SUCCESS
;
2422 case IOCTL_AFD_WINE_SET_IPX_PTYPE
:
2424 struct ipx value
= {0};
2426 /* FIXME: should we retrieve SO_DEFAULT_HEADERS first and modify it? */
2427 value
.ipx_pt
= *(DWORD
*)in_buffer
;
2428 return do_setsockopt( handle
, io
, 0, SO_DEFAULT_HEADERS
, &value
, sizeof(value
) );
2433 #define MAX_IRDA_DEVICES 10
2434 case IOCTL_AFD_WINE_GET_IRLMP_ENUMDEVICES
:
2436 char buffer
[offsetof( struct irda_device_list
, dev
[MAX_IRDA_DEVICES
] )];
2437 struct irda_device_list
*unix_list
= (struct irda_device_list
*)buffer
;
2438 socklen_t len
= sizeof(buffer
);
2439 DEVICELIST
*ws_list
= out_buffer
;
2440 int fd
, needs_close
= FALSE
;
2444 if ((status
= server_get_unix_fd( handle
, 0, &fd
, &needs_close
, NULL
, NULL
)))
2447 ret
= getsockopt( fd
, SOL_IRLMP
, IRLMP_ENUMDEVICES
, buffer
, &len
);
2448 if (needs_close
) close( fd
);
2449 if (ret
) return sock_errno_to_status( errno
);
2451 io
->Information
= offsetof( DEVICELIST
, Device
[unix_list
->len
] );
2452 if (out_size
< io
->Information
)
2453 return STATUS_BUFFER_TOO_SMALL
;
2455 TRACE( "IRLMP_ENUMDEVICES: got %u devices:\n", unix_list
->len
);
2456 ws_list
->numDevice
= unix_list
->len
;
2457 for (i
= 0; i
< unix_list
->len
; ++i
)
2459 const struct irda_device_info
*unix_dev
= &unix_list
->dev
[i
];
2460 IRDA_DEVICE_INFO
*ws_dev
= &ws_list
->Device
[i
];
2462 TRACE( "saddr %#08x, daddr %#08x, info %s, hints 0x%02x%02x\n",
2463 unix_dev
->saddr
, unix_dev
->daddr
, unix_dev
->info
, unix_dev
->hints
[0], unix_dev
->hints
[1] );
2464 memcpy( ws_dev
->irdaDeviceID
, &unix_dev
->daddr
, sizeof(unix_dev
->daddr
) );
2465 memcpy( ws_dev
->irdaDeviceName
, unix_dev
->info
, sizeof(unix_dev
->info
) );
2466 ws_dev
->irdaDeviceHints1
= unix_dev
->hints
[0];
2467 ws_dev
->irdaDeviceHints2
= unix_dev
->hints
[1];
2468 ws_dev
->irdaCharSet
= unix_dev
->charset
;
2470 status
= STATUS_SUCCESS
;
2475 case IOCTL_AFD_WINE_GET_TCP_NODELAY
:
2476 return do_getsockopt( handle
, io
, IPPROTO_TCP
, TCP_NODELAY
, out_buffer
, out_size
);
2478 case IOCTL_AFD_WINE_SET_TCP_NODELAY
:
2479 return do_setsockopt( handle
, io
, IPPROTO_TCP
, TCP_NODELAY
, in_buffer
, in_size
);
2483 if ((code
>> 16) == FILE_DEVICE_NETWORK
)
2485 /* Wine-internal ioctl */
2486 status
= STATUS_BAD_DEVICE_TYPE
;
2490 FIXME( "Unknown ioctl %#x (device %#x, access %#x, function %#x, method %#x)\n",
2491 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3 );
2492 status
= STATUS_INVALID_DEVICE_REQUEST
;
2498 if (needs_close
) close( fd
);
2500 if (status
!= STATUS_PENDING
&& !NT_ERROR(status
)) io
->Status
= status
;