ws2_32: In some cases send should block until the entire buffer is sent.
This commit is contained in:
parent
838eb4037f
commit
665e8a5e64
|
@ -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 );
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue