[PATCH] ws2_32/tests: Add more SIO_ADDRESS_LIST_CHANGE tests

Bruno Jesus 00cpxxx at gmail.com
Thu Sep 8 22:28:52 CDT 2016


AFAICS bug https://bugs.winehq.org/show_bug.cgi?id=38062 was only half fixed, returning WSAEWOULDBLOCK is not an error, it is a correct success when WSAIoctl(SIO_ADDRESS_LIST_CHANGE) is called without an overlapped structure.

WSAIoctl(SIO_ADDRESS_LIST_CHANGE, with overlapped struct) = ERROR_IO_PENDING
* results can be read waiting for the hEvent in the overlapped strucutre

WSAIoctl(SIO_ADDRESS_LIST_CHANGE, no overlapped struct) = WSAEWOULDBLOCK
* results can be read waiting in an WSACreateEvent with bit FD_ADDRESS_LIST_CHANGE

Currently, Wine is doing the first item correctly but the second one it is just being reported as an error and the event is never triggered.
Fortunately network configurations don't usually change, so only a minority of people are probably affected and nobody even notices as the applications never receive an event anyway.

Manually tested on XP/7.

Signed-off-by: Bruno Jesus <00cpxxx at gmail.com>
---
 dlls/ws2_32/tests/sock.c | 110 ++++++++++++++++++++++++++++++++++-------------
 include/winsock.h        |   1 +
 include/winsock2.h       |   1 +
 3 files changed, 83 insertions(+), 29 deletions(-)

diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index be98691..d216542 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -8349,8 +8349,9 @@ static void test_sioAddressListChange(void)
     struct in_addr net_address;
     WSAOVERLAPPED overlapped;
     struct hostent *h;
-    DWORD num_bytes, error;
-    SOCKET sock;
+    DWORD num_bytes, error, tick;
+    SOCKET sock, sock2, sock3;
+    WSAEVENT event2, event3;
     int acount;
     int ret;
 
@@ -8397,9 +8398,6 @@ todo_wine
     sock = socket(AF_INET, 0, IPPROTO_TCP);
     ok(sock != INVALID_SOCKET, "socket() failed\n");
 
-    memset(&bindAddress, 0, sizeof(bindAddress));
-    bindAddress.sin_family = AF_INET;
-    bindAddress.sin_addr.s_addr = net_address.s_addr;
     SetLastError(0xdeadbeef);
     ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
     ok (!ret, "bind() failed with error %d\n", GetLastError());
@@ -8419,9 +8417,6 @@ todo_wine
     sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
     ok(sock != INVALID_SOCKET, "socket() failed\n");
 
-    memset(&bindAddress, 0, sizeof(bindAddress));
-    bindAddress.sin_family = AF_INET;
-    bindAddress.sin_addr.s_addr = net_address.s_addr;
     SetLastError(0xdeadbeef);
     ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
     ok (!ret, "bind() failed with error %d\n", GetLastError());
@@ -8442,9 +8437,6 @@ todo_wine
     sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
     ok(sock != INVALID_SOCKET, "socket() failed\n");
 
-    memset(&bindAddress, 0, sizeof(bindAddress));
-    bindAddress.sin_family = AF_INET;
-    bindAddress.sin_addr.s_addr = net_address.s_addr;
     SetLastError(0xdeadbeef);
     ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
     ok (!ret, "bind() failed with error %d\n", GetLastError());
@@ -8461,6 +8453,40 @@ todo_wine
     CloseHandle(overlapped.hEvent);
     closesocket(sock);
 
+    /* When the socket is overlapped non-blocking and the list change is requested without
+     * an overlapped structure the error will be different. */
+    sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+    ok(sock != INVALID_SOCKET, "socket() failed\n");
+
+    SetLastError(0xdeadbeef);
+    ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
+    ok (!ret, "bind() failed with error %d\n", GetLastError());
+    set_blocking(sock, FALSE);
+
+    SetLastError(0xdeadbeef);
+    ret = WSAIoctl(sock, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &num_bytes, NULL, NULL);
+    error = GetLastError();
+    ok (ret == SOCKET_ERROR, "WSAIoctl(SIO_ADDRESS_LIST_CHANGE) failed with error %d\n", error);
+    ok (error == WSAEWOULDBLOCK, "expected 10035, got %d\n", error);
+
+    closesocket(sock);
+
+    /* Misuse of the API by using a blocking socket and not using an overlapped structure,
+     * this leads to a hang forever. */
+    if (0)
+    {
+        sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+
+        SetLastError(0xdeadbeef);
+        bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
+
+        set_blocking(sock, TRUE);
+        WSAIoctl(sock, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &num_bytes, NULL, NULL);
+        /* hang */
+
+        closesocket(sock);
+    }
+
     if (!winetest_interactive)
     {
         skip("Cannot test SIO_ADDRESS_LIST_CHANGE, interactive tests must be enabled\n");
@@ -8470,35 +8496,61 @@ todo_wine
     /* Bind an overlapped socket to the first found network interface */
     sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
     ok(sock != INVALID_SOCKET, "Expected socket to return a valid socket\n");
-    if (sock == INVALID_SOCKET)
-    {
-        skip("Cannot test SIO_ADDRESS_LIST_CHANGE, socket creation failed with %u\n",
-             WSAGetLastError());
-        return;
-    }
-    memset(&bindAddress, 0, sizeof(bindAddress));
-    bindAddress.sin_family = AF_INET;
-    bindAddress.sin_addr.s_addr = net_address.s_addr;
+    sock2 = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+    ok(sock2 != INVALID_SOCKET, "Expected socket to return a valid socket\n");
+    sock3 = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+    ok(sock3 != INVALID_SOCKET, "Expected socket to return a valid socket\n");
+
     ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
-    if (ret != 0)
-    {
-        skip("Cannot test SIO_ADDRESS_LIST_CHANGE, failed to bind, error %u\n", WSAGetLastError());
-        goto end;
-    }
+    ok(!ret, "bind failed unexpectedly\n");
+    ret = bind(sock2, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
+    ok(!ret, "bind failed unexpectedly\n");
+    ret = bind(sock3, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
+    ok(!ret, "bind failed unexpectedly\n");
+
+    set_blocking(sock2, FALSE);
+    set_blocking(sock3, FALSE);
 
     /* Wait for address changes, request that the user connects/disconnects an interface */
     memset(&overlapped, 0, sizeof(overlapped));
     overlapped.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
     ret = WSAIoctl(sock, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &num_bytes, &overlapped, NULL);
     ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n");
-    ok(WSAGetLastError() == WSA_IO_PENDING, "Expected pending last error %d\n", WSAGetLastError());
+    ok(WSAGetLastError() == WSA_IO_PENDING, "Expected pending last error, got %d\n", WSAGetLastError());
+
+    ret = WSAIoctl(sock2, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &num_bytes, NULL, NULL);
+    ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n");
+    ok(WSAGetLastError() == WSAEWOULDBLOCK, "Expected would block last error, got %d\n", WSAGetLastError());
+
+    event2 = WSACreateEvent();
+    event3 = WSACreateEvent();
+    ret = WSAEventSelect (sock2, event2, FD_ADDRESS_LIST_CHANGE);
+    ok(!ret, "WSAEventSelect failed with %d\n", WSAGetLastError());
+    /* sock3 did not request SIO_ADDRESS_LIST_CHANGE but it is trying to wait anyway */
+    ret = WSAEventSelect (sock3, event3, FD_ADDRESS_LIST_CHANGE);
+    ok(!ret, "WSAEventSelect failed with %d\n", WSAGetLastError());
+
     trace("Testing socket-based ipv4 address list change notification. Please connect/disconnect or"
-          " change the ipv4 address of any of the local network interfaces (10 second timeout).\n");
-    ret = WaitForSingleObject(overlapped.hEvent, 10000);
+          " change the ipv4 address of any of the local network interfaces (15 second timeout).\n");
+    tick = GetTickCount();
+    ret = WaitForSingleObject(overlapped.hEvent, 15000);
     ok(ret == WAIT_OBJECT_0, "failed to get overlapped event %u\n", ret);
 
-end:
+    ret = WaitForSingleObject(event2, 500);
+todo_wine
+    ok(ret == WAIT_OBJECT_0, "failed to get change event %u\n", ret);
+
+    ret = WaitForSingleObject(event3, 500);
+    ok(ret == WAIT_TIMEOUT, "unexpected change event\n");
+
+    trace("Spent %d ms waiting.\n", GetTickCount() - tick);
+
+    WSACloseEvent(event2);
+    WSACloseEvent(event3);
+
     closesocket(sock);
+    closesocket(sock2);
+    closesocket(sock3);
 }
 
 static void test_synchronous_WSAIoctl(void)
diff --git a/include/winsock.h b/include/winsock.h
index cf9adf5..f119dec 100644
--- a/include/winsock.h
+++ b/include/winsock.h
@@ -813,6 +813,7 @@ typedef struct WS(WSAData)
 #define FD_ACCEPT                  0x00000008
 #define FD_CONNECT                 0x00000010
 #define FD_CLOSE                   0x00000020
+#define FD_ADDRESS_LIST_CHANGE     0x00000200
 
 /* internal per-socket flags */
 #ifdef __WINESRC__
diff --git a/include/winsock2.h b/include/winsock2.h
index 24f0ea3..1af261f 100644
--- a/include/winsock2.h
+++ b/include/winsock2.h
@@ -101,6 +101,7 @@ extern "C" {
 #define FD_ACCEPT_BIT              3
 #define FD_CONNECT_BIT             4
 #define FD_CLOSE_BIT               5
+#define FD_ADDRESS_LIST_CHANGE_BIT 9
 
 /* Constants for LPCONDITIONPROC */
 #define CF_ACCEPT                  0x0000
-- 
2.9.3




More information about the wine-patches mailing list