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>
This commit is contained in:
Keith Packard 2013-01-14 11:23:00 -08:00
parent 98c227a222
commit 7b53fb0f9b
7 changed files with 86 additions and 3 deletions

View 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}"

View 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

View File

@ -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 */

View 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)

View 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;

View 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

View File

@ -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
@ -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);