socket-test.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. * Permission is hereby granted, free of charge, to any person obtaining
  3. * a copy of this software and associated documentation files (the
  4. * "Software"), to deal in the Software without restriction, including
  5. * without limitation the rights to use, copy, modify, merge, publish,
  6. * distribute, sublicense, and/or sell copies of the Software, and to
  7. * permit persons to whom the Software is furnished to do so, subject to
  8. * the following conditions:
  9. *
  10. * The above copyright notice and this permission notice (including the
  11. * next paragraph) shall be included in all copies or substantial
  12. * portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  18. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  19. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. * SOFTWARE.
  22. */
  23. #include <stdlib.h>
  24. #include <assert.h>
  25. #include <errno.h>
  26. #include <string.h>
  27. #include <stdio.h>
  28. #include <sys/socket.h>
  29. #include <sys/types.h>
  30. #include <sys/wait.h>
  31. #include <sys/un.h>
  32. #include <unistd.h>
  33. #include "wayland-client.h"
  34. #include "wayland-os.h"
  35. #include "wayland-server.h"
  36. #include "test-runner.h"
  37. /* Paths longer than what the .sun_path array can contain must be rejected.
  38. * This is a hard limitation of assigning a name to AF_UNIX/AF_LOCAL sockets.
  39. * See `man 7 unix`.
  40. */
  41. static struct sockaddr_un example_sockaddr_un;
  42. #define TOO_LONG (1 + sizeof example_sockaddr_un.sun_path)
  43. /* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */
  44. static const char *
  45. require_xdg_runtime_dir(void)
  46. {
  47. char *val = getenv("XDG_RUNTIME_DIR");
  48. assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test");
  49. return val;
  50. }
  51. TEST(socket_path_overflow_client_connect)
  52. {
  53. char path[TOO_LONG];
  54. struct wl_display *d;
  55. require_xdg_runtime_dir();
  56. memset(path, 'a', sizeof path);
  57. path[sizeof path - 1] = '\0';
  58. d = wl_display_connect(path);
  59. assert(d == NULL);
  60. assert(errno == ENAMETOOLONG);
  61. /* This is useless, but prevents a warning about example_sockaddr_un
  62. * being discarded from the compilation unit. */
  63. strcpy(example_sockaddr_un.sun_path, "happy now clang?");
  64. assert(example_sockaddr_un.sun_path[0] != '\0');
  65. }
  66. TEST(socket_path_overflow_server_create)
  67. {
  68. char path[TOO_LONG];
  69. struct wl_display *d;
  70. int ret;
  71. require_xdg_runtime_dir();
  72. memset(path, 'a', sizeof path);
  73. path[sizeof path - 1] = '\0';
  74. d = wl_display_create();
  75. assert(d != NULL);
  76. ret = wl_display_add_socket(d, path);
  77. assert(ret < 0);
  78. assert(errno == ENAMETOOLONG);
  79. wl_display_destroy(d);
  80. }
  81. TEST(add_existing_socket)
  82. {
  83. char path[sizeof example_sockaddr_un.sun_path];
  84. const char *name = "wayland-test-0";
  85. const char *xdg_runtime_dir;
  86. struct wl_display *d;
  87. int ret;
  88. size_t len;
  89. xdg_runtime_dir = require_xdg_runtime_dir();
  90. d = wl_display_create();
  91. assert(d != NULL);
  92. /* this one should be OK */
  93. ret = wl_display_add_socket(d, name);
  94. assert(ret == 0);
  95. /* this one should fail */
  96. ret = wl_display_add_socket(d, name);
  97. assert(ret < 0);
  98. /* the original socket should still exist.
  99. * this was a bug introduced in e2c0d47b0c77f18cd90e9c6eabb358c4d89681c8 */
  100. len = snprintf(path, sizeof example_sockaddr_un.sun_path, "%s/%s",
  101. xdg_runtime_dir, name);
  102. assert(len < sizeof example_sockaddr_un.sun_path
  103. && "Bug in test. Path too long");
  104. assert(access(path, F_OK) != -1);
  105. /* the original socket should still exist */
  106. ret = wl_display_add_socket(d, name);
  107. assert(ret < 0);
  108. wl_display_destroy(d);
  109. }
  110. TEST(add_socket_auto)
  111. {
  112. /* the number of auto sockets is currently 32,
  113. * set in wayland-server.c.
  114. */
  115. const int MAX_SOCKETS = 32;
  116. char path[sizeof example_sockaddr_un.sun_path];
  117. const char *name;
  118. const char *xdg_runtime_dir;
  119. struct wl_display *d;
  120. int i;
  121. size_t len;
  122. xdg_runtime_dir = require_xdg_runtime_dir();
  123. d = wl_display_create();
  124. assert(d != NULL);
  125. for (i = 0; i <= MAX_SOCKETS; ++i) {
  126. name = wl_display_add_socket_auto(d);
  127. assert(name != NULL);
  128. len = snprintf(path, sizeof example_sockaddr_un.sun_path,
  129. "%s/%s", xdg_runtime_dir, name);
  130. assert(len < sizeof example_sockaddr_un.sun_path
  131. && "Bug in test. Path too long");
  132. /* was the socket created correctly? */
  133. assert(access(path, F_OK) != -1);
  134. /* is the name sequential? */
  135. len = snprintf(path, sizeof example_sockaddr_un.sun_path,
  136. "wayland-%d", i);
  137. assert(strcmp(name, path) == 0);
  138. }
  139. /* next addition should return NULL */
  140. name = wl_display_add_socket_auto(d);
  141. assert(name == NULL);
  142. /* check if the socket was not deleted the last time */
  143. name = wl_display_add_socket_auto(d);
  144. assert(name == NULL);
  145. wl_display_destroy(d);
  146. }
  147. struct client_create_listener {
  148. struct wl_listener listener;
  149. struct wl_display *display;
  150. };
  151. struct client_destroy_listener {
  152. struct wl_listener listener;
  153. struct wl_display *display;
  154. };
  155. static void
  156. client_destroy_notify(struct wl_listener *l, void *data)
  157. {
  158. struct client_destroy_listener *listener =
  159. wl_container_of(l, listener, listener);
  160. wl_display_terminate(listener->display);
  161. free(listener);
  162. }
  163. static void
  164. client_create_notify(struct wl_listener *l, void *data)
  165. {
  166. struct wl_client *client = data;
  167. struct client_create_listener *listener =
  168. wl_container_of(l, listener, listener);
  169. struct client_destroy_listener *destroy_listener = (struct client_destroy_listener *)malloc(sizeof *destroy_listener);
  170. assert(destroy_listener != NULL);
  171. destroy_listener->display = listener->display;
  172. destroy_listener->listener.notify = client_destroy_notify;
  173. wl_client_add_destroy_listener(client, &destroy_listener->listener);
  174. }
  175. TEST(absolute_socket_path)
  176. {
  177. struct wl_display *display;
  178. struct client_create_listener client_create_listener;
  179. struct sockaddr_un addr;
  180. int fd;
  181. socklen_t size;
  182. const char *xdg_runtime_dir;
  183. size_t len;
  184. int ret;
  185. pid_t pid;
  186. /* It's a little weird that this test about absolute socket paths
  187. * uses XDG_RUNTIME_DIR, but that's the only location guaranteed
  188. * by test-runner to be both writable and unique. This isn't
  189. * really a problem; we'll just take care that the leaf-level
  190. * filename used for the socket isn't anything that would
  191. * accidentally be generated by a default usage of wl_display_connect(). */
  192. xdg_runtime_dir = require_xdg_runtime_dir();
  193. memset(&addr, 0, sizeof addr);
  194. len = snprintf(addr.sun_path, sizeof addr.sun_path,
  195. "%s/%s", xdg_runtime_dir, "wayland-absolute-0");
  196. assert(len < sizeof addr.sun_path
  197. && "Bug in test. Path too long");
  198. /* The path must not exist prior to binding. */
  199. assert(access(addr.sun_path, F_OK) == -1);
  200. size = offsetof (struct sockaddr_un, sun_path) + strlen(addr.sun_path);
  201. addr.sun_family = AF_LOCAL;
  202. fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
  203. assert(fd >= 0 );
  204. ret = bind(fd, (struct sockaddr *) &addr, size);
  205. assert(ret >= 0);
  206. ret = listen(fd, 128);
  207. assert(ret >= 0);
  208. /* Start server display. Be careful (by avoiding wl_display_add_socket_auto()
  209. * to offer only the absolutely qualified socket made above. */
  210. display = wl_display_create();
  211. assert(display != NULL);
  212. client_create_listener.listener.notify = client_create_notify;
  213. client_create_listener.display = display;
  214. wl_display_add_client_created_listener(display, &client_create_listener.listener);
  215. ret = wl_display_add_socket_fd(display, fd);
  216. assert(ret == 0);
  217. /* Execute client that connects to the absolutely qualified server socket path. */
  218. pid = fork();
  219. assert(pid != -1);
  220. if (pid == 0) {
  221. ret = setenv("WAYLAND_DISPLAY", addr.sun_path, 1);
  222. assert(ret == 0);
  223. struct wl_display *client_display = wl_display_connect(NULL);
  224. assert(client_display != NULL);
  225. ret = wl_display_roundtrip(client_display);
  226. assert(ret != -1);
  227. wl_display_disconnect(client_display);
  228. exit(0);
  229. assert(false);
  230. }
  231. wl_display_run(display);
  232. ret = waitpid(pid, NULL, 0);
  233. assert(ret == pid);
  234. wl_display_destroy(display);
  235. ret = unlink(addr.sun_path);
  236. assert(ret == 0);
  237. }