ws2_32: Reimplement WSARecvFrom along the lines of NtReadFile.

This commit is contained in:
Alexandre Julliard 2007-05-31 11:55:38 +02:00
parent 42e560d001
commit 6759e1c286
1 changed files with 70 additions and 54 deletions

View File

@ -4213,7 +4213,8 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
{ {
unsigned int i, options; unsigned int i, options;
int n, fd, err = WSAENOTSOCK, ret; int n, fd, err;
DWORD timeout_start = GetTickCount();
struct iovec* iovec; struct iovec* iovec;
struct ws2_async *wsa; struct ws2_async *wsa;
IO_STATUS_BLOCK* iosb; IO_STATUS_BLOCK* iosb;
@ -4232,7 +4233,7 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
if ( !iovec ) if ( !iovec )
{ {
err = WSAEFAULT; err = WSAEFAULT;
goto err_close; goto error;
} }
for (i = 0; i < dwBufferCount; i++) for (i = 0; i < dwBufferCount; i++)
@ -4241,63 +4242,82 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
iovec[i].iov_len = lpBuffers[i].len; iovec[i].iov_len = lpBuffers[i].len;
} }
if ( (lpOverlapped || lpCompletionRoutine) && for (;;)
{
n = WS2_recv( fd, iovec, dwBufferCount, lpFrom, lpFromlen, lpFlags );
if (n != -1) break;
if (errno == EINTR) continue;
if (errno != EAGAIN)
{
err = wsaErrno();
goto error;
}
if ((lpOverlapped || lpCompletionRoutine) &&
!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))) !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
{ {
wsa = WS2_make_async( s, ws2m_read, iovec, dwBufferCount, wsa = WS2_make_async( s, ws2m_read, iovec, dwBufferCount,
lpFlags, lpFrom, lpFromlen, lpFlags, lpFrom, lpFromlen,
lpOverlapped, lpCompletionRoutine, &iosb ); lpOverlapped, lpCompletionRoutine, &iosb );
if ( !wsa ) if ( !wsa )
{ {
err = WSAEFAULT; err = WSAEFAULT;
goto err_free; goto error;
}
if ((ret = ws2_queue_async( wsa, iosb )) != STATUS_PENDING)
{
err = NtStatusToWSAError( ret );
if ( !lpOverlapped )
HeapFree( GetProcessHeap(), 0, iosb );
HeapFree( GetProcessHeap(), 0, wsa );
goto err_free;
} }
release_sock_fd( s, fd ); release_sock_fd( s, fd );
/* Try immediate completion */ iosb->u.Status = STATUS_PENDING;
if ( lpOverlapped ) iosb->Information = 0;
SERVER_START_REQ( register_async )
{ {
if ( WSAGetOverlappedResult( s, lpOverlapped, req->handle = wsa->hSocket;
lpNumberOfBytesRecvd, FALSE, lpFlags) ) req->type = ASYNC_TYPE_READ;
return 0; req->async.callback = WS2_async_recv;
req->async.iosb = iosb;
if ( (err = WSAGetLastError()) != WSA_IO_INCOMPLETE ) req->async.arg = wsa;
goto error; req->async.event = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
err = wine_server_call( req );
} }
SERVER_END_REQ;
WSASetLastError( WSA_IO_PENDING ); if (err == STATUS_PENDING)
NtCurrentTeb()->num_async_io++;
else
ws2_async_terminate(wsa, iosb, err, 0);
WSASetLastError( NtStatusToWSAError( err ));
return SOCKET_ERROR; return SOCKET_ERROR;
} }
if ( _is_blocking(s) ) if ( _is_blocking(s) )
{ {
/* block here */ struct pollfd pfd;
/* FIXME: OOB and exceptfds? */
int timeout = GET_RCVTIMEO(fd); int timeout = GET_RCVTIMEO(fd);
if( !do_block(fd, POLLIN, timeout)) { if (timeout != -1)
{
timeout -= GetTickCount() - timeout_start;
if (timeout < 0) timeout = 0;
}
pfd.fd = fd;
pfd.events = POLLIN;
if (*lpFlags & WS_MSG_OOB) pfd.events |= POLLPRI;
if (!timeout || !poll( &pfd, 1, timeout ))
{
err = WSAETIMEDOUT; err = WSAETIMEDOUT;
/* a timeout is not fatal */ /* a timeout is not fatal */
_enable_event(SOCKET2HANDLE(s), FD_READ, 0, 0); _enable_event(SOCKET2HANDLE(s), FD_READ, 0, 0);
goto err_free; goto error;
} }
} }
else
n = WS2_recv( fd, iovec, dwBufferCount, lpFrom, lpFromlen, lpFlags );
if ( n == -1 )
{ {
err = wsaErrno(); err = WSAEWOULDBLOCK;
goto err_free; goto error;
}
} }
TRACE(" -> %i bytes\n", n); TRACE(" -> %i bytes\n", n);
@ -4309,13 +4329,9 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
return 0; return 0;
err_free:
HeapFree(GetProcessHeap(), 0, iovec);
err_close:
release_sock_fd( s, fd );
error: error:
HeapFree(GetProcessHeap(), 0, iovec);
release_sock_fd( s, fd );
WARN(" -> ERROR %d\n", err); WARN(" -> ERROR %d\n", err);
WSASetLastError( err ); WSASetLastError( err );
return SOCKET_ERROR; return SOCKET_ERROR;