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, ®istry_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