Implemented overlapped WSARecvFrom(), WSASendTo(), and

WSAGetOverlappedResult().
Fixed shutdown() to work correctly for overlapped sockets (do not
actually do a shutdown() system call as long as there are pending
overlapped requests).
Also added correct error reporting when trying to read or write on a
shut down connection, also for ReadFile()/WriteFile() calls.
This commit is contained in:
Martin Wilck 2002-04-25 21:34:24 +00:00 committed by Alexandre Julliard
parent bff7e69981
commit af16c98f71
4 changed files with 703 additions and 129 deletions

View File

@ -104,6 +104,7 @@
#include "wine/winbase16.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
#include "winsock2.h"
#include "ws2tcpip.h"
#include "wsipx.h"
@ -125,6 +126,53 @@ extern CRITICAL_SECTION csWSgetXXXbyYYY;
inet_ntoa(((struct sockaddr_in *)a)->sin_addr), \
ntohs(((struct sockaddr_in *)a)->sin_port))
/****************************************************************
* Async IO declarations
****************************************************************/
#include "async.h"
static DWORD ws2_async_get_status (const struct async_private *ovp);
static DWORD ws2_async_get_count (const struct async_private *ovp);
static void ws2_async_set_status (struct async_private *ovp, const DWORD status);
static void CALLBACK ws2_async_call_completion (ULONG_PTR data);
static void ws2_async_cleanup ( struct async_private *ovp );
static struct async_ops ws2_async_ops =
{
ws2_async_get_status,
ws2_async_set_status,
ws2_async_get_count,
ws2_async_call_completion,
ws2_async_cleanup
};
static struct async_ops ws2_nocomp_async_ops =
{
ws2_async_get_status,
ws2_async_set_status,
ws2_async_get_count,
NULL, /* call_completion */
ws2_async_cleanup
};
typedef struct ws2_async
{
async_private async;
LPWSAOVERLAPPED overlapped;
LPWSAOVERLAPPED user_overlapped;
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_func;
struct iovec *iovec;
int n_iovecs;
struct WS_sockaddr *addr;
union {
int val; /* for send operations */
int *ptr; /* for recv operations */
} addrlen;
DWORD flags;
} ws2_async;
/****************************************************************/
/* ----------------------------------- internal data */
/* ws_... struct conversion flags */
@ -223,13 +271,39 @@ static int _px_tcp_ops[] = {
*/
static int opentype = 0;
inline static DWORD NtStatusToWSAError ( const DWORD status )
{
/* We only need to cover the status codes set by server async request handling */
DWORD wserr;
switch ( status )
{
case STATUS_SUCCESS: wserr = 0; break;
case STATUS_PENDING: wserr = WSA_IO_PENDING; break;
case STATUS_INVALID_HANDLE: wserr = WSAENOTSOCK; break; /* WSAEBADF ? */
case STATUS_INVALID_PARAMETER: wserr = WSAEINVAL; break;
case STATUS_PIPE_DISCONNECTED: wserr = WSAESHUTDOWN; break;
case STATUS_CANCELLED: wserr = WSA_OPERATION_ABORTED; break;
case STATUS_TIMEOUT: wserr = WSAETIMEDOUT; break;
case STATUS_NO_MEMORY: wserr = WSAEFAULT; break;
default:
if ( status >= WSABASEERR && status <= WSABASEERR+1004 )
/* It is not a NT status code but a winsock error */
wserr = status;
else
{
wserr = RtlNtStatusToDosError( status );
FIXME ( "Status code %08lx converted to DOS error code %lx\n", status, wserr );
}
}
return wserr;
}
/* set last error code from NT status without mapping WSA errors */
inline static unsigned int set_error( unsigned int err )
{
if (err)
{
/* do not map WSA errors */
if ((err < WSABASEERR) || (err >= 0x10000000)) err = RtlNtStatusToDosError(err);
err = NtStatusToWSAError ( err );
SetLastError( err );
}
return err;
@ -245,10 +319,17 @@ inline static int _get_sock_fd(SOCKET s)
return fd;
}
inline static int _get_sock_fd_type( SOCKET s, enum fd_type *type, int *flags )
inline static int _get_sock_fd_type( SOCKET s, DWORD access, enum fd_type *type, int *flags )
{
int fd;
if (set_error( wine_server_handle_to_fd( s, GENERIC_READ, &fd, type, flags ) )) return -1;
if (set_error( wine_server_handle_to_fd( s, access, &fd, type, flags ) )) return -1;
if ( ( (access & GENERIC_READ) && (*flags & FD_FLAG_RECV_SHUTDOWN ) ) ||
( (access & GENERIC_WRITE) && (*flags & FD_FLAG_SEND_SHUTDOWN ) ) )
{
close (fd);
WSASetLastError ( WSAESHUTDOWN );
return -1;
}
return fd;
}
@ -904,6 +985,399 @@ inline void ws_sockaddr_free(const struct sockaddr* uaddr, const struct WS_socka
free((void*)uaddr);
}
/**************************************************************************
* Functions for handling overlapped I/O
**************************************************************************/
static DWORD ws2_async_get_status (const struct async_private *ovp)
{
return ((ws2_async*) ovp)->overlapped->Internal;
}
static VOID ws2_async_set_status (struct async_private *ovp, const DWORD status)
{
((ws2_async*) ovp)->overlapped->Internal = status;
}
static DWORD ws2_async_get_count (const struct async_private *ovp)
{
return ((ws2_async*) ovp)->overlapped->InternalHigh;
}
static void ws2_async_cleanup ( struct async_private *ap )
{
struct ws2_async *as = (struct ws2_async*) ap;
TRACE ( "as: %p uovl %p ovl %p\n", as, as->user_overlapped, as->overlapped );
if ( !as->user_overlapped )
{
if ( as->overlapped->hEvent != INVALID_HANDLE_VALUE )
WSACloseEvent ( as->overlapped->hEvent );
HeapFree ( GetProcessHeap(), 0, as->overlapped );
}
if ( as->iovec )
HeapFree ( GetProcessHeap(), 0, as->iovec );
HeapFree ( GetProcessHeap(), 0, as );
}
static void CALLBACK ws2_async_call_completion (ULONG_PTR data)
{
ws2_async* as = (ws2_async*) data;
TRACE ("data: %p\n", as);
as->completion_func ( NtStatusToWSAError (as->overlapped->Internal),
as->overlapped->InternalHigh,
as->user_overlapped,
as->flags );
ws2_async_cleanup ( &as->async );
}
/***********************************************************************
* WS2_make_async (INTERNAL)
*/
static void WS2_async_recv (async_private *as);
static void WS2_async_send (async_private *as);
inline static struct ws2_async*
WS2_make_async (SOCKET s, int fd, int type, struct iovec *iovec, DWORD dwBufferCount,
LPDWORD lpFlags, struct WS_sockaddr *addr,
LPINT addrlen, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
struct ws2_async *wsa = HeapAlloc ( GetProcessHeap(), 0, sizeof ( ws2_async ) );
TRACE ( "wsa %p\n", wsa );
if (!wsa)
return NULL;
wsa->async.ops = ( lpCompletionRoutine ? &ws2_async_ops : &ws2_nocomp_async_ops );
wsa->async.handle = (HANDLE) s;
wsa->async.fd = fd;
wsa->async.type = type;
switch (type)
{
case ASYNC_TYPE_READ:
wsa->flags = *lpFlags;
wsa->async.func = WS2_async_recv;
wsa->addrlen.ptr = addrlen;
break;
case ASYNC_TYPE_WRITE:
wsa->flags = 0;
wsa->async.func = WS2_async_send;
wsa->addrlen.val = *addrlen;
break;
default:
ERR ("Invalid async type: %d\n", type);
}
wsa->user_overlapped = lpOverlapped;
wsa->completion_func = lpCompletionRoutine;
wsa->iovec = iovec;
wsa->n_iovecs = dwBufferCount;
wsa->addr = addr;
if ( lpOverlapped )
{
wsa->overlapped = lpOverlapped;
wsa->async.event = ( lpCompletionRoutine ? INVALID_HANDLE_VALUE : lpOverlapped->hEvent );
}
else
{
wsa->overlapped = HeapAlloc ( GetProcessHeap(), 0,
sizeof (WSAOVERLAPPED) );
if ( !wsa->overlapped )
goto error;
wsa->async.event = wsa->overlapped->hEvent = INVALID_HANDLE_VALUE;
}
wsa->overlapped->InternalHigh = 0;
TRACE ( "wsa %p, ops %p, h %d, ev %d, fd %d, func %p, ov %p, uov %p, cfunc %p\n",
wsa, wsa->async.ops, wsa->async.handle, wsa->async.event, wsa->async.fd, wsa->async.func,
wsa->overlapped, wsa->user_overlapped, wsa->completion_func );
return wsa;
error:
TRACE ("Error\n");
HeapFree ( GetProcessHeap(), 0, wsa );
return NULL;
}
/***********************************************************************
* WS2_recv (INTERNAL)
*
* Work horse for both synchronous and asynchronous recv() operations.
*/
static int WS2_recv ( int fd, struct iovec* iov, int count,
struct WS_sockaddr *lpFrom, LPINT lpFromlen,
LPDWORD lpFlags )
{
struct msghdr hdr;
int n;
TRACE ( "fd %d, iovec %p, count %d addr %p, len %p, flags %lx\n",
fd, iov, count, lpFrom, lpFromlen, *lpFlags);
hdr.msg_name = NULL;
if ( lpFrom )
{
#if DEBUG_SOCKADDR
dump_sockaddr (lpFrom);
#endif
hdr.msg_namelen = *lpFromlen;
hdr.msg_name = ws_sockaddr_alloc ( lpFrom, lpFromlen, &hdr.msg_namelen );
if ( !hdr.msg_name )
{
WSASetLastError ( WSAEFAULT );
n = -1;
goto out;
}
}
else
hdr.msg_namelen = 0;
hdr.msg_iov = iov;
hdr.msg_iovlen = count;
hdr.msg_control = NULL;
hdr.msg_controllen = 0;
hdr.msg_flags = 0;
if ( (n = recvmsg (fd, &hdr, *lpFlags)) == -1 )
{
TRACE ( "recvmsg error %d\n", errno);
goto out;
}
if ( lpFrom &&
ws_sockaddr_u2ws ( hdr.msg_name, hdr.msg_namelen,
lpFrom, lpFromlen ) != 0 )
{
/* The from buffer was too small, but we read the data
* anyway. Is that really bad?
*/
WSASetLastError ( WSAEFAULT );
WARN ( "Address buffer too small\n" );
}
out:
ws_sockaddr_free ( hdr.msg_name, lpFrom );
TRACE ("-> %d\n", n);
return n;
}
/***********************************************************************
* WS2_async_recv (INTERNAL)
*
* Handler for overlapped recv() operations.
*/
static void WS2_async_recv ( async_private *as )
{
ws2_async* wsa = (ws2_async*) as;
int result, err;
TRACE ( "async %p\n", wsa );
if ( wsa->overlapped->Internal != STATUS_PENDING )
{
TRACE ( "status: %ld\n", wsa->overlapped->Internal );
return;
}
result = WS2_recv ( wsa->async.fd, wsa->iovec, wsa->n_iovecs,
wsa->addr, wsa->addrlen.ptr, &wsa->flags );
if (result >= 0)
{
wsa->overlapped->Internal = STATUS_SUCCESS;
wsa->overlapped->InternalHigh = result;
TRACE ( "received %d bytes\n", result );
_enable_event ( (SOCKET) wsa->async.handle, FD_READ, 0, 0 );
return;
}
err = wsaErrno ();
if ( err == WSAEINTR || err == WSAEWOULDBLOCK ) /* errno: EINTR / EAGAIN */
{
wsa->overlapped->Internal = STATUS_PENDING;
_enable_event ( (SOCKET) wsa->async.handle, FD_READ, 0, 0 );
TRACE ( "still pending\n" );
}
else
{
wsa->overlapped->Internal = err;
TRACE ( "Error: %x\n", err );
}
}
/***********************************************************************
* WS2_send (INTERNAL)
*
* Work horse for both synchronous and asynchronous send() operations.
*/
static int WS2_send ( int fd, struct iovec* iov, int count,
const struct WS_sockaddr *to, INT tolen, DWORD dwFlags )
{
struct msghdr hdr;
int n = -1;
TRACE ( "fd %d, iovec %p, count %d addr %p, len %d, flags %lx\n",
fd, iov, count, to, tolen, dwFlags);
hdr.msg_name = NULL;
if ( to )
{
#if DEBUG_SOCKADDR
dump_sockaddr (to);
#endif
hdr.msg_name = (struct sockaddr*) ws_sockaddr_ws2u ( to, tolen, &hdr.msg_namelen );
if ( !hdr.msg_name )
{
WSASetLastError ( WSAEFAULT );
goto out;
}
}
else
hdr.msg_namelen = 0;
hdr.msg_iov = iov;
hdr.msg_iovlen = count;
hdr.msg_control = NULL;
hdr.msg_controllen = 0;
hdr.msg_flags = 0;
n = sendmsg (fd, &hdr, dwFlags);
out:
ws_sockaddr_free ( hdr.msg_name, to );
return n;
}
/***********************************************************************
* WS2_async_send (INTERNAL)
*
* Handler for overlapped send() operations.
*/
static void WS2_async_send ( async_private *as )
{
ws2_async* wsa = (ws2_async*) as;
int result, err;
TRACE ( "async %p\n", wsa );
if ( wsa->overlapped->Internal != STATUS_PENDING )
{
TRACE ( "status: %ld\n", wsa->overlapped->Internal );
return;
}
result = WS2_send ( wsa->async.fd, wsa->iovec, wsa->n_iovecs,
wsa->addr, wsa->addrlen.val, wsa->flags );
if (result >= 0)
{
wsa->overlapped->Internal = STATUS_SUCCESS;
wsa->overlapped->InternalHigh = result;
TRACE ( "sent %d bytes\n", result );
_enable_event ( (SOCKET) wsa->async.handle, FD_WRITE, 0, 0 );
return;
}
err = wsaErrno ();
if ( err == WSAEINTR )
{
wsa->overlapped->Internal = STATUS_PENDING;
_enable_event ( (SOCKET) wsa->async.handle, FD_WRITE, 0, 0 );
TRACE ( "still pending\n" );
}
else
{
/* We set the status to a winsock error code and check for that
later in NtStatusToWSAError () */
wsa->overlapped->Internal = err;
TRACE ( "Error: %x\n", err );
}
}
/***********************************************************************
* WS2_async_shutdown (INTERNAL)
*
* Handler for shutdown() operations on overlapped sockets.
*/
static void WS2_async_shutdown ( async_private *as )
{
ws2_async* wsa = (ws2_async*) as;
int err = 1;
TRACE ( "async %p %d\n", wsa, wsa->async.type );
switch ( wsa->async.type )
{
case ASYNC_TYPE_READ:
err = shutdown ( wsa->async.fd, 0 );
break;
case ASYNC_TYPE_WRITE:
err = shutdown ( wsa->async.fd, 1 );
break;
default:
ERR ("invalid type: %d\n", wsa->async.type );
}
if ( err )
wsa->overlapped->Internal = wsaErrno ();
else
wsa->overlapped->Internal = STATUS_SUCCESS;
}
/***********************************************************************
* WS2_register_async_shutdown (INTERNAL)
*
* Helper function for WS_shutdown() on overlapped sockets.
*/
static int WS2_register_async_shutdown ( SOCKET s, int fd, int type )
{
struct ws2_async *wsa;
int ret, err = WSAEFAULT;
DWORD dwflags = 0;
int len = 0;
LPWSAOVERLAPPED ovl = HeapAlloc (GetProcessHeap(), 0, sizeof ( WSAOVERLAPPED ));
TRACE ("s %d fd %d type %d\n", s, fd, type);
if (!ovl)
goto out;
ovl->hEvent = WSACreateEvent ();
if ( ovl->hEvent == WSA_INVALID_EVENT )
goto out_free;
wsa = WS2_make_async ( s, fd, type, NULL, 0,
&dwflags, NULL, &len, ovl, NULL );
if ( !wsa )
goto out_close;
/* Hack: this will cause ws2_async_cleanup() to free the overlapped structure */
wsa->user_overlapped = NULL;
wsa->async.func = WS2_async_shutdown;
if ( (ret = register_new_async ( &wsa->async )) )
{
err = NtStatusToWSAError ( ret );
ws2_async_cleanup ( &wsa->async );
goto out;
}
return 0;
out_close:
WSACloseEvent ( ovl->hEvent );
out_free:
HeapFree ( GetProcessHeap(), 0, ovl );
out:
return err;
}
/***********************************************************************
* accept (WS2_32.1)
*/
@ -1995,25 +2469,29 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{
int i, n, fd, err = WSAENOTSOCK, flags;
int i, n, fd, err = WSAENOTSOCK, flags, ret;
struct iovec* iovec;
struct msghdr msghdr;
struct ws2_async *wsa;
enum fd_type type;
TRACE ("socket %04x, wsabuf %p, nbufs %ld, flags %ld, to %p, tolen %d, ovl %p, func %p\n",
s, lpBuffers, dwBufferCount, dwFlags,
to, tolen, lpOverlapped, lpCompletionRoutine);
fd = _get_sock_fd_type( s, &type, &flags );
fd = _get_sock_fd_type( s, GENERIC_WRITE, &type, &flags );
TRACE ( "fd=%d, type=%d, flags=%x\n", fd, type, flags );
if ( fd == -1 )
{
err = WSAGetLastError ();
goto error;
}
iovec = WS_ALLOC ( dwBufferCount * sizeof (struct iovec) );
if ( !iovec )
{
err = WSAENOBUFS;
err = WSAEFAULT;
goto err_close;
}
@ -2023,30 +2501,41 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
iovec[i].iov_len = lpBuffers[i].len;
}
msghdr.msg_name = NULL;
if (to)
if ( (lpOverlapped || lpCompletionRoutine) && flags & FD_FLAG_OVERLAPPED )
{
#if DEBUG_SOCKADDR
dump_sockaddr (to);
#endif
msghdr.msg_name = (void*) ws_sockaddr_ws2u (to, tolen, &msghdr.msg_namelen);
if ( !msghdr.msg_name )
wsa = WS2_make_async ( s, fd, ASYNC_TYPE_WRITE, iovec, dwBufferCount,
&dwFlags, (struct WS_sockaddr*) to, &tolen,
lpOverlapped, lpCompletionRoutine );
if ( !wsa )
{
err = WSAEFAULT;
goto err_free;
}
if ( ( ret = register_new_async ( &wsa->async )) )
{
err = NtStatusToWSAError ( ret );
if ( !lpOverlapped )
HeapFree ( GetProcessHeap(), 0, wsa->overlapped );
HeapFree ( GetProcessHeap(), 0, wsa );
goto err_free;
}
/* Try immediate completion */
if ( lpOverlapped && !NtResetEvent( lpOverlapped->hEvent, NULL ) )
{
if ( WSAGetOverlappedResult ( (HANDLE) s, lpOverlapped,
lpNumberOfBytesSent, FALSE, &dwFlags) )
return 0;
if ( (err = WSAGetLastError ()) != WSA_IO_INCOMPLETE )
goto error;
}
WSASetLastError ( WSA_IO_PENDING );
return SOCKET_ERROR;
}
else
msghdr.msg_namelen = 0;
msghdr.msg_iov = iovec;
msghdr.msg_iovlen = dwBufferCount;
msghdr.msg_control = NULL;
msghdr.msg_controllen = 0;
msghdr.msg_flags = 0;
/* FIXME: Treat overlapped IO here */
if (_is_blocking(s))
{
@ -2054,9 +2543,8 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
do_block(fd, 2);
}
/* FIXME: can we support MSG_PARTIAL ? How does it relate to sendmsg()'s msg_flags ? */
if ((n = sendmsg (fd, &msghdr, dwFlags)) == -1)
n = WS2_send ( fd, iovec, dwBufferCount, to, tolen, dwFlags );
if ( n == -1 )
{
err = wsaErrno();
if ( err == WSAEWOULDBLOCK )
@ -2064,24 +2552,22 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
goto err_free;
}
TRACE(" -> %i bytes\n", n);
*lpNumberOfBytesSent = n;
ws_sockaddr_free ( msghdr.msg_name, to );
WS_FREE ( iovec );
HeapFree ( GetProcessHeap(), 0, iovec );
close ( fd );
return 0;
err_free:
ws_sockaddr_free ( msghdr.msg_name, to );
WS_FREE ( iovec );
HeapFree ( GetProcessHeap(), 0, iovec );
err_close:
close ( fd );
error:
WARN (" -> ERROR %d\n", err);
SetLastError (err);
WSASetLastError (err);
return SOCKET_ERROR;
}
@ -2214,49 +2700,83 @@ INT16 WINAPI WINSOCK_setsockopt16(SOCKET16 s, INT16 level, INT16 optname,
*/
int WINAPI WS_shutdown(SOCKET s, int how)
{
int fd = _get_sock_fd(s);
int fd, fd0 = -1, fd1 = -1, flags, err = WSAENOTSOCK;
enum fd_type type;
unsigned int clear_flags = 0;
TRACE("socket %04x, how %i\n", s, how );
if (fd != -1)
fd = _get_sock_fd_type ( s, 0, &type, &flags );
TRACE("socket %04x, how %i %d %d \n", s, how, type, flags );
if (fd == -1)
return SOCKET_ERROR;
switch( how )
{
switch( how )
{
case 0: /* drop receives */
_enable_event(s, 0, 0, FD_READ);
#ifdef SHUT_RD
how = SHUT_RD;
#endif
break;
case 0: /* drop receives */
clear_flags |= FD_READ;
break;
case 1: /* drop sends */
clear_flags |= FD_WRITE;
break;
case 2: /* drop all */
clear_flags |= FD_READ|FD_WRITE;
default:
clear_flags |= FD_WINE_CONNECTED|FD_WINE_LISTENING;
}
case 1: /* drop sends */
_enable_event(s, 0, 0, FD_WRITE);
#ifdef SHUT_WR
how = SHUT_WR;
#endif
break;
if ( flags & FD_FLAG_OVERLAPPED ) {
case 2: /* drop all */
#ifdef SHUT_RDWR
how = SHUT_RDWR;
#endif
default:
WSAAsyncSelect( s, 0, 0, 0 );
break;
}
switch ( how )
{
case SD_RECEIVE:
fd0 = fd;
break;
case SD_SEND:
fd1 = fd;
break;
case SD_BOTH:
default:
fd0 = fd;
fd1 = _get_sock_fd ( s );
}
if (shutdown(fd, how) == 0)
{
if( how > 1 )
{
_enable_event(s, 0, 0, FD_WINE_CONNECTED|FD_WINE_LISTENING);
}
close(fd);
return 0;
}
SetLastError(wsaErrno());
close(fd);
}
else SetLastError(WSAENOTSOCK);
if ( fd0 != -1 )
{
err = WS2_register_async_shutdown ( s, fd0, ASYNC_TYPE_READ );
if ( err )
{
close ( fd0 );
goto error;
}
}
if ( fd1 != -1 )
{
err = WS2_register_async_shutdown ( s, fd1, ASYNC_TYPE_WRITE );
if ( err )
{
close ( fd1 );
goto error;
}
}
}
else /* non-overlapped mode */
{
if ( shutdown( fd, how ) )
{
err = wsaErrno ();
close ( fd );
goto error;
}
close(fd);
}
_enable_event( s, 0, 0, clear_flags );
if ( how > 1) WSAAsyncSelect( s, 0, 0, 0 );
return 0;
error:
_enable_event( s, 0, 0, clear_flags );
WSASetLastError ( err );
return SOCKET_ERROR;
}
@ -2685,6 +3205,44 @@ int WINAPI WSAEventSelect(SOCKET s, WSAEVENT hEvent, LONG lEvent)
return SOCKET_ERROR;
}
/**********************************************************************
* WSAGetOverlappedResult (WS2_32.40)
*/
BOOL WINAPI WSAGetOverlappedResult ( SOCKET s, LPWSAOVERLAPPED lpOverlapped,
LPDWORD lpcbTransfer, BOOL fWait,
LPDWORD lpdwFlags )
{
DWORD r;
TRACE ( "socket %d ovl %p trans %p, wait %d flags %p\n",
s, lpOverlapped, lpcbTransfer, fWait, lpdwFlags );
if ( !(lpOverlapped && lpOverlapped->hEvent) )
{
ERR ( "Invalid pointer\n" );
WSASetLastError (WSA_INVALID_PARAMETER);
return FALSE;
}
do {
r = WaitForSingleObjectEx (lpOverlapped->hEvent, fWait ? INFINITE : 0, TRUE);
} while (r == STATUS_USER_APC);
if ( lpcbTransfer )
*lpcbTransfer = lpOverlapped->InternalHigh;
if ( lpdwFlags )
*lpdwFlags = lpOverlapped->Offset;
if ( r == WAIT_OBJECT_0 )
return TRUE;
WSASetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
WSA_IO_INCOMPLETE : NtStatusToWSAError ( lpOverlapped->Internal ) );
return FALSE;
}
/***********************************************************************
* WSAAsyncSelect (WS2_32.101)
*/
@ -3285,11 +3843,9 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{
/* Uses recvmsg() in order to provide scatter-gather I/O */
int i, n, fd, err = WSAENOTSOCK, flags, ret;
struct iovec* iovec;
struct msghdr msghdr;
int fd, i, length, err = WSAENOTSOCK, flags;
struct ws2_async *wsa;
enum fd_type type;
TRACE("socket %04x, wsabuf %p, nbufs %ld, flags %ld, from %p, fromlen %ld, ovl %p, func %p\n",
@ -3297,19 +3853,19 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
(lpFromlen ? *lpFromlen : -1L),
lpOverlapped, lpCompletionRoutine);
fd = _get_sock_fd_type( s, &type, &flags );
fd = _get_sock_fd_type( s, GENERIC_READ, &type, &flags );
TRACE ( "fd=%d, type=%d, flags=%x\n", fd, type, flags );
if (fd == -1)
{
err = WSAENOTSOCK;
err = WSAGetLastError ();
goto error;
}
/* FIXME: should this be HeapAlloc() or WS_ALLOC ? */
iovec = WS_ALLOC ( dwBufferCount * sizeof (struct iovec) );
iovec = HeapAlloc ( GetProcessHeap(), 0, dwBufferCount * sizeof (struct iovec) );
if ( !iovec )
{
err = WSAENOBUFS;
err = WSAEFAULT;
goto err_close;
}
@ -3319,74 +3875,75 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
iovec[i].iov_len = lpBuffers[i].len;
}
msghdr.msg_name = NULL;
if ( lpFrom )
if ( (lpOverlapped || lpCompletionRoutine) && flags & FD_FLAG_OVERLAPPED )
{
#if DEBUG_SOCKADDR
dump_sockaddr (lpFrom);
#endif
wsa = WS2_make_async ( s, fd, ASYNC_TYPE_READ, iovec, dwBufferCount,
lpFlags, lpFrom, lpFromlen,
lpOverlapped, lpCompletionRoutine );
msghdr.msg_namelen = *lpFromlen;
msghdr.msg_name = ws_sockaddr_alloc (lpFrom, lpFromlen, &msghdr.msg_namelen);
if ( !wsa )
{
err = WSAEFAULT;
goto err_free;
}
if ( ( ret = register_new_async ( &wsa->async )) )
{
err = NtStatusToWSAError ( ret );
if ( !lpOverlapped )
HeapFree ( GetProcessHeap(), 0, wsa->overlapped );
HeapFree ( GetProcessHeap(), 0, wsa );
goto err_free;
}
/* Try immediate completion */
if ( lpOverlapped && !NtResetEvent( lpOverlapped->hEvent, NULL ) )
{
if ( WSAGetOverlappedResult ( (HANDLE) s, lpOverlapped,
lpNumberOfBytesRecvd, FALSE, lpFlags) )
return 0;
if ( (err = WSAGetLastError ()) != WSA_IO_INCOMPLETE )
goto error;
}
WSASetLastError ( WSA_IO_PENDING );
return SOCKET_ERROR;
}
else
msghdr.msg_namelen = 0;
msghdr.msg_iov = iovec;
msghdr.msg_iovlen = dwBufferCount;
msghdr.msg_control = NULL;
msghdr.msg_controllen = 0;
msghdr.msg_flags = 0;
/* FIXME: Treat overlapped IO here */
if (_is_blocking(s))
if ( _is_blocking(s) )
{
/* block here */
/* FIXME: OOB and exceptfds? */
do_block(fd, 1);
}
/* FIXME: can we support MSG_PARTIAL ?
How does it relate to recvmsg()'s msg_flags ? */
if ((length = recvmsg (fd, &msghdr, *lpFlags)) == -1)
n = WS2_recv ( fd, iovec, dwBufferCount, lpFrom, lpFromlen, lpFlags );
if ( n == -1 )
{
err = wsaErrno();
goto err_free;
}
TRACE(" -> %i bytes\n", length);
TRACE(" -> %i bytes\n", n);
*lpNumberOfBytesRecvd = n;
if ( lpFrom && ws_sockaddr_u2ws (msghdr.msg_name, msghdr.msg_namelen, lpFrom, lpFromlen) != 0 )
{
/* The from buffer was too small, but we read the data
* anyway. Is that really bad?
*/
SetLastError ( WSAEFAULT );
WARN ( " -> Address buffer too small\n" );
}
*lpNumberOfBytesRecvd = length;
WS_FREE (iovec);
ws_sockaddr_free ( msghdr.msg_name, lpFrom );
HeapFree (GetProcessHeap(), 0, iovec);
close(fd);
_enable_event(s, FD_READ, 0, 0);
return 0;
err_free:
WS_FREE (iovec);
ws_sockaddr_free ( msghdr.msg_name, lpFrom );
HeapFree (GetProcessHeap(), 0, iovec);
err_close:
close (fd);
error:
WARN(" -> ERROR %d\n", err);
SetLastError ( err );
WSASetLastError ( err );
return SOCKET_ERROR;
}

View File

@ -52,7 +52,7 @@ debug_channels (winsock)
37 stdcall WSAEnumProtocolsA(ptr ptr ptr) WSAEnumProtocolsA
38 stdcall WSAEnumProtocolsW(ptr ptr ptr) WSAEnumProtocolsW
39 stdcall WSAEventSelect(long long long) WSAEventSelect
40 stub WSAGetOverlappedResult
40 stdcall WSAGetOverlappedResult(long ptr ptr long ptr) WSAGetOverlappedResult
41 stub WSAGetQOSByName
42 stub WSAGetServiceClassInfoA
43 stub WSAGetServiceClassInfoW

View File

@ -300,12 +300,20 @@ HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
* Retrieve the Unix handle corresponding to a file handle.
* Returns -1 on failure.
*/
static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags )
static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
{
int ret, fd = -1;
int ret, flags, fd = -1;
ret = wine_server_handle_to_fd( handle, access, &fd, type, flags );
ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
if (flags_ptr) *flags_ptr = flags;
if (ret) SetLastError( RtlNtStatusToDosError(ret) );
else if (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
{
close (fd);
SetLastError ( ERROR_PIPE_NOT_CONNECTED );
return -1;
}
return fd;
}
@ -1411,7 +1419,7 @@ BOOL WINAPI GetOverlappedResult(
*lpTransferred = lpOverlapped->InternalHigh;
SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
ERROR_IO_INCOMPLETE : lpOverlapped->Internal );
ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
return (r==WAIT_OBJECT_0);
}
@ -1511,9 +1519,13 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
if ( fd < 0 )
{
WARN ( "Couldn't get FD\n" );
SetLastError ( ERROR_INVALID_PARAMETER );
return FALSE;
}
if ( ! (flags & FD_FLAG_OVERLAPPED) ) {
WARN ( "fd is not overlapped\n" );
SetLastError ( ERROR_INVALID_PARAMETER );
goto error;
}
ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
if(!ovp)
@ -1731,6 +1743,11 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
TRACE( "Couldn't get FD\n" );
return FALSE;
}
if ( ! (flags & FD_FLAG_OVERLAPPED) ) {
WARN ( "fd is not overlapped\n" );
SetLastError ( ERROR_INVALID_PARAMETER );
goto error;
}
ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
if(!ovp)

View File

@ -458,7 +458,7 @@ typedef struct {
/* The 'overlapped' data structure used by async I/O functions.
*/
typedef struct {
typedef struct _OVERLAPPED {
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;