From: Zebediah Figura zfigura@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