ntdll: Introduce IOCTL_AFD_WINE_SENDMSG.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
ac3ec2d955
commit
85a615f136
|
@ -89,6 +89,19 @@ static NTSTATUS wait_async( HANDLE handle, BOOL alertable )
|
|||
return NtWaitForSingleObject( handle, alertable, NULL );
|
||||
}
|
||||
|
||||
union unix_sockaddr
|
||||
{
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
#ifdef HAS_IPX
|
||||
struct sockaddr_ipx ipx;
|
||||
#endif
|
||||
#ifdef HAS_IRDA
|
||||
struct sockaddr_irda irda;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct async_recv_ioctl
|
||||
{
|
||||
struct async_fileio io;
|
||||
|
@ -101,6 +114,18 @@ struct async_recv_ioctl
|
|||
struct iovec iov[1];
|
||||
};
|
||||
|
||||
struct async_send_ioctl
|
||||
{
|
||||
struct async_fileio io;
|
||||
const struct WS_sockaddr *addr;
|
||||
int addr_len;
|
||||
int unix_flags;
|
||||
unsigned int sent_len;
|
||||
unsigned int count;
|
||||
unsigned int iov_cursor;
|
||||
struct iovec iov[1];
|
||||
};
|
||||
|
||||
static NTSTATUS sock_errno_to_status( int err )
|
||||
{
|
||||
switch (err)
|
||||
|
@ -147,18 +172,108 @@ static NTSTATUS sock_errno_to_status( int err )
|
|||
}
|
||||
}
|
||||
|
||||
union unix_sockaddr
|
||||
static socklen_t sockaddr_to_unix( const struct WS_sockaddr *wsaddr, int wsaddrlen, union unix_sockaddr *uaddr )
|
||||
{
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
memset( uaddr, 0, sizeof(*uaddr) );
|
||||
|
||||
switch (wsaddr->sa_family)
|
||||
{
|
||||
case WS_AF_INET:
|
||||
{
|
||||
struct WS_sockaddr_in win = {0};
|
||||
|
||||
if (wsaddrlen < sizeof(win)) return 0;
|
||||
memcpy( &win, wsaddr, sizeof(win) );
|
||||
uaddr->in.sin_family = AF_INET;
|
||||
uaddr->in.sin_port = win.sin_port;
|
||||
memcpy( &uaddr->in.sin_addr, &win.sin_addr, sizeof(win.sin_addr) );
|
||||
return sizeof(uaddr->in);
|
||||
}
|
||||
|
||||
case WS_AF_INET6:
|
||||
{
|
||||
struct WS_sockaddr_in6 win = {0};
|
||||
|
||||
if (wsaddrlen < sizeof(struct WS_sockaddr_in6_old)) return 0;
|
||||
if (wsaddrlen < sizeof(struct WS_sockaddr_in6))
|
||||
memcpy( &win, wsaddr, sizeof(struct WS_sockaddr_in6_old) );
|
||||
else
|
||||
memcpy( &win, wsaddr, sizeof(struct WS_sockaddr_in6) );
|
||||
|
||||
uaddr->in6.sin6_family = AF_INET6;
|
||||
uaddr->in6.sin6_port = win.sin6_port;
|
||||
uaddr->in6.sin6_flowinfo = win.sin6_flowinfo;
|
||||
memcpy( &uaddr->in6.sin6_addr, &win.sin6_addr, sizeof(win.sin6_addr) );
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
if (wsaddrlen >= sizeof(struct WS_sockaddr_in6))
|
||||
uaddr->in6.sin6_scope_id = win.sin6_scope_id;
|
||||
#endif
|
||||
return sizeof(uaddr->in6);
|
||||
}
|
||||
|
||||
#ifdef HAS_IPX
|
||||
struct sockaddr_ipx ipx;
|
||||
case WS_AF_IPX:
|
||||
{
|
||||
struct WS_sockaddr_ipx win = {0};
|
||||
|
||||
if (wsaddrlen < sizeof(win)) return 0;
|
||||
memcpy( &win, wsaddr, sizeof(win) );
|
||||
uaddr->ipx.sipx_family = AF_IPX;
|
||||
memcpy( &uaddr->ipx.sipx_network, win.sa_netnum, sizeof(win.sa_netnum) );
|
||||
memcpy( &uaddr->ipx.sipx_node, win.sa_nodenum, sizeof(win.sa_nodenum) );
|
||||
uaddr->ipx.sipx_port = win.sa_socket;
|
||||
return sizeof(uaddr->ipx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAS_IRDA
|
||||
struct sockaddr_irda irda;
|
||||
case WS_AF_IRDA:
|
||||
{
|
||||
SOCKADDR_IRDA win = {0};
|
||||
unsigned int lsap_sel;
|
||||
|
||||
if (wsaddrlen < sizeof(win)) return 0;
|
||||
memcpy( &win, wsaddr, sizeof(win) );
|
||||
uaddr->irda.sir_family = AF_IRDA;
|
||||
if (sscanf( win.irdaServiceName, "LSAP-SEL%u", &lsap_sel ) == 1)
|
||||
uaddr->sir_lsap_sel = lsap_sel;
|
||||
else
|
||||
{
|
||||
uaddr->sir_lsap_sel = LSAP_ANY;
|
||||
memcpy( uaddr->irda.sir_name, win.irdaServiceName, sizeof(win.irdaServiceName) );
|
||||
}
|
||||
memcpy( &uaddr->irda.sir_addr, win.irdaDeviceID, sizeof(win.irdaDeviceID) );
|
||||
return sizeof(uaddr->irda);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
case WS_AF_UNSPEC:
|
||||
switch (wsaddrlen)
|
||||
{
|
||||
default: /* likely an ipv4 address */
|
||||
case sizeof(struct WS_sockaddr_in):
|
||||
return sizeof(uaddr->in);
|
||||
|
||||
#ifdef HAS_IPX
|
||||
case sizeof(struct WS_sockaddr_ipx):
|
||||
return sizeof(uaddr->ipx);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_IRDA
|
||||
case sizeof(SOCKADDR_IRDA):
|
||||
return sizeof(uaddr->irda);
|
||||
#endif
|
||||
|
||||
case sizeof(struct WS_sockaddr_in6):
|
||||
case sizeof(struct WS_sockaddr_in6_old):
|
||||
return sizeof(uaddr->in6);
|
||||
}
|
||||
|
||||
default:
|
||||
FIXME( "unknown address family %u\n", wsaddr->sa_family );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_sockaddr *wsaddr, socklen_t wsaddrlen )
|
||||
{
|
||||
|
@ -650,6 +765,161 @@ static NTSTATUS sock_poll( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi
|
|||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS try_send( int fd, struct async_send_ioctl *async )
|
||||
{
|
||||
union unix_sockaddr unix_addr;
|
||||
struct msghdr hdr;
|
||||
ssize_t ret;
|
||||
|
||||
memset( &hdr, 0, sizeof(hdr) );
|
||||
if (async->addr)
|
||||
{
|
||||
hdr.msg_name = &unix_addr;
|
||||
hdr.msg_namelen = sockaddr_to_unix( async->addr, async->addr_len, &unix_addr );
|
||||
if (!hdr.msg_namelen)
|
||||
{
|
||||
ERR( "failed to convert address\n" );
|
||||
return STATUS_ACCESS_VIOLATION;
|
||||
}
|
||||
|
||||
#if defined(HAS_IPX) && defined(SOL_IPX)
|
||||
if (async->addr->sa_family == WS_AF_IPX)
|
||||
{
|
||||
int type;
|
||||
socklen_t len = sizeof(type);
|
||||
|
||||
/* 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 we can 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_ipx structure with the stored value.
|
||||
*/
|
||||
if (getsockopt(fd, SOL_IPX, IPX_TYPE, &type, &len) >= 0)
|
||||
unix_addr.ipx.sipx_type = type;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
hdr.msg_iov = async->iov + async->iov_cursor;
|
||||
hdr.msg_iovlen = async->count - async->iov_cursor;
|
||||
|
||||
while ((ret = sendmsg( fd, &hdr, async->unix_flags )) == -1)
|
||||
{
|
||||
if (errno == EISCONN)
|
||||
{
|
||||
hdr.msg_name = NULL;
|
||||
hdr.msg_namelen = 0;
|
||||
}
|
||||
else if (errno != EINTR)
|
||||
{
|
||||
if (errno != EWOULDBLOCK) WARN( "sendmsg: %s\n", strerror( errno ) );
|
||||
return sock_errno_to_status( errno );
|
||||
}
|
||||
}
|
||||
|
||||
async->sent_len += ret;
|
||||
|
||||
while (async->iov_cursor < async->count && ret >= async->iov[async->iov_cursor].iov_len)
|
||||
ret -= async->iov[async->iov_cursor++].iov_len;
|
||||
if (async->iov_cursor < async->count)
|
||||
{
|
||||
async->iov[async->iov_cursor].iov_base = (char *)async->iov[async->iov_cursor].iov_base + ret;
|
||||
async->iov[async->iov_cursor].iov_len -= ret;
|
||||
return STATUS_DEVICE_NOT_READY;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS async_send_proc( void *user, IO_STATUS_BLOCK *io, NTSTATUS status )
|
||||
{
|
||||
struct async_send_ioctl *async = user;
|
||||
int fd, needs_close;
|
||||
|
||||
TRACE( "%#x\n", status );
|
||||
|
||||
if (status == STATUS_ALERTED)
|
||||
{
|
||||
if ((status = server_get_unix_fd( async->io.handle, 0, &fd, &needs_close, NULL, NULL )))
|
||||
return status;
|
||||
|
||||
status = try_send( fd, async );
|
||||
TRACE( "got status %#x\n", status );
|
||||
|
||||
if (status == STATUS_DEVICE_NOT_READY)
|
||||
status = STATUS_PENDING;
|
||||
|
||||
if (needs_close) close( fd );
|
||||
}
|
||||
if (status != STATUS_PENDING)
|
||||
{
|
||||
io->Status = status;
|
||||
io->Information = async->sent_len;
|
||||
release_fileio( &async->io );
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
|
||||
IO_STATUS_BLOCK *io, int fd, const WSABUF *buffers, unsigned int count,
|
||||
const struct WS_sockaddr *addr, unsigned int addr_len, int unix_flags, int force_async )
|
||||
{
|
||||
struct async_send_ioctl *async;
|
||||
HANDLE wait_handle;
|
||||
DWORD async_size;
|
||||
NTSTATUS status;
|
||||
unsigned int i;
|
||||
ULONG options;
|
||||
|
||||
async_size = offsetof( struct async_send_ioctl, iov[count] );
|
||||
|
||||
if (!(async = (struct async_send_ioctl *)alloc_fileio( async_size, async_send_proc, handle )))
|
||||
return STATUS_NO_MEMORY;
|
||||
|
||||
async->count = count;
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
async->iov[i].iov_base = buffers[i].buf;
|
||||
async->iov[i].iov_len = buffers[i].len;
|
||||
}
|
||||
async->unix_flags = unix_flags;
|
||||
async->addr = addr;
|
||||
async->addr_len = addr_len;
|
||||
async->iov_cursor = 0;
|
||||
async->sent_len = 0;
|
||||
|
||||
status = try_send( fd, async );
|
||||
|
||||
if (status != STATUS_SUCCESS && status != STATUS_DEVICE_NOT_READY)
|
||||
{
|
||||
release_fileio( &async->io );
|
||||
return status;
|
||||
}
|
||||
|
||||
if (status == STATUS_DEVICE_NOT_READY && force_async)
|
||||
status = STATUS_PENDING;
|
||||
|
||||
if (!NT_ERROR(status))
|
||||
{
|
||||
io->Status = status;
|
||||
io->Information = async->sent_len;
|
||||
}
|
||||
|
||||
SERVER_START_REQ( send_socket )
|
||||
{
|
||||
req->status = status;
|
||||
req->total = async->sent_len;
|
||||
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 )
|
||||
|
@ -741,6 +1011,32 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
|
|||
break;
|
||||
}
|
||||
|
||||
case IOCTL_AFD_WINE_SENDMSG:
|
||||
{
|
||||
const struct afd_sendmsg_params *params = in_buffer;
|
||||
int unix_flags = 0;
|
||||
|
||||
if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
|
||||
return status;
|
||||
|
||||
if (in_size < sizeof(*params))
|
||||
{
|
||||
status = STATUS_BUFFER_TOO_SMALL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (params->ws_flags & WS_MSG_OOB)
|
||||
unix_flags |= MSG_OOB;
|
||||
if (params->ws_flags & WS_MSG_PARTIAL)
|
||||
WARN( "ignoring MSG_PARTIAL\n" );
|
||||
if (params->ws_flags & ~(WS_MSG_OOB | WS_MSG_PARTIAL))
|
||||
FIXME( "unknown flags %#x\n", params->ws_flags );
|
||||
|
||||
status = sock_send( handle, event, apc, apc_user, io, fd, params->buffers, params->count,
|
||||
params->addr, params->addr_len, unix_flags, params->force_async );
|
||||
break;
|
||||
}
|
||||
|
||||
case IOCTL_AFD_POLL:
|
||||
status = sock_poll( handle, event, apc, apc_user, io, in_buffer, in_size, out_buffer, out_size );
|
||||
break;
|
||||
|
|
|
@ -92,6 +92,7 @@ struct afd_poll_params
|
|||
#define IOCTL_AFD_WINE_CONNECT CTL_CODE(FILE_DEVICE_NETWORK, 203, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#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_ADDRESS_LIST_CHANGE CTL_CODE(FILE_DEVICE_NETWORK, 323, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
|
@ -126,4 +127,14 @@ struct afd_recvmsg_params
|
|||
WSABUF *buffers;
|
||||
};
|
||||
|
||||
struct afd_sendmsg_params
|
||||
{
|
||||
const struct WS(sockaddr) *addr;
|
||||
unsigned int addr_len;
|
||||
unsigned int ws_flags;
|
||||
int force_async;
|
||||
unsigned int count;
|
||||
const WSABUF *buffers;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1852,6 +1852,23 @@ struct poll_socket_reply
|
|||
|
||||
|
||||
|
||||
struct send_socket_request
|
||||
{
|
||||
struct request_header __header;
|
||||
char __pad_12[4];
|
||||
async_data_t async;
|
||||
unsigned int status;
|
||||
unsigned int total;
|
||||
};
|
||||
struct send_socket_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
obj_handle_t wait;
|
||||
unsigned int options;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct get_next_console_request_request
|
||||
{
|
||||
struct request_header __header;
|
||||
|
@ -5503,6 +5520,7 @@ enum request
|
|||
REQ_set_socket_deferred,
|
||||
REQ_recv_socket,
|
||||
REQ_poll_socket,
|
||||
REQ_send_socket,
|
||||
REQ_get_next_console_request,
|
||||
REQ_read_directory_changes,
|
||||
REQ_read_change,
|
||||
|
@ -5786,6 +5804,7 @@ union generic_request
|
|||
struct set_socket_deferred_request set_socket_deferred_request;
|
||||
struct recv_socket_request recv_socket_request;
|
||||
struct poll_socket_request poll_socket_request;
|
||||
struct send_socket_request send_socket_request;
|
||||
struct get_next_console_request_request get_next_console_request_request;
|
||||
struct read_directory_changes_request read_directory_changes_request;
|
||||
struct read_change_request read_change_request;
|
||||
|
@ -6067,6 +6086,7 @@ union generic_reply
|
|||
struct set_socket_deferred_reply set_socket_deferred_reply;
|
||||
struct recv_socket_reply recv_socket_reply;
|
||||
struct poll_socket_reply poll_socket_reply;
|
||||
struct send_socket_reply send_socket_reply;
|
||||
struct get_next_console_request_reply get_next_console_request_reply;
|
||||
struct read_directory_changes_reply read_directory_changes_reply;
|
||||
struct read_change_reply read_change_reply;
|
||||
|
@ -6287,7 +6307,7 @@ union generic_reply
|
|||
|
||||
/* ### protocol_version begin ### */
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 707
|
||||
#define SERVER_PROTOCOL_VERSION 708
|
||||
|
||||
/* ### protocol_version end ### */
|
||||
|
||||
|
|
|
@ -1502,6 +1502,17 @@ struct poll_socket_output
|
|||
@END
|
||||
|
||||
|
||||
/* Perform a send on a socket */
|
||||
@REQ(send_socket)
|
||||
async_data_t async; /* async I/O parameters */
|
||||
unsigned int status; /* status of initial call */
|
||||
unsigned int total; /* number of bytes already sent */
|
||||
@REPLY
|
||||
obj_handle_t wait; /* handle to wait on for blocking send */
|
||||
unsigned int options; /* device open options */
|
||||
@END
|
||||
|
||||
|
||||
/* Retrieve the next pending console ioctl request */
|
||||
@REQ(get_next_console_request)
|
||||
obj_handle_t handle; /* console server handle */
|
||||
|
|
|
@ -179,6 +179,7 @@ DECL_HANDLER(enable_socket_event);
|
|||
DECL_HANDLER(set_socket_deferred);
|
||||
DECL_HANDLER(recv_socket);
|
||||
DECL_HANDLER(poll_socket);
|
||||
DECL_HANDLER(send_socket);
|
||||
DECL_HANDLER(get_next_console_request);
|
||||
DECL_HANDLER(read_directory_changes);
|
||||
DECL_HANDLER(read_change);
|
||||
|
@ -461,6 +462,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_set_socket_deferred,
|
||||
(req_handler)req_recv_socket,
|
||||
(req_handler)req_poll_socket,
|
||||
(req_handler)req_send_socket,
|
||||
(req_handler)req_get_next_console_request,
|
||||
(req_handler)req_read_directory_changes,
|
||||
(req_handler)req_read_change,
|
||||
|
@ -1082,6 +1084,13 @@ C_ASSERT( sizeof(struct poll_socket_request) == 64 );
|
|||
C_ASSERT( FIELD_OFFSET(struct poll_socket_reply, wait) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct poll_socket_reply, options) == 12 );
|
||||
C_ASSERT( sizeof(struct poll_socket_reply) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct send_socket_request, async) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct send_socket_request, status) == 56 );
|
||||
C_ASSERT( FIELD_OFFSET(struct send_socket_request, total) == 60 );
|
||||
C_ASSERT( sizeof(struct send_socket_request) == 64 );
|
||||
C_ASSERT( FIELD_OFFSET(struct send_socket_reply, wait) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct send_socket_reply, options) == 12 );
|
||||
C_ASSERT( sizeof(struct send_socket_reply) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, handle) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, signal) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, read) == 20 );
|
||||
|
|
|
@ -768,14 +768,11 @@ static int sock_dispatch_asyncs( struct sock *sock, int event, int error )
|
|||
event &= ~(POLLIN | POLLPRI);
|
||||
}
|
||||
|
||||
if (is_fd_overlapped( sock->fd ))
|
||||
if (event & POLLOUT && async_waiting( &sock->write_q ))
|
||||
{
|
||||
if (event & POLLOUT && async_waiting( &sock->write_q ))
|
||||
{
|
||||
if (debug_level) fprintf( stderr, "activating write queue for socket %p\n", sock );
|
||||
async_wake_up( &sock->write_q, STATUS_ALERTED );
|
||||
event &= ~POLLOUT;
|
||||
}
|
||||
if (debug_level) fprintf( stderr, "activating write queue for socket %p\n", sock );
|
||||
async_wake_up( &sock->write_q, STATUS_ALERTED );
|
||||
event &= ~POLLOUT;
|
||||
}
|
||||
|
||||
if (event & (POLLERR | POLLHUP))
|
||||
|
@ -2508,3 +2505,84 @@ DECL_HANDLER(poll_socket)
|
|||
|
||||
release_object( sock );
|
||||
}
|
||||
|
||||
DECL_HANDLER(send_socket)
|
||||
{
|
||||
struct sock *sock = (struct sock *)get_handle_obj( current->process, req->async.handle, 0, &sock_ops );
|
||||
unsigned int status = req->status;
|
||||
timeout_t timeout = 0;
|
||||
struct async *async;
|
||||
struct fd *fd;
|
||||
|
||||
if (!sock) return;
|
||||
fd = sock->fd;
|
||||
|
||||
if (status != STATUS_SUCCESS)
|
||||
{
|
||||
/* send() calls only clear and reselect events if unsuccessful. */
|
||||
sock->pending_events &= ~FD_WRITE;
|
||||
sock->reported_events &= ~FD_WRITE;
|
||||
}
|
||||
|
||||
/* If we had a short write and the socket is nonblocking (and the client is
|
||||
* not trying to force the operation to be asynchronous), return success.
|
||||
* Windows actually refuses to send any data in this case, and returns
|
||||
* EWOULDBLOCK, but we have no way of doing that. */
|
||||
if (status == STATUS_DEVICE_NOT_READY && req->total && (sock->state & FD_WINE_NONBLOCKING))
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
/* send() returned EWOULDBLOCK or a short write, i.e. cannot send all data yet */
|
||||
if (status == STATUS_DEVICE_NOT_READY && !(sock->state & FD_WINE_NONBLOCKING))
|
||||
{
|
||||
#ifdef SO_SNDTIMEO
|
||||
struct timeval tv;
|
||||
socklen_t len = sizeof(tv);
|
||||
|
||||
/* Set a timeout on the async if necessary.
|
||||
*
|
||||
* We want to do this *only* if the client gave us STATUS_DEVICE_NOT_READY.
|
||||
* If the client gave us STATUS_PENDING, it expects the async to always
|
||||
* block (it was triggered by WSASend*() with a valid OVERLAPPED
|
||||
* structure) and for the timeout not to be respected. */
|
||||
if (is_fd_overlapped( fd ) && !getsockopt( get_unix_fd( fd ), SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, &len ))
|
||||
timeout = tv.tv_sec * -10000000 + tv.tv_usec * -10;
|
||||
#endif
|
||||
|
||||
status = STATUS_PENDING;
|
||||
}
|
||||
|
||||
/* are we shut down? */
|
||||
if (status == STATUS_PENDING && !(sock->state & FD_WRITE)) status = STATUS_PIPE_DISCONNECTED;
|
||||
|
||||
if ((async = create_request_async( fd, get_fd_comp_flags( fd ), &req->async )))
|
||||
{
|
||||
int success = 0;
|
||||
|
||||
if (status == STATUS_SUCCESS)
|
||||
{
|
||||
struct iosb *iosb = async_get_iosb( async );
|
||||
iosb->result = req->total;
|
||||
release_object( iosb );
|
||||
success = 1;
|
||||
}
|
||||
else if (status == STATUS_PENDING)
|
||||
{
|
||||
success = 1;
|
||||
}
|
||||
set_error( status );
|
||||
|
||||
if (timeout)
|
||||
async_set_timeout( async, timeout, STATUS_IO_TIMEOUT );
|
||||
|
||||
if (status == STATUS_PENDING)
|
||||
queue_async( &sock->write_q, async );
|
||||
|
||||
/* always reselect; we changed reported_events above */
|
||||
sock_reselect( sock );
|
||||
|
||||
reply->wait = async_handoff( async, success, NULL, 0 );
|
||||
reply->options = get_fd_options( fd );
|
||||
release_object( async );
|
||||
}
|
||||
release_object( sock );
|
||||
}
|
||||
|
|
|
@ -2150,6 +2150,19 @@ static void dump_poll_socket_reply( const struct poll_socket_reply *req )
|
|||
dump_varargs_poll_socket_output( ", sockets=", cur_size );
|
||||
}
|
||||
|
||||
static void dump_send_socket_request( const struct send_socket_request *req )
|
||||
{
|
||||
dump_async_data( " async=", &req->async );
|
||||
fprintf( stderr, ", status=%08x", req->status );
|
||||
fprintf( stderr, ", total=%08x", req->total );
|
||||
}
|
||||
|
||||
static void dump_send_socket_reply( const struct send_socket_reply *req )
|
||||
{
|
||||
fprintf( stderr, " wait=%04x", req->wait );
|
||||
fprintf( stderr, ", options=%08x", req->options );
|
||||
}
|
||||
|
||||
static void dump_get_next_console_request_request( const struct get_next_console_request_request *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%04x", req->handle );
|
||||
|
@ -4599,6 +4612,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_set_socket_deferred_request,
|
||||
(dump_func)dump_recv_socket_request,
|
||||
(dump_func)dump_poll_socket_request,
|
||||
(dump_func)dump_send_socket_request,
|
||||
(dump_func)dump_get_next_console_request_request,
|
||||
(dump_func)dump_read_directory_changes_request,
|
||||
(dump_func)dump_read_change_request,
|
||||
|
@ -4878,6 +4892,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
NULL,
|
||||
(dump_func)dump_recv_socket_reply,
|
||||
(dump_func)dump_poll_socket_reply,
|
||||
(dump_func)dump_send_socket_reply,
|
||||
(dump_func)dump_get_next_console_request_reply,
|
||||
NULL,
|
||||
(dump_func)dump_read_change_reply,
|
||||
|
@ -5157,6 +5172,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"set_socket_deferred",
|
||||
"recv_socket",
|
||||
"poll_socket",
|
||||
"send_socket",
|
||||
"get_next_console_request",
|
||||
"read_directory_changes",
|
||||
"read_change",
|
||||
|
|
Loading…
Reference in New Issue