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:
parent
98c227a222
commit
7b53fb0f9b
14
configure.ac
14
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}"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
17
src/xcbint.h
17
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
|
||||
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue