ws2_32: Use IOCTL_AFD_WINE_TRANSMIT.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
0a68921936
commit
f2305aebd9
|
@ -498,34 +498,6 @@ struct ws2_async
|
|||
struct iovec iovec[1];
|
||||
};
|
||||
|
||||
struct ws2_accept_async
|
||||
{
|
||||
struct ws2_async_io io;
|
||||
HANDLE listen_socket;
|
||||
HANDLE accept_socket;
|
||||
LPOVERLAPPED user_overlapped;
|
||||
ULONG_PTR cvalue;
|
||||
PVOID buf; /* buffer to write data to */
|
||||
int data_len;
|
||||
int local_len;
|
||||
int remote_len;
|
||||
struct ws2_async *read;
|
||||
};
|
||||
|
||||
struct ws2_transmitfile_async
|
||||
{
|
||||
struct ws2_async_io io;
|
||||
char *buffer;
|
||||
HANDLE file;
|
||||
DWORD file_read;
|
||||
DWORD file_bytes;
|
||||
DWORD bytes_per_send;
|
||||
TRANSMIT_FILE_BUFFERS buffers;
|
||||
DWORD flags;
|
||||
LARGE_INTEGER offset;
|
||||
struct ws2_async write;
|
||||
};
|
||||
|
||||
static struct ws2_async_io *async_io_freelist;
|
||||
|
||||
static void release_async_io( struct ws2_async_io *io )
|
||||
|
@ -556,32 +528,6 @@ static struct ws2_async_io *alloc_async_io( DWORD size, async_callback_t callbac
|
|||
return io;
|
||||
}
|
||||
|
||||
static NTSTATUS register_async( int type, HANDLE handle, struct ws2_async_io *async, HANDLE event,
|
||||
PIO_APC_ROUTINE apc, void *apc_context, IO_STATUS_BLOCK *io )
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
SERVER_START_REQ( register_async )
|
||||
{
|
||||
req->type = type;
|
||||
req->async.handle = wine_server_obj_handle( handle );
|
||||
req->async.user = wine_server_client_ptr( async );
|
||||
req->async.iosb = wine_server_client_ptr( io );
|
||||
req->async.event = wine_server_obj_handle( event );
|
||||
req->async.apc = wine_server_client_ptr( apc );
|
||||
req->async.apc_context = wine_server_client_ptr( apc_context );
|
||||
status = wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
/* ----------------------------------- internal data */
|
||||
|
||||
/* ws_... struct conversion flags */
|
||||
|
||||
typedef struct /* WSAAsyncSelect() control struct */
|
||||
{
|
||||
|
@ -608,15 +554,6 @@ static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS C
|
|||
|
||||
#define MAP_OPTION(opt) { WS_##opt, opt }
|
||||
|
||||
static const int ws_flags_map[][2] =
|
||||
{
|
||||
MAP_OPTION( MSG_OOB ),
|
||||
MAP_OPTION( MSG_PEEK ),
|
||||
MAP_OPTION( MSG_DONTROUTE ),
|
||||
MAP_OPTION( MSG_WAITALL ),
|
||||
{ WS_MSG_PARTIAL, 0 },
|
||||
};
|
||||
|
||||
static const int ws_sock_map[][2] =
|
||||
{
|
||||
MAP_OPTION( SO_DEBUG ),
|
||||
|
@ -710,50 +647,6 @@ static const int ws_poll_map[][2] =
|
|||
{ WS_POLLRDBAND, POLLPRI }
|
||||
};
|
||||
|
||||
static NTSTATUS sock_get_ntstatus( int err )
|
||||
{
|
||||
switch ( err )
|
||||
{
|
||||
case EBADF: return STATUS_INVALID_HANDLE;
|
||||
case EBUSY: return STATUS_DEVICE_BUSY;
|
||||
case EPERM:
|
||||
case EACCES: return STATUS_ACCESS_DENIED;
|
||||
case EFAULT: return STATUS_ACCESS_VIOLATION;
|
||||
case EINVAL: return STATUS_INVALID_PARAMETER;
|
||||
case ENFILE:
|
||||
case EMFILE: return STATUS_TOO_MANY_OPENED_FILES;
|
||||
case EINPROGRESS:
|
||||
case EWOULDBLOCK: return STATUS_DEVICE_NOT_READY;
|
||||
case EALREADY: return STATUS_NETWORK_BUSY;
|
||||
case ENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH;
|
||||
case EDESTADDRREQ: return STATUS_INVALID_PARAMETER;
|
||||
case EMSGSIZE: return STATUS_BUFFER_OVERFLOW;
|
||||
case EPROTONOSUPPORT:
|
||||
case ESOCKTNOSUPPORT:
|
||||
case EPFNOSUPPORT:
|
||||
case EAFNOSUPPORT:
|
||||
case EPROTOTYPE: return STATUS_NOT_SUPPORTED;
|
||||
case ENOPROTOOPT: return STATUS_INVALID_PARAMETER;
|
||||
case EOPNOTSUPP: return STATUS_NOT_SUPPORTED;
|
||||
case EADDRINUSE: return STATUS_SHARING_VIOLATION;
|
||||
case EADDRNOTAVAIL: return STATUS_INVALID_PARAMETER;
|
||||
case ECONNREFUSED: return STATUS_CONNECTION_REFUSED;
|
||||
case ESHUTDOWN: return STATUS_PIPE_DISCONNECTED;
|
||||
case ENOTCONN: return STATUS_INVALID_CONNECTION;
|
||||
case ETIMEDOUT: return STATUS_IO_TIMEOUT;
|
||||
case ENETUNREACH: return STATUS_NETWORK_UNREACHABLE;
|
||||
case ENETDOWN: return STATUS_NETWORK_BUSY;
|
||||
case EPIPE:
|
||||
case ECONNRESET: return STATUS_CONNECTION_RESET;
|
||||
case ECONNABORTED: return STATUS_CONNECTION_ABORTED;
|
||||
|
||||
case 0: return STATUS_SUCCESS;
|
||||
default:
|
||||
WARN("Unknown errno %d!\n", err);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
|
||||
UINT sock_get_error( int err )
|
||||
{
|
||||
switch(err)
|
||||
|
@ -830,15 +723,6 @@ static UINT wsaErrno(void)
|
|||
return sock_get_error( loc_errno );
|
||||
}
|
||||
|
||||
/* most ws2 overlapped functions return an ntstatus-based error code */
|
||||
static NTSTATUS wsaErrStatus(void)
|
||||
{
|
||||
int loc_errno = errno;
|
||||
WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno));
|
||||
|
||||
return sock_get_ntstatus(loc_errno);
|
||||
}
|
||||
|
||||
static NTSTATUS sock_error_to_ntstatus( DWORD err )
|
||||
{
|
||||
switch (err)
|
||||
|
@ -1000,21 +884,6 @@ static void _enable_event( HANDLE s, unsigned int event,
|
|||
SERVER_END_REQ;
|
||||
}
|
||||
|
||||
static DWORD sock_is_blocking(SOCKET s, BOOL *ret)
|
||||
{
|
||||
DWORD err;
|
||||
SERVER_START_REQ( get_socket_event )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) );
|
||||
req->service = FALSE;
|
||||
req->c_event = 0;
|
||||
err = NtStatusToWSAError( wine_server_call( req ));
|
||||
*ret = (reply->state & FD_WINE_NONBLOCKING) == 0;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return err;
|
||||
}
|
||||
|
||||
static unsigned int _get_sock_mask(SOCKET s)
|
||||
{
|
||||
unsigned int ret;
|
||||
|
@ -1030,14 +899,6 @@ static unsigned int _get_sock_mask(SOCKET s)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void _sync_sock_state(SOCKET s)
|
||||
{
|
||||
BOOL dummy;
|
||||
/* do a dummy wineserver request in order to let
|
||||
the wineserver run through its select loop once */
|
||||
sock_is_blocking(s, &dummy);
|
||||
}
|
||||
|
||||
static void _get_sock_errors(SOCKET s, int *events)
|
||||
{
|
||||
SERVER_START_REQ( get_socket_event )
|
||||
|
@ -1211,33 +1072,6 @@ BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* convert_flags()
|
||||
*
|
||||
* Converts send/recv flags from Windows format.
|
||||
* Return the converted flag bits, unsupported flags remain unchanged.
|
||||
*/
|
||||
static int convert_flags(int flags)
|
||||
{
|
||||
int i, out;
|
||||
if (!flags) return 0;
|
||||
|
||||
for (out = i = 0; flags && i < ARRAY_SIZE(ws_flags_map); i++)
|
||||
{
|
||||
if (ws_flags_map[i][0] & flags)
|
||||
{
|
||||
out |= ws_flags_map[i][1];
|
||||
flags &= ~ws_flags_map[i][0];
|
||||
}
|
||||
}
|
||||
if (flags)
|
||||
{
|
||||
FIXME("Unknown send/recv flags 0x%x, using anyway...\n", flags);
|
||||
out |= flags;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* convert_sockopt()
|
||||
*
|
||||
|
@ -1326,25 +1160,6 @@ static inline INT64 get_rcvsnd_timeo( int fd, BOOL is_recv)
|
|||
return (UINT64)tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
/* utility: given an fd, will block until one of the events occurs */
|
||||
static inline int do_block( int fd, int events, int timeout )
|
||||
{
|
||||
struct pollfd pfd;
|
||||
int ret;
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = events;
|
||||
|
||||
while ((ret = poll(&pfd, 1, timeout)) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
return -1;
|
||||
}
|
||||
if( ret == 0 )
|
||||
return 0;
|
||||
return pfd.revents;
|
||||
}
|
||||
|
||||
int
|
||||
convert_socktype_w2u(int windowssocktype) {
|
||||
unsigned int i;
|
||||
|
@ -1927,81 +1742,6 @@ static void WINAPI ws2_async_apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserv
|
|||
release_async_io( &wsa->io );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WS2_send (INTERNAL)
|
||||
*
|
||||
* Workhorse for both synchronous and asynchronous send() operations.
|
||||
*/
|
||||
static int WS2_send( int fd, struct ws2_async *wsa, int flags )
|
||||
{
|
||||
struct msghdr hdr;
|
||||
union generic_unix_sockaddr unix_addr;
|
||||
int n, ret;
|
||||
|
||||
hdr.msg_name = NULL;
|
||||
hdr.msg_namelen = 0;
|
||||
|
||||
if (wsa->addr)
|
||||
{
|
||||
hdr.msg_name = &unix_addr;
|
||||
hdr.msg_namelen = ws_sockaddr_ws2u( wsa->addr, wsa->addrlen.val, &unix_addr );
|
||||
if ( !hdr.msg_namelen )
|
||||
{
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(HAS_IPX) && defined(SOL_IPX)
|
||||
if(wsa->addr->sa_family == WS_AF_IPX)
|
||||
{
|
||||
struct sockaddr_ipx* uipx = (struct sockaddr_ipx*)hdr.msg_name;
|
||||
int val=0;
|
||||
socklen_t len = sizeof(int);
|
||||
|
||||
/* The packet type is stored at the ipx socket level; At least the linux kernel seems
|
||||
* to do something with it in case hdr.msg_name is NULL. Nonetheless can we use it to store
|
||||
* the packet type and then we can retrieve it using getsockopt. After that we can set the
|
||||
* ipx type in the sockaddr_opx structure with the stored value.
|
||||
*/
|
||||
if(getsockopt(fd, SOL_IPX, IPX_TYPE, &val, &len) != -1)
|
||||
uipx->sipx_type = val;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
hdr.msg_iov = wsa->iovec + wsa->first_iovec;
|
||||
hdr.msg_iovlen = wsa->n_iovecs - wsa->first_iovec;
|
||||
#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
|
||||
hdr.msg_accrights = NULL;
|
||||
hdr.msg_accrightslen = 0;
|
||||
#else
|
||||
hdr.msg_control = NULL;
|
||||
hdr.msg_controllen = 0;
|
||||
hdr.msg_flags = 0;
|
||||
#endif
|
||||
|
||||
while ((ret = sendmsg(fd, &hdr, flags)) == -1)
|
||||
{
|
||||
if (errno == EISCONN)
|
||||
{
|
||||
hdr.msg_name = 0;
|
||||
hdr.msg_namelen = 0;
|
||||
continue;
|
||||
}
|
||||
if (errno != EINTR)
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = ret;
|
||||
while (wsa->first_iovec < wsa->n_iovecs && wsa->iovec[wsa->first_iovec].iov_len <= n)
|
||||
n -= wsa->iovec[wsa->first_iovec++].iov_len;
|
||||
if (wsa->first_iovec < wsa->n_iovecs)
|
||||
{
|
||||
wsa->iovec[wsa->first_iovec].iov_base = (char*)wsa->iovec[wsa->first_iovec].iov_base + n;
|
||||
wsa->iovec[wsa->first_iovec].iov_len -= n;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* accept (WS2_32.1)
|
||||
|
@ -2097,281 +1837,54 @@ static BOOL WINAPI WS2_AcceptEx( SOCKET listener, SOCKET acceptor, void *dest, D
|
|||
return !status;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WS2_ReadFile (INTERNAL)
|
||||
*
|
||||
* Perform an APC-safe ReadFile operation
|
||||
*/
|
||||
static NTSTATUS WS2_ReadFile(HANDLE hFile, PIO_STATUS_BLOCK io_status, char* buffer, ULONG length,
|
||||
PLARGE_INTEGER offset)
|
||||
|
||||
static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE file, DWORD file_len, DWORD buffer_size,
|
||||
OVERLAPPED *overlapped, TRANSMIT_FILE_BUFFERS *buffers, DWORD flags )
|
||||
{
|
||||
int result = -1, unix_handle;
|
||||
unsigned int options;
|
||||
struct afd_transmit_params params = {0};
|
||||
IO_STATUS_BLOCK iosb, *piosb = &iosb;
|
||||
HANDLE event = NULL;
|
||||
void *cvalue = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
TRACE( "(%p,%p,0x%08x)\n", hFile, buffer,length );
|
||||
TRACE( "socket %#lx, file %p, file_len %u, buffer_size %u, overlapped %p, buffers %p, flags %#x\n",
|
||||
s, file, file_len, buffer_size, overlapped, buffers, flags );
|
||||
|
||||
status = wine_server_handle_to_fd( hFile, FILE_READ_DATA, &unix_handle, &options );
|
||||
if (status) return status;
|
||||
|
||||
while (result == -1)
|
||||
{
|
||||
if (offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
|
||||
result = pread( unix_handle, buffer, length, offset->QuadPart );
|
||||
else
|
||||
result = read( unix_handle, buffer, length );
|
||||
if (errno != EINTR)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
status = (length ? STATUS_END_OF_FILE : STATUS_SUCCESS);
|
||||
else if (result != -1)
|
||||
status = STATUS_SUCCESS;
|
||||
else if (errno != EAGAIN)
|
||||
status = wsaErrStatus();
|
||||
else
|
||||
status = STATUS_PENDING;
|
||||
|
||||
close( unix_handle );
|
||||
TRACE("= 0x%08x (%d)\n", status, result);
|
||||
if (status == STATUS_SUCCESS || status == STATUS_END_OF_FILE)
|
||||
{
|
||||
io_status->u.Status = status;
|
||||
io_status->Information = result;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WS2_transmitfile_getbuffer (INTERNAL)
|
||||
*
|
||||
* Pick the appropriate buffer for a TransmitFile send operation.
|
||||
*/
|
||||
static NTSTATUS WS2_transmitfile_getbuffer( int fd, struct ws2_transmitfile_async *wsa )
|
||||
{
|
||||
/* send any incomplete writes from a previous iteration */
|
||||
if (wsa->write.first_iovec < wsa->write.n_iovecs)
|
||||
return STATUS_PENDING;
|
||||
|
||||
/* process the header (if applicable) */
|
||||
if (wsa->buffers.Head)
|
||||
{
|
||||
wsa->write.first_iovec = 0;
|
||||
wsa->write.n_iovecs = 1;
|
||||
wsa->write.iovec[0].iov_base = wsa->buffers.Head;
|
||||
wsa->write.iovec[0].iov_len = wsa->buffers.HeadLength;
|
||||
wsa->buffers.Head = NULL;
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
/* process the main file */
|
||||
if (wsa->file)
|
||||
{
|
||||
DWORD bytes_per_send = wsa->bytes_per_send;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
NTSTATUS status;
|
||||
|
||||
iosb.Information = 0;
|
||||
/* when the size of the transfer is limited ensure that we don't go past that limit */
|
||||
if (wsa->file_bytes != 0)
|
||||
bytes_per_send = min(bytes_per_send, wsa->file_bytes - wsa->file_read);
|
||||
status = WS2_ReadFile( wsa->file, &iosb, wsa->buffer, bytes_per_send, &wsa->offset );
|
||||
if (wsa->offset.QuadPart != FILE_USE_FILE_POINTER_POSITION)
|
||||
wsa->offset.QuadPart += iosb.Information;
|
||||
if (status == STATUS_END_OF_FILE)
|
||||
wsa->file = NULL; /* continue on to the footer */
|
||||
else if (status != STATUS_SUCCESS)
|
||||
return status;
|
||||
else
|
||||
{
|
||||
if (iosb.Information)
|
||||
{
|
||||
wsa->write.first_iovec = 0;
|
||||
wsa->write.n_iovecs = 1;
|
||||
wsa->write.iovec[0].iov_base = wsa->buffer;
|
||||
wsa->write.iovec[0].iov_len = iosb.Information;
|
||||
wsa->file_read += iosb.Information;
|
||||
}
|
||||
|
||||
if (wsa->file_bytes != 0 && wsa->file_read >= wsa->file_bytes)
|
||||
wsa->file = NULL;
|
||||
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
}
|
||||
|
||||
/* send the footer (if applicable) */
|
||||
if (wsa->buffers.Tail)
|
||||
{
|
||||
wsa->write.first_iovec = 0;
|
||||
wsa->write.n_iovecs = 1;
|
||||
wsa->write.iovec[0].iov_base = wsa->buffers.Tail;
|
||||
wsa->write.iovec[0].iov_len = wsa->buffers.TailLength;
|
||||
wsa->buffers.Tail = NULL;
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WS2_transmitfile_base (INTERNAL)
|
||||
*
|
||||
* Shared implementation for both synchronous and asynchronous TransmitFile.
|
||||
*/
|
||||
static NTSTATUS WS2_transmitfile_base( int fd, struct ws2_transmitfile_async *wsa )
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = WS2_transmitfile_getbuffer( fd, wsa );
|
||||
if (status == STATUS_PENDING)
|
||||
{
|
||||
IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)wsa->write.user_overlapped;
|
||||
int n;
|
||||
|
||||
n = WS2_send( fd, &wsa->write, convert_flags(wsa->write.flags) );
|
||||
if (n >= 0)
|
||||
{
|
||||
if (iosb) iosb->Information += n;
|
||||
}
|
||||
else if (errno != EAGAIN)
|
||||
return wsaErrStatus();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WS2_async_transmitfile (INTERNAL)
|
||||
*
|
||||
* Asynchronous callback for overlapped TransmitFile operations.
|
||||
*/
|
||||
static NTSTATUS WS2_async_transmitfile( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
|
||||
{
|
||||
struct ws2_transmitfile_async *wsa = user;
|
||||
int fd;
|
||||
|
||||
if (status == STATUS_ALERTED)
|
||||
{
|
||||
if (!(status = wine_server_handle_to_fd( wsa->write.hSocket, FILE_WRITE_DATA, &fd, NULL )))
|
||||
{
|
||||
status = WS2_transmitfile_base( fd, wsa );
|
||||
close( fd );
|
||||
}
|
||||
if (status == STATUS_PENDING)
|
||||
return status;
|
||||
}
|
||||
|
||||
iosb->u.Status = status;
|
||||
release_async_io( &wsa->io );
|
||||
return status;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TransmitFile
|
||||
*/
|
||||
static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD file_bytes, DWORD bytes_per_send,
|
||||
LPOVERLAPPED overlapped, LPTRANSMIT_FILE_BUFFERS buffers,
|
||||
DWORD flags )
|
||||
{
|
||||
union generic_unix_sockaddr uaddr;
|
||||
socklen_t uaddrlen = sizeof(uaddr);
|
||||
struct ws2_transmitfile_async *wsa;
|
||||
NTSTATUS status;
|
||||
int fd;
|
||||
|
||||
TRACE("(%lx, %p, %d, %d, %p, %p, %d)\n", s, h, file_bytes, bytes_per_send, overlapped,
|
||||
buffers, flags );
|
||||
|
||||
fd = get_sock_fd( s, FILE_WRITE_DATA, NULL );
|
||||
if (fd == -1) return FALSE;
|
||||
|
||||
if (getpeername( fd, &uaddr.addr, &uaddrlen ) != 0)
|
||||
{
|
||||
release_sock_fd( s, fd );
|
||||
WSASetLastError( WSAENOTCONN );
|
||||
return FALSE;
|
||||
}
|
||||
if (flags)
|
||||
FIXME("Flags are not currently supported (0x%x).\n", flags);
|
||||
|
||||
if (h && GetFileType( h ) != FILE_TYPE_DISK)
|
||||
{
|
||||
FIXME("Non-disk file handles are not currently supported.\n");
|
||||
release_sock_fd( s, fd );
|
||||
WSASetLastError( WSAEOPNOTSUPP );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* set reasonable defaults when requested */
|
||||
if (!bytes_per_send)
|
||||
bytes_per_send = (1 << 16); /* Depends on OS version: PAGE_SIZE, 2*PAGE_SIZE, or 2^16 */
|
||||
|
||||
if (!(wsa = (struct ws2_transmitfile_async *)alloc_async_io( sizeof(*wsa) + bytes_per_send,
|
||||
WS2_async_transmitfile )))
|
||||
{
|
||||
release_sock_fd( s, fd );
|
||||
WSASetLastError( WSAEFAULT );
|
||||
return FALSE;
|
||||
}
|
||||
if (buffers)
|
||||
wsa->buffers = *buffers;
|
||||
else
|
||||
memset(&wsa->buffers, 0x0, sizeof(wsa->buffers));
|
||||
wsa->buffer = (char *)(wsa + 1);
|
||||
wsa->file = h;
|
||||
wsa->file_read = 0;
|
||||
wsa->file_bytes = file_bytes;
|
||||
wsa->bytes_per_send = bytes_per_send;
|
||||
wsa->flags = flags;
|
||||
wsa->offset.QuadPart = FILE_USE_FILE_POINTER_POSITION;
|
||||
wsa->write.hSocket = SOCKET2HANDLE(s);
|
||||
wsa->write.addr = NULL;
|
||||
wsa->write.addrlen.val = 0;
|
||||
wsa->write.flags = 0;
|
||||
wsa->write.lpFlags = &wsa->flags;
|
||||
wsa->write.control = NULL;
|
||||
wsa->write.n_iovecs = 0;
|
||||
wsa->write.first_iovec = 0;
|
||||
wsa->write.user_overlapped = overlapped;
|
||||
if (overlapped)
|
||||
{
|
||||
IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)overlapped;
|
||||
int status;
|
||||
|
||||
wsa->offset.u.LowPart = overlapped->u.s.Offset;
|
||||
wsa->offset.u.HighPart = overlapped->u.s.OffsetHigh;
|
||||
iosb->u.Status = STATUS_PENDING;
|
||||
iosb->Information = 0;
|
||||
status = register_async( ASYNC_TYPE_WRITE, SOCKET2HANDLE(s), &wsa->io,
|
||||
overlapped->hEvent, NULL, NULL, iosb );
|
||||
if(status != STATUS_PENDING) HeapFree( GetProcessHeap(), 0, wsa );
|
||||
release_sock_fd( s, fd );
|
||||
WSASetLastError( NtStatusToWSAError(status) );
|
||||
return FALSE;
|
||||
piosb = (IO_STATUS_BLOCK *)overlapped;
|
||||
if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped;
|
||||
event = overlapped->hEvent;
|
||||
overlapped->Internal = STATUS_PENDING;
|
||||
overlapped->InternalHigh = 0;
|
||||
params.offset.u.LowPart = overlapped->u.s.Offset;
|
||||
params.offset.u.HighPart = overlapped->u.s.OffsetHigh;
|
||||
}
|
||||
|
||||
do
|
||||
else
|
||||
{
|
||||
status = WS2_transmitfile_base( fd, wsa );
|
||||
if (status == STATUS_PENDING)
|
||||
{
|
||||
/* block here */
|
||||
do_block(fd, POLLOUT, -1);
|
||||
_sync_sock_state(s); /* let wineserver notice connection */
|
||||
}
|
||||
if (!(event = get_sync_event())) return -1;
|
||||
params.offset.QuadPart = FILE_USE_FILE_POINTER_POSITION;
|
||||
}
|
||||
while (status == STATUS_PENDING);
|
||||
release_sock_fd( s, fd );
|
||||
|
||||
if (status != STATUS_SUCCESS)
|
||||
WSASetLastError( NtStatusToWSAError(status) );
|
||||
HeapFree( GetProcessHeap(), 0, wsa );
|
||||
return (status == STATUS_SUCCESS);
|
||||
params.file = file;
|
||||
params.file_len = file_len;
|
||||
params.buffer_size = buffer_size;
|
||||
if (buffers) params.buffers = *buffers;
|
||||
params.flags = flags;
|
||||
|
||||
status = NtDeviceIoControlFile( (HANDLE)s, event, NULL, cvalue, piosb,
|
||||
IOCTL_AFD_WINE_TRANSMIT, ¶ms, sizeof(params), NULL, 0 );
|
||||
if (status == STATUS_PENDING && !overlapped)
|
||||
{
|
||||
if (WaitForSingleObject( event, INFINITE ) == WAIT_FAILED)
|
||||
return FALSE;
|
||||
status = piosb->u.Status;
|
||||
}
|
||||
SetLastError( NtStatusToWSAError( status ) );
|
||||
return !status;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetAcceptExSockaddrs
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue