[RFC wayland 2/2] Add a wayland protocol dumper wayland-tracer
Silvan Jegen
s.jegen at gmail.com
Sun Jul 20 03:53:27 PDT 2014
Hi
and thanks for this! I hope to learn more about the protocol by using
this tool.
I encountered two simple issues when applying your patches (see below).
On Sun, Jul 20, 2014 at 10:18:03AM +0800, Boyan Ding 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)
wayland-tracer wouldn't compile without including the -lrt switch (for
the time.h functions) like this.
wayland_tracer_LDADD = libwayland-util.la $(FFI_LIBS) -lrt
I am not sure whether this issue is specific to my setup or if this is
the best way to fix it.
> +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)
There is a trailing space here (git complained when applying the patch).
> + 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
More information about the wayland-devel
mailing list