[PATCH 4/7] Add support for receiving fds in replies
Daniel Martin
consume.noise at gmail.com
Thu Nov 7 06:11:30 PST 2013
Just a nitpick:
On 6 November 2013 01:41, Keith Packard <keithp at keithp.com> wrote:
> Requests signal which replies will have fds, and the replies report
> how many fds they expect in byte 1.
>
> Signed-off-by: Keith Packard <keithp at keithp.com>
> ---
> src/c_client.py | 65 ++++++++++++++++++++++++++++++++++++++++++++----
> src/xcb_in.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
> src/xcbext.h | 4 ++-
> src/xcbint.h | 8 +++---
> 4 files changed, 141 insertions(+), 12 deletions(-)
>
> diff --git a/src/c_client.py b/src/c_client.py
> index ed92185..4c5da0a 100644
> --- a/src/c_client.py
> +++ b/src/c_client.py
> @@ -303,6 +303,7 @@ def _c_type_setup(self, name, postfix):
> self.c_reply_name = _n(name + ('reply',))
> self.c_reply_type = _t(name + ('reply',))
> self.c_cookie_type = _t(name + ('cookie',))
> + self.c_reply_fds_name = _n(name + ('reply_fds',))
>
> self.need_aux = False
> self.need_serialize = False
> @@ -1835,7 +1836,7 @@ def c_union(self, name):
> _c_complex(self)
> _c_iterator(self, name)
>
> -def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
> +def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
> '''
> Declares a request function.
> '''
> @@ -1864,6 +1865,12 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
> # What flag is passed to xcb_request
> func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
>
> + if reply_fds:
> + if func_flags == '0':
> + func_flags = 'XCB_REQUEST_REPLY_FDS'
> + else:
> + func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
> +
> # Global extension id variable or NULL for xproto
> func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
>
> @@ -2256,6 +2263,51 @@ def _c_reply(self, name):
>
> _c('}')
>
> +def _c_reply_has_fds(self):
> + for field in self.fields:
> + if field.isfd:
> + return True
> + return False
This could be more pythonic:
return any([field.isfd for field in self.fields])
> +
> +def _c_reply_fds(self, name):
> + '''
> + Declares the function that returns fds related to the reply.
> + '''
> + spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
> + spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
> + _h('')
> + _h('/**')
> + _h(' * Return the reply fds')
> + _h(' * @param c The connection')
> + _h(' * @param reply The reply')
> + _h(' *')
> + _h(' * Returns the array of reply fds of the request asked by')
> + _h(' * ')
> + _h(' * The returned value must be freed by the caller using free().')
> + _h(' */')
> + _c('')
> + _hc('')
> + _hc('/*****************************************************************************')
> + _hc(' **')
> + _hc(' ** int * %s', self.c_reply_fds_name)
> + _hc(' ** ')
> + _hc(' ** @param xcb_connection_t%s *c', spacing1)
> + _hc(' ** @param %s *reply', self.c_reply_type)
> + _hc(' ** @returns int *')
> + _hc(' **')
> + _hc(' *****************************************************************************/')
> + _hc(' ')
> + _hc('int *')
> + _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
> + _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
> + _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
> + _c('{')
> +
> + _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
> +
> + _c('}')
> +
> +
> def _c_opcode(name, opcode):
> '''
> Declares the opcode define for requests, events, and errors.
> @@ -2816,14 +2868,17 @@ def c_request(self, name):
> # Reply structure definition
> _c_complex(self.reply)
> # Request prototypes
> - _c_request_helper(self, name, self.c_cookie_type, False, True)
> - _c_request_helper(self, name, self.c_cookie_type, False, False)
> + has_fds = _c_reply_has_fds(self.reply)
> + _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
> + _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
> if self.need_aux:
> - _c_request_helper(self, name, self.c_cookie_type, False, True, True)
> - _c_request_helper(self, name, self.c_cookie_type, False, False, True)
> + _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
> + _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
> # Reply accessors
> _c_accessors(self.reply, name + ('reply',), name)
> _c_reply(self, name)
> + if has_fds:
> + _c_reply_fds(self, name)
> else:
> # Request prototypes
> _c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
> diff --git a/src/xcb_in.c b/src/xcb_in.c
> index ac4d284..f9a10e7 100644
> --- a/src/xcb_in.c
> +++ b/src/xcb_in.c
> @@ -91,11 +91,26 @@ static void remove_finished_readers(reader_list **prev_reader, uint64_t complete
> }
> }
>
> +#if HAVE_SENDMSG
> +static int read_fds(xcb_connection_t *c, int *fds, int nfd)
> +{
> + int *ifds = &c->in.in_fd.fd[c->in.in_fd.ifd];
> + int infd = c->in.in_fd.nfd - c->in.in_fd.ifd;
> +
> + if (nfd > infd)
> + return -1;
> + memcpy(fds, ifds, nfd * sizeof (int));
> + c->in.in_fd.ifd += nfd;
> + return nfd * sizeof (int);
> +}
> +#endif
> +
> static int read_packet(xcb_connection_t *c)
> {
> xcb_generic_reply_t genrep;
> uint64_t length = 32;
> uint64_t eventlength = 0; /* length after first 32 bytes for GenericEvents */
> + int nfd = 0; /* Number of file descriptors attached to the reply */
> uint64_t bufsize;
> void *buf;
> pending_reply *pend = 0;
> @@ -165,13 +180,18 @@ static int read_packet(xcb_connection_t *c)
> genrep.length = p[2] * p[3] * 2;
> }
> length += genrep.length * 4;
> +
> + /* XXX a bit of a hack -- we "know" that all FD replys place
> + * the number of fds in the pad0 byte */
> + if (pend && pend->flags & XCB_REQUEST_REPLY_FDS)
> + nfd = genrep.pad0;
> }
>
> /* XGE events may have sizes > 32 */
> if ((genrep.response_type & 0x7f) == XCB_XGE_EVENT)
> eventlength = genrep.length * 4;
>
> - bufsize = length + eventlength +
> + bufsize = length + eventlength + nfd * sizeof(int) +
> (genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t));
> if (bufsize < INT32_MAX)
> buf = malloc((size_t) bufsize);
> @@ -199,6 +219,17 @@ static int read_packet(xcb_connection_t *c)
> }
> }
>
> +#if HAVE_SENDMSG
> + if (nfd)
> + {
> + if (read_fds(c, (int *) &((char *) buf)[length], nfd) <= 0)
> + {
> + free(buf);
> + return 0;
> + }
> + }
> +#endif
> +
> if(pend && (pend->flags & XCB_REQUEST_DISCARD_REPLY))
> {
> free(buf);
> @@ -432,6 +463,11 @@ void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_
> return ret;
> }
>
> +int *xcb_get_reply_fds(xcb_connection_t *c, void *reply, size_t reply_size)
> +{
> + return (int *) (&((char *) reply)[reply_size]);
> +}
> +
> static void insert_pending_discard(xcb_connection_t *c, pending_reply **prev_next, uint64_t seq)
> {
> pending_reply *pend;
> @@ -666,9 +702,43 @@ void _xcb_in_replies_done(xcb_connection_t *c)
>
> int _xcb_in_read(xcb_connection_t *c)
> {
> - int n = recv(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len, 0);
> - if(n > 0)
> + int n;
> +
> +#if HAVE_SENDMSG
> + struct iovec iov = {
> + .iov_base = c->in.queue + c->in.queue_len,
> + .iov_len = sizeof(c->in.queue) - c->in.queue_len,
> + };
> + struct msghdr msg = {
> + .msg_name = NULL,
> + .msg_namelen = 0,
> + .msg_iov = &iov,
> + .msg_iovlen = 1,
> + .msg_control = &c->in.in_fd,
> + .msg_controllen = sizeof (struct cmsghdr) + sizeof (int) * XCB_MAX_PASS_FD,
> + };
> + assert(c->in.in_fd.ifd == c->in.in_fd.nfd);
> + c->in.in_fd.ifd = 0;
> + c->in.in_fd.nfd = 0;
> + n = recvmsg(c->fd, &msg, 0);
> +#else
> + n = recv(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len, 0);
> +#endif
> + if(n > 0) {
> +#if HAVE_SENDMSG
> + if (msg.msg_controllen > sizeof (struct cmsghdr))
> + {
> + if (c->in.in_fd.cmsghdr.cmsg_level == SOL_SOCKET &&
> + c->in.in_fd.cmsghdr.cmsg_type == SCM_RIGHTS &&
> + !((msg.msg_flags & MSG_TRUNC) ||
> + (msg.msg_flags & MSG_CTRUNC)))
> + {
> + c->in.in_fd.nfd = (msg.msg_controllen - sizeof (struct cmsghdr)) / sizeof (int);
> + }
> + }
> +#endif
> c->in.queue_len += n;
> + }
> while(read_packet(c))
> /* empty */;
> #ifndef _WIN32
> diff --git a/src/xcbext.h b/src/xcbext.h
> index 44030c3..1eb1be7 100644
> --- a/src/xcbext.h
> +++ b/src/xcbext.h
> @@ -54,7 +54,8 @@ typedef struct {
> enum xcb_send_request_flags_t {
> XCB_REQUEST_CHECKED = 1 << 0,
> XCB_REQUEST_RAW = 1 << 1,
> - XCB_REQUEST_DISCARD_REPLY = 1 << 2
> + XCB_REQUEST_DISCARD_REPLY = 1 << 2,
> + XCB_REQUEST_REPLY_FDS = 1 << 3
> };
>
> unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
> @@ -91,6 +92,7 @@ int xcb_writev(xcb_connection_t *c, struct iovec *vector, int count, uint64_t re
>
> void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e);
> int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error);
> +int *xcb_get_reply_fds(xcb_connection_t *c, void *reply, size_t replylen);
>
>
> /* xcb_util.c */
> diff --git a/src/xcbint.h b/src/xcbint.h
> index 356350b..75d159f 100644
> --- a/src/xcbint.h
> +++ b/src/xcbint.h
> @@ -84,11 +84,12 @@ typedef void (*xcb_return_socket_func_t)(void *closure);
> #if HAVE_SENDMSG
> #define XCB_MAX_PASS_FD 16
>
> -typedef struct _xcb_out_fd {
> +typedef struct _xcb_fd {
> struct cmsghdr cmsghdr;
> int fd[XCB_MAX_PASS_FD];
> int nfd;
> -} _xcb_out_fd;
> + int ifd;
> +} _xcb_fd;
> #endif
>
> typedef struct _xcb_out {
> @@ -112,7 +113,7 @@ typedef struct _xcb_out {
> uint32_t value;
> } maximum_request_length;
> #if HAVE_SENDMSG
> - _xcb_out_fd out_fd;
> + _xcb_fd out_fd;
> #endif
> } _xcb_out;
>
> @@ -146,6 +147,7 @@ typedef struct _xcb_in {
>
> struct pending_reply *pending_replies;
> struct pending_reply **pending_replies_tail;
> + _xcb_fd in_fd;
> } _xcb_in;
>
> int _xcb_in_init(_xcb_in *in);
> --
> 1.8.4.2
>
> _______________________________________________
> xorg-devel at lists.x.org: X.Org development
> Archives: http://lists.x.org/archives/xorg-devel
> Info: http://lists.x.org/mailman/listinfo/xorg-devel
More information about the xorg-devel
mailing list