From 360b05b451fbbc2a2768fa84d86a78ec9002979a Mon Sep 17 00:00:00 2001
From: Corinna Vinschen <corinna@vinschen.de>
Date: Fri, 7 Mar 2008 14:47:48 +0000
Subject: [PATCH] 	* fhandler_socket.cc (fhandler_socket::sendto): Never
 send more than 	64K.  Add comment to explain why. 
 (fhandler_socket::sendmsg): Ditto.

---
 winsup/cygwin/ChangeLog          |  6 ++++++
 winsup/cygwin/fhandler_socket.cc | 23 +++++++++++++++++------
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index dd795bd04..4e6514297 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,9 @@
+2008-03-07  Corinna Vinschen  <corinna@vinschen.de>
+
+	* fhandler_socket.cc (fhandler_socket::sendto): Never send more than
+	64K.  Add comment to explain why.
+	(fhandler_socket::sendmsg): Ditto.
+
 2008-03-07  Corinna Vinschen  <corinna@vinschen.de>
 
 	* Makefile.in (DLL_OFILES): Add tls_pbuf.o.
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index 07d042df8..33f8ddf7e 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -1393,7 +1393,13 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags,
   if (to && !get_inet_addr (to, tolen, &sst, &tolen))
     return SOCKET_ERROR;
 
-  WSABUF wsabuf = { len, (char *) ptr };
+  /* Never write more than 64K at once to workaround a problem with
+     Winsock, which creates a temporary buffer with the total incoming
+     buffer size and copies the whole content over, regardless of
+     the size of the internal send buffer.  A buffer full condition
+     is only recognized in subsequent calls and, if len is big enough,
+     the call even might fail with an out-of-memory condition. */
+  WSABUF wsabuf = { len > 65536 ? 65536 : len, (char *) ptr };
   return send_internal (&wsabuf, 1, flags,
 			(to ? (const struct sockaddr *) &sst : NULL), tolen);
 }
@@ -1411,12 +1417,17 @@ fhandler_socket::sendmsg (const struct msghdr *msg, int flags)
     }
 
   WSABUF wsabuf[msg->msg_iovlen];
-  WSABUF *wsaptr = wsabuf + msg->msg_iovlen;
-  const struct iovec *iovptr = msg->msg_iov + msg->msg_iovlen;
-  while (--wsaptr >= wsabuf)
+  WSABUF *wsaptr = wsabuf;
+  const struct iovec *iovptr = msg->msg_iov;
+  size_t total = 0;
+  for (int i = 0; i < msg->msg_iovlen && total < 65536; ++i)
     {
-      wsaptr->len = (--iovptr)->iov_len;
-      wsaptr->buf = (char *) iovptr->iov_base;
+      if (total + iovptr->iov_len > 65536) /* See above. */
+	wsaptr->len = 65536 - total;
+      else
+	wsaptr->len = iovptr->iov_len;
+      total += wsaptr->len;
+      (wsaptr++)->buf = (char *) (iovptr++)->iov_base;
     }
 
   return send_internal (wsabuf, msg->msg_iovlen, flags,