[PATCH v2 2/3] ws2_32: Use server-side async I/O in accept().

Zebediah Figura z.figura12 at gmail.com
Mon Oct 19 11:21:19 CDT 2020


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/ws2_32/socket.c | 71 ++++++++++++++++++++------------------------
 server/async.c       |  5 ++++
 server/file.h        |  1 +
 server/sock.c        | 60 ++++++++++++++++++++++++++++++++-----
 4 files changed, 91 insertions(+), 46 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index e93c4ccf589..3efa4ebd64f 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -2673,55 +2673,50 @@ static int WS2_register_async_shutdown( SOCKET s, int type )
 /***********************************************************************
  *		accept		(WS2_32.1)
  */
-SOCKET WINAPI WS_accept(SOCKET s, struct WS_sockaddr *addr, int *addrlen32)
+SOCKET WINAPI WS_accept( SOCKET s, struct WS_sockaddr *addr, int *len )
 {
-    DWORD err;
-    int fd;
-    BOOL is_blocking;
     IO_STATUS_BLOCK io;
     NTSTATUS status;
     obj_handle_t accept_handle;
+    HANDLE sync_event;
+    SOCKET ret;
 
-    TRACE("socket %04lx\n", s );
-    err = sock_is_blocking(s, &is_blocking);
-    if (err)
-        goto error;
+    TRACE("%#lx\n", s);
 
-    for (;;)
+    if (!(sync_event = CreateEventW( NULL, TRUE, FALSE, NULL ))) return INVALID_SOCKET;
+    status = NtDeviceIoControlFile( SOCKET2HANDLE(s), (HANDLE)((ULONG_PTR)sync_event | 0), NULL, NULL, &io,
+                                    IOCTL_AFD_ACCEPT, NULL, 0, &accept_handle, sizeof(accept_handle) );
+    if (status == STATUS_PENDING)
     {
-        status = NtDeviceIoControlFile( SOCKET2HANDLE(s), NULL, NULL, NULL, &io, IOCTL_AFD_ACCEPT,
-                                        NULL, 0, &accept_handle, sizeof(accept_handle) );
-        if (!status)
+        if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED)
         {
-            SOCKET as = HANDLE2SOCKET(wine_server_ptr_handle( accept_handle ));
+            CloseHandle( sync_event );
+            return SOCKET_ERROR;
+        }
+        status = io.u.Status;
+    }
+    CloseHandle( sync_event );
+    if (status)
+    {
+        WARN("failed; status %#x\n", status);
+        WSASetLastError( NtStatusToWSAError( status ) );
+        return INVALID_SOCKET;
+    }
 
-            if (!socket_list_add(as))
-            {
-                CloseHandle(SOCKET2HANDLE(as));
-                return SOCKET_ERROR;
-            }
-            if (addr && addrlen32 && WS_getpeername(as, addr, addrlen32))
-            {
-                WS_closesocket(as);
-                return SOCKET_ERROR;
-            }
-            TRACE("\taccepted %04lx\n", as);
-            return as;
-        }
-        err = NtStatusToWSAError( status );
-        if (!is_blocking) break;
-        if (err != WSAEWOULDBLOCK) break;
-        fd = get_sock_fd( s, FILE_READ_DATA, NULL );
-        /* block here */
-        do_block(fd, POLLIN, -1);
-        _sync_sock_state(s); /* let wineserver notice connection */
-        release_sock_fd( s, fd );
+    ret = HANDLE2SOCKET(wine_server_ptr_handle( accept_handle ));
+    if (!socket_list_add( ret ))
+    {
+        CloseHandle( SOCKET2HANDLE(ret) );
+        return INVALID_SOCKET;
+    }
+    if (addr && len && WS_getpeername( ret, addr, len ))
+    {
+        WS_closesocket( ret );
+        return INVALID_SOCKET;
     }
 
-error:
-    WARN(" -> ERROR %d\n", err);
-    SetLastError(err);
-    return INVALID_SOCKET;
+    TRACE("returning %#lx\n", ret);
+    return ret;
 }
 
 /***********************************************************************
diff --git a/server/async.c b/server/async.c
index 24fed811da2..81d575b52bd 100644
--- a/server/async.c
+++ b/server/async.c
@@ -542,6 +542,11 @@ struct iosb *async_get_iosb( struct async *async )
     return async->iosb ? (struct iosb *)grab_object( async->iosb ) : NULL;
 }
 
+struct thread *async_get_thread( struct async *async )
+{
+    return async->thread;
+}
+
 int async_is_blocking( struct async *async )
 {
     return !async->event && !async->data.apc && !async->data.apc_context;
diff --git a/server/file.h b/server/file.h
index 477720f8b18..2fb634fad8d 100644
--- a/server/file.h
+++ b/server/file.h
@@ -221,6 +221,7 @@ extern struct completion *fd_get_completion( struct fd *fd, apc_param_t *p_key )
 extern void fd_copy_completion( struct fd *src, struct fd *dst );
 extern struct iosb *create_iosb( const void *in_data, data_size_t in_size, data_size_t out_size );
 extern struct iosb *async_get_iosb( struct async *async );
+extern struct thread *async_get_thread( struct async *async );
 extern int async_is_blocking( struct async *async );
 extern struct async *find_pending_async( struct async_queue *queue );
 extern void cancel_process_asyncs( struct process *process );
diff --git a/server/sock.c b/server/sock.c
index e09b0ee8ed0..5080d241439 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -175,6 +175,7 @@ static void sock_queue_async( struct fd *fd, struct async *async, int type, int
 static void sock_reselect_async( struct fd *fd, struct async_queue *queue );
 
 static int accept_into_socket( struct sock *sock, struct sock *acceptsock );
+static struct sock *accept_socket( struct sock *sock );
 static int sock_get_ntstatus( int err );
 static unsigned int sock_get_error( int err );
 
@@ -448,7 +449,7 @@ static inline int sock_error( struct fd *fd )
 static void free_accept_req( struct accept_req *req )
 {
     list_remove( &req->entry );
-    req->acceptsock->accept_recv_req = NULL;
+    if (req->acceptsock) req->acceptsock->accept_recv_req = NULL;
     release_object( req->async );
     free( req );
 }
@@ -527,11 +528,37 @@ static void complete_async_accept( struct sock *sock, struct accept_req *req )
 
     if (debug_level) fprintf( stderr, "completing accept request for socket %p\n", sock );
 
-    if (!accept_into_socket( sock, acceptsock )) return;
+    if (acceptsock)
+    {
+        if (!accept_into_socket( sock, acceptsock )) return;
 
-    iosb = async_get_iosb( async );
-    fill_accept_output( req, iosb );
-    release_object( iosb );
+        iosb = async_get_iosb( async );
+        fill_accept_output( req, iosb );
+        release_object( iosb );
+    }
+    else
+    {
+        obj_handle_t handle;
+
+        if (!(acceptsock = accept_socket( sock ))) return;
+        handle = alloc_handle_no_access_check( async_get_thread( async )->process, &acceptsock->obj,
+                                               GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, OBJ_INHERIT );
+        acceptsock->wparam = handle;
+        release_object( acceptsock );
+        if (!handle) return;
+
+        iosb = async_get_iosb( async );
+        if (!(iosb->out_data = malloc( sizeof(handle) )))
+        {
+            release_object( iosb );
+            return;
+        }
+        iosb->status = STATUS_SUCCESS;
+        iosb->out_size = sizeof(handle);
+        memcpy( iosb->out_data, &handle, sizeof(handle) );
+        release_object( iosb );
+        set_error( STATUS_ALERTED );
+    }
 }
 
 static void complete_async_accept_recv( struct accept_req *req )
@@ -1344,8 +1371,11 @@ static struct accept_req *alloc_accept_req( struct sock *acceptsock, struct asyn
         req->accepted = 0;
         req->recv_len = 0;
         req->local_len = 0;
-        req->recv_len = params->recv_len;
-        req->local_len = params->local_len;
+        if (params)
+        {
+            req->recv_len = params->recv_len;
+            req->local_len = params->local_len;
+        }
     }
     return req;
 }
@@ -1384,7 +1414,21 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
             return 0;
         }
 
-        if (!(acceptsock = accept_socket( sock ))) return 0;
+        if (!(acceptsock = accept_socket( sock )))
+        {
+            struct accept_req *req;
+
+            if (sock->state & FD_WINE_NONBLOCKING) return 0;
+            if (get_error() != (0xc0010000 | WSAEWOULDBLOCK)) return 0;
+
+            if (!(req = alloc_accept_req( NULL, async, NULL ))) return 0;
+            list_add_tail( &sock->accept_list, &req->entry );
+
+            queue_async( &sock->accept_q, async );
+            sock_reselect( sock );
+            set_error( STATUS_PENDING );
+            return 1;
+        }
         handle = alloc_handle( current->process, &acceptsock->obj,
                                GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, OBJ_INHERIT );
         acceptsock->wparam = handle;
-- 
2.28.0




More information about the wine-devel mailing list