[PATCH 3/6] ws2_32: Use IOCTL_AFD_WINE_RECVMSG in WS2_recv_base().
Zebediah Figura
z.figura12 at gmail.com
Tue May 25 20:52:52 CDT 2021
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/ws2_32/socket.c | 466 ++++++---------------------------------
dlls/ws2_32/tests/sock.c | 18 +-
2 files changed, 72 insertions(+), 412 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 3632397ef3d..620226d7296 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -197,8 +197,6 @@ static struct interface_filter generic_interface_filter = {
};
#endif /* LINUX_BOUND_IF */
-extern ssize_t CDECL __wine_locked_recvmsg( int fd, struct msghdr *hdr, int flags );
-
/*
* The actual definition of WSASendTo, wrapped in a different function name
* so that internal calls from ws2_32 itself will not trigger programs like
@@ -210,17 +208,6 @@ static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
-/*
- * Internal fundamental receive function, essentially WSARecvFrom with an
- * additional parameter to support message control headers.
- */
-static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
- LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,
- struct WS_sockaddr *lpFrom,
- LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
- LPWSABUF lpControlBuffer );
-
DECLARE_CRITICAL_SECTION(cs_if_addr_cache);
DECLARE_CRITICAL_SECTION(cs_socket_list);
@@ -715,95 +702,6 @@ static const int ws_poll_map[][2] =
{ WS_POLLRDBAND, POLLPRI }
};
-#ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
-#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
-static inline WSACMSGHDR *fill_control_message(int level, int type, WSACMSGHDR *current, ULONG *maxsize, void *data, int len)
-{
- ULONG msgsize = sizeof(WSACMSGHDR) + WSA_CMSG_ALIGN(len);
- char *ptr = (char *) current + sizeof(WSACMSGHDR);
-
- /* Make sure there is at least enough room for this entry */
- if (msgsize > *maxsize)
- return NULL;
- *maxsize -= msgsize;
- /* Fill in the entry */
- current->cmsg_len = sizeof(WSACMSGHDR) + len;
- current->cmsg_level = level;
- current->cmsg_type = type;
- memcpy(ptr, data, len);
- /* Return the pointer to where next entry should go */
- return (WSACMSGHDR *) (ptr + WSA_CMSG_ALIGN(len));
-}
-#endif /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
-
-static inline int convert_control_headers(struct msghdr *hdr, WSABUF *control)
-{
-#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
- WSACMSGHDR *cmsg_win = (WSACMSGHDR *) control->buf, *ptr;
- ULONG ctlsize = control->len;
- struct cmsghdr *cmsg_unix;
-
- ptr = cmsg_win;
- /* Loop over all the headers, converting as appropriate */
- for (cmsg_unix = CMSG_FIRSTHDR(hdr); cmsg_unix != NULL; cmsg_unix = CMSG_NXTHDR(hdr, cmsg_unix))
- {
- switch(cmsg_unix->cmsg_level)
- {
- case IPPROTO_IP:
- switch(cmsg_unix->cmsg_type)
- {
-#if defined(IP_PKTINFO)
- case IP_PKTINFO:
- {
- /* Convert the Unix IP_PKTINFO structure to the Windows version */
- struct in_pktinfo *data_unix = (struct in_pktinfo *) CMSG_DATA(cmsg_unix);
- struct WS_in_pktinfo data_win;
-
- memcpy(&data_win.ipi_addr,&data_unix->ipi_addr.s_addr,4); /* 4 bytes = 32 address bits */
- data_win.ipi_ifindex = data_unix->ipi_ifindex;
- ptr = fill_control_message(WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize,
- (void*)&data_win, sizeof(data_win));
- if (!ptr) goto error;
- } break;
-#elif defined(IP_RECVDSTADDR)
- case IP_RECVDSTADDR:
- {
- struct in_addr *addr_unix = (struct in_addr *) CMSG_DATA(cmsg_unix);
- struct WS_in_pktinfo data_win;
-
- memcpy(&data_win.ipi_addr, &addr_unix->s_addr, 4); /* 4 bytes = 32 address bits */
- data_win.ipi_ifindex = 0; /* FIXME */
- ptr = fill_control_message(WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize,
- (void*)&data_win, sizeof(data_win));
- if (!ptr) goto error;
- } break;
-#endif /* IP_PKTINFO */
- default:
- FIXME("Unhandled IPPROTO_IP message header type %d\n", cmsg_unix->cmsg_type);
- break;
- }
- break;
- default:
- FIXME("Unhandled message header level %d\n", cmsg_unix->cmsg_level);
- break;
- }
- }
-
- /* Set the length of the returned control headers */
- control->len = (char*)ptr - (char*)cmsg_win;
- return 1;
-error:
- control->len = 0;
- return 0;
-#else /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
- control->len = 0;
- return 1;
-#endif /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */
-}
-#endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */
-
-/* ----------------------------------- error handling */
-
static NTSTATUS sock_get_ntstatus( int err )
{
switch ( err )
@@ -2021,127 +1919,6 @@ static void WINAPI ws2_async_apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserv
release_async_io( &wsa->io );
}
-/***********************************************************************
- * WS2_recv (INTERNAL)
- *
- * Workhorse for both synchronous and asynchronous recv() operations.
- */
-static int WS2_recv( int fd, struct ws2_async *wsa, int flags )
-{
-#ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
- char pktbuf[512];
-#endif
- struct msghdr hdr;
- union generic_unix_sockaddr unix_sockaddr;
- int n;
-
- hdr.msg_name = NULL;
-
- if (wsa->addr)
- {
- hdr.msg_namelen = sizeof(unix_sockaddr);
- hdr.msg_name = &unix_sockaddr;
- }
- else
- hdr.msg_namelen = 0;
-
- 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 = pktbuf;
- hdr.msg_controllen = sizeof(pktbuf);
- hdr.msg_flags = 0;
-#endif
-
- while ((n = __wine_locked_recvmsg( fd, &hdr, flags )) == -1)
- {
- if (errno != EINTR)
- return -1;
- }
-
-#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
- if (wsa->control)
- {
- ERR("Message control headers cannot be properly supported on this system.\n");
- wsa->control->len = 0;
- }
-#else
- if (wsa->control && !convert_control_headers(&hdr, wsa->control))
- {
- WARN("Application passed insufficient room for control headers.\n");
- *wsa->lpFlags |= WS_MSG_CTRUNC;
- errno = EMSGSIZE;
- return -1;
- }
-#endif
-
- /* if this socket is connected and lpFrom is not NULL, Linux doesn't give us
- * msg_name and msg_namelen from recvmsg, but it does set msg_namelen to zero.
- *
- * quoting linux 2.6 net/ipv4/tcp.c:
- * "According to UNIX98, msg_name/msg_namelen are ignored
- * on connected socket. I was just happy when found this 8) --ANK"
- *
- * likewise MSDN says that lpFrom and lpFromlen are ignored for
- * connection-oriented sockets, so don't try to update lpFrom.
- */
- if (wsa->addr && hdr.msg_namelen)
- ws_sockaddr_u2ws( &unix_sockaddr.addr, wsa->addr, wsa->addrlen.ptr );
-
- return n;
-}
-
-/***********************************************************************
- * WS2_async_recv (INTERNAL)
- *
- * Handler for overlapped recv() operations.
- */
-static NTSTATUS WS2_async_recv( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
-{
- struct ws2_async *wsa = user;
- int result = 0, fd;
-
- switch (status)
- {
- case STATUS_ALERTED:
- if ((status = wine_server_handle_to_fd( wsa->hSocket, FILE_READ_DATA, &fd, NULL ) ))
- break;
-
- result = WS2_recv( fd, wsa, convert_flags(wsa->flags) );
- close( fd );
- if (result >= 0)
- {
- status = STATUS_SUCCESS;
- _enable_event( wsa->hSocket, (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0 );
- }
- else
- {
- if (errno == EAGAIN)
- {
- status = STATUS_PENDING;
- _enable_event( wsa->hSocket, (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0 );
- }
- else
- {
- result = 0;
- status = wsaErrStatus();
- }
- }
- break;
- }
- if (status != STATUS_PENDING)
- {
- iosb->u.Status = status;
- iosb->Information = result;
- if (!wsa->completion_func)
- release_async_io( &wsa->io );
- }
- return status;
-}
-
/***********************************************************************
* WS2_send (INTERNAL)
*
@@ -2663,6 +2440,69 @@ static void WINAPI WS2_GetAcceptExSockaddrs(PVOID buffer, DWORD data_size, DWORD
*remote_addr = (struct WS_sockaddr *)(cbuf + sizeof(int));
}
+
+static void WINAPI socket_apc( void *apc_user, IO_STATUS_BLOCK *io, ULONG reserved )
+{
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE func = apc_user;
+ func( NtStatusToWSAError( io->u.Status ), io->Information, (OVERLAPPED *)io, 0 );
+}
+
+static int WS2_recv_base( SOCKET s, WSABUF *buffers, DWORD buffer_count, DWORD *ret_size, DWORD *flags,
+ struct WS_sockaddr *addr, int *addr_len, OVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion, WSABUF *control )
+{
+ IO_STATUS_BLOCK iosb, *piosb = &iosb;
+ struct afd_recvmsg_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, control %p\n",
+ s, buffers, buffer_count, *flags, addr, addr_len ? *addr_len : -1, overlapped, completion, control );
+
+ 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.control = control;
+ 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_RECVMSG, ¶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
*/
@@ -5900,186 +5740,6 @@ int WINAPI WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
NULL, NULL, lpOverlapped, lpCompletionRoutine, NULL);
}
-static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
- LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,
- struct WS_sockaddr *lpFrom,
- LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
- LPWSABUF lpControlBuffer )
-{
- unsigned int i, options;
- int n, fd, err, overlapped, flags;
- struct ws2_async *wsa = NULL, localwsa;
- BOOL is_blocking;
- DWORD timeout_start = GetTickCount();
- ULONG_PTR cvalue = (lpOverlapped && ((ULONG_PTR)lpOverlapped->hEvent & 1) == 0) ? (ULONG_PTR)lpOverlapped : 0;
-
- TRACE("socket %04lx, wsabuf %p, nbufs %d, flags %d, from %p, fromlen %d, ovl %p, func %p\n",
- s, lpBuffers, dwBufferCount, *lpFlags, lpFrom,
- (lpFromlen ? *lpFromlen : -1),
- lpOverlapped, lpCompletionRoutine);
-
- fd = get_sock_fd( s, FILE_READ_DATA, &options );
- TRACE( "fd=%d, options=%x\n", fd, options );
-
- if (fd == -1) return SOCKET_ERROR;
-
- if (*lpFlags & WS_MSG_OOB)
- {
- /* It's invalid to receive OOB data from an OOBINLINED socket
- * as OOB data is turned into normal data. */
- socklen_t len = sizeof(n);
- if (!getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*) &n, &len) && n)
- {
- err = WSAEINVAL;
- 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_recv )))
- {
- err = WSAEFAULT;
- goto error;
- }
- }
- else
- wsa = &localwsa;
-
- wsa->hSocket = SOCKET2HANDLE(s);
- wsa->flags = *lpFlags;
- wsa->lpFlags = lpFlags;
- wsa->addr = lpFrom;
- wsa->addrlen.ptr = lpFromlen;
- wsa->control = lpControlBuffer;
- wsa->n_iovecs = dwBufferCount;
- wsa->first_iovec = 0;
- for (i = 0; i < dwBufferCount; i++)
- {
- /* check buffer first to trigger write watches */
- if (IsBadWritePtr( lpBuffers[i].buf, lpBuffers[i].len ))
- {
- err = WSAEFAULT;
- goto error;
- }
- wsa->iovec[i].iov_base = lpBuffers[i].buf;
- wsa->iovec[i].iov_len = lpBuffers[i].len;
- }
-
- flags = convert_flags(wsa->flags);
- for (;;)
- {
- n = WS2_recv( fd, wsa, flags );
- if (n == -1)
- {
- /* Unix-like systems return EINVAL when attempting to read OOB data from
- * an empty socket buffer, convert that to a Windows expected return. */
- if ((flags & MSG_OOB) && errno == EINVAL)
- errno = EWOULDBLOCK;
-
- if (errno != EAGAIN)
- {
- err = wsaErrno();
- goto error;
- }
- }
- else if (lpNumberOfBytesRecvd) *lpNumberOfBytesRecvd = n;
-
- if (overlapped)
- {
- IO_STATUS_BLOCK *iosb = lpOverlapped ? (IO_STATUS_BLOCK *)lpOverlapped : &wsa->local_iosb;
-
- wsa->user_overlapped = lpOverlapped;
- wsa->completion_func = lpCompletionRoutine;
- release_sock_fd( s, fd );
-
- if (n == -1)
- {
- iosb->u.Status = STATUS_PENDING;
- iosb->Information = 0;
-
- if (wsa->completion_func)
- err = register_async( ASYNC_TYPE_READ, wsa->hSocket, &wsa->io, NULL,
- ws2_async_apc, wsa, iosb );
- else
- err = register_async( ASYNC_TYPE_READ, wsa->hSocket, &wsa->io, lpOverlapped->hEvent,
- NULL, (void *)cvalue, iosb );
-
- if (err != STATUS_PENDING) HeapFree( GetProcessHeap(), 0, wsa );
- SetLastError(NtStatusToWSAError( err ));
- return SOCKET_ERROR;
- }
-
- iosb->u.Status = STATUS_SUCCESS;
- iosb->Information = 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 );
- _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0);
- return 0;
- }
-
- if (n != -1) break;
-
- if ((err = sock_is_blocking( s, &is_blocking ))) goto error;
-
- if ( is_blocking )
- {
- struct pollfd pfd;
- int poll_timeout = -1;
- INT64 timeout = get_rcvsnd_timeo(fd, TRUE);
-
- 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 = POLLIN;
- if (*lpFlags & WS_MSG_OOB) pfd.events |= POLLPRI;
-
- if (!poll_timeout || !poll( &pfd, 1, poll_timeout ))
- {
- err = WSAETIMEDOUT;
- /* a timeout is not fatal */
- _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0);
- goto error;
- }
- }
- else
- {
- _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0);
- err = WSAEWOULDBLOCK;
- goto error;
- }
- }
-
- TRACE(" -> %i bytes\n", n);
- if (wsa != &localwsa) HeapFree( GetProcessHeap(), 0, wsa );
- release_sock_fd( s, fd );
- _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0);
- 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;
-}
/***********************************************************************
* WSARecvFrom (WS2_32.69)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 912bf9ee5d8..6801392be1e 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -1891,14 +1891,14 @@ static void test_ip_pktinfo(void)
ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError());
ok(!WaitForSingleObject(ov.hEvent, 100), "wait failed\n");
ok((NTSTATUS)ov.Internal == STATUS_BUFFER_OVERFLOW, "got status %#x\n", (NTSTATUS)ov.Internal);
- todo_wine ok(ov.InternalHigh == sizeof(msg), "got size %Iu\n", ov.InternalHigh);
+ ok(ov.InternalHigh == sizeof(msg), "got size %Iu\n", ov.InternalHigh);
ok(ov.Offset == 0xdead3, "got Offset %Iu\n", ov.Offset);
ok(ov.OffsetHigh == 0xdead4, "got OffsetHigh %Iu\n", ov.OffsetHigh);
dwFlags = 0xdeadbeef;
rc = WSAGetOverlappedResult(s1, &ov, &dwSize, FALSE, &dwFlags);
ok(!rc, "expected failure\n");
ok(WSAGetLastError() == WSAEMSGSIZE, "got error %u\n", WSAGetLastError());
- todo_wine ok(dwSize == sizeof(msg), "got size %u\n", dwSize);
+ ok(dwSize == sizeof(msg), "got size %u\n", dwSize);
todo_wine ok(dwFlags == 0xdeadbeef, "got flags %#x\n", dwFlags);
ok(hdr.dwFlags == MSG_CTRUNC,
"WSARecvMsg() overlapped operation set unexpected flags %d.\n", hdr.dwFlags);
@@ -9698,11 +9698,11 @@ static DWORD CALLBACK nonblocking_async_recv_thread(void *arg)
wsabuf.len = sizeof(buffer);
memset(buffer, 0, sizeof(buffer));
ret = WSARecv(params->client, &wsabuf, 1, NULL, &flags, &overlapped, NULL);
- todo_wine_if (!params->event) ok(!ret, "got %d\n", ret);
+ ok(!ret, "got %d\n", ret);
ret = GetOverlappedResult((HANDLE)params->client, &overlapped, &size, FALSE);
ok(ret, "got error %u\n", GetLastError());
- todo_wine ok(size == 4, "got size %u\n", size);
- todo_wine_if (!params->event) ok(!strcmp(buffer, "data"), "got %s\n", debugstr_an(buffer, size));
+ ok(size == 4, "got size %u\n", size);
+ ok(!strcmp(buffer, "data"), "got %s\n", debugstr_an(buffer, size));
return 0;
}
@@ -9827,7 +9827,7 @@ static void test_nonblocking_async_recv(void)
thread = CreateThread(NULL, 0, nonblocking_async_recv_thread, ¶ms, 0, NULL);
ret = WaitForSingleObject(thread, 200);
- todo_wine ok(ret == WAIT_TIMEOUT, "expected timeout\n");
+ ok(ret == WAIT_TIMEOUT, "expected timeout\n");
ret = send(server, "data", 4, 0);
ok(ret == 4, "got %d\n", ret);
@@ -9843,7 +9843,7 @@ static void test_nonblocking_async_recv(void)
thread = CreateThread(NULL, 0, nonblocking_async_recv_thread, ¶ms, 0, NULL);
ret = WaitForSingleObject(thread, 200);
- todo_wine ok(ret == WAIT_TIMEOUT, "expected timeout\n");
+ ok(ret == WAIT_TIMEOUT, "expected timeout\n");
ret = send(server, "data", 4, 0);
ok(ret == 4, "got %d\n", ret);
@@ -9861,9 +9861,9 @@ static void test_nonblocking_async_recv(void)
ret = WSARecv(client, &wsabuf, 1, NULL, &flags, &overlapped, NULL);
ok(!ret, "got %d\n", ret);
ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, FALSE);
- todo_wine ok(ret, "got error %u\n", GetLastError());
+ ok(ret, "got error %u\n", GetLastError());
ok(size == 4, "got size %u\n", size);
- todo_wine ok(!strcmp(buffer, "data"), "got %s\n", debugstr_an(buffer, size));
+ ok(!strcmp(buffer, "data"), "got %s\n", debugstr_an(buffer, size));
closesocket(client);
closesocket(server);
--
2.30.2
More information about the wine-devel
mailing list