Alexandre Julliard : ws2_32: Reimplement WSARecvFrom along the lines of NtReadFile.

Alexandre Julliard julliard at wine.codeweavers.com
Thu May 31 08:33:37 CDT 2007


Module: wine
Branch: master
Commit: 6759e1c286823a8ea6b004ca256481d16d1852fc
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=6759e1c286823a8ea6b004ca256481d16d1852fc

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Thu May 31 11:55:38 2007 +0200

ws2_32: Reimplement WSARecvFrom along the lines of NtReadFile.

---

 dlls/ws2_32/socket.c |  116 ++++++++++++++++++++++++++++---------------------
 1 files changed, 66 insertions(+), 50 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 1eed70a..85a2269 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -4213,7 +4213,8 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
 
 {
     unsigned int i, options;
-    int n, fd, err = WSAENOTSOCK, ret;
+    int n, fd, err;
+    DWORD timeout_start = GetTickCount();
     struct iovec* iovec;
     struct ws2_async *wsa;
     IO_STATUS_BLOCK* iosb;
@@ -4232,7 +4233,7 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
     if ( !iovec )
     {
         err = WSAEFAULT;
-        goto err_close;
+        goto error;
     }
 
     for (i = 0; i < dwBufferCount; i++)
@@ -4241,65 +4242,84 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
         iovec[i].iov_len  = lpBuffers[i].len;
     }
 
-    if ( (lpOverlapped || lpCompletionRoutine) &&
-        !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
+    for (;;)
     {
-        wsa = WS2_make_async( s, ws2m_read, iovec, dwBufferCount,
-                              lpFlags, lpFrom, lpFromlen,
-                              lpOverlapped, lpCompletionRoutine, &iosb );
+        n = WS2_recv( fd, iovec, dwBufferCount, lpFrom, lpFromlen, lpFlags );
+        if (n != -1) break;
 
-        if ( !wsa )
+        if (errno == EINTR) continue;
+        if (errno != EAGAIN)
         {
-            err = WSAEFAULT;
-            goto err_free;
+            err = wsaErrno();
+            goto error;
         }
 
-        if ((ret = ws2_queue_async( wsa, iosb )) != STATUS_PENDING)
+        if ((lpOverlapped || lpCompletionRoutine) &&
+             !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
         {
-            err = NtStatusToWSAError( ret );
+            wsa = WS2_make_async( s, ws2m_read, iovec, dwBufferCount,
+                                  lpFlags, lpFrom, lpFromlen,
+                                  lpOverlapped, lpCompletionRoutine, &iosb );
+            if ( !wsa )
+            {
+                err = WSAEFAULT;
+                goto error;
+            }
+            release_sock_fd( s, fd );
 
-            if ( !lpOverlapped )
-                HeapFree( GetProcessHeap(), 0, iosb );
-            HeapFree( GetProcessHeap(), 0, wsa );
-            goto err_free;
+            iosb->u.Status = STATUS_PENDING;
+            iosb->Information = 0;
+
+            SERVER_START_REQ( register_async )
+            {
+                req->handle = wsa->hSocket;
+                req->type   = ASYNC_TYPE_READ;
+                req->async.callback = WS2_async_recv;
+                req->async.iosb     = iosb;
+                req->async.arg      = wsa;
+                req->async.event    = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
+                err = wine_server_call( req );
+            }
+            SERVER_END_REQ;
+
+            if (err == STATUS_PENDING)
+                NtCurrentTeb()->num_async_io++;
+            else
+                ws2_async_terminate(wsa, iosb, err, 0);
+
+            WSASetLastError( NtStatusToWSAError( err ));
+            return SOCKET_ERROR;
         }
-        release_sock_fd( s, fd );
 
-        /* Try immediate completion */
-        if ( lpOverlapped )
+        if ( _is_blocking(s) )
         {
-            if  ( WSAGetOverlappedResult( s, lpOverlapped,
-                                           lpNumberOfBytesRecvd, FALSE, lpFlags) )
-                return 0;
+            struct pollfd pfd;
+            int timeout = GET_RCVTIMEO(fd);
+            if (timeout != -1)
+            {
+                timeout -= GetTickCount() - timeout_start;
+                if (timeout < 0) timeout = 0;
+            }
 
-            if ( (err = WSAGetLastError()) != WSA_IO_INCOMPLETE )
+            pfd.fd = fd;
+            pfd.events = POLLIN;
+            if (*lpFlags & WS_MSG_OOB) pfd.events |= POLLPRI;
+
+            if (!timeout || !poll( &pfd, 1, timeout ))
+            {
+                err = WSAETIMEDOUT;
+                /* a timeout is not fatal */
+                _enable_event(SOCKET2HANDLE(s), FD_READ, 0, 0);
                 goto error;
+            }
         }
-
-        WSASetLastError( WSA_IO_PENDING );
-        return SOCKET_ERROR;
-    }
-
-    if ( _is_blocking(s) )
-    {
-        /* block here */
-        /* FIXME: OOB and exceptfds? */
-        int timeout = GET_RCVTIMEO(fd);
-        if( !do_block(fd, POLLIN, timeout)) {
-            err = WSAETIMEDOUT;
-            /* a timeout is not fatal */
-            _enable_event(SOCKET2HANDLE(s), FD_READ, 0, 0);
-            goto err_free;
+        else
+        {
+            err = WSAEWOULDBLOCK;
+            goto error;
         }
     }
 
-    n = WS2_recv( fd, iovec, dwBufferCount, lpFrom, lpFromlen, lpFlags );
-    if ( n == -1 )
-    {
-        err = wsaErrno();
-        goto err_free;
-    }
-
     TRACE(" -> %i bytes\n", n);
     *lpNumberOfBytesRecvd = n;
 
@@ -4309,13 +4329,9 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
 
     return 0;
 
-err_free:
+error:
     HeapFree(GetProcessHeap(), 0, iovec);
-
-err_close:
     release_sock_fd( s, fd );
-
-error:
     WARN(" -> ERROR %d\n", err);
     WSASetLastError( err );
     return SOCKET_ERROR;




More information about the wine-cvs mailing list