[PATCH 2/5] ws2_32: Use IOCTL_AFD_WINE_TRANSMIT.

Zebediah Figura z.figura12 at gmail.com
Thu May 27 18:57:30 CDT 2021


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/ws2_32/socket.c | 559 +++----------------------------------------
 1 file changed, 36 insertions(+), 523 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index ff2db136f89..24ac24dcdeb 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -498,34 +498,6 @@ struct ws2_async
     struct iovec                        iovec[1];
 };
 
-struct ws2_accept_async
-{
-    struct ws2_async_io io;
-    HANDLE              listen_socket;
-    HANDLE              accept_socket;
-    LPOVERLAPPED        user_overlapped;
-    ULONG_PTR           cvalue;
-    PVOID               buf;      /* buffer to write data to */
-    int                 data_len;
-    int                 local_len;
-    int                 remote_len;
-    struct ws2_async    *read;
-};
-
-struct ws2_transmitfile_async
-{
-    struct ws2_async_io   io;
-    char                  *buffer;
-    HANDLE                file;
-    DWORD                 file_read;
-    DWORD                 file_bytes;
-    DWORD                 bytes_per_send;
-    TRANSMIT_FILE_BUFFERS buffers;
-    DWORD                 flags;
-    LARGE_INTEGER         offset;
-    struct ws2_async      write;
-};
-
 static struct ws2_async_io *async_io_freelist;
 
 static void release_async_io( struct ws2_async_io *io )
@@ -556,32 +528,6 @@ static struct ws2_async_io *alloc_async_io( DWORD size, async_callback_t callbac
     return io;
 }
 
-static NTSTATUS register_async( int type, HANDLE handle, struct ws2_async_io *async, HANDLE event,
-                                PIO_APC_ROUTINE apc, void *apc_context, IO_STATUS_BLOCK *io )
-{
-    NTSTATUS status;
-
-    SERVER_START_REQ( register_async )
-    {
-        req->type              = type;
-        req->async.handle      = wine_server_obj_handle( handle );
-        req->async.user        = wine_server_client_ptr( async );
-        req->async.iosb        = wine_server_client_ptr( io );
-        req->async.event       = wine_server_obj_handle( event );
-        req->async.apc         = wine_server_client_ptr( apc );
-        req->async.apc_context = wine_server_client_ptr( apc_context );
-        status = wine_server_call( req );
-    }
-    SERVER_END_REQ;
-
-    return status;
-}
-
-/****************************************************************/
-
-/* ----------------------------------- internal data */
-
-/* ws_... struct conversion flags */
 
 typedef struct          /* WSAAsyncSelect() control struct */
 {
@@ -608,15 +554,6 @@ static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS C
 
 #define MAP_OPTION(opt) { WS_##opt, opt }
 
-static const int ws_flags_map[][2] =
-{
-    MAP_OPTION( MSG_OOB ),
-    MAP_OPTION( MSG_PEEK ),
-    MAP_OPTION( MSG_DONTROUTE ),
-    MAP_OPTION( MSG_WAITALL ),
-    { WS_MSG_PARTIAL, 0 },
-};
-
 static const int ws_sock_map[][2] =
 {
     MAP_OPTION( SO_DEBUG ),
@@ -710,50 +647,6 @@ static const int ws_poll_map[][2] =
     { WS_POLLRDBAND, POLLPRI }
 };
 
-static NTSTATUS sock_get_ntstatus( int err )
-{
-    switch ( err )
-    {
-        case EBADF:             return STATUS_INVALID_HANDLE;
-        case EBUSY:             return STATUS_DEVICE_BUSY;
-        case EPERM:
-        case EACCES:            return STATUS_ACCESS_DENIED;
-        case EFAULT:            return STATUS_ACCESS_VIOLATION;
-        case EINVAL:            return STATUS_INVALID_PARAMETER;
-        case ENFILE:
-        case EMFILE:            return STATUS_TOO_MANY_OPENED_FILES;
-        case EINPROGRESS:
-        case EWOULDBLOCK:       return STATUS_DEVICE_NOT_READY;
-        case EALREADY:          return STATUS_NETWORK_BUSY;
-        case ENOTSOCK:          return STATUS_OBJECT_TYPE_MISMATCH;
-        case EDESTADDRREQ:      return STATUS_INVALID_PARAMETER;
-        case EMSGSIZE:          return STATUS_BUFFER_OVERFLOW;
-        case EPROTONOSUPPORT:
-        case ESOCKTNOSUPPORT:
-        case EPFNOSUPPORT:
-        case EAFNOSUPPORT:
-        case EPROTOTYPE:        return STATUS_NOT_SUPPORTED;
-        case ENOPROTOOPT:       return STATUS_INVALID_PARAMETER;
-        case EOPNOTSUPP:        return STATUS_NOT_SUPPORTED;
-        case EADDRINUSE:        return STATUS_SHARING_VIOLATION;
-        case EADDRNOTAVAIL:     return STATUS_INVALID_PARAMETER;
-        case ECONNREFUSED:      return STATUS_CONNECTION_REFUSED;
-        case ESHUTDOWN:         return STATUS_PIPE_DISCONNECTED;
-        case ENOTCONN:          return STATUS_INVALID_CONNECTION;
-        case ETIMEDOUT:         return STATUS_IO_TIMEOUT;
-        case ENETUNREACH:       return STATUS_NETWORK_UNREACHABLE;
-        case ENETDOWN:          return STATUS_NETWORK_BUSY;
-        case EPIPE:
-        case ECONNRESET:        return STATUS_CONNECTION_RESET;
-        case ECONNABORTED:      return STATUS_CONNECTION_ABORTED;
-
-        case 0:                 return STATUS_SUCCESS;
-        default:
-            WARN("Unknown errno %d!\n", err);
-            return STATUS_UNSUCCESSFUL;
-    }
-}
-
 UINT sock_get_error( int err )
 {
 	switch(err)
@@ -830,15 +723,6 @@ static UINT wsaErrno(void)
     return sock_get_error( loc_errno );
 }
 
-/* most ws2 overlapped functions return an ntstatus-based error code */
-static NTSTATUS wsaErrStatus(void)
-{
-    int	loc_errno = errno;
-    WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno));
-
-    return sock_get_ntstatus(loc_errno);
-}
-
 static NTSTATUS sock_error_to_ntstatus( DWORD err )
 {
     switch (err)
@@ -1000,21 +884,6 @@ static void _enable_event( HANDLE s, unsigned int event,
     SERVER_END_REQ;
 }
 
-static DWORD sock_is_blocking(SOCKET s, BOOL *ret)
-{
-    DWORD err;
-    SERVER_START_REQ( get_socket_event )
-    {
-        req->handle  = wine_server_obj_handle( SOCKET2HANDLE(s) );
-        req->service = FALSE;
-        req->c_event = 0;
-        err = NtStatusToWSAError( wine_server_call( req ));
-        *ret = (reply->state & FD_WINE_NONBLOCKING) == 0;
-    }
-    SERVER_END_REQ;
-    return err;
-}
-
 static unsigned int _get_sock_mask(SOCKET s)
 {
     unsigned int ret;
@@ -1030,14 +899,6 @@ static unsigned int _get_sock_mask(SOCKET s)
     return ret;
 }
 
-static void _sync_sock_state(SOCKET s)
-{
-    BOOL dummy;
-    /* do a dummy wineserver request in order to let
-       the wineserver run through its select loop once */
-    sock_is_blocking(s, &dummy);
-}
-
 static void _get_sock_errors(SOCKET s, int *events)
 {
     SERVER_START_REQ( get_socket_event )
@@ -1211,33 +1072,6 @@ BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
     return TRUE;
 }
 
-/***********************************************************************
- *          convert_flags()
- *
- * Converts send/recv flags from Windows format.
- * Return the converted flag bits, unsupported flags remain unchanged.
- */
-static int convert_flags(int flags)
-{
-    int i, out;
-    if (!flags) return 0;
-
-    for (out = i = 0; flags && i < ARRAY_SIZE(ws_flags_map); i++)
-    {
-        if (ws_flags_map[i][0] & flags)
-        {
-            out |= ws_flags_map[i][1];
-            flags &= ~ws_flags_map[i][0];
-        }
-    }
-    if (flags)
-    {
-        FIXME("Unknown send/recv flags 0x%x, using anyway...\n", flags);
-        out |= flags;
-    }
-    return out;
-}
-
 /***********************************************************************
  *          convert_sockopt()
  *
@@ -1326,25 +1160,6 @@ static inline INT64 get_rcvsnd_timeo( int fd, BOOL is_recv)
   return (UINT64)tv.tv_sec * 1000 + tv.tv_usec / 1000;
 }
 
-/* utility: given an fd, will block until one of the events occurs */
-static inline int do_block( int fd, int events, int timeout )
-{
-  struct pollfd pfd;
-  int ret;
-
-  pfd.fd = fd;
-  pfd.events = events;
-
-  while ((ret = poll(&pfd, 1, timeout)) < 0)
-  {
-      if (errno != EINTR)
-          return -1;
-  }
-  if( ret == 0 )
-      return 0;
-  return pfd.revents;
-}
-
 int
 convert_socktype_w2u(int windowssocktype) {
     unsigned int i;
@@ -1927,81 +1742,6 @@ static void WINAPI ws2_async_apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserv
     release_async_io( &wsa->io );
 }
 
-/***********************************************************************
- *              WS2_send                (INTERNAL)
- *
- * Workhorse for both synchronous and asynchronous send() operations.
- */
-static int WS2_send( int fd, struct ws2_async *wsa, int flags )
-{
-    struct msghdr hdr;
-    union generic_unix_sockaddr unix_addr;
-    int n, ret;
-
-    hdr.msg_name = NULL;
-    hdr.msg_namelen = 0;
-
-    if (wsa->addr)
-    {
-        hdr.msg_name = &unix_addr;
-        hdr.msg_namelen = ws_sockaddr_ws2u( wsa->addr, wsa->addrlen.val, &unix_addr );
-        if ( !hdr.msg_namelen )
-        {
-            errno = EFAULT;
-            return -1;
-        }
-
-#if defined(HAS_IPX) && defined(SOL_IPX)
-        if(wsa->addr->sa_family == WS_AF_IPX)
-        {
-            struct sockaddr_ipx* uipx = (struct sockaddr_ipx*)hdr.msg_name;
-            int val=0;
-            socklen_t len = sizeof(int);
-
-            /* The packet type is stored at the ipx socket level; At least the linux kernel seems
-             *  to do something with it in case hdr.msg_name is NULL. Nonetheless can we use it to store
-             *  the packet type and then we can retrieve it using getsockopt. After that we can set the
-             *  ipx type in the sockaddr_opx structure with the stored value.
-             */
-            if(getsockopt(fd, SOL_IPX, IPX_TYPE, &val, &len) != -1)
-                uipx->sipx_type = val;
-        }
-#endif
-    }
-
-    hdr.msg_iov = wsa->iovec + wsa->first_iovec;
-    hdr.msg_iovlen = wsa->n_iovecs - wsa->first_iovec;
-#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
-    hdr.msg_accrights = NULL;
-    hdr.msg_accrightslen = 0;
-#else
-    hdr.msg_control = NULL;
-    hdr.msg_controllen = 0;
-    hdr.msg_flags = 0;
-#endif
-
-    while ((ret = sendmsg(fd, &hdr, flags)) == -1)
-    {
-        if (errno == EISCONN)
-        {
-            hdr.msg_name = 0;
-            hdr.msg_namelen = 0;
-            continue;
-        }
-        if (errno != EINTR)
-            return -1;
-    }
-
-    n = ret;
-    while (wsa->first_iovec < wsa->n_iovecs && wsa->iovec[wsa->first_iovec].iov_len <= n)
-        n -= wsa->iovec[wsa->first_iovec++].iov_len;
-    if (wsa->first_iovec < wsa->n_iovecs)
-    {
-        wsa->iovec[wsa->first_iovec].iov_base = (char*)wsa->iovec[wsa->first_iovec].iov_base + n;
-        wsa->iovec[wsa->first_iovec].iov_len -= n;
-    }
-    return ret;
-}
 
 /***********************************************************************
  *		accept		(WS2_32.1)
@@ -2097,281 +1837,54 @@ static BOOL WINAPI WS2_AcceptEx( SOCKET listener, SOCKET acceptor, void *dest, D
     return !status;
 }
 
-/***********************************************************************
- *     WS2_ReadFile                     (INTERNAL)
- *
- * Perform an APC-safe ReadFile operation
- */
-static NTSTATUS WS2_ReadFile(HANDLE hFile, PIO_STATUS_BLOCK io_status, char* buffer, ULONG length,
-                             PLARGE_INTEGER offset)
+
+static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE file, DWORD file_len, DWORD buffer_size,
+                                     OVERLAPPED *overlapped, TRANSMIT_FILE_BUFFERS *buffers, DWORD flags )
 {
-    int result = -1, unix_handle;
-    unsigned int options;
+    struct afd_transmit_params params = {0};
+    IO_STATUS_BLOCK iosb, *piosb = &iosb;
+    HANDLE event = NULL;
+    void *cvalue = NULL;
     NTSTATUS status;
 
-    TRACE( "(%p,%p,0x%08x)\n", hFile, buffer,length );
+    TRACE( "socket %#lx, file %p, file_len %u, buffer_size %u, overlapped %p, buffers %p, flags %#x\n",
+           s, file, file_len, buffer_size, overlapped, buffers, flags );
 
-    status = wine_server_handle_to_fd( hFile, FILE_READ_DATA, &unix_handle, &options );
-    if (status) return status;
-
-    while (result == -1)
-    {
-        if (offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
-            result = pread( unix_handle, buffer, length, offset->QuadPart );
-        else
-            result = read( unix_handle, buffer, length );
-        if (errno != EINTR)
-            break;
-    }
-
-    if (!result)
-        status = (length ? STATUS_END_OF_FILE : STATUS_SUCCESS);
-    else if (result != -1)
-        status = STATUS_SUCCESS;
-    else if (errno != EAGAIN)
-        status = wsaErrStatus();
-    else
-        status = STATUS_PENDING;
-
-    close( unix_handle );
-    TRACE("= 0x%08x (%d)\n", status, result);
-    if (status == STATUS_SUCCESS || status == STATUS_END_OF_FILE)
-    {
-        io_status->u.Status = status;
-        io_status->Information = result;
-    }
-
-    return status;
-}
-
-/***********************************************************************
- *     WS2_transmitfile_getbuffer       (INTERNAL)
- *
- * Pick the appropriate buffer for a TransmitFile send operation.
- */
-static NTSTATUS WS2_transmitfile_getbuffer( int fd, struct ws2_transmitfile_async *wsa )
-{
-    /* send any incomplete writes from a previous iteration */
-    if (wsa->write.first_iovec < wsa->write.n_iovecs)
-        return STATUS_PENDING;
-
-    /* process the header (if applicable) */
-    if (wsa->buffers.Head)
-    {
-        wsa->write.first_iovec       = 0;
-        wsa->write.n_iovecs          = 1;
-        wsa->write.iovec[0].iov_base = wsa->buffers.Head;
-        wsa->write.iovec[0].iov_len  = wsa->buffers.HeadLength;
-        wsa->buffers.Head            = NULL;
-        return STATUS_PENDING;
-    }
-
-    /* process the main file */
-    if (wsa->file)
-    {
-        DWORD bytes_per_send = wsa->bytes_per_send;
-        IO_STATUS_BLOCK iosb;
-        NTSTATUS status;
-
-        iosb.Information = 0;
-        /* when the size of the transfer is limited ensure that we don't go past that limit */
-        if (wsa->file_bytes != 0)
-            bytes_per_send = min(bytes_per_send, wsa->file_bytes - wsa->file_read);
-        status = WS2_ReadFile( wsa->file, &iosb, wsa->buffer, bytes_per_send, &wsa->offset );
-        if (wsa->offset.QuadPart != FILE_USE_FILE_POINTER_POSITION)
-            wsa->offset.QuadPart += iosb.Information;
-        if (status == STATUS_END_OF_FILE)
-            wsa->file = NULL; /* continue on to the footer */
-        else if (status != STATUS_SUCCESS)
-            return status;
-        else
-        {
-            if (iosb.Information)
-            {
-                wsa->write.first_iovec       = 0;
-                wsa->write.n_iovecs          = 1;
-                wsa->write.iovec[0].iov_base = wsa->buffer;
-                wsa->write.iovec[0].iov_len  = iosb.Information;
-                wsa->file_read += iosb.Information;
-            }
-
-            if (wsa->file_bytes != 0 && wsa->file_read >= wsa->file_bytes)
-                wsa->file = NULL;
-
-            return STATUS_PENDING;
-        }
-    }
-
-    /* send the footer (if applicable) */
-    if (wsa->buffers.Tail)
-    {
-        wsa->write.first_iovec       = 0;
-        wsa->write.n_iovecs          = 1;
-        wsa->write.iovec[0].iov_base = wsa->buffers.Tail;
-        wsa->write.iovec[0].iov_len  = wsa->buffers.TailLength;
-        wsa->buffers.Tail            = NULL;
-        return STATUS_PENDING;
-    }
-
-    return STATUS_SUCCESS;
-}
-
-/***********************************************************************
- *     WS2_transmitfile_base            (INTERNAL)
- *
- * Shared implementation for both synchronous and asynchronous TransmitFile.
- */
-static NTSTATUS WS2_transmitfile_base( int fd, struct ws2_transmitfile_async *wsa )
-{
-    NTSTATUS status;
-
-    status = WS2_transmitfile_getbuffer( fd, wsa );
-    if (status == STATUS_PENDING)
-    {
-        IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)wsa->write.user_overlapped;
-        int n;
-
-        n = WS2_send( fd, &wsa->write, convert_flags(wsa->write.flags) );
-        if (n >= 0)
-        {
-            if (iosb) iosb->Information += n;
-        }
-        else if (errno != EAGAIN)
-            return wsaErrStatus();
-    }
-
-    return status;
-}
-
-/***********************************************************************
- *     WS2_async_transmitfile           (INTERNAL)
- *
- * Asynchronous callback for overlapped TransmitFile operations.
- */
-static NTSTATUS WS2_async_transmitfile( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
-{
-    struct ws2_transmitfile_async *wsa = user;
-    int fd;
-
-    if (status == STATUS_ALERTED)
-    {
-        if (!(status = wine_server_handle_to_fd( wsa->write.hSocket, FILE_WRITE_DATA, &fd, NULL )))
-        {
-            status = WS2_transmitfile_base( fd, wsa );
-            close( fd );
-        }
-        if (status == STATUS_PENDING)
-            return status;
-    }
-
-    iosb->u.Status = status;
-    release_async_io( &wsa->io );
-    return status;
-}
-
-/***********************************************************************
- *     TransmitFile
- */
-static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD file_bytes, DWORD bytes_per_send,
-                                     LPOVERLAPPED overlapped, LPTRANSMIT_FILE_BUFFERS buffers,
-                                     DWORD flags )
-{
-    union generic_unix_sockaddr uaddr;
-    socklen_t uaddrlen = sizeof(uaddr);
-    struct ws2_transmitfile_async *wsa;
-    NTSTATUS status;
-    int fd;
-
-    TRACE("(%lx, %p, %d, %d, %p, %p, %d)\n", s, h, file_bytes, bytes_per_send, overlapped,
-            buffers, flags );
-
-    fd = get_sock_fd( s, FILE_WRITE_DATA, NULL );
-    if (fd == -1) return FALSE;
-
-    if (getpeername( fd, &uaddr.addr, &uaddrlen ) != 0)
-    {
-        release_sock_fd( s, fd );
-        WSASetLastError( WSAENOTCONN );
-        return FALSE;
-    }
-    if (flags)
-        FIXME("Flags are not currently supported (0x%x).\n", flags);
-
-    if (h && GetFileType( h ) != FILE_TYPE_DISK)
-    {
-        FIXME("Non-disk file handles are not currently supported.\n");
-        release_sock_fd( s, fd );
-        WSASetLastError( WSAEOPNOTSUPP );
-        return FALSE;
-    }
-
-    /* set reasonable defaults when requested */
-    if (!bytes_per_send)
-        bytes_per_send = (1 << 16); /* Depends on OS version: PAGE_SIZE, 2*PAGE_SIZE, or 2^16 */
-
-    if (!(wsa = (struct ws2_transmitfile_async *)alloc_async_io( sizeof(*wsa) + bytes_per_send,
-                                                                 WS2_async_transmitfile )))
-    {
-        release_sock_fd( s, fd );
-        WSASetLastError( WSAEFAULT );
-        return FALSE;
-    }
-    if (buffers)
-        wsa->buffers = *buffers;
-    else
-        memset(&wsa->buffers, 0x0, sizeof(wsa->buffers));
-    wsa->buffer                = (char *)(wsa + 1);
-    wsa->file                  = h;
-    wsa->file_read             = 0;
-    wsa->file_bytes            = file_bytes;
-    wsa->bytes_per_send        = bytes_per_send;
-    wsa->flags                 = flags;
-    wsa->offset.QuadPart       = FILE_USE_FILE_POINTER_POSITION;
-    wsa->write.hSocket         = SOCKET2HANDLE(s);
-    wsa->write.addr            = NULL;
-    wsa->write.addrlen.val     = 0;
-    wsa->write.flags           = 0;
-    wsa->write.lpFlags         = &wsa->flags;
-    wsa->write.control         = NULL;
-    wsa->write.n_iovecs        = 0;
-    wsa->write.first_iovec     = 0;
-    wsa->write.user_overlapped = overlapped;
     if (overlapped)
     {
-        IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)overlapped;
-        int status;
-
-        wsa->offset.u.LowPart  = overlapped->u.s.Offset;
-        wsa->offset.u.HighPart = overlapped->u.s.OffsetHigh;
-        iosb->u.Status = STATUS_PENDING;
-        iosb->Information = 0;
-        status = register_async( ASYNC_TYPE_WRITE, SOCKET2HANDLE(s), &wsa->io,
-                                 overlapped->hEvent, NULL, NULL, iosb );
-        if(status != STATUS_PENDING) HeapFree( GetProcessHeap(), 0, wsa );
-        release_sock_fd( s, fd );
-        WSASetLastError( NtStatusToWSAError(status) );
-        return FALSE;
+        piosb = (IO_STATUS_BLOCK *)overlapped;
+        if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped;
+        event = overlapped->hEvent;
+        overlapped->Internal = STATUS_PENDING;
+        overlapped->InternalHigh = 0;
+        params.offset.u.LowPart = overlapped->u.s.Offset;
+        params.offset.u.HighPart = overlapped->u.s.OffsetHigh;
     }
-
-    do
+    else
     {
-        status = WS2_transmitfile_base( fd, wsa );
-        if (status == STATUS_PENDING)
-        {
-            /* block here */
-            do_block(fd, POLLOUT, -1);
-            _sync_sock_state(s); /* let wineserver notice connection */
-        }
+        if (!(event = get_sync_event())) return -1;
+        params.offset.QuadPart = FILE_USE_FILE_POINTER_POSITION;
     }
-    while (status == STATUS_PENDING);
-    release_sock_fd( s, fd );
 
-    if (status != STATUS_SUCCESS)
-        WSASetLastError( NtStatusToWSAError(status) );
-    HeapFree( GetProcessHeap(), 0, wsa );
-    return (status == STATUS_SUCCESS);
+    params.file = file;
+    params.file_len = file_len;
+    params.buffer_size = buffer_size;
+    if (buffers) params.buffers = *buffers;
+    params.flags = flags;
+
+    status = NtDeviceIoControlFile( (HANDLE)s, event, NULL, cvalue, piosb,
+                                    IOCTL_AFD_WINE_TRANSMIT, &params, sizeof(params), NULL, 0 );
+    if (status == STATUS_PENDING && !overlapped)
+    {
+        if (WaitForSingleObject( event, INFINITE ) == WAIT_FAILED)
+            return FALSE;
+        status = piosb->u.Status;
+    }
+    SetLastError( NtStatusToWSAError( status ) );
+    return !status;
 }
 
+
 /***********************************************************************
  *     GetAcceptExSockaddrs
  */
-- 
2.30.2




More information about the wine-devel mailing list