ws2_32: Reimplement WSASendTo along the lines of NtWriteFile.

This commit is contained in:
Alexandre Julliard 2007-05-31 17:02:21 +02:00
parent c0bf8e7db5
commit 7bee1d3583
1 changed files with 78 additions and 70 deletions

View File

@ -2691,9 +2691,8 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ) LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{ {
unsigned int i, options; unsigned int i, options;
int n, fd, err = WSAENOTSOCK, ret; int n, fd, err;
struct iovec iovec[WS_MSG_MAXIOVLEN]; struct iovec iovec[WS_MSG_MAXIOVLEN];
struct ws2_async *wsa;
IO_STATUS_BLOCK* iosb; IO_STATUS_BLOCK* iosb;
TRACE("socket %04lx, wsabuf %p, nbufs %d, flags %d, to %p, tolen %d, ovl %p, func %p\n", TRACE("socket %04lx, wsabuf %p, nbufs %d, flags %d, to %p, tolen %d, ovl %p, func %p\n",
@ -2723,105 +2722,114 @@ INT WINAPI WSASendTo( 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_write, iovec, dwBufferCount, n = WS2_send( fd, iovec, dwBufferCount, to, tolen, dwFlags );
&dwFlags, (struct WS_sockaddr*) to, &tolen, if (n != -1 || errno != EINTR) break;
lpOverlapped, lpCompletionRoutine, &iosb ); }
if ( !wsa ) if (n == -1)
{
if (errno != EAGAIN)
{ {
err = WSAEFAULT; err = wsaErrno();
goto error; 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 ); struct ws2_async *wsa = WS2_make_async( s, ws2m_write, iovec, dwBufferCount,
&dwFlags, (struct WS_sockaddr*) to, &tolen,
lpOverlapped, lpCompletionRoutine, &iosb );
if ( !wsa )
{
err = WSAEFAULT;
goto error;
}
release_sock_fd( s, fd );
HeapFree( GetProcessHeap(), 0, wsa ); iosb->u.Status = STATUS_PENDING;
goto error; iosb->Information = 0;
SERVER_START_REQ( register_async )
{
req->handle = wsa->hSocket;
req->type = ASYNC_TYPE_WRITE;
req->async.callback = WS2_async_send;
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;
} }
release_sock_fd( s, fd );
/* Try immediate completion */
if ( lpOverlapped )
{
if ( WSAGetOverlappedResult( s, lpOverlapped,
lpNumberOfBytesSent, FALSE, &dwFlags) )
return 0;
if ( (err = WSAGetLastError()) != WSA_IO_INCOMPLETE )
return SOCKET_ERROR;
}
WSASetLastError( WSA_IO_PENDING );
return SOCKET_ERROR;
} }
*lpNumberOfBytesSent = 0;
if ( _is_blocking(s) ) if ( _is_blocking(s) )
{ {
/* On a blocking non-overlapped stream socket, /* On a blocking non-overlapped stream socket,
* sending blocks until the entire buffer is sent. */ * sending blocks until the entire buffer is sent. */
struct iovec *piovec = iovec; DWORD timeout_start = GetTickCount();
int finish_time = GET_SNDTIMEO(fd); unsigned int first_buff = 0;
if (finish_time >= 0)
finish_time += GetTickCount(); *lpNumberOfBytesSent = 0;
while ( dwBufferCount > 0 )
while (first_buff < dwBufferCount)
{ {
int timeout; struct pollfd pfd;
if ( finish_time >= 0 ) int timeout = GET_SNDTIMEO(fd);
if (n > 0)
{ {
timeout = finish_time - GetTickCount(); *lpNumberOfBytesSent += n;
if ( timeout < 0 ) if (iovec[first_buff].iov_len > n)
timeout = 0; iovec[first_buff].iov_len -= n;
else
{
while (n > 0) n -= iovec[first_buff++].iov_len;
if (first_buff >= dwBufferCount) break;
}
} }
else
timeout = finish_time; if (timeout != -1)
/* FIXME: exceptfds? */ {
if( !do_block(fd, POLLOUT, timeout)) { timeout -= timeout_start - GetTickCount();
if (timeout < 0) timeout = 0;
}
pfd.fd = fd;
pfd.events = POLLOUT;
if (!timeout || !poll( &pfd, 1, timeout ))
{
err = WSAETIMEDOUT; err = WSAETIMEDOUT;
goto error; /* msdn says a timeout in send is fatal */ goto error; /* msdn says a timeout in send is fatal */
} }
n = WS2_send( fd, piovec, dwBufferCount, to, tolen, dwFlags ); n = WS2_send( fd, iovec + first_buff, dwBufferCount - first_buff, to, tolen, dwFlags );
if ( n == -1 ) if (n == -1 && errno != EAGAIN && errno != EINTR)
{ {
err = wsaErrno(); err = wsaErrno();
goto error; goto error;
} }
*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;
}
}
} }
} }
else else /* non-blocking */
{ {
n = WS2_send( fd, iovec, dwBufferCount, to, tolen, dwFlags ); _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
if ( n == -1 ) if (n == -1)
{ {
err = wsaErrno(); err = WSAEWOULDBLOCK;
if ( err == WSAEWOULDBLOCK )
_enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
goto error; goto error;
} }
else
_enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
*lpNumberOfBytesSent = n; *lpNumberOfBytesSent = n;
} }