connect-rep.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Check that repeated IORING_OP_CONNECT to a socket without a listener keeps
  5. * yielding -ECONNREFUSED rather than -ECONNABORTED. Based on a reproducer
  6. * from:
  7. *
  8. * https://github.com/axboe/liburing/issues/828
  9. *
  10. * and adopted to our usual test cases. Other changes made like looping,
  11. * using different ring types, adding a memset() for reuse, etc.
  12. *
  13. */
  14. #include <stdio.h>
  15. #include <netinet/in.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18. #include <stdlib.h>
  19. #include <arpa/inet.h>
  20. #include "liburing.h"
  21. #include "helpers.h"
  22. static unsigned long ud;
  23. static int init_test_server(struct sockaddr_in *serv_addr)
  24. {
  25. socklen_t servaddr_len = sizeof(struct sockaddr_in);
  26. int fd;
  27. /* Init server socket. Bind but don't listen */
  28. fd = socket(AF_INET, SOCK_STREAM, 0);
  29. if (fd < 0) {
  30. perror("socket");
  31. return -1;
  32. }
  33. serv_addr->sin_family = AF_INET;
  34. serv_addr->sin_addr.s_addr = inet_addr("127.0.0.1");
  35. if (bind(fd, (struct sockaddr *) serv_addr, servaddr_len) < 0) {
  36. perror("bind");
  37. return -1;
  38. }
  39. /*
  40. * Get the addresses the socket is bound to because the port is chosen
  41. * by the network stack.
  42. */
  43. if (getsockname(fd, (struct sockaddr *)serv_addr, &servaddr_len) < 0) {
  44. perror("getsockname");
  45. return -1;
  46. }
  47. return fd;
  48. }
  49. static int init_test_client(void)
  50. {
  51. socklen_t addr_len = sizeof(struct sockaddr_in);
  52. struct sockaddr_in client_addr = {};
  53. int clientfd;
  54. clientfd = socket(AF_INET, SOCK_STREAM, 0);
  55. if (clientfd < 0) {
  56. perror("socket");
  57. return -1;
  58. }
  59. client_addr.sin_family = AF_INET;
  60. client_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  61. if (bind(clientfd, (struct sockaddr *)&client_addr, addr_len) < 0) {
  62. perror("bind");
  63. close(clientfd);
  64. return -1;
  65. }
  66. /*
  67. * Get the addresses the socket is bound to because the port is chosen
  68. * by the network stack.
  69. */
  70. if (getsockname(clientfd, (struct sockaddr *)&client_addr, &addr_len) < 0) {
  71. perror("getsockname");
  72. close(clientfd);
  73. return -1;
  74. }
  75. return clientfd;
  76. }
  77. static int get_completion_and_print(struct io_uring *ring)
  78. {
  79. struct io_uring_cqe *cqe;
  80. int ret, res;
  81. ret = io_uring_wait_cqe(ring, &cqe);
  82. if (ret < 0) {
  83. fprintf(stderr, "wait_cqe=%d\n", ret);
  84. return -1;
  85. }
  86. /* Mark this completion as seen */
  87. res = cqe->res;
  88. io_uring_cqe_seen(ring, cqe);
  89. return res;
  90. }
  91. static int test_connect(struct io_uring *ring,
  92. int clientfd, struct sockaddr_in *serv_addr)
  93. {
  94. struct sockaddr_in local_sa;
  95. struct io_uring_sqe *sqe;
  96. int ret;
  97. sqe = io_uring_get_sqe(ring);
  98. io_uring_prep_connect(sqe, clientfd, (const struct sockaddr *)serv_addr,
  99. sizeof(struct sockaddr_in));
  100. sqe->user_data = ++ud;
  101. memcpy(&local_sa, serv_addr, sizeof(local_sa));
  102. ret = io_uring_submit_and_wait(ring, 1);
  103. if (ret != 1) {
  104. fprintf(stderr, "submit=%d\n", ret);
  105. return T_EXIT_FAIL;
  106. }
  107. /* check for reuse at the same time */
  108. memset(&local_sa, 0xff, sizeof(local_sa));
  109. ret = get_completion_and_print(ring);
  110. if (ret != -ECONNREFUSED) {
  111. fprintf(stderr, "Connect got %d\n", ret);
  112. return T_EXIT_FAIL;
  113. }
  114. return T_EXIT_PASS;
  115. }
  116. static int test(int flags)
  117. {
  118. struct io_uring_params params = { .flags = flags, };
  119. struct sockaddr_in serv_addr = {};
  120. struct io_uring ring;
  121. int ret, clientfd, s_fd, i;
  122. if (flags & IORING_SETUP_SQPOLL)
  123. params.sq_thread_idle = 50;
  124. ret = io_uring_queue_init_params(8, &ring, &params);
  125. if (ret < 0) {
  126. fprintf(stderr, "Queue init: %d\n", ret);
  127. return T_EXIT_FAIL;
  128. }
  129. s_fd = init_test_server(&serv_addr);
  130. if (s_fd < 0)
  131. return T_EXIT_FAIL;
  132. clientfd = init_test_client();
  133. if (clientfd < 0) {
  134. close(s_fd);
  135. return T_EXIT_FAIL;
  136. }
  137. /* make sure SQPOLL thread is sleeping */
  138. if (flags & IORING_SETUP_SQPOLL)
  139. usleep(100000);
  140. for (i = 0; i < 32; i++) {
  141. ret = test_connect(&ring, clientfd, &serv_addr);
  142. if (ret == T_EXIT_SKIP)
  143. return T_EXIT_SKIP;
  144. else if (ret == T_EXIT_PASS)
  145. continue;
  146. return T_EXIT_FAIL;
  147. }
  148. close(s_fd);
  149. close(clientfd);
  150. return T_EXIT_PASS;
  151. }
  152. int main(int argc, char *argv[])
  153. {
  154. int ret;
  155. if (argc > 1)
  156. return T_EXIT_SKIP;
  157. ret = test(0);
  158. if (ret == T_EXIT_FAIL) {
  159. fprintf(stderr, "test(0) failed\n");
  160. return T_EXIT_FAIL;
  161. }
  162. ret = test(IORING_SETUP_SQPOLL);
  163. if (ret == T_EXIT_FAIL) {
  164. fprintf(stderr, "test(SQPOLL) failed\n");
  165. return T_EXIT_FAIL;
  166. }
  167. return 0;
  168. }