[RFC wayland 2/2] Add a wayland protocol dumper wayland-tracer

Marek Chalupa mchqwerty at gmail.com
Sun Jul 20 07:41:20 PDT 2014


Hi,

nice work! Some time ago I did the same, but didn't want to send it until
it's more mature (and haven't got on it since). My version works the very
same way, the only difference is that I have 'filters' there. The filter is
a function that is called for every data on socket and can be dynamically
(although now I have them statically) added to the dumper. I also use only
wl_connection (no wl_buffer)

I formated the patches for my dumper and I'm sending them here, if somebody
is interested in very similar yet different way how to do it.

Since I'm off next two weeks, feel free to do whatever you want with the
patches (or ignore them)

Regards,
Marek


On 20 July 2014 04:18, Boyan Ding <stu_dby at 126.com> wrote:

> Signed-off-by: Boyan Ding <stu_dby at 126.com>
> ---
>  .gitignore   |   1 +
>  Makefile.am  |  10 ++
>  configure.ac |   7 ++
>  src/tracer.c | 351
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 369 insertions(+)
>  create mode 100644 src/tracer.c
>
> diff --git a/.gitignore b/.gitignore
> index c146bac..510b7ae 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -54,4 +54,5 @@ sanity-test
>  signal-test
>  socket-test
>  wayland-scanner
> +wayland-tracer
>  protocol/*.[ch]
> diff --git a/Makefile.am b/Makefile.am
> index c15d8b8..f234599 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -70,6 +70,16 @@ $(BUILT_SOURCES) : wayland-scanner
>  pkgconfig_DATA += src/wayland-scanner.pc
>  else
>  wayland_scanner = wayland-scanner
> +bin_PROGRAMS =
> +endif
> +
> +if ENABLE_TRACER
> +wayland_tracer = $(top_builddir)/wayland-tracer
> +bin_PROGRAMS += wayland-tracer
> +wayland_tracer_SOURCES = src/tracer.c
> +wayland_tracer_LDADD = libwayland-util.la $(FFI_LIBS)
> +else
> +wayland_tracer = wayland-tracer
>  endif
>
>  protocol/%-protocol.c : $(top_srcdir)/protocol/%.xml
> diff --git a/configure.ac b/configure.ac
> index e16c5b5..b3e81a7 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -64,7 +64,14 @@ AC_ARG_ENABLE([documentation],
>               [],
>               [enable_documentation=yes])
>
> +AC_ARG_ENABLE([tracer],
> +              [AC_HELP_STRING([--disable-tracer],
> +                              [Disable compilation of wayland-tracer])],
> +              [],
> +              [enable_tracer=yes])
> +
>  AM_CONDITIONAL(ENABLE_SCANNER, test "x$enable_scanner" = xyes)
> +AM_CONDITIONAL(ENABLE_TRACER, test "x$enable_tracer" = xyes)
>
>  AC_ARG_WITH(icondir, [  --with-icondir=<dir>    Look for cursor icons
> here],
>                      [  ICONDIR=$withval],
> diff --git a/src/tracer.c b/src/tracer.c
> new file mode 100644
> index 0000000..23de75d
> --- /dev/null
> +++ b/src/tracer.c
> @@ -0,0 +1,351 @@
> +/*
> + * Copyright © 2014 Boyan Ding
> + *
> + * Permission to use, copy, modify, distribute, and sell this software
> and its
> + * documentation for any purpose is hereby granted without fee, provided
> that
> + * the above copyright notice appear in all copies and that both that
> copyright
> + * notice and this permission notice appear in supporting documentation,
> and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no
> representations
> + * about the suitability of this software for any purpose.  It is
> provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT
> OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
> USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
> PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stddef.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <sys/epoll.h>
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +#include <stdint.h>
> +#include <errno.h>
> +#include <assert.h>
> +
> +#include "wayland-os.h"
> +#include "wayland-private.h"
> +#include "wayland-util.h"
> +
> +#define TRACER_SERVER_SIDE 0
> +#define TRACER_CLIENT_SIDE 1
> +
> +struct tracer_connection {
> +       struct wl_connection *wl_conn;
> +       struct tracer_connection *peer;
> +       int side;
> +};
> +
> +struct tracer {
> +       struct tracer_connection *client_conn;
> +       struct tracer_connection *server_conn;
> +       int32_t epollfd;
> +};
> +
> +static int
> +tracer_dump_bin(struct tracer_connection *connection)
> +{
> +       int i, len, fdlen, fd;
> +       char buf[4096];
> +       struct wl_connection *wl_conn= connection->wl_conn;
> +       struct tracer_connection *peer = connection->peer;
> +
> +       len = wl_buffer_size(&wl_conn->in);
> +       if (len == 0)
> +               return 0;
> +
> +       wl_connection_copy(wl_conn, buf, len);
> +
> +       printf("%s Data dumped: %d bytes:\n",
> +              connection->side == TRACER_SERVER_SIDE ? "=>" : "<=", len);
> +       for (i = 0; i < len; i++) {
> +               printf("%02x ", (unsigned char)buf[i]);
> +       }
> +       printf("\n");
> +       wl_connection_consume(wl_conn, len);
> +       wl_connection_write(peer->wl_conn, buf, len);
> +
> +       fdlen = wl_buffer_size(&wl_conn->fds_in);
> +
> +       wl_buffer_copy(&wl_conn->fds_in, buf, fdlen);
> +       fdlen /= sizeof(int32_t);
> +
> +       if (fdlen != 0)
> +               printf("%d Fds in control data:", fdlen);
> +
> +       for (i = 0; i < fdlen; i++) {
> +               fd = ((int *) buf)[i];
> +               printf("%d ", fd);
> +               wl_connection_put_fd(peer->wl_conn, fd);
> +       }
> +       printf("\n");
> +
> +       wl_conn->fds_in.tail += fdlen * sizeof(int32_t);
> +       wl_connection_flush(peer->wl_conn);
> +
> +       return len;
> +}
> +
> +/* The following two functions are taken from wayland-client.c*/
> +static int
> +tracer_connect_to_socket(const char *name)
> +{
> +       struct sockaddr_un addr;
> +       socklen_t size;
> +       const char *runtime_dir;
> +       int name_size, fd;
> +
> +       runtime_dir = getenv("XDG_RUNTIME_DIR");
> +       if (!runtime_dir) {
> +               fprintf(stderr, "error: XDG_RUNTIME_DIR not set in the
> environment.\n");
> +               /* to prevent programs reporting
> +                * "failed to create display: Success" */
> +               errno = ENOENT;
> +               return -1;
> +       }
> +
> +       if (name == NULL)
> +               name = getenv("WAYLAND_DISPLAY");
> +       if (name == NULL)
> +               name = "wayland-0";
> +
> +       fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
> +       if (fd < 0)
> +               return -1;
> +
> +       memset(&addr, 0, sizeof addr);
> +       addr.sun_family = AF_LOCAL;
> +       name_size =
> +               snprintf(addr.sun_path, sizeof addr.sun_path,
> +                        "%s/%s", runtime_dir, name) + 1;
> +
> +       assert(name_size > 0);
> +       if (name_size > (int)sizeof addr.sun_path) {
> +               fprintf(stderr, "error: socket path \"%s/%s\" plus null
> terminator"
> +                      " exceeds 108 bytes\n", runtime_dir, name);
> +               close(fd);
> +               /* to prevent programs reporting
> +                * "failed to add socket: Success" */
> +               errno = ENAMETOOLONG;
> +               return -1;
> +       };
> +
> +       size = offsetof (struct sockaddr_un, sun_path) + name_size;
> +
> +       if (connect(fd, (struct sockaddr *) &addr, size) < 0) {
> +               close(fd);
> +               return -1;
> +       }
> +
> +       return fd;
> +}
> +
> +static int
> +tracer_connect_server(const char *name)
> +{
> +       char *connection, *end;
> +       int flags, fd;
> +
> +       connection = getenv("WAYLAND_SOCKET");
> +       if (connection) {
> +               fd = strtol(connection, &end, 0);
> +               if (*end != '\0')
> +                       return -1;
> +
> +               flags = fcntl(fd, F_GETFD);
> +               if (flags != -1)
> +                       fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
> +               unsetenv("WAYLAND_SOCKET");
> +       } else
> +               fd = tracer_connect_to_socket(name);
> +
> +       return fd;
> +}
> +
> +static struct tracer_connection*
> +tracer_connection_create(int fd, int side)
> +{
> +       struct tracer_connection *connection;
> +
> +       connection = malloc(sizeof *connection);
> +       if (connection == NULL) {
> +               errno = ENOMEM;
> +               return NULL;
> +       }
> +
> +       connection->wl_conn = wl_connection_create(fd);
> +       if (connection->wl_conn == NULL)
> +               return NULL;
> +
> +       connection->side = side;
> +
> +       return connection;
> +}
> +
> +static void
> +tracer_connection_destroy(struct tracer_connection *connection)
> +{
> +       wl_connection_destroy(connection->wl_conn);
> +       free(connection);
> +}
> +
> +static int
> +tracer_epoll_add_fd(struct tracer *tracer, int fd, void *userdata)
> +{
> +       struct epoll_event ev;
> +
> +       ev.events = EPOLLIN;
> +       ev.data.ptr = userdata;
> +
> +       return epoll_ctl(tracer->epollfd, EPOLL_CTL_ADD, fd, &ev);
> +}
> +
> +static struct tracer*
> +tracer_create(int serverfd, int clientfd)
> +{
> +       struct tracer *tracer;
> +
> +       tracer = malloc(sizeof *tracer);
> +
> +       if (tracer == NULL) {
> +               errno = ENOMEM;
> +               return NULL;
> +       }
> +
> +       tracer->server_conn = tracer_connection_create(serverfd,
> +                                                      TRACER_SERVER_SIDE);
> +       if (tracer->server_conn == NULL)
> +               goto err_conn;
> +
> +       tracer->client_conn = tracer_connection_create(clientfd,
> +                                                      TRACER_CLIENT_SIDE);
> +       if (tracer->client_conn == NULL)
> +               goto err_conn;
> +
> +       tracer->server_conn->peer = tracer->client_conn;
> +       tracer->client_conn->peer = tracer->server_conn;
> +
> +       tracer->epollfd = epoll_create1(0);
> +       if (tracer->epollfd < 0) {
> +               fprintf(stderr, "Failed to create epollfd: %m\n");
> +               goto err_epoll_create;
> +       }
> +
> +       if (tracer_epoll_add_fd(tracer, serverfd, tracer->server_conn) <
> 0) {
> +               fprintf(stderr, "Failed to poll serverfd: %m\n");
> +               goto err_epoll;
> +       }
> +
> +       if (tracer_epoll_add_fd(tracer, clientfd, tracer->client_conn) <
> 0) {
> +               fprintf(stderr, "Failed to poll clientfd: %m\n");
> +               goto err_epoll;
> +       }
> +
> +       return tracer;
> +
> +err_conn:
> +       free(tracer);
> +       return NULL;
> +
> +err_epoll_create:
> +       tracer_connection_destroy(tracer->server_conn);
> +       tracer_connection_destroy(tracer->client_conn);
> +       free(tracer);
> +       return NULL;
> +
> +err_epoll:
> +       close(tracer->epollfd);
> +       tracer_connection_destroy(tracer->server_conn);
> +       tracer_connection_destroy(tracer->client_conn);
> +       free(tracer);
> +       return NULL;
> +}
> +
> +static void
> +tracer_handle_data(struct tracer_connection *connection)
> +{
> +       wl_connection_read(connection->wl_conn);
> +
> +       while(tracer_dump_bin(connection) > 0);
> +}
> +
> +static void
> +tracer_run(struct tracer *tracer)
> +{
> +       struct epoll_event ev;
> +       int nfds;
> +
> +       for (;;) {
> +               nfds = epoll_wait(tracer->epollfd, &ev, 1, -1);
> +
> +               if (nfds < 0) {
> +                       fprintf(stderr, "Failed to poll: %m\n");
> +                       return ;
> +               }
> +
> +               tracer_handle_data((struct tracer_connection*)
> ev.data.ptr);
> +       }
> +}
> +
> +int
> +main(int argc, char *argv[])
> +{
> +       int sock_vec[2];
> +       int serverfd, clientfd;
> +       int ret;
> +       char sockfdstr[10];
> +       pid_t pid;
> +       struct tracer *tracer;
> +
> +       ret = socketpair(PF_LOCAL, SOCK_STREAM, 0, sock_vec);
> +       if (ret != 0) {
> +               fprintf(stderr, "Failed to create socket pair: %m\n");
> +               exit(1);
> +       }
> +
> +       pid = fork();
> +       if (pid < 0) {
> +               fprintf(stderr, "Failed to fork program: %m\n");
> +               exit(2);
> +       }
> +
> +       if (pid == 0) {
> +               close(sock_vec[0]);
> +               sprintf(sockfdstr, "%d", sock_vec[1]);
> +               setenv("WAYLAND_SOCKET", sockfdstr, 1);
> +
> +               execvp(argv[1], &argv[1]);
> +               exit(0);
> +       }
> +
> +       close(sock_vec[1]);
> +       clientfd = sock_vec[0];
> +
> +       serverfd = tracer_connect_server(NULL);
> +       if (serverfd < 0) {
> +               fprintf(stderr, "Failed to connect to wayland server:
> %m\n");
> +               exit(5);
> +       }
> +
> +       tracer = tracer_create(serverfd, clientfd);
> +       if (tracer == NULL) {
> +               fprintf(stderr, "Failed to create tracer: %m\n");
> +               exit(6);
> +       }
> +
> +       tracer_run(tracer);
> +
> +       return 0;
> +}
> +
> --
> 2.0.1
>
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20140720/578488b0/attachment-0001.html>


More information about the wayland-devel mailing list