1From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2From: Lloyd Pique <lpique@google.com> 3Date: Fri, 29 Jan 2021 14:26:03 -0800 4Subject: [PATCH 1/3] client: Support client protocol loggers 5 6This is very much based on commit 450f06e2 which added server protocol 7loggers. 8 9Adds a new pair of public API functions: 10 11* wl_display_add_protocol_logger_client allows the client to register a 12 function to be called to log each message that is sent or received. 13 14* wl_protocol_logger_client_destroy allows the client to unregister the 15 function. 16 17As with the server protocol loggers, this is akin to setting 18WAYLAND_DEBUG=1, but allows the client code to choose how the messages 19are logged, and it can also enable and disable logging at run time. 20 21The logging logic for the client was also changed to log all events, not 22just the ones that have listeners or dispatchers. 23 24Signed-off-by: Lloyd Pique <lpique@google.com> 25 26diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h 27index 0cd96e0..547ae04 100644 28--- a/src/wayland-client-core.h 29+++ b/src/wayland-client-core.h 30@@ -267,6 +267,32 @@ wl_display_read_events(struct wl_display *display); 31 void 32 wl_log_set_handler_client(wl_log_func_t handler); 33 34+enum wl_protocol_logger_client_type { 35+ WL_PROTOCOL_LOGGER_CLIENT_REQUEST, 36+ WL_PROTOCOL_LOGGER_CLIENT_EVENT, 37+}; 38+ 39+struct wl_protocol_logger_client_message { 40+ struct wl_proxy *proxy; 41+ int message_opcode; 42+ const struct wl_message *message; 43+ int arguments_count; 44+ const union wl_argument *arguments; 45+}; 46+ 47+typedef void (*wl_protocol_logger_client_func_t)( 48+ void *user_data, 49+ enum wl_protocol_logger_client_type direction, 50+ const struct wl_protocol_logger_client_message *message); 51+ 52+struct wl_protocol_logger_client * 53+wl_display_add_protocol_logger_client(struct wl_display *display, 54+ wl_protocol_logger_client_func_t, 55+ void *user_data); 56+ 57+void 58+wl_protocol_logger_client_destroy(struct wl_protocol_logger_client *logger); 59+ 60 #ifdef __cplusplus 61 } 62 #endif 63diff --git a/src/wayland-client.c b/src/wayland-client.c 64index 21d4606..7f5a651 100644 65--- a/src/wayland-client.c 66+++ b/src/wayland-client.c 67@@ -107,12 +107,47 @@ struct wl_display { 68 int reader_count; 69 uint32_t read_serial; 70 pthread_cond_t reader_cond; 71+ 72+ struct wl_list protocol_loggers; 73 }; 74 75 /** \endcond */ 76 77+struct wl_protocol_logger_client { 78+ struct wl_list link; 79+ wl_protocol_logger_client_func_t func; 80+ void *user_data; 81+}; 82+ 83 static int debug_client = 0; 84 85+static void 86+log_closure(struct wl_closure *closure, struct wl_proxy* proxy, int send) 87+{ 88+ struct wl_display *display = proxy->display; 89+ struct wl_protocol_logger_client *protocol_logger; 90+ struct wl_protocol_logger_client_message message; 91+ 92+ if (debug_client) 93+ wl_closure_print(closure, &proxy->object, send); 94+ 95+ if (!wl_list_empty(&display->protocol_loggers)) { 96+ message.proxy = proxy; 97+ message.message_opcode = closure->opcode; 98+ message.message = closure->message; 99+ message.arguments_count = closure->count; 100+ message.arguments = closure->args; 101+ wl_list_for_each(protocol_logger, &display->protocol_loggers, 102+ link) { 103+ protocol_logger->func( 104+ protocol_logger->user_data, 105+ send ? WL_PROTOCOL_LOGGER_CLIENT_REQUEST : 106+ WL_PROTOCOL_LOGGER_CLIENT_EVENT, 107+ &message); 108+ } 109+ } 110+} 111+ 112 /** 113 * This helper function wakes up all threads that are 114 * waiting for display->reader_cond (i. e. when reading is done, 115@@ -751,8 +786,7 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, 116 goto err_unlock; 117 } 118 119- if (debug_client) 120- wl_closure_print(closure, &proxy->object, true); 121+ log_closure(closure, proxy, true); 122 123 if (wl_closure_send(closure, proxy->display->connection)) { 124 wl_log("Error sending request: %s\n", strerror(errno)); 125@@ -1056,6 +1090,7 @@ wl_display_connect_to_fd(int fd) 126 pthread_mutex_init(&display->mutex, NULL); 127 pthread_cond_init(&display->reader_cond, NULL); 128 display->reader_count = 0; 129+ wl_list_init(&display->protocol_loggers); 130 131 wl_map_insert_new(&display->objects, 0, NULL); 132 133@@ -1177,6 +1212,7 @@ wl_display_disconnect(struct wl_display *display) 134 wl_map_release(&display->objects); 135 wl_event_queue_release(&display->default_queue); 136 wl_event_queue_release(&display->display_queue); 137+ wl_list_remove(&display->protocol_loggers); 138 pthread_mutex_destroy(&display->mutex); 139 pthread_cond_destroy(&display->reader_cond); 140 close(display->fd); 141@@ -1439,16 +1475,12 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) 142 143 pthread_mutex_unlock(&display->mutex); 144 145- if (proxy->dispatcher) { 146- if (debug_client) 147- wl_closure_print(closure, &proxy->object, false); 148+ log_closure(closure, proxy, false); 149 150+ if (proxy->dispatcher) { 151 wl_closure_dispatch(closure, proxy->dispatcher, 152 &proxy->object, opcode); 153 } else if (proxy->object.implementation) { 154- if (debug_client) 155- wl_closure_print(closure, &proxy->object, false); 156- 157 wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT, 158 &proxy->object, opcode, proxy->user_data); 159 } 160@@ -2280,3 +2312,60 @@ wl_log_set_handler_client(wl_log_func_t handler) 161 { 162 wl_log_handler = handler; 163 } 164+ 165+/** Adds a new protocol client logger. 166+ * 167+ * When a new protocol message arrives or is sent from the client 168+ * all the protocol logger functions will be called, carrying the 169+ * \a user_data pointer, the type of the message (request or 170+ * event) and the actual message. 171+ * The lifetime of the messages passed to the logger function ends 172+ * when they return so the messages cannot be stored and accessed 173+ * later. 174+ * 175+ * \a errno is set on error. 176+ * 177+ * \param display The display object 178+ * \param func The function to call to log a new protocol message 179+ * \param user_data The user data pointer to pass to \a func 180+ * 181+ * \return The protocol logger object on success, NULL on failure. 182+ * 183+ * \sa wl_protocol_logger_client_destroy 184+ * 185+ * \memberof wl_display 186+ */ 187+WL_EXPORT struct wl_protocol_logger_client * 188+wl_display_add_protocol_logger_client(struct wl_display *display, 189+ wl_protocol_logger_client_func_t func, 190+ void *user_data) 191+{ 192+ struct wl_protocol_logger_client *logger; 193+ 194+ logger = malloc(sizeof *logger); 195+ if (!logger) 196+ return NULL; 197+ 198+ logger->func = func; 199+ logger->user_data = user_data; 200+ wl_list_insert(&display->protocol_loggers, &logger->link); 201+ 202+ return logger; 203+} 204+ 205+/** Destroys a protocol client logger. 206+ * 207+ * This function destroys a protocol client logger and removes it from the 208+ * display it was added to with \a wl_display_add_protocol_logger_client. 209+ * The \a logger object becomes invalid after calling this function. 210+ * 211+ * \sa wl_display_add_protocol_logger_client 212+ * 213+ * \memberof wl_protocol_logger_client 214+ */ 215+WL_EXPORT void 216+wl_protocol_logger_client_destroy(struct wl_protocol_logger_client *logger) 217+{ 218+ wl_list_remove(&logger->link); 219+ free(logger); 220+} 221diff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c 222index 80c74aa..e409368 100644 223--- a/tests/protocol-logger-test.c 224+++ b/tests/protocol-logger-test.c 225@@ -52,6 +52,12 @@ struct compositor { 226 struct wl_client *client; 227 }; 228 229+struct client { 230+ struct wl_display *display; 231+ struct wl_callback *cb; 232+ int message; 233+}; 234+ 235 struct message { 236 enum wl_protocol_logger_type type; 237 const char *class; 238@@ -82,6 +88,36 @@ struct message { 239 }, 240 }; 241 242+struct client_message { 243+ enum wl_protocol_logger_client_type type; 244+ const char *class; 245+ int opcode; 246+ const char *message_name; 247+ int args_count; 248+} client_messages[] = { 249+ { 250+ .type = WL_PROTOCOL_LOGGER_CLIENT_REQUEST, 251+ .class = "wl_display", 252+ .opcode = 0, 253+ .message_name = "sync", 254+ .args_count = 1, 255+ }, 256+ { 257+ .type = WL_PROTOCOL_LOGGER_CLIENT_EVENT, 258+ .class = "wl_display", 259+ .opcode = 1, 260+ .message_name = "delete_id", 261+ .args_count = 1, 262+ }, 263+ { 264+ .type = WL_PROTOCOL_LOGGER_CLIENT_EVENT, 265+ .class = "wl_callback", 266+ .opcode = 0, 267+ .message_name = "done", 268+ .args_count = 1, 269+ }, 270+}; 271+ 272 static void 273 logger_func(void *user_data, enum wl_protocol_logger_type type, 274 const struct wl_protocol_logger_message *message) 275@@ -98,6 +134,20 @@ logger_func(void *user_data, enum wl_protocol_logger_type type, 276 c->client = wl_resource_get_client(message->resource); 277 } 278 279+static void 280+client_logger_func(void *user_data, enum wl_protocol_logger_client_type type, 281+ const struct wl_protocol_logger_client_message *message) 282+{ 283+ struct client *c = user_data; 284+ struct client_message *msg = &client_messages[c->message++]; 285+ 286+ assert(msg->type == type); 287+ assert(strcmp(msg->class, wl_proxy_get_class(message->proxy)) == 0); 288+ assert(msg->opcode == message->message_opcode); 289+ assert(strcmp(msg->message_name, message->message->name) == 0); 290+ assert(msg->args_count == message->arguments_count); 291+} 292+ 293 static void 294 callback_done(void *data, struct wl_callback *cb, uint32_t time) 295 { 296@@ -114,11 +164,9 @@ TEST(logger) 297 298 const char *socket; 299 struct compositor compositor = { 0 }; 300- struct { 301- struct wl_display *display; 302- struct wl_callback *cb; 303- } client; 304+ struct client client = { 0 }; 305 struct wl_protocol_logger *logger; 306+ struct wl_protocol_logger_client *logger_client; 307 308 require_xdg_runtime_dir(); 309 310@@ -130,6 +178,8 @@ TEST(logger) 311 logger_func, &compositor); 312 313 client.display = wl_display_connect(socket); 314+ logger_client = wl_display_add_protocol_logger_client( 315+ client.display, client_logger_func, &client); 316 client.cb = wl_display_sync(client.display); 317 wl_callback_add_listener(client.cb, &callback_listener, NULL); 318 wl_display_flush(client.display); 319@@ -142,6 +192,7 @@ TEST(logger) 320 wl_display_dispatch(client.display); 321 wl_display_disconnect(client.display); 322 323+ wl_protocol_logger_client_destroy(logger_client); 324 wl_client_destroy(compositor.client); 325 wl_protocol_logger_destroy(logger); 326 wl_display_destroy(compositor.display); 327