[PATCH v3 0/1] MR10044: Draft: server: Clear connection failure events in IOCTL_AFD_WINE_CONNECT.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53574 See details in the bug report. [Testbot run with this patch](https://testbot.winehq.org/JobDetails.pl?Key=161764) -- v3: server: Clear connection failure events in IOCTL_AFD_WINE_CONNECT. https://gitlab.winehq.org/wine/wine/-/merge_requests/10044
From: Bernhard Übelacker <bernhardu@mailbox.org> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53574 --- dlls/ws2_32/tests/sock.c | 52 ++++++++++++++++++++++++++++++++++++++++ server/sock.c | 6 +++++ 2 files changed, 58 insertions(+) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 8d589c63ea3..af96c0829d4 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -6875,6 +6875,58 @@ static void test_connect_events(struct event_test_ctx *ctx) closesocket(server); closesocket(listener); + + /* Test events getting cleared on second connect after connection got refused. + * w10pro64 sometimes takes over 2 seconds for an error to be reported, + * so make the test interactive-only. */ + //if (winetest_interactive) //disabled to run with gitlab, until leaving draft state + { + struct sockaddr_in invalid_addr; + + client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ok(client != -1, "failed to create socket, error %u\n", WSAGetLastError()); + + select_events(ctx, client, FD_ACCEPT | FD_CLOSE | FD_CONNECT | FD_OOB | FD_READ | FD_WRITE); + check_events(ctx, 0, 0, 0); + check_events(ctx, 0, 0, 0); + + memset( &invalid_addr, 0, sizeof(invalid_addr) ); + invalid_addr.sin_family = AF_INET; + invalid_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + invalid_addr.sin_port = htons(255); + + /* attempt to connect to closed port */ + ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); + ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret); + check_events(ctx, MAKELONG(FD_CONNECT, WSAECONNREFUSED), 0, 4000); + check_events(ctx, 0, 0, 0); + + /* try again to connect, should behave the same */ + ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); + ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret); + check_events(ctx, MAKELONG(FD_CONNECT, WSAECONNREFUSED), 0, 4000); + check_events(ctx, 0, 0, 0); + + ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); + ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret); + /* try with invalid size, after event set */ + ret = connect(client, (struct sockaddr *)&invalid_addr, 1); + ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret); + check_events(ctx, MAKELONG(FD_CONNECT, WSAECONNREFUSED), 0, 4000); + check_events(ctx, 0, 0, 0); + + ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); + ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret); + /* try with invalid sin_family, after event set */ + invalid_addr.sin_family = 0xf1; + ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); + ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret); + check_events(ctx, MAKELONG(FD_CONNECT, WSAECONNREFUSED), 0, 4000); + check_events(ctx, 0, 0, 0); + invalid_addr.sin_family = AF_INET; + + closesocket(client); + } } /* perform a blocking recv() even on a nonblocking socket */ diff --git a/server/sock.c b/server/sock.c index 7785d3c7706..e979e02c618 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2743,6 +2743,12 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) set_error( STATUS_INVALID_ADDRESS ); return; } + if (sock->state == SOCK_UNCONNECTED) + { + /* clear events after call to sockaddr_to_unix */ + sock->pending_events &= ~AFD_POLL_CONNECT_ERR; + sock->reported_events &= ~AFD_POLL_CONNECT_ERR; + } if (unix_addr.addr.sa_family == AF_INET && !memcmp( &unix_addr.in.sin_addr, magic_loopback_addr, 4 )) unix_addr.in.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10044
v3: [Testbot run with this patch](https://testbot.winehq.org/GetFile.pl?JobKey=161972&StepKey=1) - Add test if "stored" event gets reset with connect attempts with invalid address/size. - Move the event clearing after the call to sockaddr_to_unix. TODO: - Add test: "I.e. if you fail connection, don't check events, and then successfully connect, I would expect that the connection failure is not reported. Ideally this too should be tested." -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10044#note_129973
On Wed Feb 18 00:16:35 2026 +0000, Elizabeth Figura wrote:
Hello Elizabeth, thanks for your great feedback. I pushed v2 that addresses a few of the raised issues. But I have trouble adding the additional tests. What would an invalid address look like? Cases where sockaddr_to_unix returns zero. It's probably enough to test just one such case, e.g. if the address length is too small, or if the family is invalid. Thanks for the clarification. I added this in v3, and therefore moved in the implementation the event resetting below the call to sockaddr_to_unix.
For the test about the "successful connect": In this [Testbot run](https://testbot.winehq.org/JobDetails.pl?Key=161973) I added a connect to an open port, but I receive WSAEALREADY from native, when there is an event stored before. Is this somewhere near what you wanted to see? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10044#note_129980
On Thu Feb 19 17:18:13 2026 +0000, Bernhard Übelacker wrote:
Thanks for the clarification. I added this in v3, and therefore moved in the implementation the event resetting below the call to sockaddr_to_unix. For the test about the "successful connect": In this [Testbot run](https://testbot.winehq.org/JobDetails.pl?Key=161973) I added a connect to an open port, but I receive WSAEALREADY from native, when there is an event stored before. Is this somewhere near what you wanted to see? Your previous connect hasn't had time to resolve to a failure state yet. The socket is only connectable again once it's clear that it's actually failed to connect. You'll probably want to use a select() or WSAPoll() in order to wait for that to happen, before doing the event tests.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10044#note_130775
participants (3)
-
Bernhard Übelacker -
Bernhard Übelacker (@bernhardu) -
Elizabeth Figura (@zfigura)