xref: /aosp_15_r20/external/wayland/tests/protocol-logger-test.c (revision 84e872a0dc482bffdb63672969dd03a827d67c73)
1 /*
2  * Copyright © 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, [email protected]
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <sys/un.h>
32 #include <time.h>
33 #include <unistd.h>
34 
35 #include "wayland-client.h"
36 #include "wayland-server.h"
37 #include "test-runner.h"
38 
39 #define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0])
40 
41 /* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */
42 static const char *
require_xdg_runtime_dir(void)43 require_xdg_runtime_dir(void)
44 {
45 	char *val = getenv("XDG_RUNTIME_DIR");
46 	assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test");
47 
48 	return val;
49 }
50 
51 struct expected_compositor_message {
52 	enum wl_protocol_logger_type type;
53 	const char *class;
54 	int opcode;
55 	const char *message_name;
56 	int args_count;
57 };
58 
59 struct compositor {
60 	struct wl_display *display;
61 	struct wl_event_loop *loop;
62 	struct wl_protocol_logger *logger;
63 
64 	struct expected_compositor_message *expected_msg;
65 	int expected_msg_count;
66 	int actual_msg_count;
67 	struct wl_client *client;
68 };
69 
70 struct expected_client_message {
71 	enum wl_client_message_type type;
72 	enum wl_client_message_discarded_reason discarded_reason;
73 	const char *class;
74 	int opcode;
75 	const char *message_name;
76 	int args_count;
77 };
78 
79 struct client {
80 	struct wl_display *display;
81 	struct wl_callback *cb;
82 	struct wl_client_observer *sequence_observer;
83 	struct wl_client_observer *stderr_logger;
84 
85 	struct expected_client_message *expected_msg;
86 	int expected_msg_count;
87 	int actual_msg_count;
88 };
89 
90 #define ASSERT_LT(arg1, arg2, ...)                                            \
91 	if (arg1 >= arg2)                                                     \
92 		fprintf(stderr, __VA_ARGS__);                                 \
93 	assert(arg1 < arg2)
94 
95 #define ASSERT_EQ(arg1, arg2, ...)                                            \
96 	if (arg1 != arg2)                                                     \
97 		fprintf(stderr, __VA_ARGS__);                                 \
98 	assert(arg1 == arg2)
99 
100 #define ASSERT_STR_EQ(arg1, arg2, ...)                                        \
101 	if (strcmp(arg1, arg2) != 0)                                          \
102 		fprintf(stderr, __VA_ARGS__);                                 \
103 	assert(strcmp(arg1, arg2) == 0)
104 
105 static void
compositor_sequence_observer_func(void * user_data,enum wl_protocol_logger_type actual_type,const struct wl_protocol_logger_message * actual_msg)106 compositor_sequence_observer_func(
107 	void *user_data, enum wl_protocol_logger_type actual_type,
108 	const struct wl_protocol_logger_message *actual_msg)
109 {
110 	struct compositor *c = user_data;
111 	struct expected_compositor_message *expected_msg;
112 	int actual_msg_count = c->actual_msg_count++;
113 	char details_msg[256];
114 
115 	c->client = wl_resource_get_client(actual_msg->resource);
116 
117 	if (!c->expected_msg)
118 		return;
119 
120 	ASSERT_LT(actual_msg_count, c->expected_msg_count,
121 		  "actual count %d exceeds expected count %d\n",
122 		  actual_msg_count, c->expected_msg_count);
123 
124 	expected_msg = &c->expected_msg[actual_msg_count];
125 
126 	snprintf(details_msg, sizeof details_msg,
127 		 "compositor msg %d of %d actual [%d, '%s', %d, '%s', %d] vs "
128 		 "expected [%d, '%s', %d, '%s', %d]\n",
129 		 c->actual_msg_count, c->expected_msg_count, actual_type,
130 		 wl_resource_get_class(actual_msg->resource),
131 		 actual_msg->message_opcode, actual_msg->message->name,
132 		 actual_msg->arguments_count, expected_msg->type,
133 		 expected_msg->class, expected_msg->opcode,
134 		 expected_msg->message_name, expected_msg->args_count);
135 
136 	ASSERT_EQ(expected_msg->type, actual_type, "type mismatch: %s",
137 		  details_msg);
138 	ASSERT_STR_EQ(expected_msg->class,
139 		      wl_resource_get_class(actual_msg->resource),
140 		      "class mismatch: %s", details_msg);
141 	ASSERT_EQ(expected_msg->opcode, actual_msg->message_opcode,
142 		  "opcode mismatch: %s", details_msg);
143 	ASSERT_STR_EQ(expected_msg->message_name, actual_msg->message->name,
144 		      "message name mismatch: %s", details_msg);
145 	ASSERT_EQ(expected_msg->args_count, actual_msg->arguments_count,
146 		  "arg count mismatch: %s", details_msg);
147 }
148 
149 static void
client_sequence_observer_func(void * user_data,enum wl_client_message_type actual_type,const struct wl_client_observed_message * actual_msg)150 client_sequence_observer_func(
151 	void *user_data, enum wl_client_message_type actual_type,
152 	const struct wl_client_observed_message *actual_msg)
153 {
154 	struct client *c = user_data;
155 	struct expected_client_message *expected_msg;
156 	int actual_msg_count = c->actual_msg_count++;
157 	char details_msg[256];
158 
159 	if (!c->expected_msg)
160 		return;
161 
162 	ASSERT_LT(actual_msg_count, c->expected_msg_count,
163 		  "actual count %d exceeds expected count %d\n",
164 		  actual_msg_count, c->expected_msg_count);
165 	expected_msg = &c->expected_msg[actual_msg_count];
166 
167 	snprintf(details_msg, sizeof details_msg,
168 		 "client msg %d of %d actual [%d, %d, '%s', %d, '%s', %d] vs "
169 		 "expected [%d, %d, '%s', %d, '%s', %d]\n",
170 		 c->actual_msg_count, c->expected_msg_count, actual_type,
171 		 actual_msg->discarded_reason,
172 		 wl_proxy_get_class(actual_msg->proxy),
173 		 actual_msg->message_opcode, actual_msg->message->name,
174 		 actual_msg->arguments_count, expected_msg->type,
175 		 expected_msg->discarded_reason, expected_msg->class,
176 		 expected_msg->opcode, expected_msg->message_name,
177 		 expected_msg->args_count);
178 
179 	ASSERT_EQ(expected_msg->type, actual_type, "type mismatch: %s",
180 		  details_msg);
181 	ASSERT_EQ(expected_msg->discarded_reason, actual_msg->discarded_reason,
182 		  "discarded reason mismatch: %s", details_msg);
183 	ASSERT_STR_EQ(expected_msg->class,
184 		      wl_proxy_get_class(actual_msg->proxy),
185 		      "class mismatch: %s", details_msg);
186 	ASSERT_EQ(expected_msg->opcode, actual_msg->message_opcode,
187 		  "opcode mismatch: %s", details_msg);
188 	ASSERT_STR_EQ(expected_msg->message_name, actual_msg->message->name,
189 		      "message name mismatch: %s", details_msg);
190 	ASSERT_EQ(expected_msg->args_count, actual_msg->arguments_count,
191 		  "arg count mismatch: %s", details_msg);
192 }
193 
194 // A slightly simplified version of get_next_argument() from src/connection.c
195 static const char *
get_next_argument_type(const char * signature,char * type)196 get_next_argument_type(const char *signature, char *type)
197 {
198 	for (; *signature; ++signature) {
199 		assert(strchr("iufsonah?", *signature) != NULL);
200 		switch (*signature) {
201 		case 'i':
202 		case 'u':
203 		case 'f':
204 		case 's':
205 		case 'o':
206 		case 'n':
207 		case 'a':
208 		case 'h':
209 			*type = *signature;
210 			return signature + 1;
211 		case '?':
212 			break;
213 		}
214 	}
215 	*type = 0;
216 	return signature;
217 }
218 
219 // This duplicates what the internal wl_closure_print function does, and can be
220 // used as a starting point for a client or server that wants to log messages.
221 static void
client_log_to_stderr_demo(void * user_data,enum wl_client_message_type type,const struct wl_client_observed_message * message)222 client_log_to_stderr_demo(void *user_data, enum wl_client_message_type type,
223 			  const struct wl_client_observed_message *message)
224 {
225 	int i;
226 	char arg_type;
227 	const char *signature = message->message->signature;
228 	const union wl_argument *args = message->arguments;
229 	struct wl_proxy *arg_proxy;
230 	const char *arg_class;
231 	struct timespec tp;
232 	unsigned long long time;
233 	FILE *f;
234 	char *buffer;
235 	size_t buffer_length;
236 
237 	f = open_memstream(&buffer, &buffer_length);
238 	if (f == NULL)
239 		return;
240 
241 	clock_gettime(CLOCK_REALTIME, &tp);
242 	time = (tp.tv_sec * 1000000LL) + (tp.tv_nsec / 1000);
243 
244 	// Note: server logger will be given message->resource, and should
245 	// use wl_resource_get_class and wl_resolurce_get_id.
246 	fprintf(f, "[%7llu.%03llu] %s%s%s%s%s@%u.%s(", time / 1000, time % 1000,
247 		(message->discarded_reason_str ? "discarded[" : ""),
248 		(message->discarded_reason_str ? message->discarded_reason_str
249 					       : ""),
250 		(message->discarded_reason_str ? "] " : ""),
251 		(type == WL_CLIENT_MESSAGE_REQUEST) ? " -> " : "",
252 		wl_proxy_get_class(message->proxy),
253 		wl_proxy_get_id(message->proxy), message->message->name);
254 
255 	for (i = 0; i < message->arguments_count; i++) {
256 		signature = get_next_argument_type(signature, &arg_type);
257 		if (i > 0)
258 			fprintf(f, ", ");
259 
260 		switch (arg_type) {
261 		case 'u':
262 			fprintf(f, "%u", args[i].u);
263 			break;
264 		case 'i':
265 			fprintf(f, "%d", args[i].i);
266 			break;
267 		case 'f':
268 			fprintf(f, "%f", wl_fixed_to_double(args[i].f));
269 			break;
270 		case 's':
271 			if (args[i].s)
272 				fprintf(f, "\"%s\"", args[i].s);
273 			else
274 				fprintf(f, "nil");
275 			break;
276 		case 'o':
277 			if (args[i].o) {
278 				// Note: server logger should instead use
279 				// wl_resource_from_object, and then
280 				// wl_resource_get_class and
281 				// wl_resource_get_id.
282 				arg_proxy = wl_proxy_from_object(args[i].o);
283 				arg_class = wl_proxy_get_class(arg_proxy);
284 
285 				fprintf(f, "%s@%u",
286 					arg_class ? arg_class : "[unknown]",
287 					wl_proxy_get_id(arg_proxy));
288 			} else {
289 				fprintf(f, "nil");
290 			}
291 			break;
292 		case 'n':
293 			fprintf(f, "new id %s@",
294 				(message->message->types[i])
295 					? message->message->types[i]->name
296 					: "[unknown]");
297 			if (args[i].n != 0)
298 				fprintf(f, "%u", args[i].n);
299 			else
300 				fprintf(f, "nil");
301 			break;
302 		case 'a':
303 			fprintf(f, "array");
304 			break;
305 		case 'h':
306 			fprintf(f, "fd %d", args[i].h);
307 			break;
308 		}
309 	}
310 
311 	fprintf(f, ")\n");
312 
313 	if (fclose(f) == 0) {
314 		fprintf(stderr, "%s", buffer);
315 		free(buffer);
316 	}
317 }
318 
319 static void
callback_done(void * data,struct wl_callback * cb,uint32_t time)320 callback_done(void *data, struct wl_callback *cb, uint32_t time)
321 {
322 	wl_callback_destroy(cb);
323 }
324 
325 static const struct wl_callback_listener callback_listener = {
326 	callback_done,
327 };
328 
329 static void
logger_setup(struct compositor * compositor,struct client * client)330 logger_setup(struct compositor *compositor, struct client *client)
331 {
332 	const char *socket;
333 
334 	require_xdg_runtime_dir();
335 
336 	compositor->display = wl_display_create();
337 	compositor->loop = wl_display_get_event_loop(compositor->display);
338 	socket = wl_display_add_socket_auto(compositor->display);
339 
340 	compositor->logger = wl_display_add_protocol_logger(
341 		compositor->display, compositor_sequence_observer_func,
342 		compositor);
343 
344 	client->display = wl_display_connect(socket);
345 	client->sequence_observer = wl_display_create_client_observer(
346 		client->display, client_sequence_observer_func, client);
347 	client->stderr_logger = wl_display_create_client_observer(
348 		client->display, client_log_to_stderr_demo, client);
349 }
350 
351 static void
logger_teardown(struct compositor * compositor,struct client * client)352 logger_teardown(struct compositor *compositor, struct client *client)
353 {
354 	wl_client_observer_destroy(client->sequence_observer);
355 	wl_client_observer_destroy(client->stderr_logger);
356 	wl_display_disconnect(client->display);
357 
358 	wl_client_destroy(compositor->client);
359 	wl_protocol_logger_destroy(compositor->logger);
360 	wl_display_destroy(compositor->display);
361 }
362 
TEST(logger)363 TEST(logger)
364 {
365 	test_set_timeout(1);
366 
367 	struct expected_compositor_message compositor_messages[] = {
368 		{
369 			.type = WL_PROTOCOL_LOGGER_REQUEST,
370 			.class = "wl_display",
371 			.opcode = 0,
372 			.message_name = "sync",
373 			.args_count = 1,
374 		},
375 		{
376 			.type = WL_PROTOCOL_LOGGER_EVENT,
377 			.class = "wl_callback",
378 			.opcode = 0,
379 			.message_name = "done",
380 			.args_count = 1,
381 		},
382 		{
383 			.type = WL_PROTOCOL_LOGGER_EVENT,
384 			.class = "wl_display",
385 			.opcode = 1,
386 			.message_name = "delete_id",
387 			.args_count = 1,
388 		},
389 	};
390 	struct expected_client_message client_messages[] = {
391 		{
392 			.type = WL_CLIENT_MESSAGE_REQUEST,
393 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
394 			.class = "wl_display",
395 			.opcode = 0,
396 			.message_name = "sync",
397 			.args_count = 1,
398 		},
399 		{
400 			.type = WL_CLIENT_MESSAGE_EVENT,
401 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
402 			.class = "wl_display",
403 			.opcode = 1,
404 			.message_name = "delete_id",
405 			.args_count = 1,
406 		},
407 		{
408 			.type = WL_CLIENT_MESSAGE_EVENT,
409 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
410 			.class = "wl_callback",
411 			.opcode = 0,
412 			.message_name = "done",
413 			.args_count = 1,
414 		},
415 	};
416 	struct compositor compositor = { 0 };
417 	struct client client = { 0 };
418 
419 	logger_setup(&compositor, &client);
420 
421 	compositor.expected_msg = &compositor_messages[0];
422 	compositor.expected_msg_count = ARRAY_LENGTH(compositor_messages);
423 
424 	client.expected_msg = &client_messages[0];
425 	client.expected_msg_count = ARRAY_LENGTH(client_messages);
426 
427 	client.cb = wl_display_sync(client.display);
428 	wl_callback_add_listener(client.cb, &callback_listener, NULL);
429 	wl_display_flush(client.display);
430 
431 	while (compositor.actual_msg_count < compositor.expected_msg_count) {
432 		wl_event_loop_dispatch(compositor.loop, -1);
433 		wl_display_flush_clients(compositor.display);
434 	}
435 
436 	while (client.actual_msg_count < client.expected_msg_count) {
437 		wl_display_dispatch(client.display);
438 	}
439 
440 	logger_teardown(&compositor, &client);
441 }
442 
TEST(client_discards_if_dead_on_dispatch)443 TEST(client_discards_if_dead_on_dispatch)
444 {
445 	test_set_timeout(1);
446 
447 	struct expected_client_message client_messages[] = {
448 		{
449 			.type = WL_CLIENT_MESSAGE_REQUEST,
450 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
451 			.class = "wl_display",
452 			.opcode = 0,
453 			.message_name = "sync",
454 			.args_count = 1,
455 		},
456 		{
457 			.type = WL_CLIENT_MESSAGE_EVENT,
458 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
459 			.class = "wl_display",
460 			.opcode = 1,
461 			.message_name = "delete_id",
462 			.args_count = 1,
463 		},
464 		{
465 			.type = WL_CLIENT_MESSAGE_EVENT,
466 			.discarded_reason =
467 				WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH,
468 			.class = "wl_callback",
469 			.opcode = 0,
470 			.message_name = "done",
471 			.args_count = 1,
472 		},
473 	};
474 	struct compositor compositor = { 0 };
475 	struct client client = { 0 };
476 
477 	logger_setup(&compositor, &client);
478 
479 	compositor.expected_msg_count = 3;
480 
481 	client.expected_msg = &client_messages[0];
482 	client.expected_msg_count = ARRAY_LENGTH(client_messages);
483 
484 	client.cb = wl_display_sync(client.display);
485 	wl_callback_add_listener(client.cb, &callback_listener, NULL);
486 	wl_display_flush(client.display);
487 
488 	while (compositor.actual_msg_count < compositor.expected_msg_count) {
489 		wl_event_loop_dispatch(compositor.loop, -1);
490 		wl_display_flush_clients(compositor.display);
491 	}
492 
493 	wl_display_prepare_read(client.display);
494 	wl_display_read_events(client.display);
495 
496 	// To get a WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH, we
497 	// destroy the callback after reading client events, but before
498 	// dispatching them.
499 	wl_callback_destroy(client.cb);
500 
501 	while (client.actual_msg_count < client.expected_msg_count) {
502 		wl_display_dispatch(client.display);
503 	}
504 
505 	logger_teardown(&compositor, &client);
506 }
507 
TEST(client_discards_if_no_listener_on_dispatch)508 TEST(client_discards_if_no_listener_on_dispatch)
509 {
510 	test_set_timeout(1);
511 
512 	struct expected_client_message client_messages[] = {
513 		{
514 			.type = WL_CLIENT_MESSAGE_REQUEST,
515 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
516 			.class = "wl_display",
517 			.opcode = 0,
518 			.message_name = "sync",
519 			.args_count = 1,
520 		},
521 		{
522 			.type = WL_CLIENT_MESSAGE_EVENT,
523 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
524 			.class = "wl_display",
525 			.opcode = 1,
526 			.message_name = "delete_id",
527 			.args_count = 1,
528 		},
529 		{
530 			.type = WL_CLIENT_MESSAGE_EVENT,
531 			.discarded_reason =
532 				WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH,
533 			.class = "wl_callback",
534 			.opcode = 0,
535 			.message_name = "done",
536 			.args_count = 1,
537 		},
538 	};
539 	struct compositor compositor = { 0 };
540 	struct client client = { 0 };
541 
542 	logger_setup(&compositor, &client);
543 
544 	compositor.expected_msg_count = 3;
545 
546 	client.expected_msg = &client_messages[0];
547 	client.expected_msg_count = ARRAY_LENGTH(client_messages);
548 
549 	client.cb = wl_display_sync(client.display);
550 	wl_display_flush(client.display);
551 
552 	while (compositor.actual_msg_count < compositor.expected_msg_count) {
553 		wl_event_loop_dispatch(compositor.loop, -1);
554 		wl_display_flush_clients(compositor.display);
555 	}
556 
557 	while (client.actual_msg_count < client.expected_msg_count) {
558 		wl_display_dispatch(client.display);
559 	}
560 
561 	wl_callback_destroy(client.cb);
562 
563 	logger_teardown(&compositor, &client);
564 }
565 
TEST(client_discards_if_invalid_id_on_demarshal)566 TEST(client_discards_if_invalid_id_on_demarshal)
567 {
568 	test_set_timeout(1);
569 
570 	struct expected_client_message client_messages[] = {
571 		{
572 			.type = WL_CLIENT_MESSAGE_REQUEST,
573 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
574 			.class = "wl_display",
575 			.opcode = 0,
576 			.message_name = "sync",
577 			.args_count = 1,
578 		},
579 		{
580 			.type = WL_CLIENT_MESSAGE_EVENT,
581 			.discarded_reason =
582 				WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL,
583 			.class = "[unknown]",
584 			.opcode = 0,
585 			.message_name = "[event 0, 0 fds, 12 bytes]",
586 			.args_count = 0,
587 		},
588 		{
589 			.type = WL_CLIENT_MESSAGE_EVENT,
590 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
591 			.class = "wl_display",
592 			.opcode = 1,
593 			.message_name = "delete_id",
594 			.args_count = 1,
595 		},
596 	};
597 	struct compositor compositor = { 0 };
598 	struct client client = { 0 };
599 
600 	logger_setup(&compositor, &client);
601 
602 	compositor.expected_msg_count = 3;
603 
604 	client.expected_msg = &client_messages[0];
605 	client.expected_msg_count = ARRAY_LENGTH(client_messages);
606 
607 	client.cb = wl_display_sync(client.display);
608 	wl_display_flush(client.display);
609 
610 	while (compositor.actual_msg_count < compositor.expected_msg_count) {
611 		wl_event_loop_dispatch(compositor.loop, -1);
612 		wl_display_flush_clients(compositor.display);
613 	}
614 
615 	// To get a WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL, we
616 	// destroy the callback before reading and dispatching client events.
617 	wl_callback_destroy(client.cb);
618 
619 	while (client.actual_msg_count < client.expected_msg_count) {
620 		wl_display_dispatch(client.display);
621 	}
622 
623 	logger_teardown(&compositor, &client);
624 }
625 
626 static const struct wl_keyboard_interface keyboard_interface = { 0 };
627 
628 static void
seat_get_pointer(struct wl_client * client,struct wl_resource * resource,uint32_t id)629 seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
630 		 uint32_t id)
631 {
632 	assert(false && "Not expected to be called by client.");
633 }
634 
635 static void
seat_get_keyboard(struct wl_client * client,struct wl_resource * resource,uint32_t id)636 seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
637 		  uint32_t id)
638 {
639 	struct wl_resource *keyboard_res;
640 
641 	keyboard_res =
642 		wl_resource_create(client, &wl_keyboard_interface,
643 				   wl_resource_get_version(resource), id);
644 	wl_resource_set_implementation(keyboard_res, &keyboard_interface, NULL,
645 				       NULL);
646 
647 	wl_keyboard_send_key(keyboard_res, 0, 0, 0, 0);
648 }
649 
650 static void
seat_get_touch(struct wl_client * client,struct wl_resource * resource,uint32_t id)651 seat_get_touch(struct wl_client *client, struct wl_resource *resource,
652 	       uint32_t id)
653 {
654 	assert(false && "Not expected to be called by client.");
655 }
656 
657 static void
seat_release(struct wl_client * client,struct wl_resource * resource)658 seat_release(struct wl_client *client, struct wl_resource *resource)
659 {
660 	wl_resource_destroy(resource);
661 }
662 
663 static const struct wl_seat_interface seat_interface = {
664 	&seat_get_pointer,
665 	&seat_get_keyboard,
666 	&seat_get_touch,
667 	&seat_release,
668 };
669 
670 static void
bind_seat(struct wl_client * client,void * data,uint32_t vers,uint32_t id)671 bind_seat(struct wl_client *client, void *data, uint32_t vers, uint32_t id)
672 {
673 	struct wl_resource *seat_res;
674 
675 	seat_res = wl_resource_create(client, &wl_seat_interface, vers, id);
676 	wl_resource_set_implementation(seat_res, &seat_interface, NULL, NULL);
677 }
678 
679 static void
registry_seat_listener_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)680 registry_seat_listener_handle_global(void *data, struct wl_registry *registry,
681 				     uint32_t id, const char *intf,
682 				     uint32_t ver)
683 {
684 	uint32_t *seat_id_ptr = data;
685 
686 	if (strcmp(intf, wl_seat_interface.name) == 0) {
687 		*seat_id_ptr = id;
688 	}
689 }
690 
691 static const struct wl_registry_listener registry_seat_listener = {
692 	registry_seat_listener_handle_global, NULL
693 };
694 
TEST(client_discards_if_zombie_on_demarshal)695 TEST(client_discards_if_zombie_on_demarshal)
696 {
697 	test_set_timeout(1);
698 
699 	struct expected_client_message client_messages[] = {
700 		{
701 			.type = WL_CLIENT_MESSAGE_REQUEST,
702 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
703 			.class = "wl_display",
704 			.opcode = 1,
705 			.message_name = "get_registry",
706 			.args_count = 1,
707 		},
708 		{
709 			.type = WL_CLIENT_MESSAGE_EVENT,
710 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
711 			.class = "wl_registry",
712 			.opcode = 0,
713 			.message_name = "global",
714 			.args_count = 3,
715 		},
716 		{
717 			.type = WL_CLIENT_MESSAGE_REQUEST,
718 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
719 			.class = "wl_registry",
720 			.opcode = 0,
721 			.message_name = "bind",
722 			.args_count = 4,
723 		},
724 		{
725 			.type = WL_CLIENT_MESSAGE_REQUEST,
726 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
727 			.class = "wl_seat",
728 			.opcode = 1,
729 			.message_name = "get_keyboard",
730 			.args_count = 1,
731 		},
732 		{
733 			.type = WL_CLIENT_MESSAGE_REQUEST,
734 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
735 			.class = "wl_keyboard",
736 			.opcode = 0,
737 			.message_name = "release",
738 			.args_count = 0,
739 		},
740 		{
741 			.type = WL_CLIENT_MESSAGE_REQUEST,
742 			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
743 			.class = "wl_seat",
744 			.opcode = 3,
745 			.message_name = "release",
746 			.args_count = 0,
747 		},
748 		{
749 			.type = WL_CLIENT_MESSAGE_EVENT,
750 			.discarded_reason =
751 				WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL,
752 			.class = "[zombie]",
753 			.opcode = 3,
754 			.message_name = "[event 3, 0 fds, 24 bytes]",
755 			.args_count = 0,
756 		},
757 	};
758 
759 	struct compositor compositor = { 0 };
760 	struct client client = { 0 };
761 	struct wl_global *g_keyboard;
762 	struct wl_registry *registry;
763 	struct wl_seat *seat;
764 	struct wl_keyboard *keyboard;
765 	int32_t seat_id;
766 
767 	logger_setup(&compositor, &client);
768 
769 	client.expected_msg = &client_messages[0];
770 	client.expected_msg_count = ARRAY_LENGTH(client_messages);
771 
772 	g_keyboard = wl_global_create(compositor.display, &wl_seat_interface,
773 				      5, &compositor.display, bind_seat);
774 
775 	registry = wl_display_get_registry(client.display);
776 	wl_registry_add_listener(registry, &registry_seat_listener, &seat_id);
777 	wl_display_flush(client.display);
778 
779 	compositor.actual_msg_count = 0;
780 	compositor.expected_msg_count = 2;
781 
782 	while (compositor.actual_msg_count < compositor.expected_msg_count) {
783 		wl_event_loop_dispatch(compositor.loop, -1);
784 		wl_display_flush_clients(compositor.display);
785 	}
786 
787 	wl_display_dispatch(client.display);
788 
789 	seat = wl_registry_bind(registry, seat_id, &wl_seat_interface, 5);
790 	keyboard = wl_seat_get_keyboard(seat);
791 	wl_display_flush(client.display);
792 
793 	compositor.actual_msg_count = 0;
794 	compositor.expected_msg_count = 3;
795 
796 	while (compositor.actual_msg_count < compositor.expected_msg_count) {
797 		wl_event_loop_dispatch(compositor.loop, -1);
798 		wl_display_flush_clients(compositor.display);
799 	}
800 
801 	wl_keyboard_release(keyboard);
802 	wl_seat_release(seat);
803 
804 	wl_display_dispatch(client.display);
805 
806 	wl_registry_destroy(registry);
807 
808 	wl_global_destroy(g_keyboard);
809 
810 	logger_teardown(&compositor, &client);
811 }
812