Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ws2_32/tests/afd.c | 149 +++++++++++++++++++++++++++++++++------ dlls/ws2_32/tests/sock.c | 84 ++++++++++++++++++++++ 2 files changed, 211 insertions(+), 22 deletions(-)
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index 4b8796157aa..32daab0beab 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -1414,9 +1414,14 @@ static void test_get_events(void)
static void test_bind(void) { + const struct sockaddr_in6 bind_addr6 = {.sin6_family = AF_INET6, .sin6_addr.s6_words = {0, 0, 0, 0, 0, 0, 0, htons(1)}}; + const struct sockaddr_in6 invalid_addr6 = {.sin6_family = AF_INET6, .sin6_addr.s6_words = {htons(0x0100)}}; const struct sockaddr_in invalid_addr = {.sin_family = AF_INET, .sin_addr.s_addr = inet_addr("192.0.2.0")}; const struct sockaddr_in bind_addr = {.sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK)}; - struct afd_bind_params params = {0}; + static const size_t params6_size = offsetof(struct afd_bind_params, addr) + sizeof(struct sockaddr_in6); + static const size_t params4_size = offsetof(struct afd_bind_params, addr) + sizeof(struct sockaddr_in); + struct afd_bind_params *params = malloc(params6_size); + struct sockaddr_in6 addr6, addr6_2; struct sockaddr_in addr, addr2; struct hostent *host; IO_STATUS_BLOCK io; @@ -1427,47 +1432,48 @@ static void test_bind(void)
event = CreateEventW(NULL, TRUE, FALSE, NULL); memset(&addr, 0xcc, sizeof(addr)); + memset(params, 0, params6_size);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- params.addr.sa_family = 0xdead; + params->addr.sa_family = 0xdead; ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, sizeof(params), &addr, sizeof(addr)); + params, params4_size, &addr, sizeof(addr)); ok(ret == STATUS_INVALID_ADDRESS, "got %#x\n", ret);
- memcpy(¶ms.addr, &bind_addr, sizeof(bind_addr)); + memcpy(¶ms->addr, &bind_addr, sizeof(bind_addr)); ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, sizeof(params) - 1, &addr, sizeof(addr)); + params, params4_size - 1, &addr, sizeof(addr)); ok(ret == STATUS_INVALID_ADDRESS, "got %#x\n", ret);
- memcpy(¶ms.addr, &bind_addr, sizeof(bind_addr)); + memcpy(¶ms->addr, &bind_addr, sizeof(bind_addr)); ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, offsetof(struct afd_bind_params, addr.sa_data), &addr, sizeof(addr)); + params, offsetof(struct afd_bind_params, addr.sa_data), &addr, sizeof(addr)); ok(ret == STATUS_INVALID_ADDRESS, "got %#x\n", ret);
- memcpy(¶ms.addr, &bind_addr, sizeof(bind_addr)); + memcpy(¶ms->addr, &bind_addr, sizeof(bind_addr)); ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, offsetof(struct afd_bind_params, addr.sa_data) - 1, &addr, sizeof(addr)); + params, offsetof(struct afd_bind_params, addr.sa_data) - 1, &addr, sizeof(addr)); ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret);
- memcpy(¶ms.addr, &invalid_addr, sizeof(invalid_addr)); + memcpy(¶ms->addr, &invalid_addr, sizeof(invalid_addr)); ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, sizeof(params), &addr, sizeof(addr)); + params, params4_size, &addr, sizeof(addr)); todo_wine ok(ret == STATUS_PENDING, "got %#x\n", ret); ret = WaitForSingleObject(event, 0); ok(!ret, "got %#x\n", ret); ok(io.Status == STATUS_INVALID_ADDRESS_COMPONENT, "got %#x\n", io.Status);
- memcpy(¶ms.addr, &bind_addr, sizeof(bind_addr)); + memcpy(¶ms->addr, &bind_addr, sizeof(bind_addr)); ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, sizeof(params), &addr, sizeof(addr) - 1); + params, params4_size, &addr, sizeof(addr) - 1); ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret);
- memcpy(¶ms.addr, &bind_addr, sizeof(bind_addr)); + memcpy(¶ms->addr, &bind_addr, sizeof(bind_addr)); memset(&io, 0xcc, sizeof(io)); memset(&addr, 0xcc, sizeof(addr)); ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, sizeof(params), &addr, sizeof(addr)); + params, params4_size, &addr, sizeof(addr)); todo_wine ok(ret == STATUS_PENDING, "got %#x\n", ret); ret = WaitForSingleObject(event, 0); ok(!ret, "got %#x\n", ret); @@ -1485,16 +1491,16 @@ static void test_bind(void) ok(!memcmp(&addr, &addr2, sizeof(addr)), "addresses didn't match\n");
ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, sizeof(params), &addr, sizeof(addr)); + params, params4_size, &addr, sizeof(addr)); ok(ret == STATUS_ADDRESS_ALREADY_ASSOCIATED, "got %#x\n", ret);
s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- memcpy(¶ms.addr, &addr2, sizeof(addr2)); + memcpy(¶ms->addr, &addr2, sizeof(addr2)); memset(&io, 0xcc, sizeof(io)); memset(&addr, 0xcc, sizeof(addr)); ret = NtDeviceIoControlFile((HANDLE)s2, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, sizeof(params), &addr, sizeof(addr)); + params, params4_size, &addr, sizeof(addr)); todo_wine ok(ret == STATUS_PENDING, "got %#x\n", ret); ret = WaitForSingleObject(event, 0); ok(!ret, "got %#x\n", ret); @@ -1508,11 +1514,11 @@ static void test_bind(void)
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- memcpy(¶ms.addr, &bind_addr, sizeof(bind_addr)); + memcpy(¶ms->addr, &bind_addr, sizeof(bind_addr)); memset(&io, 0xcc, sizeof(io)); memset(&addr, 0xcc, sizeof(addr)); ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, sizeof(params), &addr, sizeof(addr)); + params, params4_size, &addr, sizeof(addr)); todo_wine ok(ret == STATUS_PENDING, "got %#x\n", ret); ret = WaitForSingleObject(event, 0); ok(!ret, "got %#x\n", ret); @@ -1539,11 +1545,11 @@ static void test_bind(void)
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- ((struct sockaddr_in *)¶ms.addr)->sin_addr.s_addr = in_addr; + ((struct sockaddr_in *)¶ms->addr)->sin_addr.s_addr = in_addr; memset(&io, 0xcc, sizeof(io)); memset(&addr, 0xcc, sizeof(addr)); ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, - ¶ms, sizeof(params), &addr, sizeof(addr)); + params, params4_size, &addr, sizeof(addr)); todo_wine ok(ret == STATUS_PENDING, "got %#x\n", ret); ret = WaitForSingleObject(event, 0); ok(!ret, "got %#x\n", ret); @@ -1563,7 +1569,106 @@ static void test_bind(void) } }
+ /* test IPv6 */ + + s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + ok(s != -1, "failed to create IPv6 socket\n"); + + params->addr.sa_family = 0xdead; + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, params6_size, &addr6, sizeof(addr6)); + ok(ret == STATUS_INVALID_ADDRESS, "got %#x\n", ret); + + memcpy(¶ms->addr, &bind_addr6, sizeof(bind_addr6)); + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, params6_size - 1, &addr6, sizeof(addr6)); + todo_wine ok(ret == STATUS_INVALID_ADDRESS, "got %#x\n", ret); + + memcpy(¶ms->addr, &bind_addr6, sizeof(bind_addr6)); + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, offsetof(struct afd_bind_params, addr) + sizeof(struct sockaddr_in6_old), &addr6, sizeof(addr6)); + todo_wine ok(ret == STATUS_INVALID_ADDRESS, "got %#x\n", ret); + + memcpy(¶ms->addr, &bind_addr6, sizeof(bind_addr6)); + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, offsetof(struct afd_bind_params, addr.sa_data), &addr6, sizeof(addr6)); + todo_wine ok(ret == STATUS_INVALID_ADDRESS, "got %#x\n", ret); + + memcpy(¶ms->addr, &bind_addr6, sizeof(bind_addr6)); + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, offsetof(struct afd_bind_params, addr.sa_data) - 1, &addr6, sizeof(addr6)); + ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); + + memcpy(¶ms->addr, &invalid_addr6, sizeof(invalid_addr6)); + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, params6_size, &addr6, sizeof(addr6)); + todo_wine ok(ret == STATUS_PENDING, "got %#x\n", ret); + ret = WaitForSingleObject(event, 0); + todo_wine ok(!ret, "got %#x\n", ret); + todo_wine ok(io.Status == STATUS_INVALID_ADDRESS_COMPONENT, "got %#x\n", io.Status); + + memcpy(¶ms->addr, &bind_addr6, sizeof(bind_addr6)); + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, params6_size, &addr6, sizeof(addr6) - 1); + todo_wine ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); + + memcpy(¶ms->addr, &bind_addr6, sizeof(bind_addr6)); + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, params6_size - 1, &addr6, sizeof(addr6) - 1); + todo_wine ok(ret == STATUS_INVALID_ADDRESS, "got %#x\n", ret); + + memcpy(¶ms->addr, &bind_addr6, sizeof(bind_addr6)); + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, params6_size, &addr6, sizeof(struct sockaddr_in6_old)); + todo_wine ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); + + memcpy(¶ms->addr, &bind_addr6, sizeof(bind_addr6)); + memset(&io, 0xcc, sizeof(io)); + memset(&addr6, 0xcc, sizeof(addr6)); + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, params6_size, &addr6, sizeof(addr6)); + todo_wine ok(ret == STATUS_PENDING, "got %#x\n", ret); + ret = WaitForSingleObject(event, 0); + todo_wine + { + ok(!ret, "got %#x\n", ret); + ok(!io.Status, "got %#x\n", io.Status); + ok(io.Information == sizeof(addr6), "got %#Ix\n", io.Information); + ok(addr6.sin6_family == AF_INET6, "got family %u\n", addr6.sin6_family); + ok(!memcmp(&addr6.sin6_addr, &bind_addr6.sin6_addr, sizeof(addr6.sin6_addr)), "address didn't match\n"); + ok(!addr6.sin6_flowinfo, "got flow info %#x\n", addr6.sin6_flowinfo); + } + ok(addr6.sin6_port, "expected nonzero port\n"); + + /* getsockname() returns EINVAL here. Possibly the socket name is cached (in shared memory?) */ + memset(&addr6_2, 0xcc, sizeof(addr6_2)); + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, + IOCTL_AFD_GETSOCKNAME, NULL, 0, &addr6_2, sizeof(addr6_2)); + ok(!ret, "got %#x\n", ret); + todo_wine ok(!memcmp(&addr6, &addr6_2, sizeof(addr6)), "addresses didn't match\n"); + + ret = NtDeviceIoControlFile((HANDLE)s, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, params6_size, &addr6, sizeof(addr6)); + ok(ret == STATUS_ADDRESS_ALREADY_ASSOCIATED, "got %#x\n", ret); + + s2 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + + memcpy(¶ms->addr, &addr6_2, sizeof(addr6_2)); + memset(&io, 0xcc, sizeof(io)); + memset(&addr6, 0xcc, sizeof(addr6)); + ret = NtDeviceIoControlFile((HANDLE)s2, event, NULL, NULL, &io, IOCTL_AFD_BIND, + params, params6_size, &addr6, sizeof(addr6)); + todo_wine ok(ret == STATUS_PENDING, "got %#x\n", ret); + ret = WaitForSingleObject(event, 0); + ok(!ret, "got %#x\n", ret); + ok(io.Status == STATUS_SHARING_VIOLATION, "got %#x\n", io.Status); + ok(!io.Information, "got %#Ix\n", io.Information); + + closesocket(s2); + closesocket(s); + CloseHandle(event); + free(params); }
static void test_getsockname(void) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index e7bd3b8fe15..f5c5acf161e 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -26,6 +26,7 @@ #include <winsock2.h> #include <windows.h> #include <winternl.h> +#include <iphlpapi.h> #include <ws2tcpip.h> #include <wsipx.h> #include <wsnwlink.h> @@ -3779,9 +3780,13 @@ static void test_getsockname(void) ok(!ret, "failed to bind, error %u\n", WSAGetLastError());
WSASetLastError(0xdeadbeef); + memset(&sa_get, 0, sizeof(sa_get)); ret = getsockname(sock, (struct sockaddr *) &sa_get, &sa_get_len); ok(!ret, "got %d\n", ret); ok(!WSAGetLastError() || WSAGetLastError() == 0xdeadbeef /* < 7 */, "got error %u\n", WSAGetLastError()); + ok(sa_get.sin_family == AF_INET, "got family %#x\n", sa_get.sin_family); + ok(sa_get.sin_port != 0, "got zero port\n"); + ok(sa_get.sin_addr.s_addr == INADDR_ANY, "got addr %08x\n", sa_get.sin_addr.s_addr);
ret = memcmp(sa_get.sin_zero, null_padding, 8); ok(ret == 0, "getsockname did not zero the sockaddr_in structure\n"); @@ -10566,6 +10571,8 @@ static void test_bind(void) { const struct sockaddr_in invalid_addr = {.sin_family = AF_INET, .sin_addr.s_addr = inet_addr("192.0.2.0")}; const struct sockaddr_in bind_addr = {.sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK)}; + IP_ADAPTER_ADDRESSES *adapters = NULL, *adapter; + ULONG ip_addrs_size = 0; struct sockaddr addr; SOCKET s, s2; int ret, len; @@ -10625,6 +10632,83 @@ static void test_bind(void) ok(!WSAGetLastError() || WSAGetLastError() == 0xdeadbeef /* win <7 */, "got error %u\n", WSAGetLastError());
closesocket(s); + + ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapters, &ip_addrs_size); + ok(ret == ERROR_BUFFER_OVERFLOW, "got error %u\n", ret); + adapters = malloc(ip_addrs_size); + ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapters, &ip_addrs_size); + ok(!ret, "got error %u\n", ret); + + for (adapter = adapters; adapter != NULL; adapter = adapter->Next) + { + const IP_ADAPTER_UNICAST_ADDRESS *unicast_addr; + + for (unicast_addr = adapter->FirstUnicastAddress; unicast_addr != NULL; unicast_addr = unicast_addr->Next) + { + short family = unicast_addr->Address.lpSockaddr->sa_family; + + s = socket(family, SOCK_STREAM, IPPROTO_TCP); + ok(s != -1, "failed to create socket, error %u\n", WSAGetLastError()); + + ret = bind(s, unicast_addr->Address.lpSockaddr, unicast_addr->Address.iSockaddrLength); + ok(!ret, "got error %u\n", WSAGetLastError()); + + closesocket(s); + + if (family == AF_INET6) + { + struct sockaddr_in6 addr6, ret_addr6; + + memcpy(&addr6, unicast_addr->Address.lpSockaddr, sizeof(addr6)); + + ok(unicast_addr->Address.iSockaddrLength == sizeof(struct sockaddr_in6), + "got unexpected length %u\n", unicast_addr->Address.iSockaddrLength); + + s = socket(family, SOCK_STREAM, IPPROTO_TCP); + ok(s != -1, "failed to create socket, error %u\n", WSAGetLastError()); + + ret = bind(s, unicast_addr->Address.lpSockaddr, sizeof(struct sockaddr_in6_old)); + todo_wine_if (!addr6.sin6_scope_id) + { + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + } + + addr6.sin6_scope_id = 0xabacab; + ret = bind(s, (struct sockaddr *)&addr6, sizeof(addr6)); + ok(ret == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == WSAEADDRNOTAVAIL, "got error %u\n", WSAGetLastError()); + + addr6.sin6_scope_id = 0; + ret = bind(s, (struct sockaddr *)&addr6, sizeof(addr6)); + todo_wine ok(!ret, "got error %u\n", WSAGetLastError()); + + memcpy(&addr6, unicast_addr->Address.lpSockaddr, sizeof(addr6)); + + len = sizeof(struct sockaddr_in6_old); + ret = getsockname(s, (struct sockaddr *)&ret_addr6, &len); + ok(ret == -1, "expected failure\n"); + todo_wine_if (addr6.sin6_scope_id) + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + len = sizeof(ret_addr6); + memset(&ret_addr6, 0, sizeof(ret_addr6)); + ret = getsockname(s, (struct sockaddr *)&ret_addr6, &len); + todo_wine_if (addr6.sin6_scope_id) + { + ok(!ret, "got error %u\n", WSAGetLastError()); + ok(ret_addr6.sin6_family == AF_INET6, "got family %u\n", ret_addr6.sin6_family); + ok(ret_addr6.sin6_port != 0, "expected nonzero port\n"); + ok(!memcmp(&ret_addr6.sin6_addr, &addr6.sin6_addr, sizeof(addr6.sin6_addr)), "address didn't match\n"); + ok(ret_addr6.sin6_scope_id == addr6.sin6_scope_id, "got scope %u\n", ret_addr6.sin6_scope_id); + } + + closesocket(s); + } + } + } + + free(adapters); }
/* Test calling methods on a socket which is currently connecting. */
bind() returns WSAEFAULT for short length, but IOCTL_AFD_BIND returns STATUS_INVALID_ADDRESS, which translates to WSAEADDRNOTAVAIL.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ws2_32/socket.c | 42 +++++++++++++++++++++++++++++++++++++++- dlls/ws2_32/tests/sock.c | 10 ++++------ 2 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index fac19355705..88d30cb2802 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1775,12 +1775,52 @@ int WINAPI WS_bind( SOCKET s, const struct WS_sockaddr *addr, int len )
TRACE( "socket %#lx, addr %s\n", s, debugstr_sockaddr(addr) );
- if (!addr || (addr->sa_family && !supported_pf( addr->sa_family ))) + if (!addr) { SetLastError( WSAEAFNOSUPPORT ); return -1; }
+ switch (addr->sa_family) + { + case WS_AF_INET: + if (len < sizeof(struct WS_sockaddr_in)) + { + SetLastError( WSAEFAULT ); + return -1; + } + break; + + case WS_AF_INET6: + if (len < sizeof(struct WS_sockaddr_in6)) + { + SetLastError( WSAEFAULT ); + return -1; + } + break; + + case WS_AF_IPX: + if (len < sizeof(struct WS_sockaddr_ipx)) + { + SetLastError( WSAEFAULT ); + return -1; + } + break; + + case WS_AF_IRDA: + if (len < sizeof(SOCKADDR_IRDA)) + { + SetLastError( WSAEFAULT ); + return -1; + } + break; + + default: + FIXME( "unknown protocol %u\n", addr->sa_family ); + SetLastError( WSAEAFNOSUPPORT ); + return -1; + } + if (!(sync_event = get_sync_event())) return -1;
params = HeapAlloc( GetProcessHeap(), 0, sizeof(int) + len ); diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index f5c5acf161e..dd880531047 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -10668,15 +10668,13 @@ static void test_bind(void) ok(s != -1, "failed to create socket, error %u\n", WSAGetLastError());
ret = bind(s, unicast_addr->Address.lpSockaddr, sizeof(struct sockaddr_in6_old)); - todo_wine_if (!addr6.sin6_scope_id) - { - ok(ret == -1, "expected failure\n"); - ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); - } + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError());
addr6.sin6_scope_id = 0xabacab; ret = bind(s, (struct sockaddr *)&addr6, sizeof(addr6)); - ok(ret == -1, "expected failure\n"); + todo_wine_if (!((const struct sockaddr_in6 *)unicast_addr->Address.lpSockaddr)->sin6_scope_id) + ok(ret == -1, "expected failure\n"); todo_wine ok(WSAGetLastError() == WSAEADDRNOTAVAIL, "got error %u\n", WSAGetLastError());
addr6.sin6_scope_id = 0;
This fixes a regression introduced by 5c009c17b3a212c3f5b0034c465077c0c593daae.
WeMod WXDrive calls bind() on every local address, but with a zero sin6_scope_id, and gets confused when this returns WSAEFAULT. Actually this is supposed to succeed on Windows, but prior to the aforementioned commit we would return WSAEINVAL, and the program seems to be happy with that.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51493 Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ws2_32/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 88d30cb2802..b4786e54b38 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1847,7 +1847,7 @@ int WINAPI WS_bind( SOCKET s, const struct WS_sockaddr *addr, int len ) HeapFree( GetProcessHeap(), 0, params ); HeapFree( GetProcessHeap(), 0, ret_addr );
- SetLastError( status == STATUS_INVALID_PARAMETER ? WSAEFAULT : NtStatusToWSAError( status ) ); + SetLastError( NtStatusToWSAError( status ) ); return status ? -1 : 0; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=94359
Your paranoid android.
=== debiant2 (32 bit report) ===
ws2_32: sock.c:8557: Test succeeded inside todo block: GetQueuedCompletionStatus returned 0 sock.c:8558: Test succeeded inside todo block: Last error was 64
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- server/sock.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/server/sock.c b/server/sock.c index 3f0526016f9..6a8cb328df2 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1844,6 +1844,8 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr return 1; } } + + freeifaddrs( ifaddrs ); return 0; }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ws2_32/tests/sock.c | 19 ++++++++--------- server/sock.c | 44 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 12 deletions(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index dd880531047..ed7d5121332 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -10679,27 +10679,24 @@ static void test_bind(void)
addr6.sin6_scope_id = 0; ret = bind(s, (struct sockaddr *)&addr6, sizeof(addr6)); - todo_wine ok(!ret, "got error %u\n", WSAGetLastError()); + todo_wine_if (!((const struct sockaddr_in6 *)unicast_addr->Address.lpSockaddr)->sin6_scope_id) + ok(!ret, "got error %u\n", WSAGetLastError());
memcpy(&addr6, unicast_addr->Address.lpSockaddr, sizeof(addr6));
len = sizeof(struct sockaddr_in6_old); ret = getsockname(s, (struct sockaddr *)&ret_addr6, &len); ok(ret == -1, "expected failure\n"); - todo_wine_if (addr6.sin6_scope_id) - ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError());
len = sizeof(ret_addr6); memset(&ret_addr6, 0, sizeof(ret_addr6)); ret = getsockname(s, (struct sockaddr *)&ret_addr6, &len); - todo_wine_if (addr6.sin6_scope_id) - { - ok(!ret, "got error %u\n", WSAGetLastError()); - ok(ret_addr6.sin6_family == AF_INET6, "got family %u\n", ret_addr6.sin6_family); - ok(ret_addr6.sin6_port != 0, "expected nonzero port\n"); - ok(!memcmp(&ret_addr6.sin6_addr, &addr6.sin6_addr, sizeof(addr6.sin6_addr)), "address didn't match\n"); - ok(ret_addr6.sin6_scope_id == addr6.sin6_scope_id, "got scope %u\n", ret_addr6.sin6_scope_id); - } + ok(!ret, "got error %u\n", WSAGetLastError()); + ok(ret_addr6.sin6_family == AF_INET6, "got family %u\n", ret_addr6.sin6_family); + ok(ret_addr6.sin6_port != 0, "expected nonzero port\n"); + ok(!memcmp(&ret_addr6.sin6_addr, &addr6.sin6_addr, sizeof(addr6.sin6_addr)), "address didn't match\n"); + ok(ret_addr6.sin6_scope_id == addr6.sin6_scope_id, "got scope %u\n", ret_addr6.sin6_scope_id);
closesocket(s); } diff --git a/server/sock.c b/server/sock.c index 6a8cb328df2..e28b0349027 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1849,6 +1849,38 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr return 0; }
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID +static unsigned int get_ipv6_interface_index( const struct in6_addr *addr ) +{ + struct ifaddrs *ifaddrs, *ifaddr; + + if (getifaddrs( &ifaddrs ) < 0) return 0; + + for (ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next) + { + if (ifaddr->ifa_addr && ifaddr->ifa_addr->sa_family == AF_INET6 + && !memcmp( &((struct sockaddr_in6 *)ifaddr->ifa_addr)->sin6_addr, addr, sizeof(*addr) )) + { + unsigned int index = if_nametoindex( ifaddr->ifa_name ); + + if (!index) + { + if (debug_level) + fprintf( stderr, "Unable to look up interface index for %s: %s\n", + ifaddr->ifa_name, strerror( errno ) ); + continue; + } + + freeifaddrs( ifaddrs ); + return index; + } + } + + freeifaddrs( ifaddrs ); + return 0; +} +#endif + /* return an errno value mapped to a WSA error */ static unsigned int sock_get_error( int err ) { @@ -2477,12 +2509,22 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) } bind_addr = unix_addr;
- if (unix_addr.addr.sa_family == WS_AF_INET) + if (unix_addr.addr.sa_family == AF_INET) { if (!memcmp( &unix_addr.in.sin_addr, magic_loopback_addr, 4 ) || bind_to_interface( sock, &unix_addr.in )) bind_addr.in.sin_addr.s_addr = htonl( INADDR_ANY ); } + else if (unix_addr.addr.sa_family == AF_INET6) + { +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID + /* Windows allows specifying zero to use the default scope. Linux + * interprets it as an interface index and requires that it be + * nonzero. */ + if (!unix_addr.in6.sin6_scope_id) + bind_addr.in6.sin6_scope_id = get_ipv6_interface_index( &unix_addr.in6.sin6_addr ); +#endif + }
if (bind( unix_fd, &bind_addr.addr, unix_len ) < 0) {
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ws2_32/tests/sock.c | 4 +++- server/sock.c | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index ed7d5121332..41fcb5d9248 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -10674,8 +10674,10 @@ static void test_bind(void) addr6.sin6_scope_id = 0xabacab; ret = bind(s, (struct sockaddr *)&addr6, sizeof(addr6)); todo_wine_if (!((const struct sockaddr_in6 *)unicast_addr->Address.lpSockaddr)->sin6_scope_id) + { ok(ret == -1, "expected failure\n"); - todo_wine ok(WSAGetLastError() == WSAEADDRNOTAVAIL, "got error %u\n", WSAGetLastError()); + ok(WSAGetLastError() == WSAEADDRNOTAVAIL, "got error %u\n", WSAGetLastError()); + }
addr6.sin6_scope_id = 0; ret = bind(s, (struct sockaddr *)&addr6, sizeof(addr6)); diff --git a/server/sock.c b/server/sock.c index e28b0349027..f730bb31c55 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1976,6 +1976,9 @@ static int sock_get_ntstatus( int err ) case ENOPROTOOPT: return STATUS_INVALID_PARAMETER; case EOPNOTSUPP: return STATUS_NOT_SUPPORTED; case EADDRINUSE: return STATUS_SHARING_VIOLATION; + /* Linux returns ENODEV when specifying an invalid sin6_scope_id; + * Windows returns STATUS_INVALID_ADDRESS_COMPONENT */ + case ENODEV: case EADDRNOTAVAIL: return STATUS_INVALID_ADDRESS_COMPONENT; case ECONNREFUSED: return STATUS_CONNECTION_REFUSED; case ESHUTDOWN: return STATUS_PIPE_DISCONNECTED;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=94362
Your paranoid android.
=== debiant2 (32 bit report) ===
ws2_32: sock.c:8557: Test succeeded inside todo block: GetQueuedCompletionStatus returned 0 sock.c:8558: Test succeeded inside todo block: Last error was 64