Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntdll/unix/socket.c | 212 +++++++++++++++++++++++++++++++++++++++ include/wine/afd.h | 12 +++ 2 files changed, 224 insertions(+)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 3d4b98e5871..6112a1260cb 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -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; diff --git a/include/wine/afd.h b/include/wine/afd.h index f003263bfc8..8199e0e2dbe 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -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
Signed-off-by: Zebediah Figura z.figura12@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 */
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=91369
Your paranoid android.
=== debiant2 (32 bit report) ===
ws2_32: sock.c:7569: Test succeeded inside todo block: GetQueuedCompletionStatus returned 0 sock.c:7570: Test succeeded inside todo block: Last error was 64
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/tests/sock.c | 379 +++++++++++++++++++++++++++------------ 1 file changed, 260 insertions(+), 119 deletions(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index f6304c0f5ce..b84ebe88c6a 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -3624,54 +3624,273 @@ static void test_getsockname(void) WSACleanup(); }
+static DWORD apc_error, apc_size; +static OVERLAPPED *apc_overlapped; +static unsigned int apc_count; + +static void WINAPI socket_apc(DWORD error, DWORD size, OVERLAPPED *overlapped, DWORD flags) +{ + ok(!flags, "got flags %#x\n", flags); + ++apc_count; + apc_error = error; + apc_size = size; + apc_overlapped = overlapped; +} + +#define check_fionread_siocatmark(a, b, c) check_fionread_siocatmark_(__LINE__, a, b, c, FALSE, FALSE) +#define check_fionread_siocatmark_todo(a, b, c) check_fionread_siocatmark_(__LINE__, a, b, c, TRUE, TRUE) +#define check_fionread_siocatmark_todo_oob(a, b, c) check_fionread_siocatmark_(__LINE__, a, b, c, FALSE, TRUE) +static void check_fionread_siocatmark_(int line, SOCKET s, unsigned int normal, unsigned int oob, + BOOL todo_normal, BOOL todo_oob) +{ + int ret, value; + DWORD size; + + value = 0xdeadbeef; + WSASetLastError(0xdeadbeef); + ret = WSAIoctl(s, FIONREAD, NULL, 0, &value, sizeof(value), &size, NULL, NULL); + ok_(__FILE__, line)(!ret, "expected success\n"); + todo_wine ok_(__FILE__, line)(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + todo_wine_if (todo_normal) ok_(__FILE__, line)(value == normal, "FIONBIO returned %u\n", value); + + value = 0xdeadbeef; + WSASetLastError(0xdeadbeef); + ret = WSAIoctl(s, SIOCATMARK, NULL, 0, &value, sizeof(value), &size, NULL, NULL); + ok_(__FILE__, line)(!ret, "expected success\n"); + todo_wine ok_(__FILE__, line)(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + todo_wine_if (todo_oob) ok_(__FILE__, line)(value == oob, "SIOCATMARK returned %u\n", value); +} + +static void test_fionread_siocatmark(void) +{ + const struct sockaddr_in bind_addr = {.sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK)}; + OVERLAPPED overlapped = {0}, *overlapped_ptr; + SOCKET client, server; + char buffer[5]; + int ret, value; + ULONG_PTR key; + HANDLE port; + DWORD size; + + tcp_socketpair(&client, &server); + set_blocking(client, FALSE); + overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + + WSASetLastError(0xdeadbeef); + ret = ioctlsocket(client, FIONREAD, (u_long *)1); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + WSASetLastError(0xdeadbeef); + ret = ioctlsocket(client, SIOCATMARK, (u_long *)1); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + WSASetLastError(0xdeadbeef); + ret = WSAIoctl(client, FIONREAD, NULL, 0, &value, sizeof(value), NULL, NULL, NULL); + todo_wine ok(ret == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + ret = WSAIoctl(client, FIONREAD, NULL, 0, &value, sizeof(value) - 1, &size, NULL, NULL); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + ok(size == 0xdeadbeef, "got size %u\n", size); + + WSASetLastError(0xdeadbeef); + ret = WSAIoctl(client, SIOCATMARK, NULL, 0, &value, sizeof(value), NULL, NULL, NULL); + todo_wine ok(ret == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + ret = WSAIoctl(client, SIOCATMARK, NULL, 0, &value, sizeof(value) - 1, &size, NULL, NULL); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + ok(size == 0xdeadbeef, "got size %u\n", size); + + check_fionread_siocatmark(client, 0, TRUE); + + port = CreateIoCompletionPort((HANDLE)client, NULL, 123, 0); + + ret = WSAIoctl(client, FIONREAD, NULL, 0, &value, sizeof(value), NULL, &overlapped, NULL); + todo_wine ok(ret == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + ret = WSAIoctl(client, SIOCATMARK, NULL, 0, &value, sizeof(value), NULL, &overlapped, NULL); + todo_wine ok(ret == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + value = 0xdeadbeef; + overlapped.Internal = 0xdeadbeef; + overlapped.InternalHigh = 0xdeadbeef; + ret = WSAIoctl(client, FIONREAD, NULL, 0, &value, sizeof(value), &size, &overlapped, NULL); + ok(!ret, "expected success\n"); + todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + ok(!value, "got %u\n", value); + todo_wine ok(size == sizeof(value), "got size %u\n", size); + ok(!overlapped.Internal, "got status %#x\n", (NTSTATUS)overlapped.Internal); + ok(!overlapped.InternalHigh, "got size %Iu\n", overlapped.InternalHigh); + + ret = GetQueuedCompletionStatus(port, &size, &key, &overlapped_ptr, 0); + ok(ret, "got error %u\n", GetLastError()); + ok(!size, "got size %u\n", size); + ok(key == 123, "got key %Iu\n", key); + ok(overlapped_ptr == &overlapped, "got overlapped %p\n", overlapped_ptr); + + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + value = 0xdeadbeef; + overlapped.Internal = 0xdeadbeef; + overlapped.InternalHigh = 0xdeadbeef; + ret = WSAIoctl(client, SIOCATMARK, NULL, 0, &value, sizeof(value), &size, &overlapped, NULL); + ok(!ret, "expected success\n"); + todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + ok(value == TRUE, "got %u\n", value); + todo_wine ok(size == sizeof(value), "got size %u\n", size); + ok(!overlapped.Internal, "got status %#x\n", (NTSTATUS)overlapped.Internal); + ok(!overlapped.InternalHigh, "got size %Iu\n", overlapped.InternalHigh); + + ret = GetQueuedCompletionStatus(port, &size, &key, &overlapped_ptr, 0); + ok(ret, "got error %u\n", GetLastError()); + ok(!size, "got size %u\n", size); + ok(key == 123, "got key %Iu\n", key); + ok(overlapped_ptr == &overlapped, "got overlapped %p\n", overlapped_ptr); + + ret = send(server, "data", 5, 0); + ok(ret == 5, "got %d\n", ret); + + check_fionread_siocatmark(client, 5, TRUE); + + ret = send(server, "a", 1, MSG_OOB); + ok(ret == 1, "got %d\n", ret); + + check_fionread_siocatmark_todo_oob(client, 5, FALSE); + + ret = send(server, "a", 1, MSG_OOB); + ok(ret == 1, "got %d\n", ret); + + check_fionread_siocatmark_todo(client, 5, FALSE); + + ret = recv(client, buffer, 3, 0); + ok(ret == 3, "got %d\n", ret); + + check_fionread_siocatmark_todo(client, 2, FALSE); + + ret = recv(client, buffer, 1, MSG_OOB); + ok(ret == 1, "got %d\n", ret); + + check_fionread_siocatmark_todo(client, 2, FALSE); + + ret = recv(client, buffer, 5, 0); + todo_wine ok(ret == 2, "got %d\n", ret); + + check_fionread_siocatmark(client, 0, FALSE); + + ret = recv(client, buffer, 1, MSG_OOB); + todo_wine ok(ret == 1, "got %d\n", ret); + + check_fionread_siocatmark_todo_oob(client, 0, TRUE); + + ret = send(server, "a", 1, MSG_OOB); + ok(ret == 1, "got %d\n", ret); + + ret = 1; + ret = setsockopt(client, SOL_SOCKET, SO_OOBINLINE, (char *)&ret, sizeof(ret)); + ok(!ret, "got error %u\n", WSAGetLastError()); + + check_fionread_siocatmark_todo_oob(client, 1, FALSE); + + ret = recv(client, buffer, 1, 0); + ok(ret == 1, "got %d\n", ret); + + check_fionread_siocatmark(client, 0, TRUE); + + ret = send(server, "a", 1, MSG_OOB); + ok(ret == 1, "got %d\n", ret); + + check_fionread_siocatmark(client, 1, TRUE); + + closesocket(client); + closesocket(server); + + server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + check_fionread_siocatmark(server, 0, TRUE); + + ret = bind(server, (const struct sockaddr *)&bind_addr, sizeof(bind_addr)); + ok(!ret, "got error %u\n", WSAGetLastError()); + + check_fionread_siocatmark(server, 0, TRUE); + + closesocket(server); + CloseHandle(overlapped.hEvent); + + /* test with APCs */ + + server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + ret = WSAIoctl(server, FIONREAD, NULL, 0, &value, sizeof(value), NULL, &overlapped, socket_apc); + todo_wine ok(ret == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + ret = WSAIoctl(server, SIOCATMARK, NULL, 0, &value, sizeof(value), NULL, &overlapped, socket_apc); + todo_wine ok(ret == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + apc_count = 0; + size = 0xdeadbeef; + ret = WSAIoctl(server, FIONREAD, NULL, 0, &value, sizeof(value), &size, &overlapped, socket_apc); + ok(!ret, "expected success\n"); + todo_wine ok(size == sizeof(value), "got size %u\n", size); + + ret = SleepEx(0, TRUE); + todo_wine ok(ret == WAIT_IO_COMPLETION, "got %d\n", ret); + if (ret == WAIT_IO_COMPLETION) + { + ok(apc_count == 1, "APC was called %u times\n", apc_count); + ok(!apc_error, "got APC error %u\n", apc_error); + ok(!apc_size, "got APC size %u\n", apc_size); + ok(apc_overlapped == &overlapped, "got APC overlapped %p\n", apc_overlapped); + } + + apc_count = 0; + size = 0xdeadbeef; + ret = WSAIoctl(server, SIOCATMARK, NULL, 0, &value, sizeof(value), &size, &overlapped, socket_apc); + ok(!ret, "expected success\n"); + todo_wine ok(size == sizeof(value), "got size %u\n", size); + + ret = SleepEx(0, TRUE); + todo_wine ok(ret == WAIT_IO_COMPLETION, "got %d\n", ret); + if (ret == WAIT_IO_COMPLETION) + { + ok(apc_count == 1, "APC was called %u times\n", apc_count); + ok(!apc_error, "got APC error %u\n", apc_error); + ok(!apc_size, "got APC size %u\n", apc_size); + ok(apc_overlapped == &overlapped, "got APC overlapped %p\n", apc_overlapped); + } + + closesocket(server); +} + static void test_ioctlsocket(void) { - SOCKET sock, src, dst; + SOCKET sock; struct tcp_keepalive kalive; - struct sockaddr_in address; - int ret, optval; - static const LONG cmds[] = {FIONBIO, FIONREAD, SIOCATMARK}; - UINT i, bytes_rec; - char data; - WSABUF bufs; + int ret; u_long arg = 0;
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ok(sock != INVALID_SOCKET, "Creating the socket failed: %d\n", WSAGetLastError());
- for(i = 0; i < ARRAY_SIZE(cmds); i++) - { - /* broken apps like defcon pass the argp value directly instead of a pointer to it */ - ret = ioctlsocket(sock, cmds[i], (u_long *)1); - ok(ret == SOCKET_ERROR, "ioctlsocket succeeded unexpectedly\n"); - ret = WSAGetLastError(); - ok(ret == WSAEFAULT, "expected WSAEFAULT, got %d instead\n", ret); - } - - /* A fresh and not connected socket has no urgent data, this test shows - * that normal(not urgent) data returns a non-zero value for SIOCATMARK. */ - - ret = ioctlsocket(sock, SIOCATMARK, &arg); - ok(ret != SOCKET_ERROR, "ioctlsocket failed unexpectedly\n"); - ok(arg, "SIOCATMARK expected a non-zero value\n"); - - /* when SO_OOBINLINE is set SIOCATMARK must always return TRUE */ - optval = 1; - ret = setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (void *)&optval, sizeof(optval)); - ok(ret != SOCKET_ERROR, "setsockopt failed unexpectedly\n"); - arg = 0; - ret = ioctlsocket(sock, SIOCATMARK, &arg); - ok(ret != SOCKET_ERROR, "ioctlsocket failed unexpectedly\n"); - ok(arg, "SIOCATMARK expected a non-zero value\n"); - - /* disable SO_OOBINLINE and get the same old behavior */ - optval = 0; - ret = setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (void *)&optval, sizeof(optval)); - ok(ret != SOCKET_ERROR, "setsockopt failed unexpectedly\n"); - arg = 0; - ret = ioctlsocket(sock, SIOCATMARK, &arg); - ok(ret != SOCKET_ERROR, "ioctlsocket failed unexpectedly\n"); - ok(arg, "SIOCATMARK expected a non-zero value\n"); + /* broken apps like defcon pass the argp value directly instead of a pointer to it */ + ret = ioctlsocket(sock, FIONBIO, (u_long *)1); + ok(ret == SOCKET_ERROR, "ioctlsocket succeeded unexpectedly\n"); + ret = WSAGetLastError(); + ok(ret == WSAEFAULT, "expected WSAEFAULT, got %d instead\n", ret);
ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &arg, 0, NULL, 0, &arg, NULL, NULL); ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n"); @@ -3706,85 +3925,6 @@ static void test_ioctlsocket(void) ok(ret == 0, "WSAIoctl failed unexpectedly\n");
closesocket(sock); - - sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - ok(sock != INVALID_SOCKET, "Creating the socket failed: %d\n", WSAGetLastError()); - - /* test FIONREAD with a fresh and non-connected socket */ - arg = 0xdeadbeef; - ret = ioctlsocket(sock, FIONREAD, &arg); - ok(ret == 0, "ioctlsocket failed unexpectedly with error %d\n", WSAGetLastError()); - ok(arg == 0, "expected 0, got %u\n", arg); - - memset(&address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = inet_addr( SERVERIP ); - address.sin_port = htons( SERVERPORT ); - ret = bind(sock, (struct sockaddr *)&address, sizeof(address)); - ok(ret == 0, "bind failed unexpectedly with error %d\n", WSAGetLastError()); - - ret = listen(sock, SOMAXCONN); - ok(ret == 0, "listen failed unexpectedly with error %d\n", WSAGetLastError()); - - /* test FIONREAD with listening socket */ - arg = 0xdeadbeef; - ret = ioctlsocket(sock, FIONREAD, &arg); - ok(ret == 0, "ioctlsocket failed unexpectedly with error %d\n", WSAGetLastError()); - ok(arg == 0, "expected 0, got %u\n", arg); - - closesocket(sock); - - tcp_socketpair(&src, &dst); - - /* test FIONREAD on TCP sockets */ - optval = 0xdeadbeef; - ret = WSAIoctl(dst, FIONREAD, NULL, 0, &optval, sizeof(optval), &arg, NULL, NULL); - ok(ret == 0, "WSAIoctl failed unexpectedly with error %d\n", WSAGetLastError()); - ok(optval == 0, "FIONREAD should have returned 0 bytes, got %d instead\n", optval); - - optval = 0xdeadbeef; - ok(send(src, "TEST", 4, 0) == 4, "failed to send test data\n"); - Sleep(100); - ret = WSAIoctl(dst, FIONREAD, NULL, 0, &optval, sizeof(optval), &arg, NULL, NULL); - ok(ret == 0, "WSAIoctl failed unexpectedly with error %d\n", WSAGetLastError()); - ok(optval == 4, "FIONREAD should have returned 4 bytes, got %d instead\n", optval); - - /* trying to read from an OOB inlined socket with MSG_OOB results in WSAEINVAL */ - set_blocking(dst, FALSE); - i = MSG_OOB; - SetLastError(0xdeadbeef); - ret = recv(dst, &data, 1, i); - ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); - ret = GetLastError(); - ok(ret == WSAEWOULDBLOCK, "expected 10035, got %d\n", ret); - bufs.len = sizeof(char); - bufs.buf = &data; - ret = WSARecv(dst, &bufs, 1, &bytes_rec, &i, NULL, NULL); - ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); - ret = GetLastError(); - ok(ret == WSAEWOULDBLOCK, "expected 10035, got %d\n", ret); - optval = 1; - ret = setsockopt(dst, SOL_SOCKET, SO_OOBINLINE, (void *)&optval, sizeof(optval)); - ok(ret != SOCKET_ERROR, "setsockopt failed unexpectedly\n"); - i = MSG_OOB; - SetLastError(0xdeadbeef); - ret = recv(dst, &data, 1, i); - ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret); - ret = GetLastError(); - ok(ret == WSAEINVAL, "expected 10022, got %d\n", ret); - bufs.len = sizeof(char); - bufs.buf = &data; - ret = WSARecv(dst, &bufs, 1, &bytes_rec, &i, NULL, NULL); - ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); - ret = GetLastError(); - ok(ret == WSAEINVAL, "expected 10022, got %d\n", ret); - - closesocket(dst); - optval = 0xdeadbeef; - ret = WSAIoctl(dst, FIONREAD, NULL, 0, &optval, sizeof(optval), &arg, NULL, NULL); - ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n"); - ok(optval == 0xdeadbeef, "FIONREAD should not have changed last error, got %d instead\n", optval); - closesocket(src); }
static BOOL drain_pause = FALSE; @@ -10031,6 +10171,7 @@ START_TEST( sock ) test_accept(); test_getpeername(); test_getsockname(); + test_fionread_siocatmark(); test_ioctlsocket();
test_WSASendMsg();
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=91370
Your paranoid android.
=== debiant2 (32 bit French report) ===
ws2_32: sock.c:4317: Test failed: got events 0x10 sock.c:4318: Test failed: expected timeout sock.c:4318: Test failed: got events 0x2
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/tests/sock.c | 140 +++++++++++++++++++++++++++++---------- 1 file changed, 104 insertions(+), 36 deletions(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index b84ebe88c6a..d337205be21 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -3876,7 +3876,104 @@ static void test_fionread_siocatmark(void) closesocket(server); }
-static void test_ioctlsocket(void) +static void test_fionbio(void) +{ + OVERLAPPED overlapped = {0}, *overlapped_ptr; + u_long one = 1, zero = 0; + HANDLE port, event; + ULONG_PTR key; + DWORD size; + SOCKET s; + int ret; + + event = CreateEventW(NULL, TRUE, FALSE, NULL); + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + port = CreateIoCompletionPort((HANDLE)s, NULL, 123, 0); + + WSASetLastError(0xdeadbeef); + ret = ioctlsocket(s, FIONBIO, (u_long *)1); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + WSASetLastError(0xdeadbeef); + ret = WSAIoctl(s, FIONBIO, &one, sizeof(one), NULL, 0, NULL, NULL, NULL); + todo_wine ok(ret == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + ret = WSAIoctl(s, FIONBIO, &one, sizeof(one) - 1, NULL, 0, &size, &overlapped, NULL); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + size = 0xdeadbeef; + WSASetLastError(0xdeadbeef); + ret = WSAIoctl(s, FIONBIO, &one, sizeof(one), NULL, 0, &size, NULL, NULL); + ok(!ret, "expected success\n"); + todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + ok(!size, "got size %u\n", size); + + ret = WSAIoctl(s, FIONBIO, &one, sizeof(one) + 1, NULL, 0, &size, NULL, NULL); + todo_wine ok(!ret, "got error %u\n", WSAGetLastError()); + + overlapped.Internal = 0xdeadbeef; + overlapped.InternalHigh = 0xdeadbeef; + size = 0xdeadbeef; + ret = WSAIoctl(s, FIONBIO, &one, sizeof(one), NULL, 0, &size, &overlapped, NULL); + ok(!ret, "expected success\n"); + ok(!size, "got size %u\n", size); + + ret = GetQueuedCompletionStatus(port, &size, &key, &overlapped_ptr, 0); + ok(ret, "got error %u\n", GetLastError()); + ok(!size, "got size %u\n", size); + ok(overlapped_ptr == &overlapped, "got overlapped %p\n", overlapped_ptr); + ok(!overlapped.Internal, "got status %#x\n", (NTSTATUS)overlapped.Internal); + ok(!overlapped.InternalHigh, "got size %Iu\n", overlapped.InternalHigh); + + ret = WSAIoctl(s, FIONBIO, &one, sizeof(one), NULL, 0, NULL, &overlapped, NULL); + todo_wine ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + ret = WSAEventSelect(s, event, FD_READ); + ok(!ret, "got error %u\n", WSAGetLastError()); + + ret = WSAIoctl(s, FIONBIO, &one, sizeof(one), NULL, 0, &size, NULL, NULL); + ok(!ret, "got error %u\n", WSAGetLastError()); + + size = 0xdeadbeef; + ret = WSAIoctl(s, FIONBIO, &zero, sizeof(zero), NULL, 0, &size, NULL, NULL); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEINVAL, "got error %u\n", WSAGetLastError()); + todo_wine ok(!size, "got size %u\n", size); + + CloseHandle(port); + closesocket(s); + CloseHandle(event); + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + ret = WSAIoctl(s, FIONBIO, &one, sizeof(one), NULL, 0, NULL, &overlapped, socket_apc); + todo_wine ok(ret == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + apc_count = 0; + size = 0xdeadbeef; + ret = WSAIoctl(s, FIONBIO, &one, sizeof(one), NULL, 0, &size, &overlapped, socket_apc); + ok(!ret, "expected success\n"); + ok(!size, "got size %u\n", size); + + ret = SleepEx(0, TRUE); + todo_wine ok(ret == WAIT_IO_COMPLETION, "got %d\n", ret); + if (ret == WAIT_IO_COMPLETION) + { + ok(apc_count == 1, "APC was called %u times\n", apc_count); + ok(!apc_error, "got APC error %u\n", apc_error); + ok(!apc_size, "got APC size %u\n", apc_size); + ok(apc_overlapped == &overlapped, "got APC overlapped %p\n", apc_overlapped); + } + + closesocket(s); +} + +static void test_keepalive_vals(void) { SOCKET sock; struct tcp_keepalive kalive; @@ -7592,35 +7689,6 @@ todo_wine closesocket(sock3); }
-static void test_synchronous_WSAIoctl(void) -{ - HANDLE io_port; - WSAOVERLAPPED overlapped, *olp; - SOCKET socket; - ULONG on; - ULONG_PTR key; - DWORD num_bytes; - BOOL ret; - int res; - - socket = WSASocketW( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED ); - ok( socket != INVALID_SOCKET, "failed to create socket %d\n", WSAGetLastError() ); - - io_port = CreateIoCompletionPort( (HANDLE)socket, NULL, 0, 0 ); - ok( io_port != NULL, "failed to create completion port %u\n", GetLastError() ); - - on = 1; - memset( &overlapped, 0, sizeof(overlapped) ); - res = WSAIoctl( socket, FIONBIO, &on, sizeof(on), NULL, 0, &num_bytes, &overlapped, NULL ); - ok( !res, "WSAIoctl failed %d\n", WSAGetLastError() ); - - ret = GetQueuedCompletionStatus( io_port, &num_bytes, &key, &olp, 10000 ); - ok( ret, "failed to get completion status %u\n", GetLastError() ); - - CloseHandle( io_port ); - closesocket( socket ); -} - /* * Provide consistent initialization for the AcceptEx IOCP tests. */ @@ -10171,8 +10239,13 @@ START_TEST( sock ) test_accept(); test_getpeername(); test_getsockname(); + + test_address_list_query(); + test_fionbio(); test_fionread_siocatmark(); - test_ioctlsocket(); + test_keepalive_vals(); + test_sioRoutingInterfaceQuery(); + test_sioAddressListChange();
test_WSASendMsg(); test_WSASendTo(); @@ -10190,13 +10263,9 @@ START_TEST( sock ) test_shutdown(); test_DisconnectEx();
- test_sioRoutingInterfaceQuery(); - test_sioAddressListChange(); - test_completion_port(); test_connect_completion_port(); test_shutdown_completion_port(); - test_address_list_query(); test_bind(); test_connecting_socket(); test_WSAGetOverlappedResult(); @@ -10206,7 +10275,6 @@ START_TEST( sock )
/* this is an io heavy test, do it at the end so the kernel doesn't start dropping packets */ test_send(); - test_synchronous_WSAIoctl(); test_wsaioctl();
Exit();
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=91371
Your paranoid android.
=== wvistau64 (64 bit report) ===
ws2_32: sock.c:3766: Test failed: FIONBIO returned 0 sock.c:3771: Test failed: SIOCATMARK returned 1 sock.c:3805: Test failed: FIONBIO returned 0 sock.c:3805: Test failed: SIOCATMARK returned 1 sock.c:3815: Test failed: FIONBIO returned 0
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/tests/sock.c | 100 ++++++++++++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 16 deletions(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index d337205be21..33ab1e1b576 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -3975,52 +3975,120 @@ static void test_fionbio(void)
static void test_keepalive_vals(void) { - SOCKET sock; + OVERLAPPED overlapped = {0}, *overlapped_ptr; struct tcp_keepalive kalive; + ULONG_PTR key; + HANDLE port; + SOCKET sock; + DWORD size; int ret; - u_long arg = 0;
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ok(sock != INVALID_SOCKET, "Creating the socket failed: %d\n", WSAGetLastError()); + port = CreateIoCompletionPort((HANDLE)sock, NULL, 123, 0);
- /* broken apps like defcon pass the argp value directly instead of a pointer to it */ - ret = ioctlsocket(sock, FIONBIO, (u_long *)1); - ok(ret == SOCKET_ERROR, "ioctlsocket succeeded unexpectedly\n"); - ret = WSAGetLastError(); - ok(ret == WSAEFAULT, "expected WSAEFAULT, got %d instead\n", ret); - - ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &arg, 0, NULL, 0, &arg, NULL, NULL); + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, 0, NULL, 0, &size, NULL, NULL); ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n"); ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + todo_wine ok(!size, "got size %u\n", size);
- ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, NULL, sizeof(struct tcp_keepalive), NULL, 0, &arg, NULL, NULL); + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, NULL, sizeof(kalive), NULL, 0, &size, NULL, NULL); ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n"); ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + todo_wine ok(!size, "got size %u\n", size);
+ WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; make_keepalive(kalive, 0, 0, 0); - ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(struct tcp_keepalive), NULL, 0, &arg, NULL, NULL); + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, &size, NULL, NULL); ok(ret == 0, "WSAIoctl failed unexpectedly\n"); + todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + ok(!size, "got size %u\n", size); + + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, NULL, NULL, NULL); + todo_wine ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, NULL, &overlapped, NULL); + todo_wine ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + overlapped.Internal = 0xdeadbeef; + overlapped.InternalHigh = 0xdeadbeef; + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive) - 1, NULL, 0, &size, &overlapped, NULL); + ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + ok(size == 0xdeadbeef, "got size %u\n", size); + todo_wine ok(overlapped.Internal == STATUS_PENDING, "got status %#x\n", (NTSTATUS)overlapped.Internal); + ok(overlapped.InternalHigh == 0xdeadbeef, "got size %Iu\n", overlapped.InternalHigh); + + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + overlapped.Internal = 0xdeadbeef; + overlapped.InternalHigh = 0xdeadbeef; + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, &size, &overlapped, NULL); + ok(ret == 0, "WSAIoctl failed unexpectedly\n"); + todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + todo_wine ok(size == 0xdeadbeef, "got size %u\n", size); + + ret = GetQueuedCompletionStatus(port, &size, &key, &overlapped_ptr, 0); + ok(ret, "got error %u\n", GetLastError()); + ok(!size, "got size %u\n", size); + ok(overlapped_ptr == &overlapped, "got overlapped %p\n", overlapped_ptr); + ok(!overlapped.Internal, "got status %#x\n", (NTSTATUS)overlapped.Internal); + ok(!overlapped.InternalHigh, "got size %Iu\n", overlapped.InternalHigh);
make_keepalive(kalive, 1, 0, 0); - ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(struct tcp_keepalive), NULL, 0, &arg, NULL, NULL); + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, &size, NULL, NULL); ok(ret == 0, "WSAIoctl failed unexpectedly\n");
make_keepalive(kalive, 1, 1000, 1000); - ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(struct tcp_keepalive), NULL, 0, &arg, NULL, NULL); + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, &size, NULL, NULL); ok(ret == 0, "WSAIoctl failed unexpectedly\n");
make_keepalive(kalive, 1, 10000, 10000); - ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(struct tcp_keepalive), NULL, 0, &arg, NULL, NULL); + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, &size, NULL, NULL); ok(ret == 0, "WSAIoctl failed unexpectedly\n");
make_keepalive(kalive, 1, 100, 100); - ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(struct tcp_keepalive), NULL, 0, &arg, NULL, NULL); + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, &size, NULL, NULL); ok(ret == 0, "WSAIoctl failed unexpectedly\n");
make_keepalive(kalive, 0, 100, 100); - ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(struct tcp_keepalive), NULL, 0, &arg, NULL, NULL); + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, &size, NULL, NULL); ok(ret == 0, "WSAIoctl failed unexpectedly\n");
+ CloseHandle(port); + closesocket(sock); + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, NULL, &overlapped, socket_apc); + todo_wine ok(ret == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + apc_count = 0; + size = 0xdeadbeef; + ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive, sizeof(kalive), NULL, 0, &size, &overlapped, socket_apc); + ok(!ret, "expected success\n"); + ok(!size, "got size %u\n", size); + + ret = SleepEx(0, TRUE); + todo_wine ok(ret == WAIT_IO_COMPLETION, "got %d\n", ret); + if (ret == WAIT_IO_COMPLETION) + { + ok(apc_count == 1, "APC was called %u times\n", apc_count); + ok(!apc_error, "got APC error %u\n", apc_error); + ok(!apc_size, "got APC size %u\n", apc_size); + ok(apc_overlapped == &overlapped, "got APC overlapped %p\n", apc_overlapped); + } + closesocket(sock); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=91372
Your paranoid android.
=== wvistau64 (64 bit report) ===
ws2_32: sock.c:3766: Test failed: FIONBIO returned 0
=== debiant2 (32 bit Japanese:Japan report) ===
ws2_32: sock.c:6639: Test failed: The wrong first client was accepted by acceptex: 2 != 1 sock.c:7845: Test succeeded inside todo block: GetQueuedCompletionStatus returned 0 sock.c:7846: Test succeeded inside todo block: Last error was 64