• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2012 Intel Corporation
3  * Copyright © 2013 Jason Ekstrand
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26 
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <assert.h>
34 #include <sys/socket.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <pthread.h>
40 #include <poll.h>
41 
42 #include "wayland-private.h"
43 #include "wayland-server.h"
44 #include "wayland-client.h"
45 #include "test-runner.h"
46 #include "test-compositor.h"
47 
48 struct display_destroy_listener {
49 	struct wl_listener listener;
50 	int done;
51 };
52 
53 static void
display_destroy_notify(struct wl_listener * l,void * data)54 display_destroy_notify(struct wl_listener *l, void *data)
55 {
56 	struct display_destroy_listener *listener;
57 
58 	listener = container_of(l, struct display_destroy_listener, listener);
59 	listener->done = 1;
60 }
61 
TEST(display_destroy_listener)62 TEST(display_destroy_listener)
63 {
64 	struct wl_display *display;
65 	struct display_destroy_listener a, b;
66 
67 	display = wl_display_create();
68 	assert(display);
69 
70 	a.listener.notify = &display_destroy_notify;
71 	a.done = 0;
72 	wl_display_add_destroy_listener(display, &a.listener);
73 
74 	assert(wl_display_get_destroy_listener(display, display_destroy_notify) ==
75 	       &a.listener);
76 
77 	b.listener.notify = display_destroy_notify;
78 	b.done = 0;
79 	wl_display_add_destroy_listener(display, &b.listener);
80 
81 	wl_list_remove(&a.listener.link);
82 
83 	wl_display_destroy(display);
84 
85 	assert(!a.done);
86 	assert(b.done);
87 }
88 
89 /* Fake 'client' which does not use wl_display_connect, and thus leaves the
90  * file descriptor passed through WAYLAND_SOCKET intact. This should not
91  * trigger an assertion in the leak check. */
92 static void
empty_client(void)93 empty_client(void)
94 {
95 	return;
96 }
97 
TEST(tc_leaks_tests)98 TEST(tc_leaks_tests)
99 {
100 	struct display *d = display_create();
101 	client_create_noarg(d, empty_client);
102 	display_run(d);
103 	display_destroy(d);
104 }
105 
106 /* This is how pre proxy-version registry binds worked,
107  * this should create a proxy that shares the display's
108  * version number: 0 */
109 static void *
old_registry_bind(struct wl_registry * wl_registry,uint32_t name,const struct wl_interface * interface,uint32_t version)110 old_registry_bind(struct wl_registry *wl_registry,
111 		  uint32_t name,
112 		  const struct wl_interface *interface,
113 		  uint32_t version)
114 {
115 	struct wl_proxy *id;
116 
117 	id = wl_proxy_marshal_constructor(
118 		(struct wl_proxy *) wl_registry, WL_REGISTRY_BIND,
119 		interface, name, interface->name, version, NULL);
120 
121 	return (void *) id;
122 }
123 
124 struct handler_info {
125 	struct wl_seat *seat;
126 	uint32_t bind_version;
127 	bool use_unversioned;
128 };
129 
130 static void
registry_handle_globals(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)131 registry_handle_globals(void *data, struct wl_registry *registry,
132 			uint32_t id, const char *intf, uint32_t ver)
133 {
134 	struct handler_info *hi = data;
135 
136 	/* This is only for the proxy version test */
137 	if (hi->bind_version)
138 		ver = hi->bind_version;
139 
140 	if (strcmp(intf, "wl_seat") == 0) {
141 		if (hi->use_unversioned)
142 			hi->seat = old_registry_bind(registry, id,
143 						     &wl_seat_interface, ver);
144 		else
145 			hi->seat = wl_registry_bind(registry, id,
146 						    &wl_seat_interface, ver);
147 		assert(hi->seat);
148 	}
149 }
150 
151 static const struct wl_registry_listener registry_listener = {
152 	registry_handle_globals,
153 	NULL
154 };
155 
156 static struct wl_seat *
client_get_seat_with_info(struct client * c,struct handler_info * hi)157 client_get_seat_with_info(struct client *c, struct handler_info *hi)
158 {
159 	struct wl_registry *reg = wl_display_get_registry(c->wl_display);
160 	assert(reg);
161 
162 	assert(hi);
163 	hi->seat = NULL;
164 	wl_registry_add_listener(reg, &registry_listener, hi);
165 	wl_display_roundtrip(c->wl_display);
166 	assert(hi->seat);
167 
168 	wl_registry_destroy(reg);
169 
170 	return hi->seat;
171 }
172 
173 static struct wl_seat *
client_get_seat(struct client * c)174 client_get_seat(struct client *c)
175 {
176 	struct handler_info hi;
177 
178 	hi.use_unversioned = false;
179 	hi.bind_version = 0;
180 
181 	return client_get_seat_with_info(c, &hi);
182 }
183 
184 static void
check_pending_error(struct client * c,struct wl_proxy * proxy)185 check_pending_error(struct client *c, struct wl_proxy *proxy)
186 {
187 	uint32_t ec, id;
188 	int err;
189 	const struct wl_interface *intf;
190 
191 	err = wl_display_get_error(c->wl_display);
192 	assert(err == EPROTO);
193 
194 	ec = wl_display_get_protocol_error(c->wl_display, &intf, &id);
195 	assert(ec == 23);
196 	assert(intf == &wl_seat_interface);
197 	assert(id == wl_proxy_get_id(proxy));
198 }
199 
200 static void
check_for_error(struct client * c,struct wl_proxy * proxy)201 check_for_error(struct client *c, struct wl_proxy *proxy)
202 {
203 	/* client should be disconnected */
204 	assert(wl_display_roundtrip(c->wl_display) == -1);
205 
206 	check_pending_error(c, proxy);
207 }
208 
209 static struct client_info *
find_client_info(struct display * d,struct wl_client * client)210 find_client_info(struct display *d, struct wl_client *client)
211 {
212 	struct client_info *ci;
213 
214 	wl_list_for_each(ci, &d->clients, link) {
215 		if (ci->wl_client == client)
216 			return ci;
217 	}
218 
219 	return NULL;
220 }
221 
222 static void
bind_seat(struct wl_client * client,void * data,uint32_t vers,uint32_t id)223 bind_seat(struct wl_client *client, void *data,
224 	  uint32_t vers, uint32_t id)
225 {
226 	struct display *d = data;
227 	struct client_info *ci;
228 	struct wl_resource *res;
229 
230 	ci = find_client_info(d, client);
231 	assert(ci);
232 
233 	res = wl_resource_create(client, &wl_seat_interface, vers, id);
234 	assert(res);
235 
236 	/* save the resource as client's info data,
237 	 * so that we can use it later */
238 	ci->data = res;
239 }
240 
241 static void
client_disconnect_nocheck(struct client * c)242 client_disconnect_nocheck(struct client *c)
243 {
244 	wl_proxy_destroy((struct wl_proxy *) c->tc);
245 	wl_display_disconnect(c->wl_display);
246 	free(c);
247 }
248 
249 static void
post_error_main(void)250 post_error_main(void)
251 {
252 	struct client *c = client_connect();
253 	struct wl_seat *seat = client_get_seat(c);
254 
255 	/* stop display so that it can post the error.
256 	 * The function should return -1, because of the posted error */
257 	assert(stop_display(c, 1) == -1);
258 
259 	/* display should have posted error, check it! */
260 	check_for_error(c, (struct wl_proxy *) seat);
261 
262 	/* don't call client_disconnect(c), because then the test would be
263 	 * aborted due to checks for error in this function */
264 	wl_proxy_destroy((struct wl_proxy *) seat);
265 	client_disconnect_nocheck(c);
266 }
267 
TEST(post_error_to_one_client)268 TEST(post_error_to_one_client)
269 {
270 	struct display *d = display_create();
271 	struct client_info *cl;
272 
273 	wl_global_create(d->wl_display, &wl_seat_interface,
274 			 1, d, bind_seat);
275 
276 	cl = client_create_noarg(d, post_error_main);
277 	display_run(d);
278 
279 	/* the display was stopped by client, so it can
280 	 * proceed in the code and post an error */
281 	assert(cl->data);
282 	wl_resource_post_error((struct wl_resource *) cl->data,
283 			       23, "Dummy error");
284 
285 	/* this one should be ignored */
286 	wl_resource_post_error((struct wl_resource *) cl->data,
287 			       21, "Dummy error (ignore)");
288 
289 	display_resume(d);
290 	display_destroy(d);
291 }
292 
293 static void
post_error_main2(void)294 post_error_main2(void)
295 {
296 	struct client *c = client_connect();
297 	struct wl_seat *seat = client_get_seat(c);
298 
299 	/* the error should not be posted for this client */
300 	assert(stop_display(c, 2) >= 0);
301 
302 	wl_proxy_destroy((struct wl_proxy *) seat);
303 	client_disconnect(c);
304 }
305 
306 static void
post_error_main3(void)307 post_error_main3(void)
308 {
309 	struct client *c = client_connect();
310 	struct wl_seat *seat = client_get_seat(c);
311 
312 	assert(stop_display(c, 2) == -1);
313 	check_for_error(c, (struct wl_proxy *) seat);
314 
315 	/* don't call client_disconnect(c), because then the test would be
316 	 * aborted due to checks for error in this function */
317 	wl_proxy_destroy((struct wl_proxy *) seat);
318 	client_disconnect_nocheck(c);
319 }
320 
321 /* all the testcases could be in one TEST, but splitting it
322  * apart is better for debugging when the test fails */
TEST(post_error_to_one_from_two_clients)323 TEST(post_error_to_one_from_two_clients)
324 {
325 	struct display *d = display_create();
326 	struct client_info *cl;
327 
328 	wl_global_create(d->wl_display, &wl_seat_interface,
329 			 1, d, bind_seat);
330 
331 	client_create_noarg(d, post_error_main2);
332 	cl = client_create_noarg(d, post_error_main3);
333 	display_run(d);
334 
335 	/* post error only to the second client */
336 	assert(cl->data);
337 	wl_resource_post_error((struct wl_resource *) cl->data,
338 			       23, "Dummy error");
339 	wl_resource_post_error((struct wl_resource *) cl->data,
340 			       21, "Dummy error (ignore)");
341 
342 	display_resume(d);
343 	display_destroy(d);
344 }
345 
346 /* all the testcases could be in one TEST, but splitting it
347  * apart is better for debugging when the test fails */
TEST(post_error_to_two_clients)348 TEST(post_error_to_two_clients)
349 {
350 	struct display *d = display_create();
351 	struct client_info *cl, *cl2;
352 
353 	wl_global_create(d->wl_display, &wl_seat_interface,
354 			 1, d, bind_seat);
355 
356 	cl = client_create_noarg(d, post_error_main3);
357 	cl2 = client_create_noarg(d, post_error_main3);
358 
359 	display_run(d);
360 
361 	/* Try to send the error to both clients */
362 	assert(cl->data && cl2->data);
363 	wl_resource_post_error((struct wl_resource *) cl->data,
364 			       23, "Dummy error");
365 	wl_resource_post_error((struct wl_resource *) cl->data,
366 			       21, "Dummy error (ignore)");
367 
368 	wl_resource_post_error((struct wl_resource *) cl2->data,
369 			       23, "Dummy error");
370 	wl_resource_post_error((struct wl_resource *) cl2->data,
371 			       21, "Dummy error (ignore)");
372 
373 	display_resume(d);
374 	display_destroy(d);
375 }
376 
377 static void
post_nomem_main(void)378 post_nomem_main(void)
379 {
380 	struct client *c = client_connect();
381 	struct wl_seat *seat = client_get_seat(c);
382 
383 	assert(stop_display(c, 1) == -1);
384 	assert(wl_display_get_error(c->wl_display) == ENOMEM);
385 
386 	wl_proxy_destroy((struct wl_proxy *) seat);
387 	client_disconnect_nocheck(c);
388 }
389 
TEST(post_nomem_tst)390 TEST(post_nomem_tst)
391 {
392 	struct display *d = display_create();
393 	struct client_info *cl;
394 
395 	wl_global_create(d->wl_display, &wl_seat_interface,
396 			 1, d, bind_seat);
397 
398 	cl = client_create_noarg(d, post_nomem_main);
399 	display_run(d);
400 
401 	assert(cl->data);
402 	wl_resource_post_no_memory((struct wl_resource *) cl->data);
403 	display_resume(d);
404 
405 	/* first client terminated. Run it again,
406 	 * but post no memory to client */
407 	cl = client_create_noarg(d, post_nomem_main);
408 	display_run(d);
409 
410 	assert(cl->data);
411 	wl_client_post_no_memory(cl->wl_client);
412 	display_resume(d);
413 
414 	display_destroy(d);
415 }
416 
417 static void
register_reading(struct wl_display * display)418 register_reading(struct wl_display *display)
419 {
420 	while(wl_display_prepare_read(display) != 0 && errno == EAGAIN)
421 		assert(wl_display_dispatch_pending(display) >= 0);
422 	assert(wl_display_flush(display) >= 0);
423 }
424 
425 /* create thread that will call prepare+read so that
426  * it will block */
427 static pthread_t
create_thread(struct client * c,void * (* func)(void *))428 create_thread(struct client *c, void *(*func)(void*))
429 {
430 	pthread_t thread;
431 
432 	c->display_stopped = 0;
433 	/* func must set display->stopped to 1 before sleeping */
434 	assert(pthread_create(&thread, NULL, func, c) == 0);
435 
436 	/* make sure the thread is sleeping. It's a little bit racy
437 	 * (setting display_stopped to 1 and calling wl_display_read_events)
438 	 * so call usleep once again after the loop ends - it should
439 	 * be sufficient... */
440 	while (c->display_stopped == 0)
441 		test_usleep(500);
442 	test_usleep(10000);
443 
444 	return thread;
445 }
446 
447 static void *
thread_read_error(void * data)448 thread_read_error(void *data)
449 {
450 	struct client *c = data;
451 
452 	register_reading(c->wl_display);
453 
454 	/*
455 	 * Calling the read right now will block this thread
456 	 * until the other thread will read the data.
457 	 * However, after invoking an error, this
458 	 * thread should be woken up or it will block indefinitely.
459 	 */
460 	c->display_stopped = 1;
461 	assert(wl_display_read_events(c->wl_display) == -1);
462 
463 	assert(wl_display_dispatch_pending(c->wl_display) == -1);
464 	assert(wl_display_get_error(c->wl_display));
465 
466 	pthread_exit(NULL);
467 }
468 
469 /* test posting an error in multi-threaded environment. */
470 static void
threading_post_err(void)471 threading_post_err(void)
472 {
473 	DISABLE_LEAK_CHECKS;
474 
475 	struct client *c = client_connect();
476 	pthread_t thread;
477 
478 	/* register read intention */
479 	register_reading(c->wl_display);
480 
481 	/* use this var as an indicator that thread is sleeping */
482 	c->display_stopped = 0;
483 
484 	/* create new thread that will register its intention too */
485 	thread = create_thread(c, thread_read_error);
486 
487 	/* so now we have sleeping thread waiting for a pthread_cond signal.
488 	 * The main thread must call wl_display_read_events().
489 	 * If this call fails, then it won't call broadcast at the
490 	 * end of the function and the sleeping thread will block indefinitely.
491 	 * Make the call fail and watch if libwayland will unblock the thread! */
492 
493 	/* create error on fd, so that wl_display_read_events will fail.
494 	 * The same can happen when server hangs up */
495 	close(wl_display_get_fd(c->wl_display));
496 	/* this read events will fail and will
497 	 * post an error that should wake the sleeping thread
498 	 * and dispatch the incoming events */
499 	assert(wl_display_read_events(c->wl_display) == -1);
500 
501 	/* kill test in 3 seconds. This should be enough time for the
502 	 * thread to exit if it's not blocking. If everything is OK, than
503 	 * the thread was woken up and the test will end before the SIGALRM */
504 	test_set_timeout(3);
505 	pthread_join(thread, NULL);
506 
507 	client_disconnect_nocheck(c);
508 }
509 
TEST(threading_errors_tst)510 TEST(threading_errors_tst)
511 {
512 	struct display *d = display_create();
513 
514 	client_create_noarg(d, threading_post_err);
515 	display_run(d);
516 
517 	display_destroy(d);
518 }
519 
520 static void *
thread_prepare_and_read(void * data)521 thread_prepare_and_read(void *data)
522 {
523 	struct client *c = data;
524 
525 	register_reading(c->wl_display);
526 
527 	c->display_stopped = 1;
528 
529 	assert(wl_display_read_events(c->wl_display) == 0);
530 	assert(wl_display_dispatch_pending(c->wl_display) == 0);
531 
532 	pthread_exit(NULL);
533 }
534 
535 /* test cancel read*/
536 static void
threading_cancel_read(void)537 threading_cancel_read(void)
538 {
539 	DISABLE_LEAK_CHECKS;
540 
541 	struct client *c = client_connect();
542 	pthread_t th1, th2, th3;
543 
544 	register_reading(c->wl_display);
545 
546 	th1 = create_thread(c, thread_prepare_and_read);
547 	th2 = create_thread(c, thread_prepare_and_read);
548 	th3 = create_thread(c, thread_prepare_and_read);
549 
550 	/* all the threads are sleeping, waiting until read or cancel
551 	 * is called. Cancel the read and let the threads proceed */
552 	wl_display_cancel_read(c->wl_display);
553 
554 	/* kill test in 3 seconds. This should be enough time for the
555 	 * thread to exit if it's not blocking. If everything is OK, than
556 	 * the thread was woken up and the test will end before the SIGALRM */
557 	test_set_timeout(3);
558 	pthread_join(th1, NULL);
559 	pthread_join(th2, NULL);
560 	pthread_join(th3, NULL);
561 
562 	client_disconnect(c);
563 }
564 
TEST(threading_cancel_read_tst)565 TEST(threading_cancel_read_tst)
566 {
567 	struct display *d = display_create();
568 
569 	client_create_noarg(d, threading_cancel_read);
570 	display_run(d);
571 
572 	display_destroy(d);
573 }
574 
575 static void
threading_read_eagain(void)576 threading_read_eagain(void)
577 {
578 	DISABLE_LEAK_CHECKS;
579 
580 	struct client *c = client_connect();
581 	pthread_t th1, th2, th3;
582 
583 	register_reading(c->wl_display);
584 
585 	th1 = create_thread(c, thread_prepare_and_read);
586 	th2 = create_thread(c, thread_prepare_and_read);
587 	th3 = create_thread(c, thread_prepare_and_read);
588 
589 	/* All the threads are sleeping, waiting until read or cancel
590 	 * is called. Since we have no data on socket waiting,
591 	 * the wl_connection_read should end up with error and set errno
592 	 * to EAGAIN. Check if the threads are woken up in this case. */
593 	assert(wl_display_read_events(c->wl_display) == 0);
594 	/* errno should be still set to EAGAIN if wl_connection_read
595 	 * set it - check if we're testing the right case */
596 	assert(errno == EAGAIN);
597 
598 	test_set_timeout(3);
599 	pthread_join(th1, NULL);
600 	pthread_join(th2, NULL);
601 	pthread_join(th3, NULL);
602 
603 	client_disconnect(c);
604 }
605 
TEST(threading_read_eagain_tst)606 TEST(threading_read_eagain_tst)
607 {
608 	struct display *d = display_create();
609 	client_create_noarg(d, threading_read_eagain);
610 
611 	display_run(d);
612 
613 	display_destroy(d);
614 }
615 
616 static void *
thread_prepare_and_read2(void * data)617 thread_prepare_and_read2(void *data)
618 {
619 	struct client *c = data;
620 
621 	while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN)
622 		assert(wl_display_dispatch_pending(c->wl_display) == -1);
623 	assert(wl_display_flush(c->wl_display) == -1);
624 
625 	c->display_stopped = 1;
626 
627 	assert(wl_display_read_events(c->wl_display) == -1);
628 	assert(wl_display_dispatch_pending(c->wl_display) == -1);
629 
630 	pthread_exit(NULL);
631 }
632 
633 static void
threading_read_after_error(void)634 threading_read_after_error(void)
635 {
636 	DISABLE_LEAK_CHECKS;
637 
638 	struct client *c = client_connect();
639 	pthread_t thread;
640 
641 	/* create an error */
642 	close(wl_display_get_fd(c->wl_display));
643 	assert(wl_display_dispatch(c->wl_display) == -1);
644 
645 	/* try to prepare for reading */
646 	while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN)
647 		assert(wl_display_dispatch_pending(c->wl_display) == -1);
648 	assert(wl_display_flush(c->wl_display) == -1);
649 
650 	assert(pthread_create(&thread, NULL,
651 			      thread_prepare_and_read2, c) == 0);
652 
653 	/* make sure thread is sleeping */
654 	while (c->display_stopped == 0)
655 		test_usleep(500);
656 	test_usleep(10000);
657 
658 	assert(wl_display_read_events(c->wl_display) == -1);
659 
660 	/* kill test in 3 seconds */
661 	test_set_timeout(3);
662 	pthread_join(thread, NULL);
663 
664 	client_disconnect_nocheck(c);
665 }
666 
TEST(threading_read_after_error_tst)667 TEST(threading_read_after_error_tst)
668 {
669 	struct display *d = display_create();
670 
671 	client_create_noarg(d, threading_read_after_error);
672 	display_run(d);
673 
674 	display_destroy(d);
675 }
676 
677 static void
wait_for_error_using_dispatch(struct client * c,struct wl_proxy * proxy)678 wait_for_error_using_dispatch(struct client *c, struct wl_proxy *proxy)
679 {
680 	int ret;
681 
682 	while (true) {
683 		/* Dispatching should eventually hit the protocol error before
684 		 * any other error. */
685 		ret = wl_display_dispatch(c->wl_display);
686 		if (ret == 0) {
687 			continue;
688 		} else {
689 			assert(errno == EPROTO);
690 			break;
691 		}
692 	}
693 
694 	check_pending_error(c, proxy);
695 }
696 
697 static void
wait_for_error_using_prepare_read(struct client * c,struct wl_proxy * proxy)698 wait_for_error_using_prepare_read(struct client *c, struct wl_proxy *proxy)
699 {
700 	int ret = 0;
701 	struct pollfd pfd[2];
702 
703 	while (true) {
704 		while (wl_display_prepare_read(c->wl_display) != 0 &&
705 		      errno == EAGAIN) {
706 			assert(wl_display_dispatch_pending(c->wl_display) >= 0);
707 		}
708 
709 		/* Flush may fail due to EPIPE if the connection is broken, but
710 		 * this must not set a fatal display error because that would
711 		 * result in it being impossible to read a potential protocol
712 		 * error. */
713 		do {
714 			ret = wl_display_flush(c->wl_display);
715 		} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
716 		assert(ret >= 0 || errno == EPIPE);
717 		assert(wl_display_get_error(c->wl_display) == 0);
718 
719 		pfd[0].fd = wl_display_get_fd(c->wl_display);
720 		pfd[0].events = POLLIN;
721 		do {
722 			ret = poll(pfd, 1, -1);
723 		} while (ret == -1 && errno == EINTR);
724 		assert(ret != -1);
725 
726 		/* We should always manage to read the error before the EPIPE
727 		 * comes this way. */
728 		assert(wl_display_read_events(c->wl_display) == 0);
729 
730 		/* Dispatching should eventually hit the protocol error before
731 		 * any other error. */
732 		ret = wl_display_dispatch_pending(c->wl_display);
733 		if (ret == 0) {
734 			continue;
735 		} else {
736 			assert(errno == EPROTO);
737 			break;
738 		}
739 	}
740 
741 	check_pending_error(c, proxy);
742 }
743 
744 static void
check_error_after_epipe(void * data)745 check_error_after_epipe(void *data)
746 {
747 	bool use_dispatch_helpers = *(bool *) data;
748 	struct client *client;
749 	struct wl_seat *seat;
750 	struct wl_callback *callback;
751 
752 	client = client_connect();
753 
754 	/* This will, according to the implementation below, cause the server
755 	 * to post an error. */
756 	seat = client_get_seat(client);
757 	wl_display_flush(client->wl_display);
758 
759 	/* The server will not actually destroy the client until it receives
760 	 * input, so send something to trigger the client destruction. */
761 	callback = wl_display_sync(client->wl_display);
762 	wl_callback_destroy(callback);
763 
764 	/* Sleep some to give the server a chance to react and destroy the
765 	 * client. */
766 	test_usleep(200000);
767 
768 	/* Wait for the protocol error and check that we reached it before
769 	 * EPIPE. */
770 	if (use_dispatch_helpers) {
771 		wait_for_error_using_dispatch(client, (struct wl_proxy *) seat);
772 	} else {
773 		wait_for_error_using_prepare_read(client,
774 						  (struct wl_proxy *) seat);
775 	}
776 
777 	wl_seat_destroy(seat);
778 	client_disconnect_nocheck(client);
779 }
780 
781 static void
bind_seat_and_post_error(struct wl_client * client,void * data,uint32_t version,uint32_t id)782 bind_seat_and_post_error(struct wl_client *client, void *data,
783 			 uint32_t version, uint32_t id)
784 {
785 	struct display *d = data;
786 	struct client_info *ci;
787 	struct wl_resource *resource;
788 
789 	ci = find_client_info(d, client);
790 	assert(ci);
791 
792 	resource = wl_resource_create(client, &wl_seat_interface, version, id);
793 	assert(resource);
794 	ci->data = resource;
795 
796 	wl_resource_post_error(ci->data, 23, "Dummy error");
797 }
798 
TEST(error_code_after_epipe)799 TEST(error_code_after_epipe)
800 {
801 	struct display *d = display_create();
802 	bool use_dispatch_helpers;
803 
804 	wl_global_create(d->wl_display, &wl_seat_interface,
805 			 1, d, bind_seat_and_post_error);
806 
807 	use_dispatch_helpers = true;
808 	client_create(d, check_error_after_epipe, &use_dispatch_helpers);
809 	display_run(d);
810 
811 	use_dispatch_helpers = false;
812 	client_create(d, check_error_after_epipe, &use_dispatch_helpers);
813 	display_run(d);
814 
815 	display_destroy(d);
816 }
817 
818 static void
check_seat_versions(struct wl_seat * seat,uint32_t ev)819 check_seat_versions(struct wl_seat *seat, uint32_t ev)
820 {
821 	struct wl_pointer *pointer;
822 
823 	assert(wl_proxy_get_version((struct wl_proxy *) seat) == ev);
824 	assert(wl_seat_get_version(seat) == ev);
825 
826 	pointer = wl_seat_get_pointer(seat);
827 	assert(wl_pointer_get_version(pointer) == ev);
828 	assert(wl_proxy_get_version((struct wl_proxy *) pointer) == ev);
829 	wl_proxy_destroy((struct wl_proxy *) pointer);
830 }
831 
832 /* Normal client with proxy versions available. */
833 static void
seat_version(void * data)834 seat_version(void *data)
835 {
836 	struct handler_info *hi = data;
837 	struct client *c = client_connect();
838 	struct wl_seat *seat;
839 
840 	/* display proxy should always be version 0 */
841 	assert(wl_proxy_get_version((struct wl_proxy *) c->wl_display) == 0);
842 
843 	seat = client_get_seat_with_info(c, hi);
844 	if (hi->use_unversioned)
845 		check_seat_versions(seat, 0);
846 	else
847 		check_seat_versions(seat, hi->bind_version);
848 
849 	wl_proxy_destroy((struct wl_proxy *) seat);
850 
851 	client_disconnect_nocheck(c);
852 }
853 
TEST(versions)854 TEST(versions)
855 {
856 	struct display *d = display_create();
857 	struct wl_global *global;
858 	int i;
859 
860 	global = wl_global_create(d->wl_display, &wl_seat_interface,
861 				  5, d, bind_seat);
862 
863 	for (i = 1; i <= 5; i++) {
864 		struct handler_info hi;
865 
866 		hi.bind_version = i;
867 		hi.use_unversioned = false;
868 		client_create(d, seat_version, &hi);
869 		hi.use_unversioned = true;
870 		client_create(d, seat_version, &hi);
871 	}
872 
873 	display_run(d);
874 
875 	wl_global_destroy(global);
876 
877 	display_destroy(d);
878 }
879 
880 static void
check_error_on_destroyed_object(void * data)881 check_error_on_destroyed_object(void *data)
882 {
883 	struct client *c;
884 	struct wl_seat *seat;
885 	uint32_t id;
886 	const struct wl_interface *intf;
887 
888 	c = client_connect();
889 	seat = client_get_seat(c);
890 
891 	/* destroy the seat proxy. The display won't know
892 	 * about it yet, so it will post the error as usual */
893 	wl_proxy_destroy((struct wl_proxy *) seat);
894 
895 	/* let display post the error. The error will
896 	 * be caught in stop_display while dispatching */
897 	assert(stop_display(c, 1) == -1);
898 
899 	/* check the returned error. Since the object was destroyed,
900 	 * we don't know the interface and id */
901 	assert(wl_display_get_error(c->wl_display) == EPROTO);
902 	assert(wl_display_get_protocol_error(c->wl_display, &intf, &id) == 23);
903 	assert(intf == NULL);
904 	assert(id == 0);
905 
906 	client_disconnect_nocheck(c);
907 }
908 
TEST(error_on_destroyed_object)909 TEST(error_on_destroyed_object)
910 {
911 	struct client_info *cl;
912 	struct display *d = display_create();
913 
914 	wl_global_create(d->wl_display, &wl_seat_interface,
915 			 1, d, bind_seat);
916 
917 	cl = client_create_noarg(d, check_error_on_destroyed_object);
918 	display_run(d);
919 
920 	/* did client bind to the seat? */
921 	assert(cl->data);
922 
923 	/* post error on the destroyed object */
924 	wl_resource_post_error((struct wl_resource *) cl->data,
925 			       23, "Dummy error");
926 	display_resume(d);
927 	display_destroy(d);
928 }
929