Damjan Jovanovic : ws2_32: In some cases send should block until the entire buffer is sent.

Alexandre Julliard julliard at wine.codeweavers.com
Tue Mar 20 08:10:59 CDT 2007


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

Author: Damjan Jovanovic <damjan.jov at gmail.com>
Date:   Mon Mar 19 15:42:40 2007 +0200

ws2_32: In some cases send should block until the entire buffer is sent.

---

 dlls/ws2_32/socket.c     |   74 ++++++++++++++++++++++++------
 dlls/ws2_32/tests/sock.c |  111 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+), 15 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 16222ca..e14eba8 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -2873,27 +2873,71 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
         return SOCKET_ERROR;
     }
 
-    if (_is_blocking(s))
+    *lpNumberOfBytesSent = 0;
+    if ( _is_blocking(s) )
     {
-        /* FIXME: exceptfds? */
-        int timeout = GET_SNDTIMEO(fd);
-        if( !do_block(fd, POLLOUT, timeout)) {
-            err = WSAETIMEDOUT;
-            goto err_free; /* msdn says a timeout in send is fatal */
+        /* 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 )
+        {
+            int timeout;
+            if ( finish_time >= 0 )
+            {
+                timeout = finish_time - GetTickCount();
+                if ( timeout < 0 )
+                    timeout = 0;
+            }
+            else
+                timeout = finish_time;
+            /* FIXME: exceptfds? */
+            if( !do_block(fd, POLLOUT, timeout)) {
+                err = WSAETIMEDOUT;
+                goto err_free; /* msdn says a timeout in send is fatal */
+            }
+
+            n = WS2_send( fd, piovec, dwBufferCount, to, tolen, dwFlags );
+            if ( n == -1 )
+            {
+                err = wsaErrno();
+                goto err_free;
+            }
+            *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;
+                }
+            }
         }
     }
-
-    n = WS2_send( fd, iovec, dwBufferCount, to, tolen, dwFlags );
-    if ( n == -1 )
+    else
     {
-        err = wsaErrno();
-        if ( err == WSAEWOULDBLOCK )
-            _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
-        goto err_free;
+        n = WS2_send( fd, iovec, dwBufferCount, to, tolen, dwFlags );
+        if ( n == -1 )
+        {
+            err = wsaErrno();
+            if ( err == WSAEWOULDBLOCK )
+                _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
+            goto err_free;
+        }
+        *lpNumberOfBytesSent = n;
     }
 
-    TRACE(" -> %i bytes\n", n);
-    *lpNumberOfBytesSent = n;
+    TRACE(" -> %i bytes\n", *lpNumberOfBytesSent);
 
     HeapFree( GetProcessHeap(), 0, iovec );
     release_sock_fd( s, fd );
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index c5bf766..bd01bd3 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -1620,6 +1620,115 @@ static void test_inet_addr(void)
     ok(addr == INADDR_NONE, "inet_addr succeeded unexpectedly\n");
 }
 
+static DWORD WINAPI drain_socket_thread(LPVOID arg)
+{
+    char buffer[1024];
+    SOCKET sock = *(SOCKET*)arg;
+
+    while (recv(sock, buffer, sizeof(buffer), 0) > 0)
+        ;
+    return 0;
+}
+
+static void test_send(void)
+{
+    SOCKET src = INVALID_SOCKET;
+    SOCKET server = INVALID_SOCKET;
+    SOCKET dst = INVALID_SOCKET;
+    HANDLE hThread = NULL;
+    struct sockaddr_in addr;
+    int len;
+    const int buflen = 1024*1024;
+    char *buffer = NULL;
+    int ret;
+
+    src = socket(AF_INET, SOCK_STREAM, 0);
+    if (src == INVALID_SOCKET)
+    {
+        ok(0, "socket failed, error %d\n", WSAGetLastError());
+        goto end;
+    }
+
+    server = socket(AF_INET, SOCK_STREAM, 0);
+    if (server == INVALID_SOCKET)
+    {
+        ok(0, "socket failed, error %d\n", WSAGetLastError());
+        goto end;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+    ret = bind(server, (struct sockaddr*)&addr, sizeof(addr));
+    if (ret != 0)
+    {
+        ok(0, "bind failed, error %d\n", WSAGetLastError());
+        goto end;
+    }
+
+    len = sizeof(addr);
+    ret = getsockname(server, (struct sockaddr*)&addr, &len);
+    if (ret != 0)
+    {
+        ok(0, "getsockname failed, error %d\n", WSAGetLastError());
+        goto end;
+    }
+
+    ret = listen(server, 1);
+    if (ret != 0)
+    {
+        ok(0, "listen failed, error %d\n", WSAGetLastError());
+        goto end;
+    }
+
+    ret = connect(src, (struct sockaddr*)&addr, sizeof(addr));
+    if (ret != 0)
+    {
+        ok(0, "connect failed, error %d\n", WSAGetLastError());
+        goto end;
+    }
+
+    len = sizeof(addr);
+    dst = accept(server, (struct sockaddr*)&addr, &len);
+    if (dst == INVALID_SOCKET)
+    {
+        ok(0, "accept failed, error %d\n", WSAGetLastError());
+        goto end;
+    }
+
+    hThread = CreateThread(NULL, 0, drain_socket_thread, &dst, 0, NULL);
+    if (hThread == NULL)
+    {
+        ok(0, "CreateThread failed, error %d\n", GetLastError());
+        goto end;
+    }
+
+    buffer = HeapAlloc(GetProcessHeap(), 0, buflen);
+    if (buffer == NULL)
+    {
+        ok(0, "HeapAlloc failed, error %d\n", GetLastError());
+        goto end;
+    }
+
+    ret = send(src, buffer, buflen, 0);
+    if (ret >= 0)
+        ok(ret == buflen, "send should have sent %d bytes, but it only sent %d\n", buflen, ret);
+    else
+        ok(0, "send failed, error %d\n", WSAGetLastError());
+
+end:
+    if (src != INVALID_SOCKET)
+        closesocket(src);
+    if (server != INVALID_SOCKET)
+        closesocket(server);
+    if (dst != INVALID_SOCKET)
+        closesocket(dst);
+    if (hThread != NULL)
+        CloseHandle(hThread);
+    if (buffer != NULL)
+        HeapFree(GetProcessHeap(), 0, buffer);
+}
+
 /**************** Main program  ***************/
 
 START_TEST( sock )
@@ -1653,5 +1762,7 @@ START_TEST( sock )
     test_getsockname();
     test_inet_addr();
 
+    test_send();
+
     Exit();
 }




More information about the wine-cvs mailing list