tst-shutdown.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /* Test the shutdown function.
  2. Copyright (C) 2024-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #include <arpa/inet.h>
  16. #include <errno.h>
  17. #include <fcntl.h>
  18. #include <stdbool.h>
  19. #include <support/check.h>
  20. #include <support/support.h>
  21. #include <support/xsocket.h>
  22. #include <support/xunistd.h>
  23. #include <sys/socket.h>
  24. #include <stdio.h>
  25. #include <fcntl.h>
  26. #include <string.h>
  27. struct connection
  28. {
  29. int sockets[2];
  30. };
  31. void
  32. establish_connection (struct connection *conn)
  33. {
  34. if (socketpair (AF_UNIX, SOCK_STREAM, 0, conn->sockets) != 0)
  35. {
  36. FAIL_EXIT1 ("socketpair (AF_UNIX, SOCK_STREAM, 0): %m\n");
  37. }
  38. }
  39. void
  40. close_connection (struct connection *conn)
  41. {
  42. xclose (conn->sockets[0]);
  43. xclose (conn->sockets[1]);
  44. }
  45. /* Open a file and check that shutdown fails with the ENOTSOCK error code. */
  46. void
  47. do_test_enotsock (void)
  48. {
  49. /* Open file and check that shutdown will fail with ENOTSOCK. */
  50. int fd = xopen ("/dev/null", O_RDWR, 0);
  51. int result = shutdown (fd, SHUT_RD);
  52. if (result == 0 || errno != ENOTSOCK)
  53. {
  54. FAIL_EXIT1 ("shutdown should fail with ENOTSOCK");
  55. }
  56. xclose (fd);
  57. }
  58. /* Test shutdown with SHUT_RD. */
  59. void
  60. do_test_shut_rd (void)
  61. {
  62. struct connection conn;
  63. const char *str = "AAAAAAA";
  64. int len = 8;
  65. int ret;
  66. void *s_buf = xmalloc (len);
  67. bzero (s_buf, len);
  68. establish_connection (&conn);
  69. int server = conn.sockets[0];
  70. int client = conn.sockets[1];
  71. /* Call shutdown with SHUT_RD on server socket. */
  72. if (shutdown (server, SHUT_RD) != 0)
  73. {
  74. FAIL_EXIT1 ("shutdown with SHUT_RD on socket %d failed", server);
  75. }
  76. ret = send (server, str, len, 0);
  77. if (ret <= 0)
  78. {
  79. FAIL_EXIT1 ("send (%d, data, %d): %m", server, len);
  80. }
  81. ret = recv (client, s_buf, len, 0);
  82. if (ret <= 0)
  83. {
  84. FAIL_EXIT1 ("recv (%d, data, %d): %m", client, len);
  85. }
  86. TEST_COMPARE_BLOB (str, len, s_buf, len);
  87. /* Send data should be disallowed on shutdown socket. */
  88. errno = 0;
  89. ret = send (client, str, len, MSG_NOSIGNAL);
  90. if (ret >= 0 || errno != EPIPE)
  91. {
  92. FAIL_EXIT1 ("Send on SHUT_RD socket should be disallowed: %m");
  93. }
  94. /* Recv should return zero and no error. */
  95. errno = 0;
  96. ret = recv (server, s_buf, len, 0);
  97. if (ret != 0 || errno != 0)
  98. {
  99. FAIL_EXIT1 ("recv should return 0 without error: %m");
  100. }
  101. close_connection (&conn);
  102. }
  103. /* Test shutdown with SHUT_WR. */
  104. void
  105. do_test_shut_wr (void)
  106. {
  107. struct connection conn;
  108. const char *str1 = "CCCCCCC";
  109. const char *str2 = "DDDDDDD";
  110. const char *str3 = "EEEEEEE";
  111. int len = 8;
  112. int ret;
  113. void *c_buf = xmalloc (len);
  114. void *s_buf = xmalloc (len);
  115. establish_connection (&conn);
  116. int server = conn.sockets[0];
  117. int client = conn.sockets[1];
  118. xwrite (client, str1, len);
  119. if (shutdown (client, SHUT_WR) != 0)
  120. {
  121. FAIL_EXIT1 ("shutdown with SHUT_WR on socket %d failed", client);
  122. }
  123. ret = send (client, str2, len, MSG_NOSIGNAL);
  124. if (ret >= 0)
  125. {
  126. FAIL_EXIT1 ("send on SHUT_WR socket should fail");
  127. }
  128. /* Read data written before shutdown and check if it's correct. */
  129. xread (server, s_buf, len);
  130. TEST_COMPARE_BLOB (str1, len, s_buf, len);
  131. /* Second read should return zero without error. */
  132. errno = 0;
  133. if (read (server, s_buf, len) != 0 || errno != 0)
  134. {
  135. FAIL_EXIT1 ("read after shutdown should return zero without error: %m");
  136. }
  137. /* Write some data to socket and check it still can be read on other side. */
  138. memcpy (s_buf, str3, len);
  139. xwrite (server, s_buf, len);
  140. xread (client, c_buf, len);
  141. TEST_COMPARE_BLOB (s_buf, len, c_buf, len);
  142. close_connection (&conn);
  143. }
  144. /* Test shutdown with SHUT_RDWR. */
  145. void
  146. do_test_shut_rdwr (void)
  147. {
  148. struct connection conn;
  149. struct sockaddr peer;
  150. socklen_t peer_len = sizeof (peer);
  151. const char *str1 = "FFFFFFF";
  152. const char *str2 = "GGGGGGG";
  153. int len = 8;
  154. int ret;
  155. void *s_buf = xmalloc (len);
  156. bzero (s_buf, len);
  157. establish_connection (&conn);
  158. int server = conn.sockets[0];
  159. int client = conn.sockets[1];
  160. /* Send some data to both sockets before shutdown. */
  161. xwrite (client, str1, len);
  162. xwrite (server, str2, len);
  163. /* Call shutdown with SHUT_RDWR on client socket. */
  164. if (shutdown (client, SHUT_RDWR) != 0)
  165. {
  166. FAIL_EXIT1 ("shutdown with SHUT_RDWR on socket %d failed", client);
  167. }
  168. /* Verify that socket is still connected. */
  169. xgetsockname (client, &peer, &peer_len);
  170. /* Read data written before shutdown. */
  171. xread (client, s_buf, len);
  172. TEST_COMPARE_BLOB (s_buf, len, str2, len);
  173. /* Second read should return zero, but no error. */
  174. errno = 0;
  175. if (read (client, s_buf, len) != 0 || errno != 0)
  176. {
  177. FAIL_EXIT1 ("read after shutdown should return zero without error: %m");
  178. }
  179. /* Send some data to shutdown socket and expect error. */
  180. errno = 0;
  181. ret = send (server, str2, len, MSG_NOSIGNAL);
  182. if (ret >= 0 || errno != EPIPE)
  183. {
  184. FAIL_EXIT1 ("send to RDWR shutdown socket should fail with EPIPE");
  185. }
  186. /* Read data written before shutdown. */
  187. xread (server, s_buf, len);
  188. TEST_COMPARE_BLOB (s_buf, len, str1, len);
  189. /* Second read should return zero, but no error. */
  190. errno = 0;
  191. if (read (server, s_buf, len) != 0 || errno != 0)
  192. {
  193. FAIL_EXIT1 ("read after shutdown should return zero without error: %m");
  194. }
  195. /* Send some data to shutdown socket and expect error. */
  196. errno = 0;
  197. ret = send (client, str1, len, MSG_NOSIGNAL);
  198. if (ret >= 0 || errno != EPIPE)
  199. {
  200. FAIL_EXIT1 ("send to RDWR shutdown socket should fail with EPIPE");
  201. }
  202. close_connection (&conn);
  203. }
  204. static int
  205. do_test (void)
  206. {
  207. do_test_enotsock ();
  208. do_test_shut_rd ();
  209. do_test_shut_wr ();
  210. do_test_shut_rdwr ();
  211. return 0;
  212. }
  213. #include <support/test-driver.c>