[PATCH 3/5] winhttp: Attemp sync websocket send even if data doesn't fit frame buffer.
Paul Gofman
pgofman at codeweavers.com
Wed Jan 26 17:03:07 CST 2022
From: Paul Gofman <gofmanp at gmail.com>
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
dlls/winhttp/request.c | 56 ++++++++++++++++++++++------------
dlls/winhttp/winhttp_private.h | 4 +++
2 files changed, 41 insertions(+), 19 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index e8576256fe7..a5bd828c9b7 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -3145,10 +3145,10 @@ static DWORD send_bytes( struct socket *socket, char *bytes, int len, int *sent,
static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHORT status, const char *buf,
DWORD buflen, BOOL final, WSAOVERLAPPED *ovr )
{
- DWORD i = 0, j, offset = 2, len = buflen;
- DWORD buffer_size, ret = 0, send_size;
- char hdr[14], *mask = NULL;
+ DWORD i, offset = 2, len = buflen;
+ DWORD buffer_size, ret = 0;
int sent_size;
+ char hdr[14];
char *ptr;
TRACE( "sending %02x frame, len %u.\n", opcode, len );
@@ -3179,7 +3179,6 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
buffer_size = len + offset + 4;
assert( buffer_size - len < MAX_FRAME_BUFFER_SIZE );
- if (ovr && buffer_size > MAX_FRAME_BUFFER_SIZE) return WSAEWOULDBLOCK;
if (buffer_size > socket->send_frame_buffer_size && socket->send_frame_buffer_size < MAX_FRAME_BUFFER_SIZE)
{
DWORD new_size;
@@ -3199,27 +3198,32 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
memcpy(ptr, hdr, offset);
ptr += offset;
- mask = &hdr[offset];
- RtlGenRandom( mask, 4 );
- memcpy( ptr, mask, 4 );
+ RtlGenRandom( socket->mask, 4 );
+ memcpy( ptr, socket->mask, 4 );
ptr += 4;
+ socket->mask_index = 0;
if (opcode == SOCKET_OPCODE_CLOSE) /* prepend status code */
{
- *ptr++ = (status >> 8) ^ mask[i++ % 4];
- *ptr++ = (status & 0xff) ^ mask[i++ % 4];
+ *ptr++ = (status >> 8) ^ socket->mask[socket->mask_index++ % 4];
+ *ptr++ = (status & 0xff) ^ socket->mask[socket->mask_index++ % 4];
}
offset = ptr - socket->send_frame_buffer;
- send_size = offset + buflen;
- while (1)
+ socket->send_remaining_size = offset + buflen;
+ socket->client_buffer_offset = 0;
+ while (socket->send_remaining_size)
{
- j = 0;
- while (j < buflen && offset < MAX_FRAME_BUFFER_SIZE)
- socket->send_frame_buffer[offset++] = buf[j++] ^ mask[i++ % 4];
+ len = min( buflen, MAX_FRAME_BUFFER_SIZE - offset );
+ for (i = 0; i < len; ++i)
+ {
+ socket->send_frame_buffer[offset++] = buf[socket->client_buffer_offset++]
+ ^ socket->mask[socket->mask_index++ % 4];
+ }
sent_size = 0;
ret = send_bytes( socket, socket->send_frame_buffer, offset, &sent_size, ovr );
+ socket->send_remaining_size -= sent_size;
if (ret)
{
if (ovr && ret == WSA_IO_PENDING)
@@ -3229,17 +3233,16 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
}
return ret;
}
- if (!(send_size -= offset)) break;
+ assert( sent_size == offset );
offset = 0;
- buf += j;
- buflen -= j;
+ buflen -= len;
}
return ERROR_SUCCESS;
}
static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, const char *buf )
{
- DWORD ret, retflags, len;
+ DWORD ret, retflags, len, i;
if (!WSAGetOverlappedResult( socket->request->netconn->socket, ovr, &len, TRUE, &retflags ))
return WSAGetLastError();
@@ -3249,6 +3252,22 @@ static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, con
ret = send_bytes( socket, socket->send_frame_buffer, socket->bytes_in_send_frame_buffer, NULL, NULL );
if (ret) return ret;
}
+
+ assert( socket->bytes_in_send_frame_buffer <= socket->send_remaining_size );
+ socket->send_remaining_size -= socket->bytes_in_send_frame_buffer;
+
+ while (socket->send_remaining_size)
+ {
+ len = min( socket->send_remaining_size, MAX_FRAME_BUFFER_SIZE );
+ for (i = 0; i < len; ++i)
+ {
+ socket->send_frame_buffer[i] = buf[socket->client_buffer_offset++]
+ ^ socket->mask[socket->mask_index++ % 4];
+ }
+ ret = send_bytes( socket, socket->send_frame_buffer, len, NULL, NULL );
+ if (ret) return ret;
+ socket->send_remaining_size -= len;
+ }
return ERROR_SUCCESS;
}
@@ -3371,7 +3390,6 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_
async_send = TRUE;
complete_async = TRUE;
}
- else if (ret == WSAEWOULDBLOCK) async_send = TRUE;
}
if (async_send)
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 639c97b126e..b41eb0ee676 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -247,6 +247,8 @@ struct socket
struct queue recv_q;
enum socket_opcode opcode;
DWORD read_size;
+ char mask[4];
+ unsigned int mask_index;
BOOL close_frame_received;
DWORD close_frame_receive_err;
USHORT status;
@@ -254,7 +256,9 @@ struct socket
DWORD reason_len;
char *send_frame_buffer;
unsigned int send_frame_buffer_size;
+ unsigned int send_remaining_size;
unsigned int bytes_in_send_frame_buffer;
+ unsigned int client_buffer_offset;
};
struct send_request
--
2.34.1
More information about the wine-devel
mailing list