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