| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| From: Lloyd Pique <lpique@google.com> |
| Date: Fri, 29 Jan 2021 17:24:56 -0800 |
| Subject: [PATCH 2/3] tests: Add demo real-world protocol logging |
| |
| Adds a real-world sample function for protocol message loging, |
| duplicating the same output produced by the internal wl_closure_print. |
| |
| Signed-off-by: Lloyd Pique <lpique@google.com> |
| |
| diff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c |
| index e409368..d0bca41 100644 |
| --- a/tests/protocol-logger-test.c |
| +++ b/tests/protocol-logger-test.c |
| @@ -29,10 +29,12 @@ |
| #include <string.h> |
| #include <stdio.h> |
| #include <sys/un.h> |
| +#include <time.h> |
| #include <unistd.h> |
| |
| #include "wayland-client.h" |
| #include "wayland-server.h" |
| +#include "wayland-util.h" |
| #include "test-runner.h" |
| |
| /* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */ |
| @@ -148,6 +150,116 @@ client_logger_func(void *user_data, enum wl_protocol_logger_client_type type, |
| assert(msg->args_count == message->arguments_count); |
| } |
| |
| +// A slightly simplified version of get_next_argument() from src/connection.c |
| +static const char* |
| +get_next_argument_type(const char *signature, char* type) |
| +{ |
| + for (; *signature; ++signature) { |
| + assert(strchr("iufsonah?", *signature) != NULL); |
| + switch (*signature) { |
| + case 'i': |
| + case 'u': |
| + case 'f': |
| + case 's': |
| + case 'o': |
| + case 'n': |
| + case 'a': |
| + case 'h': |
| + *type = *signature; |
| + return signature + 1; |
| + case '?': |
| + break; |
| + |
| + } |
| + } |
| + *type = 0; |
| + return signature; |
| +} |
| + |
| +// This duplicates what the internal wl_closure_print function does, and can be |
| +// used as a starting point for a client or server that wants to log messages. |
| +static void |
| +client_log_to_stderr_demo(void *user_data, |
| + enum wl_protocol_logger_client_type type, |
| + const struct wl_protocol_logger_client_message *message) { |
| + int i; |
| + char arg_type; |
| + const char *signature = message->message->signature; |
| + const union wl_argument* args = message->arguments; |
| + struct wl_proxy* arg_proxy; |
| + const char* arg_class; |
| + struct timespec tp; |
| + unsigned int time; |
| + |
| + clock_gettime(CLOCK_REALTIME, &tp); |
| + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); |
| + |
| + // Note: server logger will be given message->resource, and should |
| + // use wl_resource_get_class and wl_resolurce_get_id. |
| + fprintf(stderr, "[%10.3f] %s%s@%u.%s(", |
| + time / 1000.0, |
| + (type == WL_PROTOCOL_LOGGER_CLIENT_REQUEST) ? " -> " : "", |
| + wl_proxy_get_class(message->proxy), wl_proxy_get_id(message->proxy), |
| + message->message->name); |
| + |
| + for (i = 0; i < message->arguments_count; i++) { |
| + signature = get_next_argument_type(signature, &arg_type); |
| + if (i > 0) |
| + fprintf(stderr, ", "); |
| + |
| + switch (arg_type) { |
| + case 'u': |
| + fprintf(stderr, "%u", args[i].u); |
| + break; |
| + case 'i': |
| + fprintf(stderr, "%d", args[i].i); |
| + break; |
| + case 'f': |
| + fprintf(stderr, "%f", wl_fixed_to_double(args[i].f)); |
| + break; |
| + case 's': |
| + if (args[i].s) |
| + fprintf(stderr, "\"%s\"", args[i].s); |
| + else |
| + fprintf(stderr, "nil"); |
| + break; |
| + case 'o': |
| + if (args[i].o) { |
| + // Note: server logger should instead cast to |
| + // wl_resource, and use wl_resource_get_class |
| + // and wl_resource_get_id. |
| + arg_proxy = (struct wl_proxy *)(args[i].o); |
| + arg_class = wl_proxy_get_class(arg_proxy); |
| + |
| + fprintf(stderr, "%s@%u", |
| + arg_class ? arg_class : "[unknown]", |
| + wl_proxy_get_id(arg_proxy)); |
| + } else { |
| + fprintf(stderr, "nil"); |
| + } |
| + break; |
| + case 'n': |
| + fprintf(stderr, "new id %s@", |
| + (message->message->types[i]) ? |
| + message->message->types[i]->name : |
| + "[unknown]"); |
| + if (args[i].n != 0) |
| + fprintf(stderr, "%u", args[i].n); |
| + else |
| + fprintf(stderr, "nil"); |
| + break; |
| + case 'a': |
| + fprintf(stderr, "array"); |
| + break; |
| + case 'h': |
| + fprintf(stderr, "fd %d", args[i].h); |
| + break; |
| + } |
| + } |
| + |
| + fprintf(stderr, ")\n"); |
| +} |
| + |
| static void |
| callback_done(void *data, struct wl_callback *cb, uint32_t time) |
| { |
| @@ -167,6 +279,7 @@ TEST(logger) |
| struct client client = { 0 }; |
| struct wl_protocol_logger *logger; |
| struct wl_protocol_logger_client *logger_client; |
| + struct wl_protocol_logger_client *logger_client_demo; |
| |
| require_xdg_runtime_dir(); |
| |
| @@ -180,6 +293,8 @@ TEST(logger) |
| client.display = wl_display_connect(socket); |
| logger_client = wl_display_add_protocol_logger_client( |
| client.display, client_logger_func, &client); |
| + logger_client_demo = wl_display_add_protocol_logger_client( |
| + client.display, client_log_to_stderr_demo, &client); |
| client.cb = wl_display_sync(client.display); |
| wl_callback_add_listener(client.cb, &callback_listener, NULL); |
| wl_display_flush(client.display); |
| @@ -193,6 +308,7 @@ TEST(logger) |
| wl_display_disconnect(client.display); |
| |
| wl_protocol_logger_client_destroy(logger_client); |
| + wl_protocol_logger_client_destroy(logger_client_demo); |
| wl_client_destroy(compositor.client); |
| wl_protocol_logger_destroy(logger); |
| wl_display_destroy(compositor.display); |