summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2013-01-14 11:23:00 -0800
committerKeith Packard <keithp@keithp.com>2013-11-07 13:32:20 -0800
commitaa6ac19ff407834f0a57fca501602273ced2f714 (patch)
tree627e8a0c5d6ceffb05d1400e3d194044e5257790
parent9aa5b192ba7d4544c9dcf6d7687aa4730b7b9c2e (diff)
Add xcb_send_fd API
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>
-rw-r--r--configure.ac14
-rw-r--r--src/c_client.py4
-rw-r--r--src/xcb.h3
-rw-r--r--src/xcb_conn.c31
-rw-r--r--src/xcb_out.c18
-rw-r--r--src/xcbext.h2
-rw-r--r--src/xcbint.h19
7 files changed, 88 insertions, 3 deletions
diff --git a/configure.ac b/configure.ac
index 3abe833..1906174 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
@@ -257,6 +270,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 " XCB buffer size.....: ${xcb_queue_buffer_size}"
echo ""
diff --git a/src/c_client.py b/src/c_client.py
index c477bab..e5626f3 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 e782d44..fe64851 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 6a7a806..d5d3c46 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 a4f52fb..18bb5f9 100644
--- a/src/xcb_out.c
+++ b/src/xcb_out.c
@@ -260,6 +260,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 98b3c93..4c09d99 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 f9e5a52..aaf6685 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -34,6 +34,10 @@
#include "config.h"
#endif
+#if HAVE_SENDMSG
+#include <sys/socket.h>
+#endif
+
#ifdef GCC_HAS_VISIBILITY
#pragma GCC visibility push(hidden)
#endif
@@ -79,6 +83,18 @@ void *_xcb_map_remove(_xcb_map *q, unsigned int key);
/* xcb_out.c */
+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;
@@ -100,6 +116,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);