OSDN Git Service

* autoload.cc (WSAIoctl): Reintroduce.
authorcorinna <corinna>
Tue, 20 Jan 2009 11:16:59 +0000 (11:16 +0000)
committercorinna <corinna>
Tue, 20 Jan 2009 11:16:59 +0000 (11:16 +0000)
(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.

winsup/cygwin/ChangeLog
winsup/cygwin/autoload.cc
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_socket.cc
winsup/cygwin/include/cygwin/socket.h
winsup/cygwin/wincap.cc
winsup/cygwin/wincap.h

index 50f25fe..efbaffb 100644 (file)
@@ -1,3 +1,33 @@
+2009-01-20  Corinna Vinschen  <corinna@vinschen.de>
+
+       * 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  <corinna@vinschen.de>
 
        * mmap.cc (mmap64): Fix condition checking if anonymous mapping beyond
index e69a332..67f13b6 100644 (file)
@@ -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)
index c98a7d5..9d7cbd9 100644 (file)
@@ -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);
index dfaa6b1..89a1623 100644 (file)
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #define USE_SYS_TYPES_FD_SET
 #include <winsock2.h>
+#include <mswsock.h>
 #include <iphlpapi.h>
 #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);
-
-  bool waitall = (flags & MSG_WAITALL);
-  flags &= (MSG_OOB | MSG_PEEK | MSG_DONTROUTE);
+  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 = (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
index 3111e9d..f521f0a 100644 (file)
@@ -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) \
index 646e3dc..9fc2b21 100644 (file)
@@ -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));
index 038bf0b..7035275 100644 (file)
@@ -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
 };