diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 50f25fee2..efbaffb9f 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,33 @@ +2009-01-20 Corinna Vinschen + + * autoload.cc (WSAIoctl): Reintroduce. + (WSASendMsg): Define. + * fhandler.h (class fhandler_socket): Change definition of recv_internal + and send_internal to take WSAMSG pointer as parameter. + * fhandler_socket.cc (WSAID_WSARECVMSG): Define. + (LPFN_WSARECVMSG): Define. + (WSASendMsg): Declare. + (get_ext_funcptr): New function to fetch address of WSARecvMsg. + (fhandler_socket::recv_internal): Take just a LPWSAMSG parameter. + Change code accordingly. If control information is requested, + fetch address of WSARecvMsg and use that instead of WSARecvFrom. + (fhandler_socket::recvfrom): Change return type to ssize_t as + declared in fhandler.h. Accommodate changes to recv_internal. + (fhandler_socket::recvmsg): Ditto. Make sure that control information + is only requested if system, address family, and socket type support it. + (fhandler_socket::send_internal): Take just a LPWSAMSG parameter + and the flags. Change code accordingly. If control information is + provided, use WSASendMsg instead of WSASendTo. + (fhandler_socket::sendto): Drop useless comment. Accommodate changes + to send_internal. + (fhandler_socket::sendmsg): Ditto. Make sure that control information + is only provided if system, address family, and socket type support it. + * wincap.h (wincaps::has_recvmsg): New element. + (wincaps::has_sendmsg): New element + * wincap.cc: Implement above elements throughout. + * include/cygwin/socket.h (CMSG_ALIGN): Phrase in terms of alignment + of type struct cmsghdr. + 2009-01-17 Corinna Vinschen * mmap.cc (mmap64): Fix condition checking if anonymous mapping beyond diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index e69a33222..67f13b60a 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -389,7 +389,9 @@ LoadDLLfunc (WSAAsyncSelect, 16, ws2_32) LoadDLLfunc (WSAEnumNetworkEvents, 12, ws2_32) LoadDLLfunc (WSAEventSelect, 12, ws2_32) LoadDLLfunc (WSAGetLastError, 0, ws2_32) +LoadDLLfunc (WSAIoctl, 36, ws2_32) LoadDLLfunc (WSARecvFrom, 36, ws2_32) +LoadDLLfunc (WSASendMsg, 24, ws2_32) LoadDLLfunc (WSASendTo, 36, ws2_32) LoadDLLfunc (WSASetLastError, 4, ws2_32) // LoadDLLfunc (WSAStartup, 8, ws2_32) diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index c98a7d533..9d7cbd9f3 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -483,16 +483,13 @@ class fhandler_socket: public fhandler_base int open (int flags, mode_t mode = 0); ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1); - inline ssize_t recv_internal (struct _WSABUF *wsabuf, DWORD wsacnt, - DWORD flags, - struct sockaddr *from, int *fromlen); + inline ssize_t recv_internal (struct _WSAMSG *wsamsg); ssize_t recvfrom (void *ptr, size_t len, int flags, struct sockaddr *from, int *fromlen); ssize_t recvmsg (struct msghdr *msg, int flags); ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1); - inline ssize_t send_internal (struct _WSABUF *wsabuf, DWORD wsacnt, int flags, - const struct sockaddr *to, int tolen); + inline ssize_t send_internal (struct _WSAMSG *wsamsg, int flags); ssize_t sendto (const void *ptr, size_t len, int flags, const struct sockaddr *to, int tolen); ssize_t sendmsg (const struct msghdr *msg, int flags); diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index dfaa6b1c8..89a162361 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -19,6 +19,7 @@ #include #define USE_SYS_TYPES_FD_SET #include +#include #include #include "cygerrno.h" #include "security.h" @@ -1277,16 +1278,52 @@ fhandler_socket::readv (const struct iovec *const iov, const int iovcnt, return recvmsg (&msg, 0); } +extern "C" { +#define WSAID_WSARECVMSG \ + {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}; +typedef int (WSAAPI *LPFN_WSARECVMSG)(SOCKET,LPWSAMSG,LPDWORD,LPWSAOVERLAPPED, + LPWSAOVERLAPPED_COMPLETION_ROUTINE); +int WSAAPI WSASendMsg(SOCKET,LPWSAMSG,DWORD,LPDWORD, LPWSAOVERLAPPED, + LPWSAOVERLAPPED_COMPLETION_ROUTINE); +}; + +/* There's no DLL which exports the symbol WSARecvMsg. One has to call + WSAIoctl as below to fetch the function pointer. Why on earth did the + MS developers decide not to export a normal symbol for these extension + functions? */ +inline int +get_ext_funcptr (SOCKET sock, void *funcptr) +{ + DWORD bret; + const GUID guid = WSAID_WSARECVMSG; + return WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, + (void *) &guid, sizeof (GUID), funcptr, sizeof (void *), + &bret, NULL, NULL); +} + inline ssize_t -fhandler_socket::recv_internal (WSABUF *wsabuf, DWORD wsacnt, DWORD flags, - struct sockaddr *from, int *fromlen) +fhandler_socket::recv_internal (LPWSAMSG wsamsg) { ssize_t res = 0; DWORD ret = 0, wret; - int evt_mask = FD_READ | ((flags & MSG_OOB) ? FD_OOB : 0); + int evt_mask = FD_READ | ((wsamsg->dwFlags & MSG_OOB) ? FD_OOB : 0); + LPWSABUF wsabuf = wsamsg->lpBuffers; + ULONG wsacnt = wsamsg->dwBufferCount; + bool use_recvmsg = false; + static LPFN_WSARECVMSG WSARecvMsg; - bool waitall = (flags & MSG_WAITALL); - flags &= (MSG_OOB | MSG_PEEK | MSG_DONTROUTE); + bool waitall = (wsamsg->dwFlags & MSG_WAITALL); + wsamsg->dwFlags &= (MSG_OOB | MSG_PEEK | MSG_DONTROUTE); + if (wsamsg->Control.len > 0) + { + if (!WSARecvMsg + && get_ext_funcptr (get_socket (), &WSARecvMsg) == SOCKET_ERROR) + { + set_winsock_errno (); + return SOCKET_ERROR; + } + use_recvmsg = true; + } if (waitall) { if (get_socket_type () != SOCK_STREAM) @@ -1295,7 +1332,7 @@ fhandler_socket::recv_internal (WSABUF *wsabuf, DWORD wsacnt, DWORD flags, set_winsock_errno (); return SOCKET_ERROR; } - if (is_nonblocking () || (flags & (MSG_OOB | MSG_PEEK))) + if (is_nonblocking () || (wsamsg->dwFlags & (MSG_OOB | MSG_PEEK))) waitall = false; } @@ -1305,8 +1342,12 @@ fhandler_socket::recv_internal (WSABUF *wsabuf, DWORD wsacnt, DWORD flags, while (!(res = wait_for_events (evt_mask | FD_CLOSE)) || saw_shutdown_read ()) { - res = WSARecvFrom (get_socket (), wsabuf, wsacnt, &wret, - &flags, from, fromlen, NULL, NULL); + if (use_recvmsg) + res = WSARecvMsg (get_socket (), wsamsg, &wret, NULL, NULL); + else + res = WSARecvFrom (get_socket (), wsabuf, wsacnt, &wret, + &wsamsg->dwFlags, wsamsg->name, &wsamsg->namelen, + NULL, NULL); if (!res) { ret += wret; @@ -1353,32 +1394,34 @@ fhandler_socket::recv_internal (WSABUF *wsabuf, DWORD wsacnt, DWORD flags, return ret; } -int +ssize_t fhandler_socket::recvfrom (void *ptr, size_t len, int flags, struct sockaddr *from, int *fromlen) { WSABUF wsabuf = { len, (char *) ptr }; - return recv_internal (&wsabuf, 1, flags, from, fromlen); + WSAMSG wsamsg = { from, from && fromlen ? *fromlen : 0, + &wsabuf, 1, + { 0, NULL}, + flags }; + ssize_t ret = recv_internal (&wsamsg); + if (fromlen) + *fromlen = wsamsg.namelen; + return ret; } -int +ssize_t fhandler_socket::recvmsg (struct msghdr *msg, int flags) { - if (CYGWIN_VERSION_CHECK_FOR_USING_ANCIENT_MSGHDR) - ((struct OLD_msghdr *) msg)->msg_accrightslen = 0; - else + /* TODO: Descriptor passing on AF_LOCAL sockets. */ + + /* Disappointing but true: Even if WSARecvMsg is supported, it's only + supported for datagram and raw sockets. */ + if (!wincap.has_recvmsg () || get_socket_type () == SOCK_STREAM + || get_addr_family () == AF_LOCAL) { msg->msg_controllen = 0; - msg->msg_flags = 0; - } - if (get_addr_family () == AF_LOCAL) - { - /* On AF_LOCAL sockets the (fixed-size) name of the shared memory - area used for descriptor passing is transmitted first. - If this string is empty, no descriptors are passed and we can - go ahead recv'ing the normal data blocks. Otherwise start - special handling for descriptor passing. */ - /*TODO*/ + if (!CYGWIN_VERSION_CHECK_FOR_USING_ANCIENT_MSGHDR) + msg->msg_flags = 0; } WSABUF wsabuf[msg->msg_iovlen]; @@ -1389,11 +1432,19 @@ fhandler_socket::recvmsg (struct msghdr *msg, int flags) wsaptr->len = (--iovptr)->iov_len; wsaptr->buf = (char *) iovptr->iov_base; } - - struct sockaddr *from = (struct sockaddr *) msg->msg_name; - int *fromlen = from ? &msg->msg_namelen : NULL; - - return recv_internal (wsabuf, msg->msg_iovlen, flags, from, fromlen); + WSAMSG wsamsg = { (struct sockaddr *) msg->msg_name, msg->msg_namelen, + wsabuf, msg->msg_iovlen, + { msg->msg_controllen, (char *) msg->msg_control }, + flags }; + ssize_t ret = recv_internal (&wsamsg); + if (ret >= 0) + { + msg->msg_namelen = wsamsg.namelen; + msg->msg_controllen = wsamsg.Control.len; + if (!CYGWIN_VERSION_CHECK_FOR_USING_ANCIENT_MSGHDR) + msg->msg_flags = wsamsg.dwFlags; + } + return ret; } int @@ -1415,26 +1466,35 @@ fhandler_socket::writev (const struct iovec *const iov, const int iovcnt, } inline ssize_t -fhandler_socket::send_internal (struct _WSABUF *wsabuf, DWORD wsacnt, int flags, - const struct sockaddr *to, int tolen) +fhandler_socket::send_internal (struct _WSAMSG *wsamsg, int flags) { int res = 0; DWORD ret = 0, err = 0, sum = 0, off = 0; WSABUF buf; + bool use_sendmsg = false; - for (DWORD i = 0; i < wsacnt; off >= wsabuf[i].len && (++i, off = 0)) + if (wsamsg->Control.len > 0) + use_sendmsg = true; + for (DWORD i = 0; i < wsamsg->dwBufferCount; + off >= wsamsg->lpBuffers[i].len && (++i, off = 0)) { - buf.buf = wsabuf[i].buf + off; - buf.len = wsabuf[i].len - off; + buf.buf = wsamsg->lpBuffers[i].buf + off; + buf.len = wsamsg->lpBuffers[i].len - off; if (buf.len > 65536) /* See KB 823764 */ buf.len = 65536; do { - if ((res = WSASendTo (get_socket (), &buf, 1, &ret, - flags & (MSG_OOB | MSG_DONTROUTE), to, tolen, - NULL, NULL)) - && (err = WSAGetLastError ()) == WSAEWOULDBLOCK) + if (use_sendmsg) + res = WSASendMsg (get_socket (), wsamsg, + flags & (MSG_OOB | MSG_DONTROUTE), &ret, + NULL, NULL); + else + res = WSASendTo (get_socket (), &buf, 1, &ret, + flags & (MSG_OOB | MSG_DONTROUTE), + wsamsg->name, wsamsg->namelen, + NULL, NULL); + if (res && (err = WSAGetLastError ()) == WSAEWOULDBLOCK) { LOCK_EVENTS; wsock_events->events &= ~FD_WRITE; @@ -1467,7 +1527,7 @@ fhandler_socket::send_internal (struct _WSABUF *wsabuf, DWORD wsacnt, int flags, if (get_errno () == ESHUTDOWN && get_socket_type () == SOCK_STREAM) { set_errno (EPIPE); - if (! (flags & MSG_NOSIGNAL)) + if (!(flags & MSG_NOSIGNAL)) raise (SIGPIPE); } } @@ -1484,28 +1544,18 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, if (to && !get_inet_addr (to, tolen, &sst, &tolen)) return SOCKET_ERROR; - /* 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, (char *) ptr }; - return send_internal (&wsabuf, 1, flags, - (to ? (const struct sockaddr *) &sst : NULL), tolen); + WSAMSG wsamsg = { to ? (struct sockaddr *) &sst : NULL, tolen, + &wsabuf, 1, + { 0, NULL}, + 0 }; + return send_internal (&wsamsg, flags); } int fhandler_socket::sendmsg (const struct msghdr *msg, int flags) { - 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*/ - } + /* TODO: Descriptor passing on AF_LOCAL sockets. */ WSABUF wsabuf[msg->msg_iovlen]; WSABUF *wsaptr = wsabuf; @@ -1515,9 +1565,17 @@ fhandler_socket::sendmsg (const struct msghdr *msg, int flags) wsaptr->len = iovptr->iov_len; (wsaptr++)->buf = (char *) (iovptr++)->iov_base; } - - return send_internal (wsabuf, msg->msg_iovlen, flags, - (struct sockaddr *) msg->msg_name, msg->msg_namelen); + WSAMSG wsamsg = { (struct sockaddr *) msg->msg_name, msg->msg_namelen, + wsabuf, msg->msg_iovlen, + /* Disappointing but true: Even if WSASendMsg is + supported, it's only supported for datagram and + raw sockets. */ + { !wincap.has_sendmsg () + || get_socket_type () == SOCK_STREAM + || get_addr_family () == AF_LOCAL + ? 0 : msg->msg_controllen, (char *) msg->msg_control }, + 0 }; + return send_internal (&wsamsg, flags); } int diff --git a/winsup/cygwin/include/cygwin/socket.h b/winsup/cygwin/include/cygwin/socket.h index 3111e9dd5..f521f0ad8 100644 --- a/winsup/cygwin/include/cygwin/socket.h +++ b/winsup/cygwin/include/cygwin/socket.h @@ -80,7 +80,8 @@ struct cmsghdr }; #define CMSG_ALIGN(len) \ - (((len) + sizeof (size_t) - 1) & ~(sizeof (size_t) - 1)) + (((len) + __alignof__ (struct cmsghdr) - 1) \ + & ~(__alignof__ (struct cmsghdr) - 1)) #define CMSG_LEN(len) \ (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) #define CMSG_SPACE(len) \ diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 646e3dc80..9fc2b211f 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -51,6 +51,8 @@ wincaps wincap_unknown __attribute__((section (".cygwin_dll_common"), shared)) = has_restricted_stack_args:false, has_transactions:false, ts_has_dep_problem:false, + has_recvmsg:false, + has_sendmsg:false, }; wincaps wincap_nt4 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -84,6 +86,8 @@ wincaps wincap_nt4 __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_stack_args:false, has_transactions:false, ts_has_dep_problem:false, + has_recvmsg:false, + has_sendmsg:false, }; wincaps wincap_nt4sp4 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -117,6 +121,8 @@ wincaps wincap_nt4sp4 __attribute__((section (".cygwin_dll_common"), shared)) = has_restricted_stack_args:false, has_transactions:false, ts_has_dep_problem:false, + has_recvmsg:false, + has_sendmsg:false, }; wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -150,6 +156,8 @@ wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_stack_args:false, has_transactions:false, ts_has_dep_problem:false, + has_recvmsg:false, + has_sendmsg:false, }; wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -183,6 +191,8 @@ wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = has_restricted_stack_args:false, has_transactions:false, ts_has_dep_problem:false, + has_recvmsg:false, + has_sendmsg:false, }; wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -216,6 +226,8 @@ wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_stack_args:false, has_transactions:false, ts_has_dep_problem:false, + has_recvmsg:true, + has_sendmsg:false, }; wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -249,6 +261,8 @@ wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_stack_args:false, has_transactions:false, ts_has_dep_problem:false, + has_recvmsg:true, + has_sendmsg:false, }; wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -282,6 +296,8 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_stack_args:false, has_transactions:false, ts_has_dep_problem:false, + has_recvmsg:true, + has_sendmsg:false, }; wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -315,6 +331,8 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_stack_args:true, has_transactions:false, ts_has_dep_problem:false, + has_recvmsg:true, + has_sendmsg:false, }; wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -348,6 +366,8 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_stack_args:false, has_transactions:true, ts_has_dep_problem:false, + has_recvmsg:true, + has_sendmsg:true, }; wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index 038bf0b59..703527526 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -43,6 +43,8 @@ struct wincaps unsigned has_restricted_stack_args : 1; unsigned has_transactions : 1; unsigned ts_has_dep_problem : 1; + unsigned has_recvmsg : 1; + unsigned has_sendmsg : 1; }; class wincapc @@ -92,6 +94,8 @@ public: bool IMPLEMENT (has_restricted_stack_args) bool IMPLEMENT (has_transactions) bool IMPLEMENT (ts_has_dep_problem) + bool IMPLEMENT (has_recvmsg) + bool IMPLEMENT (has_sendmsg) #undef IMPLEMENT };