From 4d147a03bdf2bdbec4e95f9f8a870568a9b8d007 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 4 Sep 2002 09:39:35 +0000 Subject: * fhandler.h (fhandler_socket::read): Remove method. (fhandler_socket::write): Ditto. (fhandler_socket::readv): New method. (fhandler_socket::writev): Ditto. (fhandler_socket::recvmsg): Add new optional argument. (fhandler_socket::sendmsg): Ditto. * fhandler.cc (fhandler_socket::read): Remove method. (fhandler_socket::write): Ditto. (fhandler_socket::readv): New method. (fhandler_socket::writev): Ditto. (fhandler_socket::recvmsg): Use win32's scatter/gather IO where possible. (fhandler_socket::sendmsg): Ditto. * net.cc (cygwin_recvmsg): Check the msghdr's iovec fields. (cygwin_sendmsg): Ditto. Add omitted sigframe. --- winsup/cygwin/ChangeLog | 18 ++ winsup/cygwin/fhandler.h | 8 +- winsup/cygwin/fhandler_socket.cc | 395 ++++++++++++++++++++++++++++----------- winsup/cygwin/net.cc | 16 +- 4 files changed, 324 insertions(+), 113 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 6840ef8..0c309e2 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,21 @@ +2002-09-03 Conrad Scott + + * fhandler.h (fhandler_socket::read): Remove method. + (fhandler_socket::write): Ditto. + (fhandler_socket::readv): New method. + (fhandler_socket::writev): Ditto. + (fhandler_socket::recvmsg): Add new optional argument. + (fhandler_socket::sendmsg): Ditto. + * fhandler.cc (fhandler_socket::read): Remove method. + (fhandler_socket::write): Ditto. + (fhandler_socket::readv): New method. + (fhandler_socket::writev): Ditto. + (fhandler_socket::recvmsg): Use win32's scatter/gather IO where + possible. + (fhandler_socket::sendmsg): Ditto. + * net.cc (cygwin_recvmsg): Check the msghdr's iovec fields. + (cygwin_sendmsg): Ditto. Add omitted sigframe. + 2002-09-02 Kazuhiro Fujieda * cygwin.din: Revert exporting new wchar functions. diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 786c2ad..a1e5304 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -400,15 +400,15 @@ class fhandler_socket: public fhandler_base int getsockname (struct sockaddr *name, int *namelen); int getpeername (struct sockaddr *name, int *namelen); - int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3))); + ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1); int recvfrom (void *ptr, size_t len, int flags, struct sockaddr *from, int *fromlen); - int recvmsg (struct msghdr *msg, int flags); + int recvmsg (struct msghdr *msg, int flags, ssize_t tot = -1); - int write (const void *ptr, size_t len); + ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1); int sendto (const void *ptr, size_t len, int flags, const struct sockaddr *to, int tolen); - int sendmsg (const struct msghdr *msg, int flags); + int sendmsg (const struct msghdr *msg, int flags, ssize_t tot = -1); int ioctl (unsigned int cmd, void *); int fcntl (int cmd, void *); diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 94866e3..f0a8195 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -660,60 +660,69 @@ fhandler_socket::getpeername (struct sockaddr *name, int *namelen) return res; } -int __stdcall -fhandler_socket::read (void *ptr, size_t len) +int +fhandler_socket::readv (const struct iovec *const iov, const int iovcnt, + ssize_t tot) { - return recvfrom (ptr, len, 0, NULL, NULL); + struct msghdr msg = + { + msg_name: NULL, + msg_namelen: 0, + msg_iov: (struct iovec *) iov, // const_cast + msg_iovlen: iovcnt, + msg_accrights: NULL, + msg_accrightslen: 0 + }; + + return recvmsg (&msg, 0, tot); } int fhandler_socket::recvfrom (void *ptr, size_t len, int flags, struct sockaddr *from, int *fromlen) { - int res = -1; - wsock_event wsock_evt; - LPWSAOVERLAPPED ovr; + int res; + DWORD ret; flags &= MSG_WINMASK; - if (is_nonblocking () || !(ovr = wsock_evt.prepare ())) - { - debug_printf ("Fallback to winsock 1 recvfrom call"); - if ((res = ::recvfrom (get_socket (), (char *) ptr, len, flags, from, - fromlen)) - == SOCKET_ERROR) - { - set_winsock_errno (); - res = -1; - } - } + if (!winsock2_active) + ret = res = ::recvfrom (get_socket (), + (char *) ptr, len, flags, + from, fromlen); else { WSABUF wsabuf = { len, (char *) ptr }; - DWORD ret = 0; - if (WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *)&flags, - from, fromlen, ovr, NULL) != SOCKET_ERROR) - res = ret; - else if ((res = WSAGetLastError ()) != WSA_IO_PENDING) + + if (is_nonblocking ()) + res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *) &flags, + from, fromlen, + NULL, NULL); + else { - set_winsock_errno (); - res = -1; + wsock_event wsock_evt; + res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *) &flags, + from, fromlen, + wsock_evt.prepare (), NULL); + + if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) + ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); } - else if ((res = wsock_evt.wait (get_socket (), (DWORD *)&flags)) == -1) - set_winsock_errno (); } + if (res == SOCKET_ERROR) + { + res = -1; + set_winsock_errno (); + } + else + res = ret; + return res; } int -fhandler_socket::recvmsg (struct msghdr *msg, int flags) +fhandler_socket::recvmsg (struct msghdr *msg, int flags, ssize_t tot) { - int res = -1; - int nb; - size_t tot = 0; - char *buf, *p; - struct iovec *iov = msg->msg_iov; - if (get_addr_family () == AF_LOCAL) { /* On AF_LOCAL sockets the (fixed-size) name of the shared memory @@ -723,120 +732,294 @@ fhandler_socket::recvmsg (struct msghdr *msg, int flags) special handling for descriptor passing. */ /*TODO*/ } - for (int i = 0; i < msg->msg_iovlen; ++i) - tot += iov[i].iov_len; - buf = (char *) alloca (tot); - if (tot != 0 && buf == NULL) + + struct iovec *const iov = msg->msg_iov; + const int iovcnt = msg->msg_iovlen; + + int res; + + if (!winsock2_active) { - set_errno (ENOMEM); - return -1; + if (iovcnt == 1) + res = recvfrom (iov->iov_base, iov->iov_len, flags, + (struct sockaddr *) msg->msg_name, + &msg->msg_namelen); + else + { + if (tot == -1) // i.e. if not pre-calculated by the caller. + { + tot = 0; + const struct iovec *iovptr = iov + iovcnt; + do + { + iovptr -= 1; + tot += iovptr->iov_len; + } + while (iovptr != iov); + } + + char *buf = (char *) alloca (tot); + + if (!buf) + { + set_errno (ENOMEM); + res = -1; + } + else + { + res = recvfrom (buf, tot, flags, + (struct sockaddr *) msg->msg_name, + &msg->msg_namelen); + + const struct iovec *iovptr = iov; + int nbytes = res; + + while (nbytes > 0) + { + const int frag = min (nbytes, (ssize_t) iovptr->iov_len); + memcpy (iovptr->iov_base, buf, frag); + buf += frag; + iovptr += 1; + nbytes -= frag; + } + } + } } - nb = res = recvfrom (buf, tot, flags, (struct sockaddr *) msg->msg_name, - (int *) &msg->msg_namelen); - p = buf; - while (nb > 0) + else { - ssize_t cnt = iov->iov_len; - if (nb < cnt) - cnt = nb; - memcpy (iov->iov_base, p, cnt); - p += cnt; - nb -= cnt; - ++iov; + WSABUF wsabuf[iovcnt]; + + { + const struct iovec *iovptr = iov + iovcnt; + WSABUF *wsaptr = wsabuf + iovcnt; + do + { + iovptr -= 1; + wsaptr -= 1; + wsaptr->len = iovptr->iov_len; + wsaptr->buf = (char *) iovptr->iov_base; + } + while (wsaptr != wsabuf); + } + + DWORD ret; + + if (is_nonblocking ()) + res = WSARecvFrom (get_socket (), + wsabuf, iovcnt, &ret, (DWORD *) &flags, + (struct sockaddr *) msg->msg_name, + &msg->msg_namelen, + NULL, NULL); + else + { + wsock_event wsock_evt; + res = WSARecvFrom (get_socket (), + wsabuf, iovcnt, &ret, (DWORD *) &flags, + (struct sockaddr *) msg->msg_name, + &msg->msg_namelen, + wsock_evt.prepare (), NULL); + + if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) + ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); + } + + if (res == SOCKET_ERROR) + { + res = -1; + set_winsock_errno (); + } + else + res = ret; } + return res; } int -fhandler_socket::write (const void *ptr, size_t len) +fhandler_socket::writev (const struct iovec *const iov, const int iovcnt, + ssize_t tot) { - return sendto (ptr, len, 0, NULL, 0); + struct msghdr msg = + { + msg_name: NULL, + msg_namelen: 0, + msg_iov: (struct iovec *) iov, // const_cast + msg_iovlen: iovcnt, + msg_accrights: NULL, + msg_accrightslen: 0 + }; + + return sendmsg (&msg, 0, tot); } int fhandler_socket::sendto (const void *ptr, size_t len, int flags, const struct sockaddr *to, int tolen) { - int res = -1; - wsock_event wsock_evt; - LPWSAOVERLAPPED ovr; sockaddr_in sin; if (to && !get_inet_addr (to, tolen, &sin, &tolen)) return -1; - if (is_nonblocking () || !(ovr = wsock_evt.prepare ())) - { - debug_printf ("Fallback to winsock 1 sendto call"); - if ((res = ::sendto (get_socket (), (const char *) ptr, len, - flags & MSG_WINMASK, - (to ? (sockaddr *) &sin : NULL), - tolen)) == SOCKET_ERROR) - { - set_winsock_errno (); - res = -1; - } - } + int res; + DWORD ret; + + if (!winsock2_active) + res = ::sendto (get_socket (), (const char *) ptr, len, + flags & MSG_WINMASK, + (to ? (const struct sockaddr *) &sin : NULL), tolen); else { WSABUF wsabuf = { len, (char *) ptr }; - DWORD ret = 0; - if (WSASendTo (get_socket (), &wsabuf, 1, &ret, - (DWORD)(flags & MSG_WINMASK), - (to ? (sockaddr *) &sin : NULL), - tolen, - ovr, NULL) != SOCKET_ERROR) - res = ret; - else if ((res = WSAGetLastError ()) != WSA_IO_PENDING) + + if (is_nonblocking ()) + res = WSASendTo (get_socket (), &wsabuf, 1, &ret, + flags & MSG_WINMASK, + (to ? (const struct sockaddr *) &sin : NULL), tolen, + NULL, NULL); + else { - set_winsock_errno (); - res = -1; + wsock_event wsock_evt; + res = WSASendTo (get_socket (), &wsabuf, 1, &ret, + flags & MSG_WINMASK, + (to ? (const struct sockaddr *) &sin : NULL), tolen, + wsock_evt.prepare (), NULL); + + if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) + ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); } - else if ((res = wsock_evt.wait (get_socket (), (DWORD *)&flags)) == -1) - set_winsock_errno (); } + if (res == SOCKET_ERROR) + { + res = -1; + set_winsock_errno (); + } + else + res = ret; + /* Special handling for SIGPIPE */ - if (get_errno () == ESHUTDOWN) + if (res == -1 && get_errno () == ESHUTDOWN) { set_errno (EPIPE); if (! (flags & MSG_NOSIGNAL)) _raise (SIGPIPE); } + return res; } int -fhandler_socket::sendmsg (const struct msghdr *msg, int flags) +fhandler_socket::sendmsg (const struct msghdr *msg, int flags, ssize_t tot) { - size_t tot = 0; - char *buf, *p; - struct iovec *iov = msg->msg_iov; - - if (get_addr_family () == AF_LOCAL) - { - /* For AF_LOCAL/AF_UNIX sockets, if descriptors are given, start - the special handling for descriptor passing. Otherwise just - transmit an empty string to tell the receiver that no - descriptor passing is done. */ + if (get_addr_family () == AF_LOCAL) + { + /* For AF_LOCAL/AF_UNIX sockets, if descriptors are given, start + the special handling for descriptor passing. Otherwise just + transmit an empty string to tell the receiver that no + descriptor passing is done. */ /*TODO*/ - } - for(int i = 0; i < msg->msg_iovlen; ++i) - tot += iov[i].iov_len; - buf = (char *) alloca (tot); - if (tot != 0 && buf == NULL) - { - set_errno (ENOMEM); - return -1; - } - p = buf; - for (int i = 0; i < msg->msg_iovlen; ++i) + } + + struct iovec *const iov = msg->msg_iov; + const int iovcnt = msg->msg_iovlen; + + int res; + + if (!winsock2_active) + { + if (iovcnt == 1) + res = sendto (iov->iov_base, iov->iov_len, flags, + (struct sockaddr *) msg->msg_name, + msg->msg_namelen); + else + { + if (tot == -1) // i.e. if not pre-calculated by the caller. + { + tot = 0; + const struct iovec *iovptr = iov + iovcnt; + do + { + iovptr -= 1; + tot += iovptr->iov_len; + } + while (iovptr != iov); + } + + char *const buf = (char *) alloca (tot); + + if (!buf) + { + set_errno (ENOMEM); + res = -1; + } + else + { + char *bufptr = buf; + const struct iovec *iovptr = iov; + int nbytes = tot; + + while (nbytes != 0) + { + const int frag = min (nbytes, (ssize_t) iovptr->iov_len); + memcpy (bufptr, iovptr->iov_base, frag); + bufptr += frag; + iovptr += 1; + nbytes -= frag; + } + + res = sendto (buf, tot, flags, + (struct sockaddr *) msg->msg_name, + msg->msg_namelen); + } + } + } + else + { + WSABUF wsabuf[iovcnt]; + { - memcpy (p, iov[i].iov_base, iov[i].iov_len); - p += iov[i].iov_len; + const struct iovec *iovptr = iov + iovcnt; + WSABUF *wsaptr = wsabuf + iovcnt; + do + { + iovptr -= 1; + wsaptr -= 1; + wsaptr->len = iovptr->iov_len; + wsaptr->buf = (char *) iovptr->iov_base; + } + while (wsaptr != wsabuf); } - return sendto (buf, tot, flags, (struct sockaddr *) msg->msg_name, - msg->msg_namelen); + + DWORD ret; + + if (is_nonblocking ()) + res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, flags, + (struct sockaddr *) msg->msg_name, + msg->msg_namelen, + NULL, NULL); + else + { + wsock_event wsock_evt; + res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, flags, + (struct sockaddr *) msg->msg_name, + msg->msg_namelen, + wsock_evt.prepare (), NULL); + + if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) + ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); + } + + if (res == SOCKET_ERROR) + { + res = -1; + set_winsock_errno (); + } + else + res = ret; + } + + return res; } int diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index aa52a3c..7733d6e 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -2112,7 +2112,11 @@ cygwin_recvmsg (int fd, struct msghdr *msg, int flags) || !fh) res = -1; else - res = fh->recvmsg (msg, flags); + { + res = check_iovec_for_read (msg->msg_iov, msg->msg_iovlen); + if (res > 0) + res = fh->recvmsg (msg, flags, res); // res == iovec tot + } syscall_printf ("%d = recvmsg (%d, %p, %x)", res, fd, msg, flags); return res; @@ -2123,6 +2127,8 @@ extern "C" int cygwin_sendmsg (int fd, const struct msghdr *msg, int flags) { int res; + sigframe thisframe (mainthread); + fhandler_socket *fh = get (fd); if (__check_invalid_read_ptr_errno (msg, sizeof msg) @@ -2131,8 +2137,12 @@ cygwin_sendmsg (int fd, const struct msghdr *msg, int flags) (unsigned) msg->msg_namelen)) || !fh) res = -1; - else - res = fh->sendmsg (msg, flags); + else + { + res = check_iovec_for_write (msg->msg_iov, msg->msg_iovlen); + if (res > 0) + res = fh->sendmsg (msg, flags, res); // res == iovec tot + } syscall_printf ("%d = sendmsg (%d, %p, %x)", res, fd, msg, flags); return res; -- cgit v1.1