Add xcb_send_fd API
authorKeith Packard <keithp@keithp.com>
Mon, 14 Jan 2013 19:23:00 +0000 (11:23 -0800)
committerKeith Packard <keithp@keithp.com>
Thu, 7 Nov 2013 22:02:35 +0000 (14:02 -0800)
This uses sendmsg to transmit file descriptors from the application to
the X server

Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-By: Uli Schlachter <psychon@znc.in>
configure.ac
src/c_client.py
src/xcb.h
src/xcb_conn.c
src/xcb_out.c
src/xcbext.h
src/xcbint.h

index 4a30584..54cda2f 100644 (file)
@@ -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}"
index a6f8edd..cc26f72 100644 (file)
@@ -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
index c251330..1fd1f6c 100644 (file)
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -87,6 +87,9 @@ extern "C" {
 /** Connection closed because the server does not have a screen matching the display. */
 #define XCB_CONN_CLOSED_INVALID_SCREEN 6
 
+/** Connection closed because some FD passing operation failed */
+#define XCB_CONN_CLOSED_FDPASSING_FAILED 7
+
 #define XCB_TYPE_PAD(T,I) (-(I) & (sizeof(T) > 4 ? 3 : sizeof(T) - 1))
 
 /* Opaque structures */
index 7dd25d3..c06c7cb 100644 (file)
@@ -214,9 +214,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)
index 429fa99..1a3aca5 100644 (file)
@@ -263,6 +263,24 @@ 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
+    if (c->has_error)
+        return;
+    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;
index 4e1f2f7..44030c3 100644 (file)
@@ -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
index 7f9ab28..391a4e1 100644 (file)
 #include "config.h"
 #endif
 
+#if HAVE_SENDMSG
+#include <sys/socket.h>
+#endif
+
 #ifdef GCC_HAS_VISIBILITY
 #pragma GCC visibility push(hidden)
 #endif
@@ -81,6 +85,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 +115,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);