accept-non-empty.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Check that kernels that support it will return IORING_CQE_F_SOCK_NONEMPTY
  5. * on accepts requests where more connections are pending.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <stdint.h>
  10. #include <assert.h>
  11. #include <errno.h>
  12. #include <fcntl.h>
  13. #include <unistd.h>
  14. #include <sys/socket.h>
  15. #include <sys/time.h>
  16. #include <sys/resource.h>
  17. #include <sys/un.h>
  18. #include <netinet/tcp.h>
  19. #include <netinet/in.h>
  20. #include <arpa/inet.h>
  21. #include <pthread.h>
  22. #include "liburing.h"
  23. #include "helpers.h"
  24. static int no_more_accept;
  25. #define MAX_ACCEPTS 8
  26. struct data {
  27. pthread_t thread;
  28. pthread_barrier_t barrier;
  29. pthread_barrier_t conn_barrier;
  30. int connects;
  31. };
  32. static int start_accept_listen(int port_off, int extra_flags)
  33. {
  34. struct sockaddr_in addr;
  35. int32_t val = 1;
  36. int fd, ret;
  37. fd = socket(AF_INET, SOCK_STREAM | extra_flags, IPPROTO_TCP);
  38. ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
  39. assert(ret != -1);
  40. ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
  41. assert(ret != -1);
  42. addr.sin_family = AF_INET;
  43. addr.sin_port = htons(0x1235 + port_off);
  44. addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  45. ret = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
  46. assert(ret != -1);
  47. ret = listen(fd, 20000);
  48. assert(ret != -1);
  49. return fd;
  50. }
  51. static void *connect_fn(void *data)
  52. {
  53. struct sockaddr_in addr = { };
  54. struct data *d = data;
  55. int i;
  56. pthread_barrier_wait(&d->barrier);
  57. addr.sin_family = AF_INET;
  58. addr.sin_port = htons(0x1235);
  59. addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  60. for (i = 0; i < d->connects; i++) {
  61. int s;
  62. s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  63. if (s < 0) {
  64. perror("socket");
  65. break;
  66. }
  67. if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
  68. perror("connect");
  69. break;
  70. }
  71. }
  72. if (i)
  73. pthread_barrier_wait(&d->conn_barrier);
  74. return NULL;
  75. }
  76. static void setup_thread(struct data *d, int nconns)
  77. {
  78. d->connects = nconns;
  79. pthread_barrier_init(&d->barrier, NULL, 2);
  80. pthread_barrier_init(&d->conn_barrier, NULL, 2);
  81. pthread_create(&d->thread, NULL, connect_fn, d);
  82. }
  83. static int test_maccept(struct data *d, int flags, int fixed)
  84. {
  85. struct io_uring_params p = { };
  86. struct io_uring ring;
  87. struct io_uring_cqe *cqe;
  88. struct io_uring_sqe *sqe;
  89. int err = 0, fd, ret, i, *fds;
  90. p.flags = flags;
  91. ret = io_uring_queue_init_params(8, &ring, &p);
  92. if (ret == -EINVAL) {
  93. return T_EXIT_SKIP;
  94. } else if (ret < 0) {
  95. fprintf(stderr, "ring setup failure: %d\n", ret);
  96. return T_EXIT_FAIL;
  97. }
  98. if (!(p.features & IORING_FEAT_RECVSEND_BUNDLE)) {
  99. no_more_accept = 1;
  100. return 0;
  101. }
  102. setup_thread(d, MAX_ACCEPTS);
  103. fds = malloc(MAX_ACCEPTS * sizeof(int));
  104. memset(fds, -1, MAX_ACCEPTS * sizeof(int));
  105. if (fixed) {
  106. io_uring_register_ring_fd(&ring);
  107. ret = io_uring_register_files(&ring, fds, MAX_ACCEPTS);
  108. if (ret) {
  109. fprintf(stderr, "file reg %d\n", ret);
  110. return -1;
  111. }
  112. }
  113. fd = start_accept_listen(0, 0);
  114. pthread_barrier_wait(&d->barrier);
  115. if (d->connects > 1)
  116. pthread_barrier_wait(&d->conn_barrier);
  117. for (i = 0; i < d->connects; i++) {
  118. sqe = io_uring_get_sqe(&ring);
  119. if (fixed)
  120. io_uring_prep_accept_direct(sqe, fd, NULL, NULL, 0, i);
  121. else
  122. io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
  123. ret = io_uring_submit_and_wait(&ring, 1);
  124. assert(ret != -1);
  125. ret = io_uring_wait_cqe(&ring, &cqe);
  126. assert(!ret);
  127. if (cqe->res < 0) {
  128. fprintf(stderr, "res=%d\n", cqe->res);
  129. break;
  130. }
  131. fds[i] = cqe->res;
  132. if (d->connects == 1) {
  133. if (cqe->flags & IORING_CQE_F_SOCK_NONEMPTY) {
  134. fprintf(stderr, "Non-empty sock on single?\n");
  135. err = 1;
  136. break;
  137. }
  138. } else {
  139. int last = i + 1 == d->connects;
  140. if (last && cqe->flags & IORING_CQE_F_SOCK_NONEMPTY) {
  141. fprintf(stderr, "Non-empty sock on last?\n");
  142. err = 1;
  143. break;
  144. } else if (!last && !(cqe->flags & IORING_CQE_F_SOCK_NONEMPTY)) {
  145. fprintf(stderr, "Empty on multi connect?\n");
  146. err = 1;
  147. break;
  148. }
  149. }
  150. io_uring_cqe_seen(&ring, cqe);
  151. }
  152. close(fd);
  153. if (!fixed) {
  154. for (i = 0; i < MAX_ACCEPTS; i++)
  155. if (fds[i] != -1)
  156. close(fds[i]);
  157. }
  158. free(fds);
  159. io_uring_queue_exit(&ring);
  160. return err;
  161. }
  162. static int test(int flags, int fixed)
  163. {
  164. struct data d;
  165. void *tret;
  166. int ret;
  167. ret = test_maccept(&d, flags, fixed);
  168. if (ret) {
  169. fprintf(stderr, "test conns=1 failed\n");
  170. return ret;
  171. }
  172. if (no_more_accept)
  173. return T_EXIT_SKIP;
  174. pthread_join(d.thread, &tret);
  175. ret = test_maccept(&d, flags, fixed);
  176. if (ret) {
  177. fprintf(stderr, "test conns=MAX failed\n");
  178. return ret;
  179. }
  180. pthread_join(d.thread, &tret);
  181. return 0;
  182. }
  183. int main(int argc, char *argv[])
  184. {
  185. int ret;
  186. if (argc > 1)
  187. return T_EXIT_SKIP;
  188. ret = test(0, 0);
  189. if (no_more_accept)
  190. return T_EXIT_SKIP;
  191. if (ret) {
  192. fprintf(stderr, "test 0 0 failed\n");
  193. return ret;
  194. }
  195. ret = test(IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN, 0);
  196. if (ret) {
  197. fprintf(stderr, "test DEFER 0 failed\n");
  198. return ret;
  199. }
  200. ret = test(0, 1);
  201. if (ret) {
  202. fprintf(stderr, "test 0 1 failed\n");
  203. return ret;
  204. }
  205. ret = test(IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN, 1);
  206. if (ret) {
  207. fprintf(stderr, "test DEFER 1 failed\n");
  208. return ret;
  209. }
  210. return 0;
  211. }