From 884057f77f0630f1edac87bbce8f4809d40b7e1d Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Thu, 7 Nov 2013 16:47:38 -0800
Subject: [PATCH] Use the CMSG macros for getting at our FDs.

The manual stuff was only working on 32-bit userspace -- struct
alignment was breaking the estimates on 64.  It also fixes trying to
memcpy nfd bytes instead of ints.
---
 src/xcb_in.c | 35 ++++++++++++++++++++---------------
 1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/src/xcb_in.c b/src/xcb_in.c
index 839f615..901929f 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -888,17 +888,14 @@ int _xcb_in_read(xcb_connection_t *c)
         .iov_base = c->in.queue + c->in.queue_len,
         .iov_len = sizeof(c->in.queue) - c->in.queue_len,
     };
-    struct {
-        struct cmsghdr  cmsghdr;
-        int fd[XCB_MAX_PASS_FD];
-    } fds;
+    char fd_data[CMSG_SPACE(XCB_MAX_PASS_FD * sizeof(int))];
     struct msghdr msg = {
         .msg_name = NULL,
         .msg_namelen = 0,
         .msg_iov = &iov,
         .msg_iovlen = 1,
-        .msg_control = &fds,
-        .msg_controllen = sizeof (struct cmsghdr) + sizeof(int) * (XCB_MAX_PASS_FD - c->in.in_fd.nfd),
+        .msg_control = fd_data,
+        .msg_controllen = sizeof(fd_data),
     };
     n = recvmsg(c->fd, &msg, 0);
 
@@ -916,16 +913,24 @@ int _xcb_in_read(xcb_connection_t *c)
 #endif
     if(n > 0) {
 #if HAVE_SENDMSG
-        if (msg.msg_controllen > sizeof (struct cmsghdr))
-        {
-            if (fds.cmsghdr.cmsg_level == SOL_SOCKET &&
-                fds.cmsghdr.cmsg_type == SCM_RIGHTS)
+	struct cmsghdr *hdr;
+
+	for (hdr = CMSG_FIRSTHDR(&msg);
+	     hdr != NULL;
+	     hdr = CMSG_NXTHDR(&msg, hdr))
+	{
+	    if (hdr->cmsg_level == SOL_SOCKET &&
+                hdr->cmsg_type == SCM_RIGHTS)
             {
-                int nfd = (msg.msg_controllen - sizeof (struct cmsghdr)) / sizeof (int);
-                memmove(&c->in.in_fd.fd[c->in.in_fd.nfd],
-                        fds.fd,
-                        nfd);
-                c->in.in_fd.nfd += nfd;
+		/* Weird, there's a CMSG_LEN to go from size to
+		 * cmsg_len, but not the other way around.
+		 */
+		int nfd = ((CMSG_LEN(sizeof(int)) - hdr->cmsg_len) /
+			   sizeof(int)) + 1;
+		unsigned char *fds = CMSG_DATA(hdr);
+                memcpy(&c->in.in_fd.fd[c->in.in_fd.nfd], fds,
+		       nfd * sizeof(int));
+		c->in.in_fd.nfd += nfd;
             }
         }
 #endif
-- 
1.8.4.rc3

