[PATCH v4 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) -- v4: 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 | 118 ++++++++++++++++++++++++++++++++++++--- server/sock.c | 6 ++ 2 files changed, 117 insertions(+), 7 deletions(-) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 8d589c63ea3..bd6b051f3e9 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -6423,12 +6423,13 @@ static void select_events(struct event_test_ctx *ctx, SOCKET socket, LONG events ctx->socket = socket; } -#define check_events(a, b, c, d) check_events_(__LINE__, a, b, c, d, FALSE, FALSE) -#define check_events_todo(a, b, c, d) check_events_(__LINE__, a, b, c, d, TRUE, TRUE) -#define check_events_todo_event(a, b, c, d) check_events_(__LINE__, a, b, c, d, TRUE, FALSE) -#define check_events_todo_msg(a, b, c, d) check_events_(__LINE__, a, b, c, d, FALSE, TRUE) +#define check_events(ctx, f1, f2, t) check_events_(__LINE__, ctx, f1, f2, 0, t, FALSE, FALSE) +#define check_events3(ctx, f1, f2, f3, t) check_events_(__LINE__, ctx, f1, f2, f3, t, FALSE, FALSE) +#define check_events_todo(ctx, f1, f2, t) check_events_(__LINE__, ctx, f1, f2, 0, t, TRUE, TRUE) +#define check_events_todo_event(ctx, f1, f2, t) check_events_(__LINE__, ctx, f1, f2, 0, t, TRUE, FALSE) +#define check_events_todo_msg(ctx, f1, f2, t) check_events_(__LINE__, ctx, f1, f2, 0, t, FALSE, TRUE) static void check_events_(int line, struct event_test_ctx *ctx, - LONG flag1, LONG flag2, DWORD timeout, BOOL todo_event, BOOL todo_msg) + LONG flag1, LONG flag2, LONG flag3, DWORD timeout, BOOL todo_event, BOOL todo_msg) { int ret; @@ -6442,7 +6443,7 @@ static void check_events_(int line, struct event_test_ctx *ctx, ret = PeekMessageA(&msg, ctx->window, WM_USER, WM_USER, PM_REMOVE); while (!ret && !MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_POSTMESSAGE)) ret = PeekMessageA(&msg, ctx->window, WM_USER, WM_USER, PM_REMOVE); - todo_wine_if (todo_msg && !ret) ok_(__FILE__, line)(ret, "expected a message\n"); + todo_wine_if (todo_msg && !ret) ok_(__FILE__, line)(ret, "expected a message (flag1)\n"); if (ret) { ok_(__FILE__, line)(msg.wParam == ctx->socket, @@ -6459,10 +6460,19 @@ static void check_events_(int line, struct event_test_ctx *ctx, ret = PeekMessageA(&msg, ctx->window, WM_USER, WM_USER, PM_REMOVE); while (!ret && !MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_POSTMESSAGE)) ret = PeekMessageA(&msg, ctx->window, WM_USER, WM_USER, PM_REMOVE); - ok_(__FILE__, line)(ret, "expected a message\n"); + ok_(__FILE__, line)(ret, "expected a message (flag2)\n"); ok_(__FILE__, line)(msg.wParam == ctx->socket, "got wparam %#Ix\n", msg.wParam); todo_wine_if (todo_msg) ok_(__FILE__, line)(msg.lParam == flag2, "got second event %#Ix\n", msg.lParam); } + if (flag3) + { + ret = PeekMessageA(&msg, ctx->window, WM_USER, WM_USER, PM_REMOVE); + while (!ret && !MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_POSTMESSAGE)) + ret = PeekMessageA(&msg, ctx->window, WM_USER, WM_USER, PM_REMOVE); + ok_(__FILE__, line)(ret, "expected a message (flag3)\n"); + ok_(__FILE__, line)(msg.wParam == ctx->socket, "got wparam %#Ix\n", msg.wParam); + todo_wine_if (todo_msg) ok_(__FILE__, line)(msg.lParam == flag3, "got second event %#Ix\n", msg.lParam); + } MsgWaitForMultipleObjects(0, NULL, FALSE, 10, QS_POSTMESSAGE); ret = PeekMessageA(&msg, ctx->window, WM_USER, WM_USER, PM_REMOVE); todo_wine_if (todo_msg && ret) ok_(__FILE__, line)(!ret, "got unexpected event %#Ix\n", msg.lParam); @@ -6875,6 +6885,96 @@ 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); + + /* set event by connecting 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); + + /* set event by connecting to closed port, second try, 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); + + /* set event by connecting to closed port */ + 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 was 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); + + /* set event by connecting to closed port */ + 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 was 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); + + /* setup listener */ + listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ok(listener != -1, "failed to create socket, error %u\n", WSAGetLastError()); + ret = bind(listener, (const struct sockaddr *)&addr, sizeof(addr)); + ok(!ret, "failed to bind, error %u\n", WSAGetLastError()); + len = sizeof(destaddr); + ret = getsockname(listener, (struct sockaddr *)&destaddr, &len); + ok(!ret, "failed to get address, error %u\n", WSAGetLastError()); + ret = listen(listener, 2); + ok(!ret, "failed to listen, error %u\n", WSAGetLastError()); + 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); + + /* set event by connecting 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_poll_todo(client, 0); + Sleep(2000); + /* try successful connect, after event was set */ + ret = connect(client, (struct sockaddr *)&destaddr, sizeof(destaddr)); + ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret); + ok(WSAGetLastError() == WSAEWOULDBLOCK, "expected WSAEWOULDBLOCK, got %u\n", WSAGetLastError()); + check_poll(client, POLLWRNORM); + if (ctx->is_message) + check_events3(ctx, MAKELONG(FD_CONNECT, WSAECONNREFUSED), FD_CONNECT, FD_WRITE, 4000); + else + check_events(ctx, MAKELONG(FD_CONNECT | FD_WRITE, WSAECONNREFUSED), 0, 4000); + check_events(ctx, 0, 0, 0); + + closesocket(client); + + closesocket(listener); + } } /* perform a blocking recv() even on a nonblocking socket */ @@ -7353,6 +7453,7 @@ static void test_events(void) struct event_test_ctx ctx; ctx.is_message = FALSE; + winetest_push_context("is_message=0"); ctx.event = CreateEventW(NULL, TRUE, FALSE, NULL); test_accept_events(&ctx); @@ -7364,7 +7465,9 @@ static void test_events(void) CloseHandle(ctx.event); + winetest_pop_context(); ctx.is_message = TRUE; + winetest_push_context("is_message=1"); ctx.window = CreateWindowA("Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); test_accept_events(&ctx); @@ -7375,6 +7478,7 @@ static void test_events(void) test_oob_events(&ctx); DestroyWindow(ctx.window); + winetest_pop_context(); } static void test_ipv6only(void) 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
v4: [Testbot run with this patch](https://testbot.winehq.org/JobDetails.pl?Key=163114) - Add check_events3, a variant that takes three messages. - Add test that does a successful connection after a failed connection attempt. (Did not get it working without the Sleep.) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10044#note_141385
I would just not run these tests in message mode. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10044#note_141445
participants (3)
-
Bernhard Übelacker -
Bernhard Übelacker (@bernhardu) -
Elizabeth Figura (@zfigura)