From: Ivan Savinov <isavinov@gmail.com> Linux sendmsg() rejects a msg_iovlen greater than IOV_MAX (1024) with EMSGSIZE, but native WSASend() has no such restriction for stream sockets. Wine currently forwards the whole WSABUF array unmodified, so any application issuing a WSASend() with more buffers than that gets an unexpected WSAEMSGSIZE and typically tears down the connection (observed with a gRPC/C++ server batching HTTP/2 frame slices into a single WSASend()). Clamp msg_iovlen to IOV_MAX for SOCK_STREAM sockets and let the existing short write handling resend the remaining buffers in a subsequent sendmsg() call. Datagram sockets are left alone, since clamping would split the datagram; supporting more than IOV_MAX buffers there would require coalescing the payload instead. Signed-off-by: Ivan Savinov <isavinov@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> --- dlls/ntdll/unix/socket.c | 5 +++++ dlls/ws2_32/tests/sock.c | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index ab301f13949..529f9b689f1 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -25,6 +25,7 @@ #include "config.h" #include <assert.h> #include <errno.h> +#include <limits.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> @@ -1087,6 +1088,10 @@ static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) hdr.msg_iov = async->iov + async->iov_cursor; hdr.msg_iovlen = async->count - async->iov_cursor; + /* Linux sendmsg() rejects msg_iovlen > IOV_MAX with EMSGSIZE, unlike native + * WSASend(), which imposes no such limit. Clamp for stream sockets and let + * the short write handling below resend the remaining buffers. */ + if (sock_type == SOCK_STREAM && hdr.msg_iovlen > IOV_MAX) hdr.msg_iovlen = IOV_MAX; while ((ret = sendmsg( fd, &hdr, async->unix_flags )) == -1) { diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index b6d5bcefdad..27219e93bab 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -14644,7 +14644,6 @@ static void test_send_many_buffers(void) sent = 0xdeadbeef; ret = WSASend(client, bufs, count, &sent, 0, NULL, NULL); - todo_wine ok(!ret, "got %d, error %u.\n", ret, WSAGetLastError()); if (!ret) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11316