[dovecot-cvs] dovecot/src/lib fdpass.c,1.31,1.32

cras at dovecot.org cras at dovecot.org
Thu Jul 22 21:59:16 EEST 2004


Update of /home/cvs/dovecot/src/lib
In directory talvi:/tmp/cvs-serv9155/lib

Modified Files:
	fdpass.c 
Log Message:
Added BUGGY_CMSG_HEADERS #define to workaround some OS bugs. Updated
comments and macros to be more accurate.



Index: fdpass.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/fdpass.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -d -r1.31 -r1.32
--- fdpass.c	29 Jun 2004 12:10:36 -0000	1.31
+++ fdpass.c	22 Jul 2004 18:59:14 -0000	1.32
@@ -4,8 +4,9 @@
    fdpass.c - File descriptor passing between processes via UNIX sockets
 
    This isn't fully portable, but pretty much all UNIXes nowadays should
-   support this. If you're having runtime problems, check the end of fd_read()
-   and play with the if condition.
+   support this. If you're having runtime problems with fd_read(), check the
+   end of fd_read() and play with the if condition. If you're having problems
+   with fd_send(), try defining BUGGY_CMSG_HEADERS.
 
    If this file doesn't compile at all, you should check if this is supported
    in your system at all. It may require some extra #define to enable it.
@@ -18,7 +19,6 @@
 #  define _XOPEN_SOURCE 4 /* for IRIX */
 #endif
 
-
 #if !defined(_AIX) && !defined(_XOPEN_SOURCE_EXTENDED)
 #  define _XOPEN_SOURCE_EXTENDED /* for Tru64, breaks AIX */
 #endif
@@ -30,25 +30,57 @@
 #include <sys/un.h>
 #include <sys/uio.h>
 
-/* Solaris uses 32bit socklen_t as cmsg_len, so with Solaris we use
-   _CMSG_DATA_ALIGN() macro to do the alignment for us.
+/* RFC 2292 defines CMSG_*() macros, but some operating systems don't have them
+   so we'll define our own if they don't exist.
+
+   CMSG_LEN(data) is used to calculate size of sizeof(struct cmsghdr) +
+   sizeof(data) and padding between them.
+
+   CMSG_SPACE(data) also calculates the padding needed after the data, in case
+   multiple objects are sent.
+
+   cmsghdr contains cmsg_len field and two integers. cmsg_len is sometimes
+   defined as sockaddr_t and sometimes size_t, so it can be either 32bit or
+   64bit. This padding is added by compiler in sizeof(struct cmsghdr).
+
+   Padding required by CMSG_DATA() can vary. Usually it wants size_t or 32bit.
+   With Solaris it's in _CMSG_DATA_ALIGNMENT (32bit), we assume others want
+   size_t.
+
+   We don't really need CMSG_SPACE() to be exactly correct, because currently
+   we send only one object at a time. But anyway I'm trying to keep that
+   correct in case it's sometimes needed..
+*/
+
+#ifdef BUGGY_CMSG_HEADERS
+/* Some OSes have broken CMSG macros in 64bit systems. The macros use 64bit
+   alignmentation while kernel uses 32bit alignmentation. */
+#  undef CMSG_SPACE
+#  undef CMSG_LEN
+#  undef CMSG_DATA
+#  define CMSG_DATA(cmsg) ((char *)((cmsg) + 1))
+#  define _CMSG_DATA_ALIGNMENT sizeof(uint32_t)
+#  define _CMSG_HDR_ALIGNMENT sizeof(uint32_t)
+#endif
 
-   Perhaps the best solution would be to change sizeof(size_t) calculations
-   to sizeof(cmsg->cmsg_len)? At least if other OSes have similiar problems.. */
 #ifndef CMSG_SPACE
-#  if defined(_CMSG_DATA_ALIGN) && defined(_CMSG_HDR_ALIGN)  /* for Solaris */
-#    define CMSG_SPACE(len) \
-	(_CMSG_DATA_ALIGN(len) + _CMSG_DATA_ALIGN(sizeof(struct cmsghdr)))
-#    define CMSG_LEN(len) \
-	(_CMSG_DATA_ALIGN(sizeof(struct cmsghdr)) + (len))
-#  else
-#    define CMSG_ALIGN(len) \
-	(((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
-#    define CMSG_SPACE(len) \
-	(CMSG_ALIGN(len) + CMSG_ALIGN(sizeof(struct cmsghdr)))
-#    define CMSG_LEN(len) \
-	(CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+#  define MY_ALIGN(len, align) \
+	(((len) + align - 1) & ~(align - 1))
+
+/* Alignment between cmsghdr and data */
+#  ifndef _CMSG_DATA_ALIGNMENT
+#    define _CMSG_DATA_ALIGNMENT sizeof(size_t)
 #  endif
+/* Alignment between data and next cmsghdr */
+#  ifndef _CMSG_HDR_ALIGNMENT
+#    define _CMSG_HDR_ALIGNMENT sizeof(size_t)
+#  endif
+
+#  define CMSG_SPACE(len) \
+	(MY_ALIGN(sizeof(struct cmsghdr), _CMSG_DATA_ALIGNMENT) + \
+	 MY_ALIGN(len, _CMSG_HDR_ALIGNMENT))
+#  define CMSG_LEN(len) \
+	(MY_ALIGN(sizeof(struct cmsghdr), _CMSG_DATA_ALIGNMENT) + (len))
 #endif
 
 #ifdef SCM_RIGHTS
@@ -63,7 +95,7 @@
 	/* at least one byte is required to be sent with fd passing */
 	i_assert(size > 0 && size < SSIZE_T_MAX);
 
-	memset(&msg, 0, sizeof (struct msghdr));
+	memset(&msg, 0, sizeof(struct msghdr));
 
         iov.iov_base = (void *) data;
         iov.iov_len = size;
@@ -72,7 +104,7 @@
 	msg.msg_iovlen = 1;
 
 	if (send_fd != -1) {
-		/* set the control and controllen before CMSG_FIRSTHDR() */
+		/* set the control and controllen before CMSG_FIRSTHDR(). */
 		memset(buf, 0, sizeof(buf));
 		msg.msg_control = buf;
 		msg.msg_controllen = sizeof(buf);
@@ -83,8 +115,9 @@
 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
 		*((int *) CMSG_DATA(cmsg)) = send_fd;
 
-		/* set the real length we want to use. it's different than
-		   sizeof(buf) in 64bit systems. */
+		/* set the real length we want to use. Do it after all is
+		   set just in case CMSG macros required the extra padding
+		   in the end. */
 		msg.msg_controllen = cmsg->cmsg_len;
 	}
 



More information about the dovecot-cvs mailing list