This fixes a `todo_wine` in ws2_32's socket tests.
-- v3: server: Ignore EADDRINUSE from listen() unless the provided socket is wildcarded.
From: Ally Sommers dropbear.sh@gmail.com
--- dlls/ws2_32/tests/sock.c | 2 +- server/sock.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index e6ab5065cfe..4bf705ecf96 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -2241,7 +2241,7 @@ static void test_reuseaddr(void) rc = listen(s1, 1); ok(!rc, "got error %d.\n", WSAGetLastError()); rc = listen(s2, 1); - todo_wine ok(!rc, "got error %d.\n", WSAGetLastError()); + ok(!rc, "got error %d.\n", WSAGetLastError()); rc = connect(s3, tests[i].addr_loopback, tests[i].addrlen); ok(!rc, "got error %d.\n", WSAGetLastError());
diff --git a/server/sock.c b/server/sock.c index 2aae9aefbf0..bb70ce3703a 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2525,6 +2525,21 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
if (listen( unix_fd, params->backlog ) < 0) { + if (errno == EADDRINUSE) + switch (sock->family) + { + case WS_AF_INET: + if (sock->addr.in.sin_addr.S_un.S_addr != htonl( INADDR_ANY )) + return; + case WS_AF_INET6: + { + union unix_sockaddr unix_addr; + socklen_t len = sockaddr_to_unix(&sock->addr.addr, sizeof(struct WS_sockaddr_in6), &unix_addr); + if (len && !IN6_IS_ADDR_UNSPECIFIED(&unix_addr.in6.sin6_addr)) + return; + } + } + set_error( sock_get_ntstatus( errno ) ); return; }
What is the purpose if this patch, does it fix any real application? The meaning of that test is that with SO_REUSADDR on Windows multiple sockets can be bound to the same address, and a newly bound socket may actually receive connection on it, either at once or when the other socket will be closed. Maybe it is possible to achieve with Linux SO_REUSEPORT and BPF filters, but probably not by ignoring an error on listen.
On 21 Jul 2023, at 0:23, Ally Sommers wine@gitlab.winehq.org wrote:
From: Ally Sommers dropbear.sh@gmail.com
dlls/ws2_32/tests/sock.c | 2 +- server/sock.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index e6ab5065cfe..4bf705ecf96 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -2241,7 +2241,7 @@ static void test_reuseaddr(void) rc = listen(s1, 1); ok(!rc, "got error %d.\n", WSAGetLastError()); rc = listen(s2, 1);
todo_wine ok(!rc, "got error %d.\n", WSAGetLastError());
ok(!rc, "got error %d.\n", WSAGetLastError()); rc = connect(s3, tests[i].addr_loopback, tests[i].addrlen); ok(!rc, "got error %d.\n", WSAGetLastError());
diff --git a/server/sock.c b/server/sock.c index 2aae9aefbf0..bb70ce3703a 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2525,6 +2525,21 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
if (listen( unix_fd, params->backlog ) < 0) {
if (errno == EADDRINUSE)
switch (sock->family)
{
case WS_AF_INET:
if (sock->addr.in.sin_addr.S_un.S_addr != htonl( INADDR_ANY ))
return;
case WS_AF_INET6:
{
union unix_sockaddr unix_addr;
socklen_t len = sockaddr_to_unix(&sock->addr.addr, sizeof(struct WS_sockaddr_in6), &unix_addr);
if (len && !IN6_IS_ADDR_UNSPECIFIED(&unix_addr.in6.sin6_addr))
return;
}
}
set_error( sock_get_ntstatus( errno ) ); return; }
-- GitLab