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 (;;)
!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
{ {
wsa = WS2_make_async( s, ws2m_read, iovec, dwBufferCount, n = WS2_recv( fd, iovec, dwBufferCount, lpFrom, lpFromlen, lpFlags );
lpFlags, lpFrom, lpFromlen, if (n != -1) break;
lpOverlapped, lpCompletionRoutine, &iosb );
if ( !wsa ) if (errno == EINTR) continue;
if (errno != EAGAIN)
{ {
err = WSAEFAULT; err = wsaErrno();
goto err_free; goto error;
} }
if ((ret = ws2_queue_async( wsa, iosb )) != STATUS_PENDING) if ((lpOverlapped || lpCompletionRoutine) &&
!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
{ {
err = NtStatusToWSAError( ret ); wsa = WS2_make_async( s, ws2m_read, iovec, dwBufferCount,
lpFlags, lpFrom, lpFromlen,
if ( !lpOverlapped ) lpOverlapped, lpCompletionRoutine, &iosb );
HeapFree( GetProcessHeap(), 0, iosb ); if ( !wsa )
HeapFree( GetProcessHeap(), 0, wsa ); {
goto err_free; err = WSAEFAULT;
}
release_sock_fd( s, fd );
/* Try immediate completion */
if ( lpOverlapped )
{
if ( WSAGetOverlappedResult( s, lpOverlapped,
lpNumberOfBytesRecvd, FALSE, lpFlags) )
return 0;
if ( (err = WSAGetLastError()) != WSA_IO_INCOMPLETE )
goto error; goto error;
}
release_sock_fd( s, fd );
iosb->u.Status = STATUS_PENDING;
iosb->Information = 0;
SERVER_START_REQ( register_async )
{
req->handle = wsa->hSocket;
req->type = ASYNC_TYPE_READ;
req->async.callback = WS2_async_recv;
req->async.iosb = iosb;
req->async.arg = wsa;
req->async.event = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
err = wine_server_call( req );
}
SERVER_END_REQ;
if (err == STATUS_PENDING)
NtCurrentTeb()->num_async_io++;
else
ws2_async_terminate(wsa, iosb, err, 0);
WSASetLastError( NtStatusToWSAError( err ));
return SOCKET_ERROR;
} }
WSASetLastError( WSA_IO_PENDING ); if ( _is_blocking(s) )
return SOCKET_ERROR; {
} struct pollfd pfd;
int timeout = GET_RCVTIMEO(fd);
if (timeout != -1)
{
timeout -= GetTickCount() - timeout_start;
if (timeout < 0) timeout = 0;
}
if ( _is_blocking(s) ) pfd.fd = fd;
{ pfd.events = POLLIN;
/* block here */ if (*lpFlags & WS_MSG_OOB) pfd.events |= POLLPRI;
/* FIXME: OOB and exceptfds? */
int timeout = GET_RCVTIMEO(fd); if (!timeout || !poll( &pfd, 1, timeout ))
if( !do_block(fd, POLLIN, 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
{
err = WSAEWOULDBLOCK;
goto error;
} }
}
n = WS2_recv( fd, iovec, dwBufferCount, lpFrom, lpFromlen, lpFlags );
if ( n == -1 )
{
err = wsaErrno();
goto err_free;
} }
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;