diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 425de1085..08013867f 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,11 @@ +2008-07-27 Corinna Vinschen + + * fhandler_socket.cc (fhandler_socket::send_internal): Send never more + then 64K bytes at once. For blocking sockets, loop until entire data + has been sent or an error occurs. + (fhandler_socket::sendto): Drop code which sends on 64K bytes. + (fhandler_socket::sendmsg): Ditto. + 2008-07-26 Christopher Faylor * fhandler_tty.cc (fhandler_pty_master::setup): Reorganize so that all diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index e770a7cb0..176838de8 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -1415,38 +1415,57 @@ fhandler_socket::send_internal (struct _WSABUF *wsabuf, DWORD wsacnt, int flags, const struct sockaddr *to, int tolen) { int res = 0; - DWORD ret = 0, err = 0; + DWORD ret = 0, err = 0, sum = 0, off = 0; + WSABUF buf; - do + for (DWORD i = 0; i < wsacnt; off >= wsabuf[i].len && (++i, off = 0)) { - if ((res = WSASendTo (get_socket (), wsabuf, wsacnt, &ret, - flags & (MSG_OOB | MSG_DONTROUTE), to, tolen, NULL, NULL)) - && (err = WSAGetLastError ()) == WSAEWOULDBLOCK) + buf.buf = wsabuf[i].buf + off; + buf.len = wsabuf[i].len - off; + if (buf.len > 65536) /* See KB 823764 */ + buf.len = 65536; + + do { - LOCK_EVENTS; - wsock_events->events &= ~FD_WRITE; - UNLOCK_EVENTS; + if ((res = WSASendTo (get_socket (), &buf, 1, &ret, + flags & (MSG_OOB | MSG_DONTROUTE), to, tolen, + NULL, NULL)) + && (err = WSAGetLastError ()) == WSAEWOULDBLOCK) + { + LOCK_EVENTS; + wsock_events->events &= ~FD_WRITE; + UNLOCK_EVENTS; + } } + while (res && err == WSAEWOULDBLOCK + && !(res = wait_for_events (FD_WRITE | FD_CLOSE))); + + if (!res) + { + off += ret; + sum += ret; + } + else if (is_nonblocking () || err != WSAEWOULDBLOCK) + break; } - while (res && err == WSAEWOULDBLOCK - && !(res = wait_for_events (FD_WRITE | FD_CLOSE))); - - if (res == SOCKET_ERROR) - set_winsock_errno (); - else - res = ret; - - /* Special handling for EPIPE and SIGPIPE. - - EPIPE is generated if the local end has been shut down on a connection - oriented socket. In this case the process will also receive a SIGPIPE - unless MSG_NOSIGNAL is set. */ - if (res == SOCKET_ERROR && get_errno () == ESHUTDOWN - && get_socket_type () == SOCK_STREAM) + + if (sum) + res = sum; + else if (res == SOCKET_ERROR) { - set_errno (EPIPE); - if (! (flags & MSG_NOSIGNAL)) - raise (SIGPIPE); + set_winsock_errno (); + + /* Special handling for EPIPE and SIGPIPE. + + EPIPE is generated if the local end has been shut down on a connection + oriented socket. In this case the process will also receive a SIGPIPE + unless MSG_NOSIGNAL is set. */ + if (get_errno () == ESHUTDOWN && get_socket_type () == SOCK_STREAM) + { + set_errno (EPIPE); + if (! (flags & MSG_NOSIGNAL)) + raise (SIGPIPE); + } } return res; @@ -1467,7 +1486,7 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, 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 }; + WSABUF wsabuf = { len, (char *) ptr }; return send_internal (&wsabuf, 1, flags, (to ? (const struct sockaddr *) &sst : NULL), tolen); } @@ -1487,14 +1506,9 @@ fhandler_socket::sendmsg (const struct msghdr *msg, int flags) WSABUF wsabuf[msg->msg_iovlen]; 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) + for (int i = 0; i < msg->msg_iovlen; ++i) { - if (total + iovptr->iov_len > 65536) /* See above. */ - wsaptr->len = 65536 - total; - else - wsaptr->len = iovptr->iov_len; - total += wsaptr->len; + wsaptr->len = iovptr->iov_len; (wsaptr++)->buf = (char *) (iovptr++)->iov_base; }