From: Zebediah Figura zfigura@codeweavers.com
--- dlls/ws2_32/tests/sock.c | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 5ed0f286c55..c89f48879aa 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -3983,6 +3983,7 @@ static void test_select(void) .sin_addr.s_addr = htonl(INADDR_LOOPBACK), .sin_port = 255, }; + SOCKET client2, server2;
fdWrite = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); set_blocking(fdWrite, FALSE); @@ -4082,6 +4083,65 @@ static void test_select(void)
closesocket(fdWrite);
+ /* Test listening after a failed connection. */ + + fdWrite = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + set_blocking(fdWrite, FALSE); + + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + address.sin_port = 0; + ret = bind(fdWrite, (struct sockaddr *)&address, sizeof(address)); + ok(!ret, "got %d\n", ret); + + ret = connect(fdWrite, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); + ok(ret == -1, "got %d\n", ret); + ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); + + FD_ZERO(&exceptfds); + FD_SET(fdWrite, &exceptfds); + select_timeout.tv_sec = 10; + ret = select(0, NULL, NULL, &exceptfds, &select_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + + len = sizeof(address); + ret = getsockname(fdWrite, (struct sockaddr *)&address, &len); + ok(!ret, "got error %lu\n", GetLastError()); + + /* Linux seems to forbid this. We'd need to replace the underlying fd. */ + ret = listen(fdWrite, 1); + todo_wine ok(!ret, "got error %lu\n", GetLastError()); + + if (!ret) + { + client2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ret = connect(client2, (struct sockaddr *)&address, sizeof(address)); + ok(!ret, "got error %lu\n", GetLastError()); + + server2 = accept(fdWrite, NULL, NULL); + ok(server2 != INVALID_SOCKET, "got %d\n", ret); + + closesocket(server2); + closesocket(client2); + } + + len = sizeof(id); + id = 0xdeadbeef; + ret = getsockopt(fdWrite, SOL_SOCKET, SO_ERROR, (char *)&id, &len); + ok(!ret, "getsockopt failed with %d\n", WSAGetLastError()); + ok(id == WSAECONNREFUSED, "got error %lu\n", id); + + FD_ZERO_ALL(); + FD_SET(fdWrite, &readfds); + FD_SET(fdWrite, &writefds); + FD_SET(fdWrite, &exceptfds); + select_timeout.tv_sec = 0; + ret = select(0, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 1, "got %d\n", ret); + ok(FD_ISSET(fdWrite, &exceptfds), "fdWrite socket is not in the set\n"); + + closesocket(fdWrite); + /* test polling after a (synchronous) failure */
fdWrite = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -4090,6 +4150,12 @@ static void test_select(void) ok(ret == -1, "got %d\n", ret); ok(WSAGetLastError() == WSAECONNREFUSED, "got error %u\n", WSAGetLastError());
+ len = sizeof(id); + id = 0xdeadbeef; + ret = getsockopt(fdWrite, SOL_SOCKET, SO_ERROR, (char *)&id, &len); + ok(!ret, "getsockopt failed with %d\n", WSAGetLastError()); + todo_wine ok(!id, "got error %lu\n", id); + FD_ZERO_ALL(); FD_SET(fdWrite, &readfds); FD_SET(fdWrite, &writefds);
From: Zebediah Figura zfigura@codeweavers.com
This reverts commit 24b64534e592e47e5cac70e497a98c0ddbc3941b.
We no longer perform any blocking waits on the client side, so shutdown() is no longer necessary.
Moreover, shutting down is not always correct. Under some conditions, closing a TCP socket should trigger RST without FIN (namely, when SO_LINGER is on but has a zero timeout). By reverting this commit we match Windows behaviour in this respect.
---
This causes many tests to fail, but this is largely because we are now properly sending RST instead of FIN. --- dlls/ws2_32/tests/afd.c | 9 ++++----- dlls/ws2_32/tests/sock.c | 30 +++++++++++++++--------------- server/sock.c | 7 +------ 3 files changed, 20 insertions(+), 26 deletions(-)
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index f2dccd465a3..9852d54ecb9 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -162,8 +162,7 @@ static void check_poll_(int line, SOCKET s, HANDLE event, int mask, int expect, ok_(__FILE__, line)(out_params.count == 1, "got count %u\n", out_params.count); ok_(__FILE__, line)(out_params.sockets[0].socket == s, "got socket %#Ix\n", out_params.sockets[0].socket); todo_wine_if (todo) ok_(__FILE__, line)(out_params.sockets[0].flags == expect, "got flags %#x\n", out_params.sockets[0].flags); - todo_wine_if (expect & AFD_POLL_RESET) - ok_(__FILE__, line)(!out_params.sockets[0].status, "got status %#x\n", out_params.sockets[0].status); + ok_(__FILE__, line)(!out_params.sockets[0].status, "got status %#x\n", out_params.sockets[0].status); }
static void test_poll(void) @@ -1408,7 +1407,7 @@ static void test_poll_reset(void) ok(out_params->count == 1, "got count %u\n", out_params->count); ok(out_params->sockets[0].socket == client, "got socket %#Ix\n", out_params->sockets[0].socket); todo_wine ok(out_params->sockets[0].flags == AFD_POLL_RESET, "got flags %#x\n", out_params->sockets[0].flags); - ok(!out_params->sockets[0].status, "got status %#x\n", out_params->sockets[0].status); + todo_wine ok(!out_params->sockets[0].status, "got status %#x\n", out_params->sockets[0].status);
check_poll_todo(client, event, AFD_POLL_WRITE | AFD_POLL_CONNECT | AFD_POLL_RESET);
@@ -2044,7 +2043,7 @@ static void test_get_events_reset(void) ok(!ret, "got %#x\n", ret); todo_wine ok(params.flags == (AFD_POLL_RESET | AFD_POLL_CONNECT | AFD_POLL_WRITE), "got flags %#x\n", params.flags); for (i = 0; i < ARRAY_SIZE(params.status); ++i) - ok(!params.status[i], "got status[%u] %#x\n", i, params.status[i]); + todo_wine_if (i == AFD_POLL_BIT_HUP) ok(!params.status[i], "got status[%u] %#x\n", i, params.status[i]);
closesocket(client);
@@ -2062,7 +2061,7 @@ static void test_get_events_reset(void) ok(!ret, "got %#x\n", ret); todo_wine ok(params.flags == (AFD_POLL_RESET | AFD_POLL_WRITE), "got flags %#x\n", params.flags); for (i = 0; i < ARRAY_SIZE(params.status); ++i) - ok(!params.status[i], "got status[%u] %#x\n", i, params.status[i]); + todo_wine_if (i == AFD_POLL_BIT_HUP) ok(!params.status[i], "got status[%u] %#x\n", i, params.status[i]);
closesocket(server);
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index c89f48879aa..490b3b96e51 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -7018,12 +7018,12 @@ static void test_WSARecv(void) close_with_rst(src);
dwret = WaitForSingleObject(ov.hEvent, 1000); - ok(dwret == WAIT_OBJECT_0, "Waiting for disconnect event failed with %ld + errno %ld\n", dwret, GetLastError()); + todo_wine ok(dwret == WAIT_OBJECT_0, "Waiting for disconnect event failed with %ld + errno %ld\n", dwret, GetLastError());
bret = GetOverlappedResult((HANDLE)dest, &ov, &bytesReturned, FALSE); - todo_wine ok(!bret, "expected failure\n"); + ok(!bret, "expected failure\n"); todo_wine ok(GetLastError() == ERROR_NETNAME_DELETED, "got error %lu\n", GetLastError()); - ok(bytesReturned == 0, "Bytes received is %ld\n", bytesReturned); + todo_wine ok(bytesReturned == 0, "Bytes received is %ld\n", bytesReturned); closesocket(dest); dest = INVALID_SOCKET;
@@ -9668,11 +9668,11 @@ static void test_completion_port(void) olp = (WSAOVERLAPPED *)0xdeadbeef;
bret = GetQueuedCompletionStatus(io_port, &num_bytes, &key, &olp, 100); - todo_wine ok(bret == FALSE, "GetQueuedCompletionStatus returned %d\n", bret); + ok(bret == FALSE, "GetQueuedCompletionStatus returned %d\n", bret); todo_wine ok(GetLastError() == ERROR_NETNAME_DELETED, "Last error was %ld\n", GetLastError()); - ok(key == 125, "Key is %Iu\n", key); - ok(num_bytes == 0, "Number of bytes received is %lu\n", num_bytes); - ok(olp == &ov, "Overlapped structure is at %p\n", olp); + todo_wine ok(key == 125, "Key is %Iu\n", key); + todo_wine ok(num_bytes == 0, "Number of bytes received is %lu\n", num_bytes); + todo_wine ok(olp == &ov, "Overlapped structure is at %p\n", olp);
SetLastError(0xdeadbeef); key = 0xdeadbeef; @@ -9721,10 +9721,10 @@ static void test_completion_port(void)
bret = GetQueuedCompletionStatus( io_port, &num_bytes, &key, &olp, 200 ); ok(bret == FALSE, "GetQueuedCompletionStatus returned %u\n", bret ); - ok(GetLastError() == WAIT_TIMEOUT, "Last error was %ld\n", GetLastError()); - ok(key == 0xdeadbeef, "Key is %Iu\n", key); - ok(num_bytes == 0xdeadbeef, "Number of bytes transferred is %lu\n", num_bytes); - ok(!olp, "Overlapped structure is at %p\n", olp); + todo_wine ok(GetLastError() == WAIT_TIMEOUT, "Last error was %ld\n", GetLastError()); + todo_wine ok(key == 0xdeadbeef, "Key is %Iu\n", key); + todo_wine ok(num_bytes == 0xdeadbeef, "Number of bytes transferred is %lu\n", num_bytes); + todo_wine ok(!olp, "Overlapped structure is at %p\n", olp);
if (dest != INVALID_SOCKET) closesocket(dest); @@ -12851,11 +12851,11 @@ static void test_tcp_reset(void) close_with_rst(server);
ret = WaitForSingleObject(overlapped.hEvent, 1000); - ok(!ret, "wait failed\n"); + todo_wine ok(!ret, "wait failed\n"); ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, FALSE); - todo_wine ok(!ret, "expected failure\n"); + ok(!ret, "expected failure\n"); todo_wine ok(GetLastError() == ERROR_NETNAME_DELETED, "got error %lu\n", GetLastError()); - ok(!size, "got size %lu\n", size); + todo_wine ok(!size, "got size %lu\n", size); todo_wine ok((NTSTATUS)overlapped.Internal == STATUS_CONNECTION_RESET, "got status %#lx\n", (NTSTATUS)overlapped.Internal);
len = sizeof(error); @@ -12868,7 +12868,7 @@ static void test_tcp_reset(void) WSASetLastError(0xdeadbeef); size = 0xdeadbeef; ret = WSARecv(client, &wsabuf, 1, &size, &flags, &overlapped, NULL); - todo_wine ok(ret == -1, "got %d\n", ret); + ok(ret == -1, "got %d\n", ret); todo_wine ok(WSAGetLastError() == WSAECONNRESET, "got error %u\n", WSAGetLastError());
check_poll_todo(client, POLLERR | POLLHUP | POLLWRNORM); diff --git a/server/sock.c b/server/sock.c index 4eef5c1ddb7..31a04579fce 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1467,12 +1467,7 @@ static void sock_destroy( struct object *obj ) free_async_queue( &sock->connect_q ); free_async_queue( &sock->poll_q ); if (sock->event) release_object( sock->event ); - if (sock->fd) - { - /* shut the socket down to force pending poll() calls in the client to return */ - shutdown( get_unix_fd(sock->fd), SHUT_RDWR ); - release_object( sock->fd ); - } + if (sock->fd) release_object( sock->fd ); }
static struct sock *create_socket(void)
From: Zebediah Figura zfigura@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52815 --- dlls/ws2_32/tests/sock.c | 32 ++++++++++++++++---------------- server/sock.c | 6 ++---- 2 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 490b3b96e51..b0f07b9ab58 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -7018,12 +7018,12 @@ static void test_WSARecv(void) close_with_rst(src);
dwret = WaitForSingleObject(ov.hEvent, 1000); - todo_wine ok(dwret == WAIT_OBJECT_0, "Waiting for disconnect event failed with %ld + errno %ld\n", dwret, GetLastError()); + ok(dwret == WAIT_OBJECT_0, "Waiting for disconnect event failed with %ld + errno %ld\n", dwret, GetLastError());
bret = GetOverlappedResult((HANDLE)dest, &ov, &bytesReturned, FALSE); ok(!bret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_NETNAME_DELETED, "got error %lu\n", GetLastError()); - todo_wine ok(bytesReturned == 0, "Bytes received is %ld\n", bytesReturned); + ok(GetLastError() == ERROR_NETNAME_DELETED, "got error %lu\n", GetLastError()); + ok(bytesReturned == 0, "Bytes received is %ld\n", bytesReturned); closesocket(dest); dest = INVALID_SOCKET;
@@ -9669,10 +9669,10 @@ static void test_completion_port(void)
bret = GetQueuedCompletionStatus(io_port, &num_bytes, &key, &olp, 100); ok(bret == FALSE, "GetQueuedCompletionStatus returned %d\n", bret); - todo_wine ok(GetLastError() == ERROR_NETNAME_DELETED, "Last error was %ld\n", GetLastError()); - todo_wine ok(key == 125, "Key is %Iu\n", key); - todo_wine ok(num_bytes == 0, "Number of bytes received is %lu\n", num_bytes); - todo_wine ok(olp == &ov, "Overlapped structure is at %p\n", olp); + ok(GetLastError() == ERROR_NETNAME_DELETED, "Last error was %ld\n", GetLastError()); + ok(key == 125, "Key is %Iu\n", key); + ok(num_bytes == 0, "Number of bytes received is %lu\n", num_bytes); + ok(olp == &ov, "Overlapped structure is at %p\n", olp);
SetLastError(0xdeadbeef); key = 0xdeadbeef; @@ -9721,10 +9721,10 @@ static void test_completion_port(void)
bret = GetQueuedCompletionStatus( io_port, &num_bytes, &key, &olp, 200 ); ok(bret == FALSE, "GetQueuedCompletionStatus returned %u\n", bret ); - todo_wine ok(GetLastError() == WAIT_TIMEOUT, "Last error was %ld\n", GetLastError()); - todo_wine ok(key == 0xdeadbeef, "Key is %Iu\n", key); - todo_wine ok(num_bytes == 0xdeadbeef, "Number of bytes transferred is %lu\n", num_bytes); - todo_wine ok(!olp, "Overlapped structure is at %p\n", olp); + ok(GetLastError() == WAIT_TIMEOUT, "Last error was %ld\n", GetLastError()); + ok(key == 0xdeadbeef, "Key is %Iu\n", key); + ok(num_bytes == 0xdeadbeef, "Number of bytes transferred is %lu\n", num_bytes); + ok(!olp, "Overlapped structure is at %p\n", olp);
if (dest != INVALID_SOCKET) closesocket(dest); @@ -12851,12 +12851,12 @@ static void test_tcp_reset(void) close_with_rst(server);
ret = WaitForSingleObject(overlapped.hEvent, 1000); - todo_wine ok(!ret, "wait failed\n"); + ok(!ret, "wait failed\n"); ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, FALSE); ok(!ret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_NETNAME_DELETED, "got error %lu\n", GetLastError()); - todo_wine ok(!size, "got size %lu\n", size); - todo_wine ok((NTSTATUS)overlapped.Internal == STATUS_CONNECTION_RESET, "got status %#lx\n", (NTSTATUS)overlapped.Internal); + ok(GetLastError() == ERROR_NETNAME_DELETED, "got error %lu\n", GetLastError()); + ok(!size, "got size %lu\n", size); + ok((NTSTATUS)overlapped.Internal == STATUS_CONNECTION_RESET, "got status %#lx\n", (NTSTATUS)overlapped.Internal);
len = sizeof(error); ret = getsockopt(client, SOL_SOCKET, SO_ERROR, (char *)&error, &len); @@ -12868,7 +12868,7 @@ static void test_tcp_reset(void) WSASetLastError(0xdeadbeef); size = 0xdeadbeef; ret = WSARecv(client, &wsabuf, 1, &size, &flags, &overlapped, NULL); - ok(ret == -1, "got %d\n", ret); + todo_wine ok(ret == -1, "got %d\n", ret); todo_wine ok(WSAGetLastError() == WSAECONNRESET, "got error %u\n", WSAGetLastError());
check_poll_todo(client, POLLERR | POLLHUP | POLLWRNORM); diff --git a/server/sock.c b/server/sock.c index 31a04579fce..95335df8fd3 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1046,10 +1046,8 @@ static int sock_dispatch_asyncs( struct sock *sock, int event, int error ) int status = sock_get_ntstatus( error ); struct accept_req *req, *next;
- if (sock->rd_shutdown || sock->hangup) - async_wake_up( &sock->read_q, status ); - if (sock->wr_shutdown) - async_wake_up( &sock->write_q, status ); + async_wake_up( &sock->read_q, status ); + async_wake_up( &sock->write_q, status );
LIST_FOR_EACH_ENTRY_SAFE( req, next, &sock->accept_list, struct accept_req, entry ) {
From: Zebediah Figura zfigura@codeweavers.com
In multiple cases errors may be reported only once by the host socket implementation, but should persist for Windows sockets. These cases are currently not handled by poll_socket().
poll_socket() also does not include logic for filtering out events when asyncs are queued or alerted on the relevant socket.
Hence, instead of duplicating more logic, remove the logic already duplicated, and just call sock_poll_event(), so that there is one central place where events are translated.
Mark the currently active poll async with a special "pending" field so that poll_socket() does not attempt to complete it before all sockets are checked. --- server/sock.c | 53 +++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 36 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 95335df8fd3..b96f81a0ea8 100644 --- a/server/sock.c +++ b/server/sock.c @@ -124,6 +124,7 @@ struct poll_req struct timeout_user *timeout; timeout_t orig_timeout; int exclusive; + int pending; unsigned int count; struct { @@ -981,8 +982,11 @@ static void complete_async_polls( struct sock *sock, int event, int error ) req->sockets[i].flags = req->sockets[i].mask & flags; req->sockets[i].status = sock_get_ntstatus( error );
- complete_async_poll( req, STATUS_SUCCESS ); - break; + if (req->pending) + { + complete_async_poll( req, STATUS_SUCCESS ); + break; + } } } } @@ -3002,32 +3006,6 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) } }
-static int poll_single_socket( struct sock *sock, int mask ) -{ - struct pollfd pollfd; - - pollfd.fd = get_unix_fd( sock->fd ); - pollfd.events = poll_flags_from_afd( sock, mask ); - if (pollfd.events < 0 || poll( &pollfd, 1, 0 ) < 0) - return 0; - - if (sock->state == SOCK_CONNECTING && (pollfd.revents & (POLLERR | POLLHUP))) - pollfd.revents &= ~POLLOUT; - - if ((mask & AFD_POLL_HUP) && (pollfd.revents & POLLIN) && sock->type == WS_SOCK_STREAM) - { - char dummy; - - if (!recv( get_unix_fd( sock->fd ), &dummy, 1, MSG_PEEK )) - { - pollfd.revents &= ~POLLIN; - pollfd.revents |= POLLHUP; - } - } - - return get_poll_flags( sock, pollfd.revents ) & mask; -} - static void handle_exclusive_poll(struct poll_req *req) { unsigned int i; @@ -3065,6 +3043,7 @@ static void poll_socket( struct sock *poll_sock, struct async *async, int exclus return;
req->timeout = NULL; + req->pending = 0; if (timeout && timeout != TIMEOUT_INFINITE && !(req->timeout = add_timeout_user( timeout, async_poll_timeout, req ))) { @@ -3103,26 +3082,28 @@ static void poll_socket( struct sock *poll_sock, struct async *async, int exclus { struct sock *sock = req->sockets[i].sock; int mask = req->sockets[i].mask; - int flags = poll_single_socket( sock, mask ); + struct pollfd pollfd;
- if (flags) - { - signaled = TRUE; - req->sockets[i].flags = flags; - req->sockets[i].status = sock_get_ntstatus( sock_error( sock ) ); - } + pollfd.fd = get_unix_fd( sock->fd ); + pollfd.events = poll_flags_from_afd( sock, mask ); + if (pollfd.events >= 0 && poll( &pollfd, 1, 0 ) >= 0) + sock_poll_event( sock->fd, pollfd.revents );
/* FIXME: do other error conditions deserve a similar treatment? */ if (sock->state != SOCK_CONNECTING && sock->errors[AFD_POLL_BIT_CONNECT_ERR] && (mask & AFD_POLL_CONNECT_ERR)) { - signaled = TRUE; req->sockets[i].flags |= AFD_POLL_CONNECT_ERR; req->sockets[i].status = sock_get_ntstatus( sock->errors[AFD_POLL_BIT_CONNECT_ERR] ); } + + if (req->sockets[i].flags) + signaled = TRUE; }
if (!timeout || signaled) complete_async_poll( req, STATUS_SUCCESS ); + else + req->pending = 1;
for (i = 0; i < req->count; ++i) sock_reselect( req->sockets[i].sock );