[PATCH] winhttp: Use lock in send_frame().

Paul Gofman pgofman at codeweavers.com
Wed Feb 2 02:53:27 CST 2022


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
     While web socket sends are not actually supposed to be queued before the previous one completed, send for pongs
     or socket shutdown may be called in parallel. Only the first call will go for synchronous send attempt but the
     next queued call have a chance of hitting socket_send() before the first sync one returns.
     The sync outside of send_frame() (which is needed if the send wasn't completed synchronously) is provided by
     the queueing logic around pending_sends counter.

 dlls/winhttp/request.c         | 12 +++++++++---
 dlls/winhttp/winhttp_private.h |  1 +
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 728b1895ba7..756b40d8987 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -3111,6 +3111,7 @@ HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR
     socket->hdr.callback = request->hdr.callback;
     socket->hdr.notify_mask = request->hdr.notify_mask;
     socket->hdr.context = context;
+    InitializeSRWLock( &socket->send_lock );
 
     addref_object( &request->hdr );
     socket->request = request;
@@ -3153,6 +3154,8 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
 
     TRACE( "sending %02x frame, len %u.\n", opcode, len );
 
+    AcquireSRWLockExclusive( &socket->send_lock );
+
     if (opcode == SOCKET_OPCODE_CLOSE) len += sizeof(status);
 
     hdr[0] = final ? (char)FIN_BIT : 0;
@@ -3188,7 +3191,8 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
         if (!(new = realloc( socket->send_frame_buffer, new_size )))
         {
             ERR("Out of memory, buffer_size %u.\n", buffer_size);
-            return ERROR_OUTOFMEMORY;
+            ret = ERROR_OUTOFMEMORY;
+            goto done;
         }
         socket->send_frame_buffer = new;
         socket->send_frame_buffer_size = new_size;
@@ -3231,13 +3235,15 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
                 memmove( socket->send_frame_buffer, socket->send_frame_buffer + sent_size, offset - sent_size );
                 socket->bytes_in_send_frame_buffer = offset - sent_size;
             }
-            return ret;
+            goto done;
         }
         assert( sent_size == offset );
         offset = 0;
         buflen -= len;
     }
-    return ERROR_SUCCESS;
+done:
+    ReleaseSRWLockExclusive( &socket->send_lock );
+    return ret;
 }
 
 static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, const char *buf )
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 3e4e1eb298d..732f0afaa88 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -259,6 +259,7 @@ struct socket
     unsigned int send_remaining_size;
     unsigned int bytes_in_send_frame_buffer;
     unsigned int client_buffer_offset;
+    SRWLOCK send_lock;
 };
 
 struct send_request
-- 
2.34.1




More information about the wine-devel mailing list