Module: wine Branch: master Commit: 4e6a5d62ad2bbccafa751812ca31eb9ffa25727e URL: https://gitlab.winehq.org/wine/wine/-/commit/4e6a5d62ad2bbccafa751812ca31eb9...
Author: Paul Gofman pgofman@codeweavers.com Date: Wed Feb 15 16:29:32 2023 -0600
server: Retry socket connection on ECONNABORTED error.
---
dlls/ws2_32/tests/afd.c | 8 +------- dlls/ws2_32/tests/sock.c | 41 ++++++++++++++++++++++++++--------------- server/sock.c | 11 +++++++++++ 3 files changed, 38 insertions(+), 22 deletions(-)
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index 3215ddaef62..b07fb40fe3f 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -569,13 +569,7 @@ static void test_poll(void)
ret = connect(client, (struct sockaddr *)&addr, sizeof(addr)); ok(ret == -1, "got %d\n", ret); - todo_wine ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - if (WSAGetLastError() == WSAECONNABORTED) - { - ret = connect(client, (struct sockaddr *)&addr, sizeof(addr)); - ok(ret == -1, "got %d\n", ret); - ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - } + ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError());
/* A subsequent poll call returns no events, or times out. However, this * can't be reliably tested, as e.g. Linux will fail the connection diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 58dcf9e7f4e..17298ca4136 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -4352,13 +4352,7 @@ static void test_select(void)
ret = connect(fdWrite, (const struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); ok(ret == -1, "got %d\n", ret); - todo_wine ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - if (WSAGetLastError() == WSAECONNABORTED) - { - ret = connect(fdWrite, (const struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); - ok(ret == -1, "got %d\n", ret); - ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - } + ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError());
len = sizeof(id); id = 0xdeadbeef; @@ -4380,13 +4374,7 @@ static void test_select(void) ok(!ret, "got error %u\n", WSAGetLastError()); ret = connect(fdWrite, (const struct sockaddr *)&address, sizeof(address)); ok(ret == -1, "got %d\n", ret); - todo_wine ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - if (WSAGetLastError() == WSAECONNABORTED) - { - ret = connect(fdWrite, (const struct sockaddr *)&address, sizeof(address)); - ok(ret == -1, "got %d\n", ret); - ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - } + ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError());
FD_ZERO_ALL(); FD_SET(fdWrite, &readfds); @@ -8320,7 +8308,6 @@ static void test_connect(void)
closesocket(connector); closesocket(acceptor); - closesocket(listener);
tcp_socketpair(&connector, &acceptor);
@@ -8380,6 +8367,30 @@ static void test_connect(void)
WSACloseEvent(overlapped.hEvent); closesocket(connector); + + /* Test connect after previous connect attempt failure. */ + connector = socket(AF_INET, SOCK_STREAM, 0); + ok(connector != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError()); + + conaddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + conaddress.sin_port = htons(255); + iret = connect(connector, (struct sockaddr *)&conaddress, sizeof(conaddress)); + ok(iret == -1, "connection succeeded.\n"); + + ok(WSAGetLastError() == WSAECONNREFUSED, "got error %u\n", WSAGetLastError()); + set_blocking( connector, FALSE ); + iret = getsockname(listener, (struct sockaddr*)&address, &addrlen); + ok(!iret, "failed to get address, error %u\n", WSAGetLastError()); + + iret = connect(connector, (struct sockaddr *)&address, sizeof(address)); + ok(iret == -1 && WSAGetLastError() == WSAEWOULDBLOCK, "unexpected iret %d, error %d.\n", + iret, WSAGetLastError()); + acceptor = accept(listener, NULL, NULL); + ok(acceptor != INVALID_SOCKET, "could not accept socket error %d\n", WSAGetLastError()); + + closesocket(acceptor); + closesocket(connector); + closesocket(listener); }
static void test_AcceptEx(void) diff --git a/server/sock.c b/server/sock.c index a64cb22404e..610e0a94cc0 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2602,6 +2602,17 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) unix_addr.in.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
ret = connect( unix_fd, &unix_addr.addr, unix_len ); + if (ret < 0 && errno == ECONNABORTED) + { + /* On Linux with nonblocking socket if the previous connect() failed for any reason (including + * timeout), next connect will fail. If the error code was queried by getsockopt( SO_ERROR ) + * the error code returned now is ECONNABORTED (otherwise that is the actual connect() failure + * error code). If we got here after previous connect attempt on the socket that means + * we already queried SO_ERROR in sock_error(), so retrying on ECONNABORTED only is + * sufficient. */ + ret = connect( unix_fd, &unix_addr.addr, unix_len ); + } + if (ret < 0 && errno != EINPROGRESS) { set_error( sock_get_ntstatus( errno ) );