[PATCH 1/3] winhttp: Don't allow websocket send if another non-control send is pending.

Paul Gofman pgofman at codeweavers.com
Thu Feb 24 12:14:39 CST 2022


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
     Similar to WinHttpWebSocketReceive() but requires a separate variable because control frame send may be queued
     from read operation for pong.
     It is not quite straightforward to add to test as most of the time the send is executed synchronously. I
     tested that manually however and repeated sends without wait in between trigger this error on Windows.

     I am not aware of any app depending on this behaviour but it simplifies the synchronization for the next patch.

 dlls/winhttp/request.c         | 16 +++++++++++++++-
 dlls/winhttp/winhttp_private.h |  1 +
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index d0732952e11..de011060236 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -3349,6 +3349,7 @@ static void CALLBACK task_socket_send( TP_CALLBACK_INSTANCE *instance, void *ctx
     else                   ret = socket_send( s->socket, s->type, s->buf, s->len, NULL );
 
     send_io_complete( &s->socket->hdr );
+    InterlockedExchange( &s->socket->pending_noncontrol_send, 0 );
     socket_send_complete( s->socket, ret, s->type, s->len );
 
     release_object( &s->socket->hdr );
@@ -3386,8 +3387,16 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_
         BOOL async_send, complete_async = FALSE;
         struct socket_send *s;
 
+        if (InterlockedCompareExchange( &socket->pending_noncontrol_send, 1, 0 ))
+        {
+            WARN( "Previous send is still queued.\n" );
+            release_object( &socket->hdr );
+            return ERROR_INVALID_OPERATION;
+        }
+
         if (!(s = malloc( sizeof(*s) )))
         {
+            InterlockedExchange( &socket->pending_noncontrol_send, 0 );
             release_object( &socket->hdr );
             return ERROR_OUTOFMEMORY;
         }
@@ -3417,11 +3426,16 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_
             if ((ret = queue_task( &socket->send_q, task_socket_send, s )))
             {
                 InterlockedDecrement( &socket->hdr.pending_sends );
+                InterlockedExchange( &socket->pending_noncontrol_send, 0 );
                 release_object( &socket->hdr );
                 free( s );
             }
         }
-        else InterlockedDecrement( &socket->hdr.pending_sends );
+        else
+        {
+            InterlockedDecrement( &socket->hdr.pending_sends );
+            InterlockedExchange( &socket->pending_noncontrol_send, 0 );
+        }
         ReleaseSRWLockExclusive( &socket->send_lock );
         if (!async_send)
         {
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 732f0afaa88..cf6655f561f 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -260,6 +260,7 @@ struct socket
     unsigned int bytes_in_send_frame_buffer;
     unsigned int client_buffer_offset;
     SRWLOCK send_lock;
+    volatile LONG pending_noncontrol_send;
 };
 
 struct send_request
-- 
2.35.1




More information about the wine-devel mailing list