From: "Erich E. Hoover" Subject: [PATCH 1/3] ws2_32: Implement SIO_ADDRESS_LIST_CHANGE with NotifyAddrChange (try 2). Message-Id: Date: Sun, 4 Aug 2013 22:24:59 -0600 The attached patch is the next step in the series of fixes for Silverlight/PlayReady under Wine. This particular patch does not impact Netflix, but it does impact a number of other PlayReady streaming services (and a variety of non-streaming sites as well). Sorry it's taken so long to get back to this, life has been busy lately. With this patch the SIO_ADDRESS_LIST_CHANGE call gets passed on to NotifyAddrChange, which effectively fixes a problem where Silverlight apps can loop forever calling SIO_ADDRESS_LIST_CHANGE (Bug #32328). Part 2 actually implements the NotifyAddrChange call on Linux, though this patch is sufficient on its own to resolve the bug since the overlapped IO event no longer gets triggered. This version of the patch has bee updated to include tests that show that the notification is not tied to the socket. For example, changing an interface that the socket is not bound to still results in an overlapped notification. It's worth noting that these tests require interactive mode and a PC with two network cards, so for my testing I used an actual (non-VM) Windows 7 box with a wired and a wireless card. From 70355c45b14d7cb1db277d6bdddbb31217a86625 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Sun, 4 Aug 2013 22:06:22 -0600 Subject: ws2_32: Implement SIO_ADDRESS_LIST_CHANGE with NotifyAddrChange. --- dlls/ws2_32/socket.c | 15 ++++++++-- dlls/ws2_32/tests/sock.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 462f153..bf988b7 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -3414,10 +3414,19 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID } case WS_SIO_ADDRESS_LIST_CHANGE: - FIXME("-> SIO_ADDRESS_LIST_CHANGE request: stub\n"); - /* FIXME: error and return code depend on whether socket was created - * with WSA_FLAG_OVERLAPPED, but there is no easy way to get this */ + { + BOOL is_blocking; + HANDLE handle; + + TRACE("-> SIO_ADDRESS_LIST_CHANGE request\n"); + + if (overlapped || (_is_blocking( s, &is_blocking ) && is_blocking)) + status = NotifyAddrChange( &handle, overlapped ); + else + status = WSAEWOULDBLOCK; + overlapped = NULL; /* managed by NotifyAddrChange */ break; + } case WS_SIO_ADDRESS_LIST_QUERY: { diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 5ce4959..d0e1bbc 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -5487,6 +5487,75 @@ static void test_sioRoutingInterfaceQuery(void) closesocket(sock); } +static void test_sioAddressListChange(void) +{ + struct sockaddr_in bindAddress; + struct in_addr net_address; + WSAOVERLAPPED overlapped; + struct hostent *h; + DWORD num_bytes; + SOCKET sock; + int acount; + int ret; + + if (!winetest_interactive) + { + skip("Cannot test SIO_ADDRESS_LIST_CHANGE, interactive tests must be enabled\n"); + return; + } + + /* Use gethostbyname to find the list of local network interfaces */ + h = gethostbyname(""); + if (!h) + { + skip("Cannot test SIO_ADDRESS_LIST_CHANGE, gethostbyname failed with %u\n", + WSAGetLastError()); + return; + } + for (acount = 0; h->h_addr_list[acount]; acount++); + if (acount < 2) + { + skip("Cannot test SIO_ADDRESS_LIST_CHANGE, test requires at least two network cards.\n"); + return; + } + net_address.s_addr = *(ULONG *) h->h_addr_list[0]; + + /* 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; + 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; + } + + /* Wait for address changes, request that the user change one of the other interfaces */ + memset(&overlapped, 0, sizeof(overlapped)); + overlapped.hEvent = CreateEvent(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()); + trace("Testing socket-based ipv4 address list change notification. Please connect/disconnect or" + " change the ipv4 address of any of the local network interfaces EXCEPT for the one" + " attached to %s (10 second timeout).\n", + inet_ntoa(net_address)); + ret = WaitForSingleObject(overlapped.hEvent, 10000); + todo_wine ok(ret == WAIT_OBJECT_0, "failed to get overlapped event %u\n", ret); + +end: + closesocket(sock); +} + static void test_synchronous_WSAIoctl(void) { HANDLE previous_port, io_port; @@ -6361,6 +6430,7 @@ START_TEST( sock ) test_ConnectEx(); test_sioRoutingInterfaceQuery(); + test_sioAddressListChange(); test_WSAAsyncGetServByPort(); test_WSAAsyncGetServByName(); -- 1.7.9.5