Alexandre Julliard : ws2_32: Reimplement WSASendTo along the lines of NtWriteFile.

Alexandre Julliard julliard at wine.codeweavers.com
Mon Jun 4 08:14:24 CDT 2007


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

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Thu May 31 17:02:21 2007 +0200

ws2_32: Reimplement WSASendTo along the lines of NtWriteFile.

---

 dlls/ws2_32/socket.c |  144 ++++++++++++++++++++++++++-----------------------
 1 files changed, 76 insertions(+), 68 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 2bd4c14..a616172 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -2691,9 +2691,8 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
                       LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
 {
     unsigned int i, options;
-    int n, fd, err = WSAENOTSOCK, ret;
+    int n, fd, err;
     struct iovec iovec[WS_MSG_MAXIOVLEN];
-    struct ws2_async *wsa;
     IO_STATUS_BLOCK* iosb;
 
     TRACE("socket %04lx, wsabuf %p, nbufs %d, flags %d, to %p, tolen %d, ovl %p, func %p\n",
@@ -2723,105 +2722,114 @@ INT WINAPI WSASendTo( 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_write, iovec, dwBufferCount,
-                              &dwFlags, (struct WS_sockaddr*) to, &tolen,
-                              lpOverlapped, lpCompletionRoutine, &iosb );
-        if ( !wsa )
+        n = WS2_send( fd, iovec, dwBufferCount, to, tolen, dwFlags );
+        if (n != -1 || errno != EINTR) break;
+    }
+    if (n == -1)
+    {
+        if (errno != EAGAIN)
         {
-            err = WSAEFAULT;
+            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 );
+            struct ws2_async *wsa = WS2_make_async( s, ws2m_write, iovec, dwBufferCount,
+                                                    &dwFlags, (struct WS_sockaddr*) to, &tolen,
+                                                    lpOverlapped, lpCompletionRoutine, &iosb );
+            if ( !wsa )
+            {
+                err = WSAEFAULT;
+                goto error;
+            }
+            release_sock_fd( s, fd );
 
-            HeapFree( GetProcessHeap(), 0, wsa );
-            goto error;
-        }
-        release_sock_fd( s, fd );
+            iosb->u.Status = STATUS_PENDING;
+            iosb->Information = 0;
 
-        /* Try immediate completion */
-        if ( lpOverlapped )
-        {
-            if  ( WSAGetOverlappedResult( s, lpOverlapped,
-                                          lpNumberOfBytesSent, FALSE, &dwFlags) )
-                return 0;
+            SERVER_START_REQ( register_async )
+            {
+                req->handle = wsa->hSocket;
+                req->type   = ASYNC_TYPE_WRITE;
+                req->async.callback = WS2_async_send;
+                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 = WSAGetLastError()) != WSA_IO_INCOMPLETE )
-                return SOCKET_ERROR;
-        }
+            if (err == STATUS_PENDING)
+                NtCurrentTeb()->num_async_io++;
+            else
+                ws2_async_terminate(wsa, iosb, err, 0);
 
-        WSASetLastError( WSA_IO_PENDING );
-        return SOCKET_ERROR;
+            WSASetLastError( NtStatusToWSAError( err ));
+            return SOCKET_ERROR;
+        }
     }
 
-    *lpNumberOfBytesSent = 0;
     if ( _is_blocking(s) )
     {
         /* On a blocking non-overlapped stream socket,
          * sending blocks until the entire buffer is sent. */
-        struct iovec *piovec = iovec;
-        int finish_time = GET_SNDTIMEO(fd);
-        if (finish_time >= 0)
-            finish_time += GetTickCount();
-        while ( dwBufferCount > 0 )
+        DWORD timeout_start = GetTickCount();
+        unsigned int first_buff = 0;
+
+        *lpNumberOfBytesSent = 0;
+
+        while (first_buff < dwBufferCount)
         {
-            int timeout;
-            if ( finish_time >= 0 )
+            struct pollfd pfd;
+            int timeout = GET_SNDTIMEO(fd);
+
+            if (n > 0)
             {
-                timeout = finish_time - GetTickCount();
-                if ( timeout < 0 )
-                    timeout = 0;
+                *lpNumberOfBytesSent += n;
+                if (iovec[first_buff].iov_len > n)
+                    iovec[first_buff].iov_len -= n;
+                else
+                {
+                    while (n > 0) n -= iovec[first_buff++].iov_len;
+                    if (first_buff >= dwBufferCount) break;
+                }
             }
-            else
-                timeout = finish_time;
-            /* FIXME: exceptfds? */
-            if( !do_block(fd, POLLOUT, timeout)) {
+
+            if (timeout != -1)
+            {
+                timeout -= timeout_start - GetTickCount();
+                if (timeout < 0) timeout = 0;
+            }
+
+            pfd.fd = fd;
+            pfd.events = POLLOUT;
+
+            if (!timeout || !poll( &pfd, 1, timeout ))
+            {
                 err = WSAETIMEDOUT;
                 goto error; /* msdn says a timeout in send is fatal */
             }
 
-            n = WS2_send( fd, piovec, dwBufferCount, to, tolen, dwFlags );
-            if ( n == -1 )
+            n = WS2_send( fd, iovec + first_buff, dwBufferCount - first_buff, to, tolen, dwFlags );
+            if (n == -1 && errno != EAGAIN && errno != EINTR)
             {
                 err = wsaErrno();
                 goto error;
             }
-            *lpNumberOfBytesSent += n;
-
-            while ( n > 0 )
-            {
-                if ( piovec->iov_len > n )
-                {
-                    piovec->iov_base = (char*)piovec->iov_base + n;
-                    piovec->iov_len -= n;
-                    n = 0;
-                }
-                else
-                {
-                    n -= piovec->iov_len;
-                    --dwBufferCount;
-                    ++piovec;
-                }
-            }
         }
     }
-    else
+    else  /* non-blocking */
     {
-        n = WS2_send( fd, iovec, dwBufferCount, to, tolen, dwFlags );
-        if ( n == -1 )
+        _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
+        if (n == -1)
         {
-            err = wsaErrno();
-            if ( err == WSAEWOULDBLOCK )
-                _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
+            err = WSAEWOULDBLOCK;
             goto error;
         }
-        else
-            _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
         *lpNumberOfBytesSent = n;
     }
 




More information about the wine-cvs mailing list