mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-15 01:29:47 +00:00
ntdll: Introduce 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
d8968b955c
commit
0a68921936
|
@ -71,6 +71,8 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
|
||||
|
||||
#define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
|
||||
|
||||
static async_data_t server_async( HANDLE handle, struct async_fileio *user, HANDLE event,
|
||||
PIO_APC_ROUTINE apc, void *apc_context, IO_STATUS_BLOCK *io )
|
||||
{
|
||||
|
@ -126,6 +128,23 @@ struct async_send_ioctl
|
|||
struct iovec iov[1];
|
||||
};
|
||||
|
||||
struct async_transmit_ioctl
|
||||
{
|
||||
struct async_fileio io;
|
||||
HANDLE file;
|
||||
char *buffer;
|
||||
unsigned int buffer_size; /* allocated size of buffer */
|
||||
unsigned int read_len; /* amount of valid data currently in the buffer */
|
||||
unsigned int head_cursor; /* amount of header data already sent */
|
||||
unsigned int file_cursor; /* amount of file data already sent */
|
||||
unsigned int buffer_cursor; /* amount of data currently in the buffer already sent */
|
||||
unsigned int tail_cursor; /* amount of tail data already sent */
|
||||
unsigned int file_len; /* total file length to send */
|
||||
DWORD flags;
|
||||
TRANSMIT_FILE_BUFFERS buffers;
|
||||
LARGE_INTEGER offset;
|
||||
};
|
||||
|
||||
static NTSTATUS sock_errno_to_status( int err )
|
||||
{
|
||||
switch (err)
|
||||
|
@ -921,6 +940,182 @@ static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi
|
|||
return status;
|
||||
}
|
||||
|
||||
static ssize_t do_send( int fd, const void *buffer, size_t len, int flags )
|
||||
{
|
||||
ssize_t ret;
|
||||
while ((ret = send( fd, buffer, len, flags )) < 0 && errno == EINTR);
|
||||
if (ret < 0 && errno != EWOULDBLOCK) WARN( "send: %s\n", strerror( errno ) );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static NTSTATUS try_transmit( int sock_fd, int file_fd, struct async_transmit_ioctl *async )
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
while (async->head_cursor < async->buffers.HeadLength)
|
||||
{
|
||||
TRACE( "sending %u bytes of header data\n", async->buffers.HeadLength - async->head_cursor );
|
||||
ret = do_send( sock_fd, (char *)async->buffers.Head + async->head_cursor,
|
||||
async->buffers.HeadLength - async->head_cursor, 0 );
|
||||
if (ret < 0) return sock_errno_to_status( errno );
|
||||
TRACE( "send returned %zd\n", ret );
|
||||
async->head_cursor += ret;
|
||||
}
|
||||
|
||||
while (async->buffer_cursor < async->read_len)
|
||||
{
|
||||
TRACE( "sending %u bytes of file data\n", async->read_len - async->buffer_cursor );
|
||||
ret = do_send( sock_fd, async->buffer + async->buffer_cursor,
|
||||
async->read_len - async->buffer_cursor, 0 );
|
||||
if (ret < 0) return sock_errno_to_status( errno );
|
||||
TRACE( "send returned %zd\n", ret );
|
||||
async->buffer_cursor += ret;
|
||||
async->file_cursor += ret;
|
||||
}
|
||||
|
||||
if (async->file && async->buffer_cursor == async->read_len)
|
||||
{
|
||||
unsigned int read_size = async->buffer_size;
|
||||
|
||||
if (async->file_len)
|
||||
read_size = min( read_size, async->file_len - async->file_cursor );
|
||||
|
||||
TRACE( "reading %u bytes of file data\n", read_size );
|
||||
do
|
||||
{
|
||||
if (async->offset.QuadPart == FILE_USE_FILE_POINTER_POSITION)
|
||||
ret = read( file_fd, async->buffer, read_size );
|
||||
else
|
||||
ret = pread( file_fd, async->buffer, read_size, async->offset.QuadPart );
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
if (ret < 0) return errno_to_status( errno );
|
||||
TRACE( "read returned %zd\n", ret );
|
||||
|
||||
async->read_len = ret;
|
||||
async->buffer_cursor = 0;
|
||||
if (async->offset.QuadPart != FILE_USE_FILE_POINTER_POSITION)
|
||||
async->offset.QuadPart += ret;
|
||||
|
||||
if (ret < read_size || (async->file_len && async->file_cursor == async->file_len))
|
||||
async->file = NULL;
|
||||
return STATUS_PENDING; /* still more data to send */
|
||||
}
|
||||
|
||||
while (async->tail_cursor < async->buffers.TailLength)
|
||||
{
|
||||
TRACE( "sending %u bytes of tail data\n", async->buffers.TailLength - async->tail_cursor );
|
||||
ret = do_send( sock_fd, (char *)async->buffers.Tail + async->tail_cursor,
|
||||
async->buffers.TailLength - async->tail_cursor, 0 );
|
||||
if (ret < 0) return sock_errno_to_status( errno );
|
||||
TRACE( "send returned %zd\n", ret );
|
||||
async->tail_cursor += ret;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS async_transmit_proc( void *user, IO_STATUS_BLOCK *io, NTSTATUS status )
|
||||
{
|
||||
int sock_fd, file_fd = -1, sock_needs_close = FALSE, file_needs_close = FALSE;
|
||||
struct async_transmit_ioctl *async = user;
|
||||
|
||||
TRACE( "%#x\n", status );
|
||||
|
||||
if (status == STATUS_ALERTED)
|
||||
{
|
||||
if ((status = server_get_unix_fd( async->io.handle, 0, &sock_fd, &sock_needs_close, NULL, NULL )))
|
||||
return status;
|
||||
|
||||
if (async->file && (status = server_get_unix_fd( async->file, 0, &file_fd, &file_needs_close, NULL, NULL )))
|
||||
{
|
||||
if (sock_needs_close) close( sock_fd );
|
||||
return status;
|
||||
}
|
||||
|
||||
status = try_transmit( sock_fd, file_fd, async );
|
||||
TRACE( "got status %#x\n", status );
|
||||
|
||||
if (status == STATUS_DEVICE_NOT_READY)
|
||||
status = STATUS_PENDING;
|
||||
|
||||
if (sock_needs_close) close( sock_fd );
|
||||
if (file_needs_close) close( file_fd );
|
||||
}
|
||||
if (status != STATUS_PENDING)
|
||||
{
|
||||
io->Status = status;
|
||||
io->Information = async->head_cursor + async->file_cursor + async->tail_cursor;
|
||||
release_fileio( &async->io );
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS sock_transmit( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
|
||||
IO_STATUS_BLOCK *io, int fd, const struct afd_transmit_params *params )
|
||||
{
|
||||
int file_fd, file_needs_close = FALSE;
|
||||
struct async_transmit_ioctl *async;
|
||||
enum server_fd_type file_type;
|
||||
union unix_sockaddr addr;
|
||||
socklen_t addr_len;
|
||||
HANDLE wait_handle;
|
||||
NTSTATUS status;
|
||||
ULONG options;
|
||||
|
||||
addr_len = sizeof(addr);
|
||||
if (getpeername( fd, &addr.addr, &addr_len ) != 0)
|
||||
return STATUS_INVALID_CONNECTION;
|
||||
|
||||
if (params->file)
|
||||
{
|
||||
if ((status = server_get_unix_fd( params->file, 0, &file_fd, &file_needs_close, &file_type, NULL )))
|
||||
return status;
|
||||
if (file_needs_close) close( file_fd );
|
||||
|
||||
if (file_type != FD_TYPE_FILE)
|
||||
{
|
||||
FIXME( "unsupported file type %#x\n", file_type );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(async = (struct async_transmit_ioctl *)alloc_fileio( sizeof(*async), async_transmit_proc, handle )))
|
||||
return STATUS_NO_MEMORY;
|
||||
|
||||
async->file = params->file;
|
||||
async->buffer_size = params->buffer_size ? params->buffer_size : 65536;
|
||||
if (!(async->buffer = malloc( async->buffer_size )))
|
||||
{
|
||||
release_fileio( &async->io );
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
async->read_len = 0;
|
||||
async->head_cursor = 0;
|
||||
async->file_cursor = 0;
|
||||
async->buffer_cursor = 0;
|
||||
async->tail_cursor = 0;
|
||||
async->file_len = params->file_len;
|
||||
async->flags = params->flags;
|
||||
async->buffers = params->buffers;
|
||||
async->offset = params->offset;
|
||||
|
||||
SERVER_START_REQ( send_socket )
|
||||
{
|
||||
req->status = STATUS_PENDING;
|
||||
req->total = 0;
|
||||
req->async = server_async( handle, &async->io, event, apc, apc_user, io );
|
||||
status = wine_server_call( req );
|
||||
wait_handle = wine_server_ptr_handle( reply->wait );
|
||||
options = reply->options;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (status != STATUS_PENDING) release_fileio( &async->io );
|
||||
|
||||
if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io,
|
||||
ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size )
|
||||
{
|
||||
|
@ -1037,6 +1232,23 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
|
|||
break;
|
||||
}
|
||||
|
||||
case IOCTL_AFD_WINE_TRANSMIT:
|
||||
{
|
||||
const struct afd_transmit_params *params = in_buffer;
|
||||
|
||||
if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
|
||||
return status;
|
||||
|
||||
if (in_size < sizeof(*params))
|
||||
{
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
break;
|
||||
}
|
||||
|
||||
status = sock_transmit( handle, event, apc, apc_user, io, fd, params );
|
||||
break;
|
||||
}
|
||||
|
||||
case IOCTL_AFD_POLL:
|
||||
status = sock_poll( handle, event, apc, apc_user, io, in_buffer, in_size, out_buffer, out_size );
|
||||
break;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <winternl.h>
|
||||
#include <winioctl.h>
|
||||
#include <mswsock.h>
|
||||
#include "wine/server_protocol.h"
|
||||
|
||||
#ifdef USE_WS_PREFIX
|
||||
|
@ -93,6 +94,7 @@ struct afd_poll_params
|
|||
#define IOCTL_AFD_WINE_SHUTDOWN CTL_CODE(FILE_DEVICE_NETWORK, 204, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_AFD_WINE_RECVMSG CTL_CODE(FILE_DEVICE_NETWORK, 205, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_AFD_WINE_SENDMSG CTL_CODE(FILE_DEVICE_NETWORK, 206, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_AFD_WINE_TRANSMIT CTL_CODE(FILE_DEVICE_NETWORK, 207, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define IOCTL_AFD_WINE_ADDRESS_LIST_CHANGE CTL_CODE(FILE_DEVICE_NETWORK, 323, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
|
@ -137,4 +139,14 @@ struct afd_sendmsg_params
|
|||
const WSABUF *buffers;
|
||||
};
|
||||
|
||||
struct afd_transmit_params
|
||||
{
|
||||
HANDLE file;
|
||||
DWORD file_len;
|
||||
DWORD buffer_size;
|
||||
LARGE_INTEGER offset;
|
||||
TRANSMIT_FILE_BUFFERS buffers;
|
||||
DWORD flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue