[PATCH] ws2_32: Allow user to enable IP dual stack (v4).

Roman Pišl rpisl at seznam.cz
Mon Oct 17 13:21:49 CDT 2016


IP dual stack (v4+v6) should be disabled by default, but previous code
was setting IPV6_V6ONLY in bind() which prevented user to override it.
This patch moves setting IPV6_V6ONLY to socket creation time.

Based on https://www.winehq.org/pipermail/wine-patches/2016-July/151919.html

Signed-off-by: Matthieu Nottale <matthieu.nottale at infinit.io>
Signed-off-by: Roman Pišl <rpisl at seznam.cz>
---
 dlls/ws2_32/socket.c     | 23 +++++++++-------------
 dlls/ws2_32/tests/sock.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index e8c5130..d14e9d6 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -3240,20 +3240,6 @@ int WINAPI WS_bind(SOCKET s, const struct WS_sockaddr* name, int namelen)
             }
             else
             {
-#ifdef IPV6_V6ONLY
-                const struct sockaddr_in6 *in6 = (const struct sockaddr_in6*) &uaddr;
-                if (name->sa_family == WS_AF_INET6 &&
-                    !memcmp(&in6->sin6_addr, &in6addr_any, sizeof(struct in6_addr)))
-                {
-                    int enable = 1;
-                    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(enable)) == -1)
-                    {
-                        release_sock_fd( s, fd );
-                        SetLastError(WSAEAFNOSUPPORT);
-                        return SOCKET_ERROR;
-                    }
-                }
-#endif
                 if (name->sa_family == WS_AF_INET)
                 {
                     struct sockaddr_in *in4 = (struct sockaddr_in*) &uaddr;
@@ -7233,6 +7219,15 @@ SOCKET WINAPI WSASocketW(int af, int type, int protocol,
         TRACE("\tcreated %04lx\n", ret );
         if (ipxptype > 0)
             set_ipx_packettype(ret, ipxptype);
+
+#ifdef IPV6_V6ONLY
+        if (unixaf == AF_INET6)
+        {
+            int enable = 1;
+            int fd = get_sock_fd(ret, 0, NULL);
+            setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(enable));
+        }
+#endif
        return ret;
     }
 
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index a144bd3..a676255 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -1732,7 +1732,7 @@ static void test_so_reuseaddr(void)
     DWORD err;
 
     saddr.sin_family      = AF_INET;
-    saddr.sin_port        = htons(9375);
+    saddr.sin_port        = htons(SERVERPORT+1);
     saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
 
     s1=socket(AF_INET, SOCK_STREAM, 0);
@@ -6110,6 +6110,8 @@ static void test_ipv6only(void)
     struct sockaddr_in sin4;
     struct sockaddr_in6 sin6;
     int ret;
+    int enabled;
+    int len;
 
     memset(&sin4, 0, sizeof(sin4));
     sin4.sin_family = AF_INET;
@@ -6142,6 +6144,50 @@ static void test_ipv6only(void)
     ok(!ret, "Could not bind IPv4 address (LastError: %d; %d expected if IPv6 binds to IPv4 as well).\n",
         WSAGetLastError(), WSAEADDRINUSE);
 
+    closesocket(v4);
+    closesocket(v6);
+    v4 = INVALID_SOCKET;
+    v6 = INVALID_SOCKET;
+
+    /* Test again, this time disabling V6ONLY. */
+    sin4.sin_port = htons(SERVERPORT+2);
+    sin6.sin6_port = htons(SERVERPORT+2);
+
+    v6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+    ok(v6 != INVALID_SOCKET, "Could not create IPv6 socket (LastError: %d; %d expected if IPv6 not available).\n",
+        WSAGetLastError(), WSAEAFNOSUPPORT);
+
+    enabled = 2;
+    len = sizeof(enabled);
+    ret = getsockopt(v6, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&enabled, &len);
+    if (ret) {
+        skip("Could not check IPV6_V6ONLY (option not supported?) ((LastError: %d).\n", WSAGetLastError());
+        goto end;
+    }
+    ok(enabled == 1, "IPV6_V6ONLY is not enabled by default.\n");
+
+    enabled = 0;
+    ret = setsockopt(v6, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&enabled, len);
+    ok(!ret, "Failed to disable IPV6_V6ONLY (LastError: %d).\n", WSAGetLastError());
+
+    ret = bind(v6, (struct sockaddr*)&sin6, sizeof(sin6));
+    ok(!ret, "Could not bind IPv6 address (LastError: %d).\n", WSAGetLastError());
+
+    enabled = 2;
+    len = sizeof(enabled);
+    getsockopt(v6, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&enabled, &len);
+    ok(enabled == 0, "IPV6_V6ONLY is enabled after bind.\n");
+
+    v4 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ok(v4 != INVALID_SOCKET, "Could not create IPv4 socket (LastError: %d).\n",
+        WSAGetLastError());
+
+    WSASetLastError(0xdeadbeef);
+    bind(v4, (struct sockaddr*)&sin4, sizeof(sin4));
+
+    ok(WSAGetLastError() == WSAEADDRINUSE, "Failed to disable IPV6_V6ONLY (LastError: %d; %d expected if IPv6 binds to IPv4 as well).\n",
+        WSAGetLastError(), WSAEADDRINUSE);
+
 end:
     if (v4 != INVALID_SOCKET)
         closesocket(v4);
@@ -8024,7 +8070,7 @@ static void test_TransmitFile(void)
     /* Setup a properly connected socket for transfers */
     memset(&bindAddress, 0, sizeof(bindAddress));
     bindAddress.sin_family = AF_INET;
-    bindAddress.sin_port = htons(9375);
+    bindAddress.sin_port = htons(SERVERPORT+1);
     bindAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
     iret = bind(server, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
     if (iret != 0)
-- 
2.7.3




More information about the wine-patches mailing list