]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1566. [port] Support for the cmsg framework on Solaris and HP/UX.
authorMark Andrews <marka@isc.org>
Thu, 29 Jan 2004 04:39:19 +0000 (04:39 +0000)
committerMark Andrews <marka@isc.org>
Thu, 29 Jan 2004 04:39:19 +0000 (04:39 +0000)
                        This also solved the problem that match-destinations
                        for IPv6 addresses did not work on these systems.
                        [RT #10221]

CHANGES
acconfig.h
config.h.in
configure.in
lib/isc/unix/socket.c

diff --git a/CHANGES b/CHANGES
index e11ef1992eb797b420794eda282fa0582958e625..689040addd858f5d1545a40464d5dd592e22f40c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
 1567.  [bug]           B.ROOT-SERVERS.NET is now 192.228.79.201.
 
-1566.  [placeholder]   rt10221
+1566.  [port]          Support for the cmsg framework on Solaris and HP/UX.
+                       This also solved the problem that match-destinations
+                       for IPv6 addresses did not work on these systems.
+                       [RT #10221]
 
 1565.  [bug]           CD flag should be copied to outgoing queries unless
                        the query is under a secure entry point in which case
index 7e6fef6e747d1b7e19b560e6959679aef5ba45e0..7925cc3336ec4ca3de34df5caac6c87c54336708 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: acconfig.h,v 1.42 2004/01/07 05:48:14 marka Exp $ */
+/* $Id: acconfig.h,v 1.43 2004/01/29 04:39:18 marka Exp $ */
 
 /***
  *** This file is not to be included by any public header files, because
 /* define if you have the NET_RT_IFLIST sysctl variable and sys/sysctl.h */
 #undef HAVE_IFLIST_SYSCTL
 
-/* define if you need to #define _XPG4_2 before including sys/socket.h */
-#undef NEED_XPG4_2_BEFORE_SOCKET_H
-
-/* define if you need to #define _XOPEN_SOURCE_ENTENDED before including
- * sys/socket.h
- */
-#undef NEED_XSE_BEFORE_SOCKET_H
-
 /* define if chroot() is available */
 #undef HAVE_CHROOT
 
index 962324e5b11ca758e5174dded393abf31125099d..7b46e5e9d98b554ab234cf1aa85ac3c25a9b0ef0 100644 (file)
@@ -16,7 +16,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: config.h.in,v 1.57 2004/01/07 05:49:10 marka Exp $ */
+/* $Id: config.h.in,v 1.58 2004/01/29 04:39:18 marka Exp $ */
 
 /***
  *** This file is not to be included by any public header files, because
 /* define if you have the NET_RT_IFLIST sysctl variable and sys/sysctl.h */
 #undef HAVE_IFLIST_SYSCTL
 
-/* define if you need to #define _XPG4_2 before including sys/socket.h */
-#undef NEED_XPG4_2_BEFORE_SOCKET_H
-
-/* define if you need to #define _XOPEN_SOURCE_ENTENDED before including
- * sys/socket.h
- */
-#undef NEED_XSE_BEFORE_SOCKET_H
-
 /* define if chroot() is available */
 #undef HAVE_CHROOT
 
index 6085c10cdc957eb596fd85497b69d12d8787b319..07b1767ab90adbdecb64f67fc955ea90c689555e 100644 (file)
@@ -18,7 +18,7 @@ AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl
 esyscmd([sed "s/^/# /" COPYRIGHT])dnl
 AC_DIVERT_POP()dnl
 
-AC_REVISION($Revision: 1.350 $)
+AC_REVISION($Revision: 1.351 $)
 
 AC_INIT(lib/dns/name.c)
 AC_PREREQ(2.13)
@@ -204,14 +204,26 @@ if test "$ac_env_CFLAGS_set" != set -a "X$GCC" = "Xyes"; then
 fi
 
 #
-#      OSF 5.0: recv/send are only avaliable with -D_POSIX_PII_SOCKET or
-#      -D_XOPEN_SOURCE_EXTENDED.
+# OS dependent CC flags
 #
 case "$host" in
+       # OSF 5.0: recv/send are only avaliable with -D_POSIX_PII_SOCKET or
+       # -D_XOPEN_SOURCE_EXTENDED.
        *-dec-osf*)
                STD_CDEFINES="$STD_CDEFINES -D_POSIX_PII_SOCKET"
                CPPFLAGS="$CPPFLAGS -D_POSIX_PII_SOCKET"
                ;;
+       #HP-UX: need -D_XOPEN_SOURCE_EXTENDED and -lxnet for CMSG macros
+       *-hp-hpux*)
+               STD_CDEFINES="$STD_CDEFINES -D_XOPEN_SOURCE_EXTENDED"
+               CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE_EXTENDED"
+               LIBS="-lxnet $LIBS"
+               ;;
+       # Solaris: need -D_XPG4_2 and -D__EXTENSIONS__ for CMSG macros
+       *-solaris*)
+               STD_CDEFINES="$STD_CDEFINES -D_XPG4_2 -D__EXTENSIONS__"
+               CPPFLAGS="$CPPFLAGS -D_XPG4_2 -D__EXTENSIONS__"
+               ;;
 esac
 
 AC_HEADER_STDC
index c8fa9191700586513aaa74c8516f603e7320366e..ab57cb0cd9e95df663162584747cfa6b694120d9 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: socket.c,v 1.233 2004/01/26 23:33:32 marka Exp $ */
+/* $Id: socket.c,v 1.234 2004/01/29 04:39:19 marka Exp $ */
 
 #include <config.h>
 
@@ -126,35 +126,6 @@ typedef isc_event_t intev_t;
 #endif
 #endif
 
-/*
- * Check to see if we have even basic support for cracking messages from
- * the control data returned from/sent via recvmsg()/sendmsg().
- */
-#if defined(USE_CMSG) && (!defined(CMSG_LEN) || !defined(CMSG_SPACE))
-#undef USE_CMSG
-#endif
-
-/*
- * Determine the size of the control data buffer.
- */
-#if USE_CMSG
-
-#ifdef ISC_PLATFORM_HAVEIPV6
-#define CMSG_BUF_V6_SIZE (CMSG_SPACE(sizeof(struct in6_pktinfo)))
-#else
-#define CMSG_BUF_V6_SIZE 0
-#endif
-
-#ifdef SO_TIMESTAMP
-#define CMSG_BUF_TS_SIZE (CMSG_SPACE(sizeof(struct timeval)))
-#else
-#define CMSG_BUF_TS_SIZE 0
-#endif
-
-#define CMSG_BUF_SIZE (CMSG_BUF_V6_SIZE + CMSG_BUF_TS_SIZE)
-
-#endif /* USE_CMSG */
-
 /*
  * The number of times a send operation is repeated if the result is EINTR.
  */
@@ -199,6 +170,11 @@ struct isc_socket {
 #ifdef ISC_NET_RECVOVERFLOW
        unsigned char           overflow; /* used for MSG_TRUNC fake */
 #endif
+
+       char                    *recvcmsgbuf;
+       ISC_SOCKADDR_LEN_T      recvcmsgbuflen;
+       char                    *sendcmsgbuf;
+       ISC_SOCKADDR_LEN_T      sendcmsgbuflen;
 };
 
 #define SOCKET_MANAGER_MAGIC   ISC_MAGIC('I', 'O', 'm', 'g')
@@ -255,11 +231,9 @@ static void internal_recv(isc_task_t *, isc_event_t *);
 static void internal_send(isc_task_t *, isc_event_t *);
 static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *);
 static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *,
-                             struct msghdr *, char *cmsg,
-                             struct iovec *, size_t *);
+                             struct msghdr *, struct iovec *, size_t *);
 static void build_msghdr_recv(isc_socket_t *, isc_socketevent_t *,
-                             struct msghdr *, char *cmsg,
-                             struct iovec *, size_t *);
+                             struct msghdr *, struct iovec *, size_t *);
 
 #define SELECT_POKE_SHUTDOWN           (-1)
 #define SELECT_POKE_NOTHING            (-2)
@@ -472,6 +446,55 @@ make_nonblock(int fd) {
        return (ISC_R_SUCCESS);
 }
 
+#ifdef USE_CMSG
+/*
+ * Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
+ * In order to ensure as much portability as possible, we provide wrapper
+ * functions of these macros.
+ * Note that cmsg_space() could run slow on OSes that do not have
+ * CMSG_SPACE.
+ */
+static inline ISC_SOCKADDR_LEN_T
+cmsg_len(ISC_SOCKADDR_LEN_T len) {
+#ifdef CMSG_LEN
+       return (CMSG_LEN(len));
+#else
+       ISC_SOCKADDR_LEN_T hdrlen;
+
+       hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(NULL); /* XXX */
+       return (hdrlen + len);
+#endif
+}
+
+static inline ISC_SOCKADDR_LEN_T
+cmsg_space(ISC_SOCKADDR_LEN_T len) {
+#ifdef CMSG_SPACE
+       return (CMSG_SPACE(len));
+#else
+       struct msghdr msg;
+       struct cmsghdr *cmsgp;
+       /*
+        * XXX: The buffer length is an ad-hoc value, but should be enough
+        * in a practical sense.
+        */
+       char dummybuf[sizeof(struct cmsghdr) + 1024];
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_control = dummybuf;
+       msg.msg_controllen = sizeof(dummybuf);
+
+       cmsgp = (struct cmsghdr *)dummybuf;
+       cmsgp->cmsg_len = cmsg_len(len);
+
+       cmsgp = CMSG_NXTHDR(&msg, cmsgp);
+       if (cmsgp != NULL)
+               return ((void *)cmsgp - (void *)msg.msg_control);
+       else
+               return (0);
+#endif 
+}
+#endif /* USE_CMSG */
+
 /*
  * Process control messages received on a socket.
  */
@@ -580,8 +603,7 @@ process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) {
  */
 static void
 build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
-                 struct msghdr *msg, char *cmsg,
-                 struct iovec *iov, size_t *write_countp)
+                 struct msghdr *msg, struct iovec *iov, size_t *write_countp)
 {
        unsigned int iovcount;
        isc_buffer_t *buffer;
@@ -589,10 +611,6 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
        size_t write_count;
        size_t skip_count;
 
-#ifndef USE_CMSG
-       UNUSED(cmsg);
-#endif
-
        memset(msg, 0, sizeof(*msg));
 
        if (sock->type == isc_sockettype_udp) {
@@ -669,13 +687,14 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
                           "sendto pktinfo data, ifindex %u",
                           dev->pktinfo.ipi6_ifindex);
 
-               msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
-               msg->msg_control = (void *)cmsg;
+               msg->msg_controllen = cmsg_space(sizeof(struct in6_pktinfo));
+               INSIST(msg->msg_controllen <= sock->sendcmsgbuflen);
+               msg->msg_control = (void *)sock->sendcmsgbuf;
 
-               cmsgp = (struct cmsghdr *)cmsg;
+               cmsgp = (struct cmsghdr *)sock->sendcmsgbuf;
                cmsgp->cmsg_level = IPPROTO_IPV6;
                cmsgp->cmsg_type = IPV6_PKTINFO;
-               cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+               cmsgp->cmsg_len = cmsg_len(sizeof(struct in6_pktinfo));
                pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
                memcpy(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo));
        }
@@ -703,18 +722,13 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
  */
 static void
 build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
-                 struct msghdr *msg, char *cmsg,
-                 struct iovec *iov, size_t *read_countp)
+                 struct msghdr *msg, struct iovec *iov, size_t *read_countp)
 {
        unsigned int iovcount;
        isc_buffer_t *buffer;
        isc_region_t available;
        size_t read_count;
 
-#ifndef USE_CMSG
-       UNUSED(cmsg);
-#endif
-
        memset(msg, 0, sizeof(struct msghdr));
 
        if (sock->type == isc_sockettype_udp) {
@@ -796,8 +810,8 @@ build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
        msg->msg_flags = 0;
 #if defined(USE_CMSG)
        if (sock->type == isc_sockettype_udp) {
-               msg->msg_control = cmsg;
-               msg->msg_controllen = CMSG_BUF_SIZE;
+               msg->msg_control = sock->recvcmsgbuf;
+               msg->msg_controllen = sock->recvcmsgbuflen;
        }
 #endif /* USE_CMSG */
 #else /* ISC_NET_BSD44MSGHDR */
@@ -882,14 +896,9 @@ doio_recv(isc_socket_t *sock, isc_socketevent_t *dev) {
        struct msghdr msghdr;
        isc_buffer_t *buffer;
        int recv_errno;
-#if USE_CMSG
-       char cmsg[CMSG_BUF_SIZE];
-#else
-       char *cmsg = NULL;
-#endif
        char strbuf[ISC_STRERRORSIZE];
 
-       build_msghdr_recv(sock, dev, &msghdr, cmsg, iov, &read_count);
+       build_msghdr_recv(sock, dev, &msghdr, iov, &read_count);
 
 #if defined(ISC_SOCKET_DEBUG)
        dump_msg(&msghdr);
@@ -1041,16 +1050,11 @@ doio_send(isc_socket_t *sock, isc_socketevent_t *dev) {
        size_t write_count;
        struct msghdr msghdr;
        char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-#if USE_CMSG
-       char cmsg[CMSG_BUF_SIZE];
-#else
-       char *cmsg = NULL;
-#endif
        int attempts = 0;
        int send_errno;
        char strbuf[ISC_STRERRORSIZE];
 
-       build_msghdr_send(sock, dev, &msghdr, cmsg, iov, &write_count);
+       build_msghdr_send(sock, dev, &msghdr, iov, &write_count);
 
  resend:
        cc = sendmsg(sock->fd, &msghdr, 0);
@@ -1186,6 +1190,7 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
 {
        isc_socket_t *sock;
        isc_result_t ret;
+       ISC_SOCKADDR_LEN_T cmsgbuflen;
 
        sock = isc_mem_get(manager->mctx, sizeof(*sock));
 
@@ -1203,6 +1208,37 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
 
        ISC_LINK_INIT(sock, link);
 
+       sock->recvcmsgbuf = NULL;
+       sock->sendcmsgbuf = NULL;
+
+       /*
+        * set up cmsg buffers
+        */
+       cmsgbuflen = 0;
+#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIPV6)
+       cmsgbuflen = cmsg_space(sizeof(struct in6_pktinfo));
+#endif
+#if defined(USE_CMSG) && defined(SO_TIMESTAMP)
+       cmsgbuflen += cmsg_space(sizeof(struct timeval));
+#endif
+       sock->recvcmsgbuflen = cmsgbuflen;
+       if (sock->recvcmsgbuflen != 0) {
+               sock->recvcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen);
+               if (sock->recvcmsgbuf == NULL)
+                       goto error;
+       }
+
+       cmsgbuflen = 0;
+#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIPV6)
+       cmsgbuflen = cmsg_space(sizeof(struct in6_pktinfo));
+#endif
+       sock->sendcmsgbuflen = cmsgbuflen;
+       if (sock->sendcmsgbuflen != 0) {
+               sock->sendcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen);
+               if (sock->sendcmsgbuf == NULL)
+                       goto error;
+       }
+
        /*
         * set up list of readers and writers to be initially empty
         */
@@ -1247,6 +1283,12 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
        return (ISC_R_SUCCESS);
 
  error:
+       if (sock->recvcmsgbuf != NULL)
+               isc_mem_put(manager->mctx, sock->recvcmsgbuf,
+                           sock->recvcmsgbuflen);
+       if (sock->sendcmsgbuf != NULL)
+               isc_mem_put(manager->mctx, sock->sendcmsgbuf,
+                           sock->sendcmsgbuflen);
        isc_mem_put(manager->mctx, sock, sizeof(*sock));
 
        return (ret);
@@ -1274,6 +1316,13 @@ free_socket(isc_socket_t **socketp) {
        INSIST(ISC_LIST_EMPTY(sock->accept_list));
        INSIST(!ISC_LINK_LINKED(sock, link));
 
+       if (sock->recvcmsgbuf != NULL)
+               isc_mem_put(sock->manager->mctx, sock->recvcmsgbuf,
+                           sock->recvcmsgbuflen);
+       if (sock->sendcmsgbuf != NULL)
+               isc_mem_put(sock->manager->mctx, sock->sendcmsgbuf,
+                           sock->sendcmsgbuflen);
+
        sock->magic = 0;
 
        DESTROYLOCK(&sock->lock);
@@ -1415,6 +1464,15 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
 #endif /* SO_TIMESTAMP */
 
 #if defined(ISC_PLATFORM_HAVEIPV6)
+               if (pf == AF_INET6 && sock->recvcmsgbuflen == 0) {
+                       /*
+                        * Warn explicitly because this anomaly can be hidden
+                        * in usual operation (and unexpectedly appear later).
+                        */
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "No buffer available to receive "
+                                        "IPv6 destination");
+               }
 #ifdef IPV6_RECVPKTINFO
                /* 2292bis */
                if ((pf == AF_INET6)