[PATCH 2/5] ws2_32: Use IOCTL_AFD_WINE_TRANSMIT.
Zebediah Figura
z.figura12 at gmail.com
Thu May 27 18:57:30 CDT 2021
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/ws2_32/socket.c | 559 +++----------------------------------------
1 file changed, 36 insertions(+), 523 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index ff2db136f89..24ac24dcdeb 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -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
*/
--
2.30.2
More information about the wine-devel
mailing list