unix_connreset.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Selftest for AF_UNIX socket close and ECONNRESET behaviour.
  4. *
  5. * This test verifies:
  6. * 1. SOCK_STREAM returns EOF when the peer closes normally.
  7. * 2. SOCK_STREAM returns ECONNRESET if peer closes with unread data.
  8. * 3. SOCK_SEQPACKET returns EOF when the peer closes normally.
  9. * 4. SOCK_SEQPACKET returns ECONNRESET if the peer closes with unread data.
  10. * 5. SOCK_DGRAM does not return ECONNRESET when the peer closes.
  11. *
  12. * These tests document the intended Linux behaviour.
  13. *
  14. */
  15. #define _GNU_SOURCE
  16. #include <string.h>
  17. #include <fcntl.h>
  18. #include <unistd.h>
  19. #include <errno.h>
  20. #include <sys/socket.h>
  21. #include <sys/un.h>
  22. #include "../../kselftest_harness.h"
  23. #define SOCK_PATH "/tmp/af_unix_connreset.sock"
  24. static void remove_socket_file(void)
  25. {
  26. unlink(SOCK_PATH);
  27. }
  28. FIXTURE(unix_sock)
  29. {
  30. int server;
  31. int client;
  32. int child;
  33. };
  34. FIXTURE_VARIANT(unix_sock)
  35. {
  36. int socket_type;
  37. const char *name;
  38. };
  39. FIXTURE_VARIANT_ADD(unix_sock, stream) {
  40. .socket_type = SOCK_STREAM,
  41. .name = "SOCK_STREAM",
  42. };
  43. FIXTURE_VARIANT_ADD(unix_sock, dgram) {
  44. .socket_type = SOCK_DGRAM,
  45. .name = "SOCK_DGRAM",
  46. };
  47. FIXTURE_VARIANT_ADD(unix_sock, seqpacket) {
  48. .socket_type = SOCK_SEQPACKET,
  49. .name = "SOCK_SEQPACKET",
  50. };
  51. FIXTURE_SETUP(unix_sock)
  52. {
  53. struct sockaddr_un addr = {};
  54. int err;
  55. addr.sun_family = AF_UNIX;
  56. strcpy(addr.sun_path, SOCK_PATH);
  57. remove_socket_file();
  58. self->server = socket(AF_UNIX, variant->socket_type, 0);
  59. ASSERT_LT(-1, self->server);
  60. err = bind(self->server, (struct sockaddr *)&addr, sizeof(addr));
  61. ASSERT_EQ(0, err);
  62. if (variant->socket_type == SOCK_STREAM ||
  63. variant->socket_type == SOCK_SEQPACKET) {
  64. err = listen(self->server, 1);
  65. ASSERT_EQ(0, err);
  66. }
  67. self->client = socket(AF_UNIX, variant->socket_type | SOCK_NONBLOCK, 0);
  68. ASSERT_LT(-1, self->client);
  69. err = connect(self->client, (struct sockaddr *)&addr, sizeof(addr));
  70. ASSERT_EQ(0, err);
  71. }
  72. FIXTURE_TEARDOWN(unix_sock)
  73. {
  74. if (variant->socket_type == SOCK_STREAM ||
  75. variant->socket_type == SOCK_SEQPACKET)
  76. close(self->child);
  77. close(self->client);
  78. close(self->server);
  79. remove_socket_file();
  80. }
  81. /* Test 1: peer closes normally */
  82. TEST_F(unix_sock, eof)
  83. {
  84. char buf[16] = {};
  85. ssize_t n;
  86. if (variant->socket_type == SOCK_STREAM ||
  87. variant->socket_type == SOCK_SEQPACKET) {
  88. self->child = accept(self->server, NULL, NULL);
  89. ASSERT_LT(-1, self->child);
  90. close(self->child);
  91. } else {
  92. close(self->server);
  93. }
  94. n = recv(self->client, buf, sizeof(buf), 0);
  95. if (variant->socket_type == SOCK_STREAM ||
  96. variant->socket_type == SOCK_SEQPACKET) {
  97. ASSERT_EQ(0, n);
  98. } else {
  99. ASSERT_EQ(-1, n);
  100. ASSERT_EQ(EAGAIN, errno);
  101. }
  102. }
  103. /* Test 2: peer closes with unread data */
  104. TEST_F(unix_sock, reset_unread_behavior)
  105. {
  106. char buf[16] = {};
  107. ssize_t n;
  108. /* Send data that will remain unread */
  109. send(self->client, "hello", 5, 0);
  110. if (variant->socket_type == SOCK_DGRAM) {
  111. /* No real connection, just close the server */
  112. close(self->server);
  113. } else {
  114. self->child = accept(self->server, NULL, NULL);
  115. ASSERT_LT(-1, self->child);
  116. /* Peer closes before client reads */
  117. close(self->child);
  118. }
  119. n = recv(self->client, buf, sizeof(buf), 0);
  120. ASSERT_EQ(-1, n);
  121. if (variant->socket_type == SOCK_STREAM ||
  122. variant->socket_type == SOCK_SEQPACKET) {
  123. ASSERT_EQ(ECONNRESET, errno);
  124. } else {
  125. ASSERT_EQ(EAGAIN, errno);
  126. }
  127. }
  128. /* Test 3: closing unaccepted (embryo) server socket should reset client. */
  129. TEST_F(unix_sock, reset_closed_embryo)
  130. {
  131. char buf[16] = {};
  132. ssize_t n;
  133. if (variant->socket_type == SOCK_DGRAM) {
  134. snprintf(_metadata->results->reason,
  135. sizeof(_metadata->results->reason),
  136. "Test only applies to SOCK_STREAM and SOCK_SEQPACKET");
  137. exit(KSFT_XFAIL);
  138. }
  139. /* Close server without accept()ing */
  140. close(self->server);
  141. n = recv(self->client, buf, sizeof(buf), 0);
  142. ASSERT_EQ(-1, n);
  143. ASSERT_EQ(ECONNRESET, errno);
  144. }
  145. TEST_HARNESS_MAIN