[PATCH 6/6] ws2_32: Use IOCTL_AFD_WINE_SENDMSG in WS2_sendto().
Zebediah Figura
z.figura12 at gmail.com
Tue May 25 20:52:55 CDT 2021
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/ws2_32/socket.c | 334 ++++++++++-----------------------------
dlls/ws2_32/tests/sock.c | 2 +-
2 files changed, 88 insertions(+), 248 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 620226d7296..ff2db136f89 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -197,17 +197,6 @@ static struct interface_filter generic_interface_filter = {
};
#endif /* LINUX_BOUND_IF */
-/*
- * The actual definition of WSASendTo, wrapped in a different function name
- * so that internal calls from ws2_32 itself will not trigger programs like
- * Garena, which hooks WSASendTo/WSARecvFrom calls.
- */
-static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
- LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
- const struct WS_sockaddr *to, int tolen,
- LPWSAOVERLAPPED lpOverlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
-
DECLARE_CRITICAL_SECTION(cs_if_addr_cache);
DECLARE_CRITICAL_SECTION(cs_socket_list);
@@ -433,6 +422,25 @@ static BOOL socket_list_add(SOCKET socket)
return TRUE;
}
+
+static BOOL socket_list_find( SOCKET socket )
+{
+ unsigned int i;
+
+ EnterCriticalSection( &cs_socket_list );
+ for (i = 0; i < socket_list_size; ++i)
+ {
+ if (socket_list[i] == socket)
+ {
+ LeaveCriticalSection( &cs_socket_list );
+ return TRUE;
+ }
+ }
+ LeaveCriticalSection( &cs_socket_list );
+ return FALSE;
+}
+
+
static void socket_list_remove(SOCKET socket)
{
unsigned int i;
@@ -1995,61 +2003,6 @@ static int WS2_send( int fd, struct ws2_async *wsa, int flags )
return ret;
}
-/***********************************************************************
- * WS2_async_send (INTERNAL)
- *
- * Handler for overlapped send() operations.
- */
-static NTSTATUS WS2_async_send( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
-{
- struct ws2_async *wsa = user;
- int result = 0, fd;
-
- switch (status)
- {
- case STATUS_ALERTED:
- if ( wsa->n_iovecs <= wsa->first_iovec )
- {
- /* Nothing to do */
- status = STATUS_SUCCESS;
- break;
- }
- if ((status = wine_server_handle_to_fd( wsa->hSocket, FILE_WRITE_DATA, &fd, NULL ) ))
- break;
-
- /* check to see if the data is ready (non-blocking) */
- result = WS2_send( fd, wsa, convert_flags(wsa->flags) );
- close( fd );
-
- if (result >= 0)
- {
- if (wsa->first_iovec < wsa->n_iovecs)
- status = STATUS_PENDING;
- else
- status = STATUS_SUCCESS;
-
- iosb->Information += result;
- }
- else if (errno == EAGAIN)
- {
- status = STATUS_PENDING;
- }
- else
- {
- status = wsaErrStatus();
- }
- break;
- }
- if (status != STATUS_PENDING)
- {
- iosb->u.Status = status;
- if (!wsa->completion_func)
- release_async_io( &wsa->io );
- }
- return status;
-}
-
-
/***********************************************************************
* accept (WS2_32.1)
*/
@@ -2502,6 +2455,72 @@ static int WS2_recv_base( SOCKET s, WSABUF *buffers, DWORD buffer_count, DWORD *
return status ? -1 : 0;
}
+static int WS2_sendto( SOCKET s, WSABUF *buffers, DWORD buffer_count, DWORD *ret_size, DWORD flags,
+ const struct WS_sockaddr *addr, int addr_len, OVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion )
+{
+ IO_STATUS_BLOCK iosb, *piosb = &iosb;
+ struct afd_sendmsg_params params;
+ PIO_APC_ROUTINE apc = NULL;
+ HANDLE event = NULL;
+ void *cvalue = NULL;
+ NTSTATUS status;
+
+ TRACE( "socket %#lx, buffers %p, buffer_count %u, flags %#x, addr %p, "
+ "addr_len %d, overlapped %p, completion %p\n",
+ s, buffers, buffer_count, flags, addr, addr_len, overlapped, completion );
+
+ if (!socket_list_find( s ))
+ {
+ SetLastError( WSAENOTSOCK );
+ return -1;
+ }
+
+ if (!overlapped && !ret_size)
+ {
+ SetLastError( WSAEFAULT );
+ return -1;
+ }
+
+ if (overlapped)
+ {
+ piosb = (IO_STATUS_BLOCK *)overlapped;
+ if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped;
+ event = overlapped->hEvent;
+ }
+ else
+ {
+ if (!(event = get_sync_event())) return -1;
+ }
+ piosb->u.Status = STATUS_PENDING;
+
+ if (completion)
+ {
+ event = NULL;
+ cvalue = completion;
+ apc = socket_apc;
+ }
+
+ params.addr = addr;
+ params.addr_len = addr_len;
+ params.ws_flags = flags;
+ params.force_async = !!overlapped;
+ params.count = buffer_count;
+ params.buffers = buffers;
+
+ status = NtDeviceIoControlFile( (HANDLE)s, event, apc, cvalue, piosb,
+ IOCTL_AFD_WINE_SENDMSG, ¶ms, sizeof(params), NULL, 0 );
+ if (status == STATUS_PENDING && !overlapped)
+ {
+ if (WaitForSingleObject( event, INFINITE ) == WAIT_FAILED)
+ return -1;
+ status = piosb->u.Status;
+ }
+ if (!status && ret_size) *ret_size = piosb->Information;
+ SetLastError( NtStatusToWSAError( status ) );
+ return status ? -1 : 0;
+}
+
/***********************************************************************
* WSASendMsg
@@ -4725,187 +4744,6 @@ INT WINAPI WSASendDisconnect( SOCKET s, LPWSABUF lpBuffers )
}
-static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
- LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
- const struct WS_sockaddr *to, int tolen,
- LPWSAOVERLAPPED lpOverlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
-{
- unsigned int i, options;
- int n, fd, err, overlapped, flags;
- struct ws2_async *wsa = NULL, localwsa;
- int totalLength = 0;
- DWORD bytes_sent;
- BOOL is_blocking;
-
- TRACE("socket %04lx, wsabuf %p, nbufs %d, flags %d, to %p, tolen %d, ovl %p, func %p\n",
- s, lpBuffers, dwBufferCount, dwFlags,
- to, tolen, lpOverlapped, lpCompletionRoutine);
-
- fd = get_sock_fd( s, FILE_WRITE_DATA, &options );
- TRACE( "fd=%d, options=%x\n", fd, options );
-
- if ( fd == -1 ) return SOCKET_ERROR;
-
- if (!lpOverlapped && !lpNumberOfBytesSent)
- {
- err = WSAEFAULT;
- goto error;
- }
-
- overlapped = (lpOverlapped || lpCompletionRoutine) &&
- !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
- if (overlapped || dwBufferCount > 1)
- {
- if (!(wsa = (struct ws2_async *)alloc_async_io( offsetof(struct ws2_async, iovec[dwBufferCount]),
- WS2_async_send )))
- {
- err = WSAEFAULT;
- goto error;
- }
- }
- else
- wsa = &localwsa;
-
- wsa->hSocket = SOCKET2HANDLE(s);
- wsa->addr = (struct WS_sockaddr *)to;
- wsa->addrlen.val = tolen;
- wsa->flags = dwFlags;
- wsa->lpFlags = &wsa->flags;
- wsa->control = NULL;
- wsa->n_iovecs = dwBufferCount;
- wsa->first_iovec = 0;
- for ( i = 0; i < dwBufferCount; i++ )
- {
- wsa->iovec[i].iov_base = lpBuffers[i].buf;
- wsa->iovec[i].iov_len = lpBuffers[i].len;
- totalLength += lpBuffers[i].len;
- }
-
- flags = convert_flags(dwFlags);
- n = WS2_send( fd, wsa, flags );
- if (n == -1 && errno != EAGAIN)
- {
- err = wsaErrno();
- goto error;
- }
-
- if (overlapped)
- {
- IO_STATUS_BLOCK *iosb = lpOverlapped ? (IO_STATUS_BLOCK *)lpOverlapped : &wsa->local_iosb;
- ULONG_PTR cvalue = (lpOverlapped && ((ULONG_PTR)lpOverlapped->hEvent & 1) == 0) ? (ULONG_PTR)lpOverlapped : 0;
-
- wsa->user_overlapped = lpOverlapped;
- wsa->completion_func = lpCompletionRoutine;
- release_sock_fd( s, fd );
-
- if (n == -1 || n < totalLength)
- {
- iosb->u.Status = STATUS_PENDING;
- iosb->Information = n == -1 ? 0 : n;
-
- if (wsa->completion_func)
- err = register_async( ASYNC_TYPE_WRITE, wsa->hSocket, &wsa->io, NULL,
- ws2_async_apc, wsa, iosb );
- else
- err = register_async( ASYNC_TYPE_WRITE, wsa->hSocket, &wsa->io, lpOverlapped->hEvent,
- NULL, (void *)cvalue, iosb );
-
- /* Enable the event only after starting the async. The server will deliver it as soon as
- the async is done. */
- _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
-
- if (err != STATUS_PENDING) HeapFree( GetProcessHeap(), 0, wsa );
- SetLastError(NtStatusToWSAError( err ));
- return SOCKET_ERROR;
- }
-
- iosb->u.Status = STATUS_SUCCESS;
- iosb->Information = n;
- if (lpNumberOfBytesSent) *lpNumberOfBytesSent = n;
- if (!wsa->completion_func)
- {
- if (cvalue) WS_AddCompletion( s, cvalue, STATUS_SUCCESS, n, FALSE );
- if (lpOverlapped->hEvent) SetEvent( lpOverlapped->hEvent );
- HeapFree( GetProcessHeap(), 0, wsa );
- }
- else NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)ws2_async_apc,
- (ULONG_PTR)wsa, (ULONG_PTR)iosb, 0 );
- SetLastError(ERROR_SUCCESS);
- return 0;
- }
-
- if ((err = sock_is_blocking( s, &is_blocking ))) goto error;
-
- if ( is_blocking )
- {
- /* On a blocking non-overlapped stream socket,
- * sending blocks until the entire buffer is sent. */
- DWORD timeout_start = GetTickCount();
-
- bytes_sent = n == -1 ? 0 : n;
-
- while (wsa->first_iovec < wsa->n_iovecs)
- {
- struct pollfd pfd;
- int poll_timeout = -1;
- INT64 timeout = get_rcvsnd_timeo(fd, FALSE);
-
- if (timeout)
- {
- timeout -= GetTickCount() - timeout_start;
- if (timeout < 0) poll_timeout = 0;
- else poll_timeout = timeout <= INT_MAX ? timeout : INT_MAX;
- }
-
- pfd.fd = fd;
- pfd.events = POLLOUT;
-
- if (!poll_timeout || !poll( &pfd, 1, poll_timeout ))
- {
- err = WSAETIMEDOUT;
- goto error; /* msdn says a timeout in send is fatal */
- }
-
- n = WS2_send( fd, wsa, flags );
- if (n == -1 && errno != EAGAIN)
- {
- err = wsaErrno();
- goto error;
- }
-
- if (n >= 0)
- bytes_sent += n;
- }
- }
- else /* non-blocking */
- {
- if (n < totalLength)
- _enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
- if (n == -1)
- {
- err = WSAEWOULDBLOCK;
- goto error;
- }
- bytes_sent = n;
- }
-
- TRACE(" -> %i bytes\n", bytes_sent);
-
- if (lpNumberOfBytesSent) *lpNumberOfBytesSent = bytes_sent;
- if (wsa != &localwsa) HeapFree( GetProcessHeap(), 0, wsa );
- release_sock_fd( s, fd );
- SetLastError(ERROR_SUCCESS);
- return 0;
-
-error:
- if (wsa != &localwsa) HeapFree( GetProcessHeap(), 0, wsa );
- release_sock_fd( s, fd );
- WARN(" -> ERROR %d\n", err);
- SetLastError(err);
- return SOCKET_ERROR;
-}
-
/***********************************************************************
* WSASendTo (WS2_32.74)
*/
@@ -4915,6 +4753,7 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{
+ /* Garena hooks WSASendTo(), so we need a wrapper */
return WS2_sendto( s, lpBuffers, dwBufferCount,
lpNumberOfBytesSent, dwFlags,
to, tolen,
@@ -5750,6 +5589,7 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{
+ /* Garena hooks WSARecvFrom(), so we need a wrapper */
return WS2_recv_base( s, lpBuffers, dwBufferCount,
lpNumberOfBytesRecvd, lpFlags,
lpFrom, lpFromlen,
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 6801392be1e..f6304c0f5ce 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -4301,7 +4301,7 @@ static void test_write_events(struct event_test_ctx *ctx)
if (!broken(1))
{
while (send(server, buffer, buffer_size, 0) == buffer_size);
- todo_wine ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError());
+ ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError());
while (recv(client, buffer, buffer_size, 0) > 0);
ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError());
--
2.30.2
More information about the wine-devel
mailing list