From: Zebediah Figura <zfigura(a)codeweavers.com> Tests show that the socket is shut down, but sending further data doesn't result in a TCP reset, so we need to keep the socket itself open until the TCP connection is closed. --- dlls/http.sys/http.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/dlls/http.sys/http.c b/dlls/http.sys/http.c index e16805ccbdb..a1cb77cdfe3 100644 --- a/dlls/http.sys/http.c +++ b/dlls/http.sys/http.c @@ -19,6 +19,7 @@ */ #include <assert.h> +#include <stdbool.h> #include "ntstatus.h" #define WIN32_NO_STATUS #include "wine/http.h" @@ -55,6 +56,7 @@ struct connection char *buffer; unsigned int len, size; + bool shutdown; /* If there is a request fully received and waiting to be read, the * "available" parameter will be TRUE. Either there is no queue matching @@ -112,7 +114,7 @@ static struct list request_queues = LIST_INIT(request_queues); static void accept_connection(SOCKET socket) { struct connection *conn; - ULONG true = 1; + ULONG one = 1; SOCKET peer; if ((peer = accept(socket, NULL, NULL)) == INVALID_SOCKET) @@ -135,15 +137,22 @@ static void accept_connection(SOCKET socket) } conn->size = 8192; WSAEventSelect(peer, request_event, FD_READ | FD_CLOSE); - ioctlsocket(peer, FIONBIO, &true); + ioctlsocket(peer, FIONBIO, &one); conn->socket = peer; list_add_head(&connections, &conn->entry); } -static void close_connection(struct connection *conn) +static void shutdown_connection(struct connection *conn) { heap_free(conn->buffer); shutdown(conn->socket, SD_BOTH); + conn->shutdown = true; +} + +static void close_connection(struct connection *conn) +{ + if (!conn->shutdown) + shutdown_connection(conn); closesocket(conn->socket); list_remove(&conn->entry); heap_free(conn); @@ -594,12 +603,24 @@ static void send_400(struct connection *conn) strcat(buffer, response_body); if (send(conn->socket, buffer, strlen(buffer), 0) < 0) ERR("Failed to send 400 response, error %u.\n", WSAGetLastError()); + shutdown_connection(conn); } static void receive_data(struct connection *conn) { int len, ret; + if (conn->shutdown) + { + WSANETWORKEVENTS events; + + if ((ret = WSAEnumNetworkEvents(conn->socket, NULL, &events)) < 0) + ERR("Failed to enumerate network events, error %u.\n", WSAGetLastError()); + if (events.lNetworkEvents & FD_CLOSE) + close_connection(conn); + return; + } + /* We might be waiting for an IRP, but always call recv() anyway, since we * might have been woken up by the socket closing. */ if ((len = recv(conn->socket, conn->buffer + conn->len, conn->size - conn->len, 0)) <= 0) @@ -654,7 +675,6 @@ static void receive_data(struct connection *conn) { WARN("Failed to parse request; shutting down connection.\n"); send_400(conn); - close_connection(conn); } } @@ -715,8 +735,8 @@ static NTSTATUS http_add_url(struct request_queue *queue, IRP *irp) struct listening_socket *listening_sock; char *url, *endptr; size_t queue_url_len, new_url_len; - ULONG true = 1; SOCKET s = INVALID_SOCKET; + ULONG one = 1; TRACE("host %s, context %s.\n", debugstr_a(params->url), wine_dbgstr_longlong(params->context)); @@ -823,7 +843,7 @@ static NTSTATUS http_add_url(struct request_queue *queue, IRP *irp) listening_sock->socket = s; list_add_head(&listening_sockets, &listening_sock->entry); - ioctlsocket(s, FIONBIO, &true); + ioctlsocket(s, FIONBIO, &one); WSAEventSelect(s, request_event, FD_ACCEPT); } @@ -1002,7 +1022,6 @@ static NTSTATUS http_send_response(struct request_queue *queue, IRP *irp) { WARN("Failed to parse request; shutting down connection.\n"); send_400(conn); - close_connection(conn); } } else -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/544