[PATCH 6/6] ws2_32: Move the setsockopt(IPV6_V6ONLY) implementation to ntdll.

Zebediah Figura zfigura at codeweavers.com
Fri Jul 30 00:00:47 CDT 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/ntdll/unix/socket.c | 23 +++++++++++++
 dlls/ws2_32/socket.c     | 73 +---------------------------------------
 include/wine/afd.h       |  1 +
 3 files changed, 25 insertions(+), 72 deletions(-)

diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c
index bda23d0b9b1..24090c1a17b 100644
--- a/dlls/ntdll/unix/socket.c
+++ b/dlls/ntdll/unix/socket.c
@@ -1899,6 +1899,29 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
         case IOCTL_AFD_WINE_GET_IPV6_V6ONLY:
             return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_V6ONLY, out_buffer, out_size );
 
+        case IOCTL_AFD_WINE_SET_IPV6_V6ONLY:
+        {
+            int fd, needs_close = FALSE;
+            union unix_sockaddr addr;
+            socklen_t len = sizeof(addr);
+            NTSTATUS status;
+            int ret;
+
+            if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
+                return status;
+
+            if (!getsockname( fd, &addr.addr, &len ) && addr.addr.sa_family == AF_INET && !addr.in.sin_port)
+            {
+                /* changing IPV6_V6ONLY succeeds on an unbound IPv4 socket */
+                WARN( "ignoring IPV6_V6ONLY on an unbound IPv4 socket\n" );
+                return STATUS_SUCCESS;
+            }
+
+            ret = setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, in_buffer, in_size );
+            if (needs_close) close( fd );
+            return ret ? sock_errno_to_status( errno ) : STATUS_SUCCESS;
+        }
+
         default:
         {
             if ((code >> 16) == FILE_DEVICE_NETWORK)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 30faad3a546..a28c25ec697 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -1081,56 +1081,6 @@ unsigned int ws_sockaddr_ws2u( const struct WS_sockaddr *wsaddr, int wsaddrlen,
     return uaddrlen;
 }
 
-static BOOL is_sockaddr_bound(const struct sockaddr *uaddr, int uaddrlen)
-{
-    switch (uaddr->sa_family)
-    {
-#ifdef HAS_IPX
-        case AF_IPX:
-        {
-            static const struct sockaddr_ipx emptyAddr;
-            struct sockaddr_ipx *ipx = (struct sockaddr_ipx*) uaddr;
-            return ipx->sipx_port
-            || memcmp(&ipx->sipx_network, &emptyAddr.sipx_network, sizeof(emptyAddr.sipx_network))
-            || memcmp(&ipx->sipx_node, &emptyAddr.sipx_node, sizeof(emptyAddr.sipx_node));
-        }
-#endif
-        case AF_INET6:
-        {
-            static const struct sockaddr_in6 emptyAddr;
-            const struct sockaddr_in6 *in6 = (const struct sockaddr_in6*) uaddr;
-            return in6->sin6_port || memcmp(&in6->sin6_addr, &emptyAddr.sin6_addr, sizeof(struct in6_addr));
-        }
-        case AF_INET:
-        {
-            static const struct sockaddr_in emptyAddr;
-            const struct sockaddr_in *in = (const struct sockaddr_in*) uaddr;
-            return in->sin_port || memcmp(&in->sin_addr, &emptyAddr.sin_addr, sizeof(struct in_addr));
-        }
-        case AF_UNSPEC:
-            return FALSE;
-        default:
-            FIXME("unknown address family %d\n", uaddr->sa_family);
-            return TRUE;
-    }
-}
-
-/* Returns -1 if getsockname fails, 0 if not bound, 1 otherwise */
-static int is_fd_bound(int fd, union generic_unix_sockaddr *uaddr, socklen_t *uaddrlen)
-{
-    union generic_unix_sockaddr inaddr;
-    socklen_t inlen;
-    int res;
-
-    if (!uaddr) uaddr = &inaddr;
-    if (!uaddrlen) uaddrlen = &inlen;
-
-    *uaddrlen = sizeof(inaddr);
-    res = getsockname(fd, &uaddr->addr, uaddrlen);
-    if (!res) res = is_sockaddr_bound(&uaddr->addr, *uaddrlen);
-    return res;
-}
-
 /* Returns 0 if successful, -1 if the buffer is too small */
 int ws_sockaddr_u2ws(const struct sockaddr *uaddr, struct WS_sockaddr *wsaddr, int *wsaddrlen)
 {
@@ -3644,29 +3594,8 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
             return server_setsockopt( s, IOCTL_AFD_WINE_SET_IPV6_UNICAST_IF, optval, optlen );
 
         case WS_IPV6_V6ONLY:
-        {
-            union generic_unix_sockaddr uaddr;
-            socklen_t uaddrlen;
-            int bound;
+            return server_setsockopt( s, IOCTL_AFD_WINE_SET_IPV6_V6ONLY, optval, optlen );
 
-            fd = get_sock_fd( s, 0, NULL );
-            if (fd == -1) return SOCKET_ERROR;
-
-            bound = is_fd_bound(fd, &uaddr, &uaddrlen);
-            release_sock_fd( s, fd );
-            if (bound == 0 && uaddr.addr.sa_family == AF_INET)
-            {
-                /* Changing IPV6_V6ONLY succeeds on AF_INET (IPv4) socket
-                 * on Windows (with IPv6 support) if the socket is unbound.
-                 * It is essentially a noop, though Windows does store the value
-                 */
-                WARN("Silently ignoring IPPROTO_IPV6+IPV6_V6ONLY on AF_INET socket\n");
-                return 0;
-            }
-            level = IPPROTO_IPV6;
-            optname = IPV6_V6ONLY;
-            break;
-        }
         default:
             FIXME("Unknown IPPROTO_IPV6 optname 0x%08x\n", optname);
             return SOCKET_ERROR;
diff --git a/include/wine/afd.h b/include/wine/afd.h
index 47ddd09f1c0..9a1edb1fda6 100644
--- a/include/wine/afd.h
+++ b/include/wine/afd.h
@@ -222,6 +222,7 @@ struct afd_get_events_params
 #define IOCTL_AFD_WINE_GET_IPV6_UNICAST_IF              WINE_AFD_IOC(277)
 #define IOCTL_AFD_WINE_SET_IPV6_UNICAST_IF              WINE_AFD_IOC(278)
 #define IOCTL_AFD_WINE_GET_IPV6_V6ONLY                  WINE_AFD_IOC(279)
+#define IOCTL_AFD_WINE_SET_IPV6_V6ONLY                  WINE_AFD_IOC(280)
 
 struct afd_create_params
 {
-- 
2.30.2




More information about the wine-devel mailing list