ntdll: Implement IOCTL_AFD_RECV.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50366 Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5d3fde087a
commit
b8f4061df0
dlls/ntdll
include/wine
server
|
@ -57,6 +57,7 @@ C_SRCS = \
|
|||
unix/signal_arm64.c \
|
||||
unix/signal_i386.c \
|
||||
unix/signal_x86_64.c \
|
||||
unix/socket.c \
|
||||
unix/sync.c \
|
||||
unix/system.c \
|
||||
unix/tape.c \
|
||||
|
|
|
@ -4645,7 +4645,7 @@ struct async_irp
|
|||
|
||||
static struct async_fileio *fileio_freelist;
|
||||
|
||||
static void release_fileio( struct async_fileio *io )
|
||||
void release_fileio( struct async_fileio *io )
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
|
@ -4655,7 +4655,7 @@ static void release_fileio( struct async_fileio *io )
|
|||
}
|
||||
}
|
||||
|
||||
static struct async_fileio *alloc_fileio( DWORD size, async_callback_t callback, HANDLE handle )
|
||||
struct async_fileio *alloc_fileio( DWORD size, async_callback_t callback, HANDLE handle )
|
||||
{
|
||||
/* first free remaining previous fileinfos */
|
||||
struct async_fileio *io = InterlockedExchangePointer( (void **)&fileio_freelist, NULL );
|
||||
|
@ -5729,6 +5729,9 @@ NTSTATUS WINAPI NtDeviceIoControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUT
|
|||
|
||||
switch (device)
|
||||
{
|
||||
case FILE_DEVICE_BEEP:
|
||||
status = sock_ioctl( handle, event, apc, apc_context, io, code, in_buffer, in_size, out_buffer, out_size );
|
||||
break;
|
||||
case FILE_DEVICE_DISK:
|
||||
case FILE_DEVICE_CD_ROM:
|
||||
case FILE_DEVICE_DVD:
|
||||
|
|
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
* Windows sockets
|
||||
*
|
||||
* Copyright 2021 Zebediah Figura for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#pragma makedep unix
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winioctl.h"
|
||||
#define USE_WS_PREFIX
|
||||
#include "winsock2.h"
|
||||
#include "wine/afd.h"
|
||||
|
||||
#include "unix_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
|
||||
|
||||
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 )
|
||||
{
|
||||
async_data_t async;
|
||||
async.handle = wine_server_obj_handle( handle );
|
||||
async.user = wine_server_client_ptr( user );
|
||||
async.iosb = wine_server_client_ptr( io );
|
||||
async.event = wine_server_obj_handle( event );
|
||||
async.apc = wine_server_client_ptr( apc );
|
||||
async.apc_context = wine_server_client_ptr( apc_context );
|
||||
return async;
|
||||
}
|
||||
|
||||
static NTSTATUS wait_async( HANDLE handle, BOOL alertable )
|
||||
{
|
||||
return NtWaitForSingleObject( handle, alertable, NULL );
|
||||
}
|
||||
|
||||
struct async_recv_ioctl
|
||||
{
|
||||
struct async_fileio io;
|
||||
int unix_flags;
|
||||
unsigned int count;
|
||||
struct iovec iov[1];
|
||||
};
|
||||
|
||||
static NTSTATUS sock_errno_to_status( 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 EHOSTUNREACH: return STATUS_HOST_UNREACHABLE;
|
||||
case ENETDOWN: return STATUS_NETWORK_BUSY;
|
||||
case EPIPE:
|
||||
case ECONNRESET: return STATUS_CONNECTION_RESET;
|
||||
case ECONNABORTED: return STATUS_CONNECTION_ABORTED;
|
||||
case EISCONN: return STATUS_CONNECTION_ACTIVE;
|
||||
|
||||
case 0: return STATUS_SUCCESS;
|
||||
default:
|
||||
FIXME( "unknown errno %d\n", err );
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
|
||||
extern ssize_t CDECL __wine_locked_recvmsg( int fd, struct msghdr *hdr, int flags );
|
||||
|
||||
static NTSTATUS try_recv( int fd, struct async_recv_ioctl *async, ULONG_PTR *size )
|
||||
{
|
||||
#ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
|
||||
char control_buffer[512];
|
||||
#endif
|
||||
struct msghdr hdr;
|
||||
ssize_t ret;
|
||||
|
||||
memset( &hdr, 0, sizeof(hdr) );
|
||||
hdr.msg_iov = async->iov;
|
||||
hdr.msg_iovlen = async->count;
|
||||
#ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
|
||||
hdr.msg_control = control_buffer;
|
||||
hdr.msg_controllen = sizeof(control_buffer);
|
||||
#endif
|
||||
while ((ret = __wine_locked_recvmsg( fd, &hdr, async->unix_flags )) < 0 && errno == EINTR);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Unix-like systems return EINVAL when attempting to read OOB data from
|
||||
* an empty socket buffer; Windows returns WSAEWOULDBLOCK. */
|
||||
if ((async->unix_flags & MSG_OOB) && errno == EINVAL)
|
||||
errno = EWOULDBLOCK;
|
||||
|
||||
if (errno != EWOULDBLOCK) WARN( "recvmsg: %s\n", strerror( errno ) );
|
||||
return sock_errno_to_status( errno );
|
||||
}
|
||||
|
||||
*size = ret;
|
||||
return (hdr.msg_flags & MSG_TRUNC) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS async_recv_proc( void *user, IO_STATUS_BLOCK *io, NTSTATUS status )
|
||||
{
|
||||
struct async_recv_ioctl *async = user;
|
||||
ULONG_PTR information = 0;
|
||||
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_recv( fd, async, &information );
|
||||
TRACE( "got status %#x, %#lx bytes read\n", status, information );
|
||||
|
||||
if (status == STATUS_DEVICE_NOT_READY)
|
||||
status = STATUS_PENDING;
|
||||
|
||||
if (needs_close) close( fd );
|
||||
}
|
||||
if (status != STATUS_PENDING)
|
||||
{
|
||||
io->Status = status;
|
||||
io->Information = information;
|
||||
release_fileio( &async->io );
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io,
|
||||
int fd, const WSABUF *buffers, unsigned int count, int unix_flags, int force_async )
|
||||
{
|
||||
struct async_recv_ioctl *async;
|
||||
ULONG_PTR information;
|
||||
HANDLE wait_handle;
|
||||
DWORD async_size;
|
||||
NTSTATUS status;
|
||||
unsigned int i;
|
||||
ULONG options;
|
||||
|
||||
async_size = offsetof( struct async_recv_ioctl, iov[count] );
|
||||
|
||||
if (!(async = (struct async_recv_ioctl *)alloc_fileio( async_size, async_recv_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;
|
||||
|
||||
status = try_recv( fd, async, &information );
|
||||
|
||||
if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW && 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 = information;
|
||||
}
|
||||
|
||||
SERVER_START_REQ( recv_socket )
|
||||
{
|
||||
req->status = status;
|
||||
req->total = information;
|
||||
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 )
|
||||
{
|
||||
int fd, needs_close;
|
||||
NTSTATUS status;
|
||||
|
||||
TRACE( "handle %p, code %#x, in_buffer %p, in_size %u, out_buffer %p, out_size %u\n",
|
||||
handle, code, in_buffer, in_size, out_buffer, out_size );
|
||||
|
||||
if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
|
||||
return status;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case IOCTL_AFD_LISTEN:
|
||||
{
|
||||
const struct afd_listen_params *params = in_buffer;
|
||||
|
||||
TRACE( "backlog %u\n", params->backlog );
|
||||
if (out_size) FIXME( "unexpected output size %u\n", out_size );
|
||||
if (params->unknown1) FIXME( "listen: got unknown1 %#x\n", params->unknown1 );
|
||||
if (params->unknown2) FIXME( "listen: got unknown2 %#x\n", params->unknown2 );
|
||||
|
||||
status = STATUS_BAD_DEVICE_TYPE;
|
||||
break;
|
||||
}
|
||||
|
||||
case IOCTL_AFD_RECV:
|
||||
{
|
||||
const struct afd_recv_params *params = in_buffer;
|
||||
int unix_flags = 0;
|
||||
|
||||
if (out_size) FIXME( "unexpected output size %u\n", out_size );
|
||||
|
||||
if (in_size < sizeof(struct afd_recv_params))
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((params->msg_flags & (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) == 0 ||
|
||||
(params->msg_flags & (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) == (AFD_MSG_NOT_OOB | AFD_MSG_OOB))
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
if (params->msg_flags & ~(AFD_MSG_NOT_OOB | AFD_MSG_OOB | AFD_MSG_PEEK | AFD_MSG_WAITALL))
|
||||
FIXME( "unknown msg_flags %#x\n", params->msg_flags );
|
||||
if (params->recv_flags & ~AFD_RECV_FORCE_ASYNC)
|
||||
FIXME( "unknown recv_flags %#x\n", params->recv_flags );
|
||||
|
||||
if (params->msg_flags & AFD_MSG_OOB)
|
||||
unix_flags |= MSG_OOB;
|
||||
if (params->msg_flags & AFD_MSG_PEEK)
|
||||
unix_flags |= MSG_PEEK;
|
||||
if (params->msg_flags & AFD_MSG_WAITALL)
|
||||
FIXME( "MSG_WAITALL is not supported\n" );
|
||||
|
||||
status = sock_recv( handle, event, apc, apc_user, io, fd, params->buffers, params->count,
|
||||
unix_flags, !!(params->recv_flags & AFD_RECV_FORCE_ASYNC) );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
FIXME( "Unknown ioctl %#x (device %#x, access %#x, function %#x, method %#x)\n",
|
||||
code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3 );
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_close) close( fd );
|
||||
return status;
|
||||
}
|
|
@ -257,10 +257,14 @@ extern NTSTATUS serial_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROU
|
|||
IO_STATUS_BLOCK *io, ULONG code, void *in_buffer,
|
||||
ULONG in_size, void *out_buffer, ULONG out_size ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS serial_FlushBuffersFile( int fd ) DECLSPEC_HIDDEN;
|
||||
extern 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 ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS tape_DeviceIoControl( HANDLE device, 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 ) DECLSPEC_HIDDEN;
|
||||
|
||||
extern struct async_fileio *alloc_fileio( DWORD size, async_callback_t callback, HANDLE handle ) DECLSPEC_HIDDEN;
|
||||
extern void release_fileio( struct async_fileio *io ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS errno_to_status( int err ) DECLSPEC_HIDDEN;
|
||||
extern BOOL get_redirect( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *redir ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition ) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -21,10 +21,12 @@
|
|||
#ifndef __WINE_WINE_AFD_H
|
||||
#define __WINE_WINE_AFD_H
|
||||
|
||||
#include <winternl.h>
|
||||
#include <winioctl.h>
|
||||
#include "wine/server_protocol.h"
|
||||
|
||||
#define IOCTL_AFD_LISTEN CTL_CODE(FILE_DEVICE_BEEP, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||
#define IOCTL_AFD_RECV CTL_CODE(FILE_DEVICE_BEEP, 0x805, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||
|
||||
struct afd_listen_params
|
||||
{
|
||||
|
@ -33,6 +35,21 @@ struct afd_listen_params
|
|||
int unknown2;
|
||||
};
|
||||
|
||||
#define AFD_RECV_FORCE_ASYNC 0x2
|
||||
|
||||
#define AFD_MSG_NOT_OOB 0x0020
|
||||
#define AFD_MSG_OOB 0x0040
|
||||
#define AFD_MSG_PEEK 0x0080
|
||||
#define AFD_MSG_WAITALL 0x4000
|
||||
|
||||
struct afd_recv_params
|
||||
{
|
||||
const WSABUF *buffers;
|
||||
unsigned int count;
|
||||
int recv_flags;
|
||||
int msg_flags;
|
||||
};
|
||||
|
||||
#define IOCTL_AFD_WINE_CREATE CTL_CODE(FILE_DEVICE_NETWORK, 200, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_AFD_WINE_ACCEPT CTL_CODE(FILE_DEVICE_NETWORK, 201, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_AFD_WINE_ACCEPT_INTO CTL_CODE(FILE_DEVICE_NETWORK, 202, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
|
|
@ -1818,6 +1818,23 @@ struct set_socket_deferred_reply
|
|||
|
||||
|
||||
|
||||
struct recv_socket_request
|
||||
{
|
||||
struct request_header __header;
|
||||
char __pad_12[4];
|
||||
async_data_t async;
|
||||
unsigned int status;
|
||||
unsigned int total;
|
||||
};
|
||||
struct recv_socket_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
obj_handle_t wait;
|
||||
unsigned int options;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct get_next_console_request_request
|
||||
{
|
||||
struct request_header __header;
|
||||
|
@ -5467,6 +5484,7 @@ enum request
|
|||
REQ_get_socket_info,
|
||||
REQ_enable_socket_event,
|
||||
REQ_set_socket_deferred,
|
||||
REQ_recv_socket,
|
||||
REQ_get_next_console_request,
|
||||
REQ_read_directory_changes,
|
||||
REQ_read_change,
|
||||
|
@ -5748,6 +5766,7 @@ union generic_request
|
|||
struct get_socket_info_request get_socket_info_request;
|
||||
struct enable_socket_event_request enable_socket_event_request;
|
||||
struct set_socket_deferred_request set_socket_deferred_request;
|
||||
struct recv_socket_request recv_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;
|
||||
|
@ -6027,6 +6046,7 @@ union generic_reply
|
|||
struct get_socket_info_reply get_socket_info_reply;
|
||||
struct enable_socket_event_reply enable_socket_event_reply;
|
||||
struct set_socket_deferred_reply set_socket_deferred_reply;
|
||||
struct recv_socket_reply recv_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;
|
||||
|
@ -6247,7 +6267,7 @@ union generic_reply
|
|||
|
||||
/* ### protocol_version begin ### */
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 702
|
||||
#define SERVER_PROTOCOL_VERSION 703
|
||||
|
||||
/* ### protocol_version end ### */
|
||||
|
||||
|
|
|
@ -2076,6 +2076,12 @@ unsigned int get_fd_options( struct fd *fd )
|
|||
return fd->options;
|
||||
}
|
||||
|
||||
/* retrieve the completion flags for the fd */
|
||||
unsigned int get_fd_comp_flags( struct fd *fd )
|
||||
{
|
||||
return fd->comp_flags;
|
||||
}
|
||||
|
||||
/* check if fd is in overlapped mode */
|
||||
int is_fd_overlapped( struct fd *fd )
|
||||
{
|
||||
|
|
|
@ -89,6 +89,7 @@ extern struct fd *get_fd_object_for_mapping( struct fd *fd, unsigned int access,
|
|||
extern void *get_fd_user( struct fd *fd );
|
||||
extern void set_fd_user( struct fd *fd, const struct fd_ops *ops, struct object *user );
|
||||
extern unsigned int get_fd_options( struct fd *fd );
|
||||
extern unsigned int get_fd_comp_flags( struct fd *fd );
|
||||
extern int is_fd_overlapped( struct fd *fd );
|
||||
extern int get_unix_fd( struct fd *fd );
|
||||
extern int is_same_file_fd( struct fd *fd1, struct fd *fd2 );
|
||||
|
|
|
@ -1479,6 +1479,17 @@ enum server_fd_type
|
|||
@END
|
||||
|
||||
|
||||
/* Perform a recv on a socket */
|
||||
@REQ(recv_socket)
|
||||
async_data_t async; /* async I/O parameters */
|
||||
unsigned int status; /* status of initial call */
|
||||
unsigned int total; /* number of bytes already read */
|
||||
@REPLY
|
||||
obj_handle_t wait; /* handle to wait on for blocking recv */
|
||||
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 */
|
||||
|
|
|
@ -177,6 +177,7 @@ DECL_HANDLER(get_socket_event);
|
|||
DECL_HANDLER(get_socket_info);
|
||||
DECL_HANDLER(enable_socket_event);
|
||||
DECL_HANDLER(set_socket_deferred);
|
||||
DECL_HANDLER(recv_socket);
|
||||
DECL_HANDLER(get_next_console_request);
|
||||
DECL_HANDLER(read_directory_changes);
|
||||
DECL_HANDLER(read_change);
|
||||
|
@ -457,6 +458,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_get_socket_info,
|
||||
(req_handler)req_enable_socket_event,
|
||||
(req_handler)req_set_socket_deferred,
|
||||
(req_handler)req_recv_socket,
|
||||
(req_handler)req_get_next_console_request,
|
||||
(req_handler)req_read_directory_changes,
|
||||
(req_handler)req_read_change,
|
||||
|
@ -1064,6 +1066,13 @@ C_ASSERT( sizeof(struct enable_socket_event_request) == 32 );
|
|||
C_ASSERT( FIELD_OFFSET(struct set_socket_deferred_request, handle) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct set_socket_deferred_request, deferred) == 16 );
|
||||
C_ASSERT( sizeof(struct set_socket_deferred_request) == 24 );
|
||||
C_ASSERT( FIELD_OFFSET(struct recv_socket_request, async) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct recv_socket_request, status) == 56 );
|
||||
C_ASSERT( FIELD_OFFSET(struct recv_socket_request, total) == 60 );
|
||||
C_ASSERT( sizeof(struct recv_socket_request) == 64 );
|
||||
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, wait) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, options) == 12 );
|
||||
C_ASSERT( sizeof(struct recv_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 );
|
||||
|
|
|
@ -653,14 +653,15 @@ static int sock_dispatch_asyncs( struct sock *sock, int event, int error )
|
|||
async_terminate( sock->connect_req->async, get_error() );
|
||||
}
|
||||
|
||||
if (event & (POLLIN | POLLPRI) && async_waiting( &sock->read_q ))
|
||||
{
|
||||
if (debug_level) fprintf( stderr, "activating read queue for socket %p\n", sock );
|
||||
async_wake_up( &sock->read_q, STATUS_ALERTED );
|
||||
event &= ~(POLLIN | POLLPRI);
|
||||
}
|
||||
|
||||
if (is_fd_overlapped( sock->fd ))
|
||||
{
|
||||
if (event & (POLLIN|POLLPRI) && async_waiting( &sock->read_q ))
|
||||
{
|
||||
if (debug_level) fprintf( stderr, "activating read queue for socket %p\n", sock );
|
||||
async_wake_up( &sock->read_q, STATUS_ALERTED );
|
||||
event &= ~(POLLIN|POLLPRI);
|
||||
}
|
||||
if (event & POLLOUT && async_waiting( &sock->write_q ))
|
||||
{
|
||||
if (debug_level) fprintf( stderr, "activating write queue for socket %p\n", sock );
|
||||
|
@ -2129,3 +2130,73 @@ DECL_HANDLER(get_socket_info)
|
|||
|
||||
release_object( &sock->obj );
|
||||
}
|
||||
|
||||
DECL_HANDLER(recv_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;
|
||||
|
||||
/* recv() returned EWOULDBLOCK, i.e. no data available yet */
|
||||
if (status == STATUS_DEVICE_NOT_READY && !(sock->state & FD_WINE_NONBLOCKING))
|
||||
{
|
||||
#ifdef SO_RCVTIMEO
|
||||
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 WSARecv*() 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_RCVTIMEO, (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_READ)) status = STATUS_PIPE_DISCONNECTED;
|
||||
|
||||
sock->pending_events &= ~FD_READ;
|
||||
sock->reported_events &= ~FD_READ;
|
||||
|
||||
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->read_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 );
|
||||
}
|
||||
|
|
|
@ -2094,6 +2094,19 @@ static void dump_set_socket_deferred_request( const struct set_socket_deferred_r
|
|||
fprintf( stderr, ", deferred=%04x", req->deferred );
|
||||
}
|
||||
|
||||
static void dump_recv_socket_request( const struct recv_socket_request *req )
|
||||
{
|
||||
dump_async_data( " async=", &req->async );
|
||||
fprintf( stderr, ", status=%08x", req->status );
|
||||
fprintf( stderr, ", total=%08x", req->total );
|
||||
}
|
||||
|
||||
static void dump_recv_socket_reply( const struct recv_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 );
|
||||
|
@ -4540,6 +4553,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_get_socket_info_request,
|
||||
(dump_func)dump_enable_socket_event_request,
|
||||
(dump_func)dump_set_socket_deferred_request,
|
||||
(dump_func)dump_recv_socket_request,
|
||||
(dump_func)dump_get_next_console_request_request,
|
||||
(dump_func)dump_read_directory_changes_request,
|
||||
(dump_func)dump_read_change_request,
|
||||
|
@ -4817,6 +4831,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_get_socket_info_reply,
|
||||
NULL,
|
||||
NULL,
|
||||
(dump_func)dump_recv_socket_reply,
|
||||
(dump_func)dump_get_next_console_request_reply,
|
||||
NULL,
|
||||
(dump_func)dump_read_change_reply,
|
||||
|
@ -5094,6 +5109,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"get_socket_info",
|
||||
"enable_socket_event",
|
||||
"set_socket_deferred",
|
||||
"recv_socket",
|
||||
"get_next_console_request",
|
||||
"read_directory_changes",
|
||||
"read_change",
|
||||
|
|
Loading…
Reference in New Issue