[PATCH 4/5] winhttp: Allow synchronous nonblocking send in send_socket_shutdown().

Paul Gofman pgofman at codeweavers.com
Wed Jan 26 17:03:08 CST 2022


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/winhttp/request.c            | 75 +++++++++++++++++++++----------
 dlls/winhttp/tests/notification.c |  2 +-
 dlls/winhttp/winhttp_private.h    |  2 +
 3 files changed, 55 insertions(+), 24 deletions(-)

diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index a5bd828c9b7..62f53995258 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -3727,6 +3727,19 @@ DWORD WINAPI WinHttpWebSocketReceive( HINTERNET hsocket, void *buf, DWORD len, D
     return ret;
 }
 
+static void socket_shutdown_complete( struct socket *socket, DWORD ret )
+{
+    if (!ret) send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NULL, 0 );
+    else
+    {
+        WINHTTP_WEB_SOCKET_ASYNC_RESULT result;
+        result.AsyncResult.dwResult = API_WRITE_DATA;
+        result.AsyncResult.dwError  = ret;
+        result.Operation = WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION;
+        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
+    }
+}
+
 static void CALLBACK task_socket_shutdown( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
 {
     struct socket_shutdown *s = ctx;
@@ -3734,21 +3747,11 @@ static void CALLBACK task_socket_shutdown( TP_CALLBACK_INSTANCE *instance, void
 
     TRACE("running %p\n", work);
 
-    ret = send_frame( s->socket, SOCKET_OPCODE_CLOSE, s->status, s->reason, s->len, TRUE, NULL );
-    send_io_complete( &s->socket->hdr );
+    if (s->complete_async) ret = complete_send_frame( s->socket, &s->ovr, s->reason );
+    else                   ret = send_frame( s->socket, SOCKET_OPCODE_CLOSE, s->status, s->reason, s->len, TRUE, NULL );
 
-    if (s->send_callback)
-    {
-        if (!ret) send_callback( &s->socket->hdr, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NULL, 0 );
-        else
-        {
-            WINHTTP_WEB_SOCKET_ASYNC_RESULT result;
-            result.AsyncResult.dwResult = API_WRITE_DATA;
-            result.AsyncResult.dwError  = ret;
-            result.Operation = WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION;
-            send_callback( &s->socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
-        }
-    }
+    send_io_complete( &s->socket->hdr );
+    if (s->send_callback) socket_shutdown_complete( s->socket, ret );
     release_object( &s->socket->hdr );
     free( s );
 }
@@ -3762,22 +3765,48 @@ static DWORD send_socket_shutdown( struct socket *socket, USHORT status, const v
 
     if (socket->request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
     {
+        BOOL async_send, complete_async = FALSE;
         struct socket_shutdown *s;
 
         if (!(s = malloc( sizeof(*s) ))) return FALSE;
-        s->socket = socket;
-        s->status = status;
-        memcpy( s->reason, reason, len );
-        s->len    = len;
-        s->send_callback = send_callback;
 
-        addref_object( &socket->hdr );
-        InterlockedIncrement( &socket->hdr.pending_sends );
-        if ((ret = queue_task( &socket->send_q, task_socket_shutdown, s )))
+        async_send = InterlockedIncrement( &socket->hdr.pending_sends ) > 1 || socket->hdr.recursion_count >= 3;
+        if (!async_send)
+        {
+            memset( &s->ovr, 0, sizeof(s->ovr) );
+            if ((ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE, &s->ovr )) == WSA_IO_PENDING)
+            {
+                async_send = TRUE;
+                complete_async = TRUE;
+            }
+        }
+
+        if (async_send)
+        {
+            s->complete_async = complete_async;
+            s->socket = socket;
+            s->status = status;
+            memcpy( s->reason, reason, len );
+            s->len    = len;
+            s->send_callback = send_callback;
+
+            addref_object( &socket->hdr );
+            if ((ret = queue_task( &socket->send_q, task_socket_shutdown, s )))
+            {
+                InterlockedDecrement( &socket->hdr.pending_sends );
+                release_object( &socket->hdr );
+                free( s );
+            }
+        }
+        else
         {
             InterlockedDecrement( &socket->hdr.pending_sends );
-            release_object( &socket->hdr );
             free( s );
+            if (send_callback)
+            {
+                socket_shutdown_complete( socket, ret );
+                ret = ERROR_SUCCESS;
+            }
         }
     }
     else ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE, NULL );
diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c
index 5ec8740f66e..1ae7e1af2e7 100644
--- a/dlls/winhttp/tests/notification.c
+++ b/dlls/winhttp/tests/notification.c
@@ -677,7 +677,7 @@ static const struct notification websocket_test[] =
     { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL },
     { winhttp_websocket_send,             WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL },
     { winhttp_websocket_send,             WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL },
-    { winhttp_websocket_shutdown,         WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NF_SIGNAL },
+    { winhttp_websocket_shutdown,         WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL },
     { winhttp_websocket_receive,          WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SAVE_BUFFER | NF_SIGNAL },
     { winhttp_websocket_receive,          WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SAVE_BUFFER | NF_SIGNAL },
     { winhttp_websocket_close,            WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, NF_SIGNAL },
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index b41eb0ee676..3e4e1eb298d 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -323,6 +323,8 @@ struct socket_shutdown
     char reason[123];
     DWORD len;
     BOOL send_callback;
+    WSAOVERLAPPED ovr;
+    BOOL complete_async;
 };
 
 struct object_header *addref_object( struct object_header * ) DECLSPEC_HIDDEN;
-- 
2.34.1




More information about the wine-devel mailing list