[Xcb] [PATCH 4/8] Add xcb_send_fd API

Keith Packard keithp at keithp.com
Thu Nov 7 04:45:41 CET 2013


This uses sendmsg to transmit file descriptors from the application to
the X server

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 configure.ac    | 14 ++++++++++++++
 src/c_client.py |  4 ++++
 src/xcb_auth.c  | 11 ++++++-----
 src/xcb_conn.c  | 39 +++++++++++++++++++++++++++++++++------
 src/xcb_ext.c   |  3 +++
 src/xcb_in.c    |  9 +++++----
 src/xcb_list.c  |  3 +++
 src/xcb_out.c   | 19 +++++++++++++++++++
 src/xcb_xid.c   |  4 ++++
 src/xcbext.h    |  2 ++
 src/xcbint.h    | 13 +++++++++++++
 11 files changed, 106 insertions(+), 15 deletions(-)

diff --git a/configure.ac b/configure.ac
index 4a30584..47c31a1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -81,6 +81,19 @@ AC_HEADER_STDC
 AC_SEARCH_LIBS(getaddrinfo, socket)
 AC_SEARCH_LIBS(connect, socket)
 
+have_sendmsg="no"
+case $host_os in
+linux*)
+	AC_SEARCH_LIBS(sendmsg, socket, [have_sendmsg="yes"], [have_sendmsg="no"])
+	;;
+esac
+
+case x$have_sendmsg in
+xyes)
+	AC_DEFINE([HAVE_SENDMSG],1,[Define if your platform supports sendmsg])
+	;;
+esac
+
 have_win32="no"
 lt_enable_auto_import=""
 case $host_os in
@@ -250,6 +263,7 @@ echo "  Package: ${PACKAGE_NAME} ${PACKAGE_VERSION}"
 echo ""
 echo "  Configuration"
 echo "    XDM support.........: ${have_xdmcp}"
+echo "    sendmsg fd passing..: ${have_sendmsg}"
 echo "    Build unit tests....: ${HAVE_CHECK}"
 echo "      with html results.: ${HTML_CHECK_RESULT}"
 echo "    XCB buffer size.....: ${xcb_queue_buffer_size}"
diff --git a/src/c_client.py b/src/c_client.py
index a6f8edd..cc26f72 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -2149,6 +2149,10 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
         # no padding necessary - _serialize() keeps track of padding automatically
 
     _c('    ')
+    for field in param_fields:
+        if field.isfd:
+            _c('    xcb_send_fd(c, %s);', field.c_field_name)
+    
     _c('    xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
     
     # free dyn. all. data, if any
diff --git a/src/xcb_auth.c b/src/xcb_auth.c
index a5b730c..2f7c93e 100644
--- a/src/xcb_auth.c
+++ b/src/xcb_auth.c
@@ -34,6 +34,12 @@
 #include <sys/param.h>
 #include <unistd.h>
 #include <stdlib.h>
+#ifndef _WIN32
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#endif
 
 #ifdef __INTERIX
 /* _don't_ ask. interix has INADDR_LOOPBACK in here. */
@@ -47,11 +53,6 @@
 #include <X11/Xwindows.h>
 #endif
 #include "xcb_windefs.h"
-#else
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/un.h>
 #endif /* _WIN32 */
 
 #include "xcb.h"
diff --git a/src/xcb_conn.c b/src/xcb_conn.c
index 7dd25d3..0237d16 100644
--- a/src/xcb_conn.c
+++ b/src/xcb_conn.c
@@ -38,6 +38,11 @@
 #include <errno.h>
 #include <limits.h>
 
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif /* !_WIN32 */
+
 #include "xcb.h"
 #include "xcbint.h"
 #if USE_POLL
@@ -48,9 +53,6 @@
 
 #ifdef _WIN32
 #include "xcb_windefs.h"
-#else
-#include <sys/socket.h>
-#include <netinet/in.h>
 #endif /* _WIN32 */
 
 /* SHUT_RDWR is fairly recent and is not available on all platforms */
@@ -214,9 +216,34 @@ static int write_vec(xcb_connection_t *c, struct iovec **vector, int *count)
     if (n > IOV_MAX)
 	n = IOV_MAX;
 
-    n = writev(c->fd, *vector, n);
-    if(n < 0 && errno == EAGAIN)
-        return 1;
+#if HAVE_SENDMSG
+    if (c->out.out_fd.nfd) {
+	struct msghdr msg = {
+	    .msg_name = NULL,
+	    .msg_namelen = 0,
+	    .msg_iov = *vector,
+	    .msg_iovlen = n,
+	    .msg_control = &c->out.out_fd,
+	    .msg_controllen = sizeof (struct cmsghdr) + c->out.out_fd.nfd * sizeof (int),
+	};
+        int i;
+	c->out.out_fd.cmsghdr.cmsg_len = msg.msg_controllen;
+	c->out.out_fd.cmsghdr.cmsg_level = SOL_SOCKET;
+	c->out.out_fd.cmsghdr.cmsg_type = SCM_RIGHTS;
+	n = sendmsg(c->fd, &msg, 0);
+        if(n < 0 && errno == EAGAIN)
+            return 1;
+        for (i = 0; i < c->out.out_fd.nfd; i++)
+            close(c->out.out_fd.fd[i]);
+        c->out.out_fd.nfd = 0;
+    } else
+#endif
+    {
+	n = writev(c->fd, *vector, n);
+        if(n < 0 && errno == EAGAIN)
+            return 1;
+    }
+    
 #endif /* _WIN32 */    
 
     if(n <= 0)
diff --git a/src/xcb_ext.c b/src/xcb_ext.c
index 831f283..1ff2b05 100644
--- a/src/xcb_ext.c
+++ b/src/xcb_ext.c
@@ -31,6 +31,9 @@
 
 #include <stdlib.h>
 #include <string.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
 
 #include "xcb.h"
 #include "xcbext.h"
diff --git a/src/xcb_in.c b/src/xcb_in.c
index 8a7af92..ac4d284 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -36,16 +36,17 @@
 #include <stdio.h>
 #include <errno.h>
 
+#ifndef _WIN32
+#include <sys/select.h>
+#include <sys/socket.h>
+#endif
+
 #include "xcb.h"
 #include "xcbext.h"
 #include "xcbint.h"
 #if USE_POLL
 #include <poll.h>
 #endif
-#ifndef _WIN32
-#include <sys/select.h>
-#include <sys/socket.h>
-#endif
 
 #ifdef _WIN32
 #include "xcb_windefs.h"
diff --git a/src/xcb_list.c b/src/xcb_list.c
index 129540b..075c535 100644
--- a/src/xcb_list.c
+++ b/src/xcb_list.c
@@ -30,6 +30,9 @@
 #endif
 
 #include <stdlib.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
 
 #include "xcb.h"
 #include "xcbint.h"
diff --git a/src/xcb_out.c b/src/xcb_out.c
index 429fa99..ed8458c 100644
--- a/src/xcb_out.c
+++ b/src/xcb_out.c
@@ -33,6 +33,9 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
 
 #include "xcb.h"
 #include "xcbext.h"
@@ -263,6 +266,22 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
     return request;
 }
 
+void
+xcb_send_fd(xcb_connection_t *c, int fd)
+{
+#if HAVE_SENDMSG
+    pthread_mutex_lock(&c->iolock);
+    while (c->out.out_fd.nfd == XCB_MAX_PASS_FD) {
+	_xcb_out_flush_to(c, c->out.request);
+	if (c->has_error)
+	    break;
+    }
+    if (!c->has_error)
+	c->out.out_fd.fd[c->out.out_fd.nfd++] = fd;
+    pthread_mutex_unlock(&c->iolock);
+#endif
+}
+
 int xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), void *closure, int flags, uint64_t *sent)
 {
     int ret;
diff --git a/src/xcb_xid.c b/src/xcb_xid.c
index 79a9a27..3c5682c 100644
--- a/src/xcb_xid.c
+++ b/src/xcb_xid.c
@@ -31,6 +31,10 @@
 
 #include <assert.h>
 #include <stdlib.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+
 #include "xcb.h"
 #include "xcbext.h"
 #include "xcbint.h"
diff --git a/src/xcbext.h b/src/xcbext.h
index 4e1f2f7..44030c3 100644
--- a/src/xcbext.h
+++ b/src/xcbext.h
@@ -59,6 +59,8 @@ enum xcb_send_request_flags_t {
 
 unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
 
+void xcb_send_fd(xcb_connection_t *c, int fd);
+
 /* xcb_take_socket allows external code to ask XCB for permission to
  * take over the write side of the socket and send raw data with
  * xcb_writev. xcb_take_socket provides the sequence number of the last
diff --git a/src/xcbint.h b/src/xcbint.h
index 7f9ab28..b2dfed3 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -81,6 +81,16 @@ void *_xcb_map_remove(_xcb_map *q, unsigned int key);
 
 typedef void (*xcb_return_socket_func_t)(void *closure);
 
+#if HAVE_SENDMSG
+#define XCB_MAX_PASS_FD	16
+
+typedef struct _xcb_fd {
+    struct cmsghdr cmsghdr;
+    int fd[XCB_MAX_PASS_FD];
+    int nfd;
+} _xcb_fd;
+#endif
+
 typedef struct _xcb_out {
     pthread_cond_t cond;
     int writing;
@@ -101,6 +111,9 @@ typedef struct _xcb_out {
         xcb_big_requests_enable_cookie_t cookie;
         uint32_t value;
     } maximum_request_length;
+#if HAVE_SENDMSG
+    _xcb_fd out_fd;
+#endif
 } _xcb_out;
 
 int _xcb_out_init(_xcb_out *out);
-- 
1.8.4.2



More information about the Xcb mailing list