From 7b53fb0f9bddae77b3ab8823743db57faee4e99b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 14 Jan 2013 11:23:00 -0800 Subject: [PATCH] Add xcb_send_fd API This uses sendmsg to transmit file descriptors from the application to the X server Signed-off-by: Keith Packard Reviewed-By: Uli Schlachter --- configure.ac | 14 ++++++++++++++ src/c_client.py | 4 ++++ src/xcb.h | 3 +++ src/xcb_conn.c | 31 ++++++++++++++++++++++++++++--- src/xcb_out.c | 18 ++++++++++++++++++ src/xcbext.h | 2 ++ src/xcbint.h | 17 +++++++++++++++++ 7 files changed, 86 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 4a30584..54cda2f 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.h b/src/xcb.h index c251330..1fd1f6c 100644 --- 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 */ diff --git a/src/xcb_conn.c b/src/xcb_conn.c index 7dd25d3..c06c7cb 100644 --- a/src/xcb_conn.c +++ b/src/xcb_conn.c @@ -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) diff --git a/src/xcb_out.c b/src/xcb_out.c index 429fa99..1a3aca5 100644 --- a/src/xcb_out.c +++ b/src/xcb_out.c @@ -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; 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..391a4e1 100644 --- a/src/xcbint.h +++ b/src/xcbint.h @@ -34,6 +34,10 @@ #include "config.h" #endif +#if HAVE_SENDMSG +#include +#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); -- 2.34.1