[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