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
9aa5b192ba
commit
aa6ac19ff4
14
configure.ac
14
configure.ac
|
@ -81,6 +81,19 @@ AC_HEADER_STDC
|
||||||
AC_SEARCH_LIBS(getaddrinfo, socket)
|
AC_SEARCH_LIBS(getaddrinfo, socket)
|
||||||
AC_SEARCH_LIBS(connect, 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"
|
have_win32="no"
|
||||||
lt_enable_auto_import=""
|
lt_enable_auto_import=""
|
||||||
case $host_os in
|
case $host_os in
|
||||||
|
@ -257,6 +270,7 @@ echo " Package: ${PACKAGE_NAME} ${PACKAGE_VERSION}"
|
||||||
echo ""
|
echo ""
|
||||||
echo " Configuration"
|
echo " Configuration"
|
||||||
echo " XDM support.........: ${have_xdmcp}"
|
echo " XDM support.........: ${have_xdmcp}"
|
||||||
|
echo " sendmsg fd passing..: ${have_sendmsg}"
|
||||||
echo " Build unit tests....: ${HAVE_CHECK}"
|
echo " Build unit tests....: ${HAVE_CHECK}"
|
||||||
echo " XCB buffer size.....: ${xcb_queue_buffer_size}"
|
echo " XCB buffer size.....: ${xcb_queue_buffer_size}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
@ -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
|
# no padding necessary - _serialize() keeps track of padding automatically
|
||||||
|
|
||||||
_c(' ')
|
_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)
|
_c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
|
||||||
|
|
||||||
# free dyn. all. data, if any
|
# 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. */
|
/** Connection closed because the server does not have a screen matching the display. */
|
||||||
#define XCB_CONN_CLOSED_INVALID_SCREEN 6
|
#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))
|
#define XCB_TYPE_PAD(T,I) (-(I) & (sizeof(T) > 4 ? 3 : sizeof(T) - 1))
|
||||||
|
|
||||||
/* Opaque structures */
|
/* Opaque structures */
|
||||||
|
|
|
@ -214,9 +214,34 @@ static int write_vec(xcb_connection_t *c, struct iovec **vector, int *count)
|
||||||
if (n > IOV_MAX)
|
if (n > IOV_MAX)
|
||||||
n = IOV_MAX;
|
n = IOV_MAX;
|
||||||
|
|
||||||
|
#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);
|
n = writev(c->fd, *vector, n);
|
||||||
if(n < 0 && errno == EAGAIN)
|
if(n < 0 && errno == EAGAIN)
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
if(n <= 0)
|
if(n <= 0)
|
||||||
|
|
|
@ -260,6 +260,24 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
|
||||||
return request;
|
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 xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), void *closure, int flags, uint64_t *sent)
|
||||||
{
|
{
|
||||||
int ret;
|
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);
|
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
|
/* 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
|
* 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
|
* xcb_writev. xcb_take_socket provides the sequence number of the last
|
||||||
|
|
19
src/xcbint.h
19
src/xcbint.h
|
@ -34,6 +34,10 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_SENDMSG
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef GCC_HAS_VISIBILITY
|
#ifdef GCC_HAS_VISIBILITY
|
||||||
#pragma GCC visibility push(hidden)
|
#pragma GCC visibility push(hidden)
|
||||||
#endif
|
#endif
|
||||||
|
@ -79,6 +83,18 @@ void *_xcb_map_remove(_xcb_map *q, unsigned int key);
|
||||||
|
|
||||||
/* xcb_out.c */
|
/* 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 {
|
typedef struct _xcb_out {
|
||||||
pthread_cond_t cond;
|
pthread_cond_t cond;
|
||||||
int writing;
|
int writing;
|
||||||
|
@ -100,6 +116,9 @@ typedef struct _xcb_out {
|
||||||
xcb_big_requests_enable_cookie_t cookie;
|
xcb_big_requests_enable_cookie_t cookie;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
} maximum_request_length;
|
} maximum_request_length;
|
||||||
|
#if HAVE_SENDMSG
|
||||||
|
_xcb_fd out_fd;
|
||||||
|
#endif
|
||||||
} _xcb_out;
|
} _xcb_out;
|
||||||
|
|
||||||
int _xcb_out_init(_xcb_out *out);
|
int _xcb_out_init(_xcb_out *out);
|
||||||
|
|
Loading…
Reference in New Issue