Module: wine Branch: master Commit: 665e8a5e6494b936ad41bf7e557fabf1211d831d URL: http://source.winehq.org/git/wine.git/?a=commit;h=665e8a5e6494b936ad41bf7e55...
Author: Damjan Jovanovic damjan.jov@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(); }