blob: 89e4c59144f17f29b581b177f77e547671da55b4 [file] [log] [blame]
Jens Axboee5024352020-02-11 20:34:12 -07001/* SPDX-License-Identifier: MIT */
Jens Axboef2ee0432019-10-17 17:21:25 -06002/*
3 * Check that IORING_OP_ACCEPT works, and send some data across to verify we
4 * didn't get a junk fd.
5 */
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdint.h>
9#include <assert.h>
10
11#include <errno.h>
12#include <fcntl.h>
13#include <unistd.h>
14#include <sys/socket.h>
Jens Axboec1177122019-11-10 21:23:56 -070015#include <sys/time.h>
16#include <sys/resource.h>
Jens Axboef2ee0432019-10-17 17:21:25 -060017#include <sys/un.h>
18#include <netinet/tcp.h>
19#include <netinet/in.h>
20
Jens Axboea8f85362019-11-12 12:30:38 -070021#include "liburing.h"
Jens Axboef2ee0432019-10-17 17:21:25 -060022
Jens Axboea9bb08d2019-10-18 08:20:31 -060023static int no_accept;
24
Jens Axboea80dabe2019-12-24 10:25:45 -070025struct data {
26 char buf[128];
27 struct iovec iov;
28};
29
Jens Axboef2ee0432019-10-17 17:21:25 -060030static void queue_send(struct io_uring *ring, int fd)
31{
32 struct io_uring_sqe *sqe;
Jens Axboea80dabe2019-12-24 10:25:45 -070033 struct data *d;
Jens Axboef2ee0432019-10-17 17:21:25 -060034
Jens Axboea80dabe2019-12-24 10:25:45 -070035 d = malloc(sizeof(*d));
36 d->iov.iov_base = d->buf;
37 d->iov.iov_len = sizeof(d->buf);
Jens Axboef2ee0432019-10-17 17:21:25 -060038
39 sqe = io_uring_get_sqe(ring);
Jens Axboea80dabe2019-12-24 10:25:45 -070040 io_uring_prep_writev(sqe, fd, &d->iov, 1, 0);
Jens Axboef2ee0432019-10-17 17:21:25 -060041}
42
43static void queue_recv(struct io_uring *ring, int fd)
44{
45 struct io_uring_sqe *sqe;
Jens Axboea80dabe2019-12-24 10:25:45 -070046 struct data *d;
Jens Axboef2ee0432019-10-17 17:21:25 -060047
Jens Axboea80dabe2019-12-24 10:25:45 -070048 d = malloc(sizeof(*d));
49 d->iov.iov_base = d->buf;
50 d->iov.iov_len = sizeof(d->buf);
Jens Axboef2ee0432019-10-17 17:21:25 -060051
52 sqe = io_uring_get_sqe(ring);
Jens Axboea80dabe2019-12-24 10:25:45 -070053 io_uring_prep_readv(sqe, fd, &d->iov, 1, 0);
Jens Axboef2ee0432019-10-17 17:21:25 -060054}
55
56static int accept_conn(struct io_uring *ring, int fd)
57{
58 struct io_uring_sqe *sqe;
59 struct io_uring_cqe *cqe;
60 int ret;
61
62 sqe = io_uring_get_sqe(ring);
63 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
64
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +000065 ret = io_uring_submit(ring);
66 assert(ret != -1);
Jens Axboef2ee0432019-10-17 17:21:25 -060067
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +000068 ret = io_uring_wait_cqe(ring, &cqe);
69 assert(!ret);
Jens Axboef2ee0432019-10-17 17:21:25 -060070 ret = cqe->res;
71 io_uring_cqe_seen(ring, cqe);
72 return ret;
73}
74
Jens Axboec1177122019-11-10 21:23:56 -070075static int start_accept_listen(struct sockaddr_in *addr, int port_off)
Jens Axboe7de62532019-11-10 10:09:36 -070076{
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +000077 int fd, ret;
Jens Axboe7de62532019-11-10 10:09:36 -070078
79 fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
80
81 int32_t val = 1;
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +000082 ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
83 assert(ret != -1);
84 ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
85 assert(ret != -1);
Jens Axboe7de62532019-11-10 10:09:36 -070086
87 struct sockaddr_in laddr;
88
89 if (!addr)
90 addr = &laddr;
91
92 addr->sin_family = AF_INET;
Jens Axboec1177122019-11-10 21:23:56 -070093 addr->sin_port = 0x1235 + port_off;
Jens Axboe7de62532019-11-10 10:09:36 -070094 addr->sin_addr.s_addr = 0x0100007fU;
95
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +000096 ret = bind(fd, (struct sockaddr*)addr, sizeof(*addr));
97 assert(ret != -1);
98 ret = listen(fd, 128);
99 assert(ret != -1);
Jens Axboe7de62532019-11-10 10:09:36 -0700100
101 return fd;
102}
103
Jens Axboe6b998552019-10-18 11:12:26 -0600104static int test(struct io_uring *ring, int accept_should_error)
Jens Axboef2ee0432019-10-17 17:21:25 -0600105{
Jens Axboef2ee0432019-10-17 17:21:25 -0600106 struct io_uring_cqe *cqe;
Jens Axboe7de62532019-11-10 10:09:36 -0700107 struct sockaddr_in addr;
Jens Axboef2ee0432019-10-17 17:21:25 -0600108 uint32_t head;
109 uint32_t count = 0;
110 int done = 0;
111 int p_fd[2];
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000112 int ret;
Jens Axboef2ee0432019-10-17 17:21:25 -0600113
Jens Axboec1177122019-11-10 21:23:56 -0700114 int32_t val, recv_s0 = start_accept_listen(&addr, 0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600115
116 p_fd[1] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
117
118 val = 1;
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000119 ret = setsockopt(p_fd[1], IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
120 assert(ret != -1);
Jens Axboef2ee0432019-10-17 17:21:25 -0600121
122 int32_t flags = fcntl(p_fd[1], F_GETFL, 0);
123 assert(flags != -1);
124
125 flags |= O_NONBLOCK;
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000126 ret = fcntl(p_fd[1], F_SETFL, flags);
127 assert(ret != -1);
Jens Axboef2ee0432019-10-17 17:21:25 -0600128
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000129 ret = connect(p_fd[1], (struct sockaddr*)&addr, sizeof(addr));
130 assert(ret == -1);
Jens Axboef2ee0432019-10-17 17:21:25 -0600131
132 flags = fcntl(p_fd[1], F_GETFL, 0);
133 assert(flags != -1);
134
135 flags &= ~O_NONBLOCK;
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000136 ret = fcntl(p_fd[1], F_SETFL, flags);
137 assert(ret != -1);
Jens Axboef2ee0432019-10-17 17:21:25 -0600138
Jens Axboea9bb08d2019-10-18 08:20:31 -0600139 p_fd[0] = accept_conn(ring, recv_s0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600140 if (p_fd[0] == -EINVAL) {
Jens Axboe6b998552019-10-18 11:12:26 -0600141 if (accept_should_error)
Jens Axboea9bb08d2019-10-18 08:20:31 -0600142 goto out;
Jens Axboef2ee0432019-10-17 17:21:25 -0600143 fprintf(stdout, "Accept not supported, skipping\n");
Jens Axboea9bb08d2019-10-18 08:20:31 -0600144 no_accept = 1;
Jens Axboef2ee0432019-10-17 17:21:25 -0600145 goto out;
Jens Axboe6b998552019-10-18 11:12:26 -0600146 } else if (p_fd[0] < 0) {
147 if (accept_should_error &&
148 (p_fd[0] == -EBADF || p_fd[0] == -EINVAL))
149 goto out;
150 fprintf(stderr, "Accept got %d\n", p_fd[0]);
151 goto err;
Jens Axboef2ee0432019-10-17 17:21:25 -0600152 }
Jens Axboef2ee0432019-10-17 17:21:25 -0600153
Jens Axboea9bb08d2019-10-18 08:20:31 -0600154 queue_send(ring, p_fd[1]);
155 queue_recv(ring, p_fd[0]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600156
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000157 ret = io_uring_submit_and_wait(ring, 2);
158 assert(ret != -1);
Jens Axboef2ee0432019-10-17 17:21:25 -0600159
160 while (count < 2) {
Jens Axboea9bb08d2019-10-18 08:20:31 -0600161 io_uring_for_each_cqe(ring, head, cqe) {
Jens Axboef2ee0432019-10-17 17:21:25 -0600162 if (cqe->res < 0) {
163 fprintf(stderr, "Got cqe res %d\n", cqe->res);
164 done = 1;
165 break;
166 }
167 assert(cqe->res == 128);
168 count++;
169 }
170
171 assert(count <= 2);
Jens Axboea9bb08d2019-10-18 08:20:31 -0600172 io_uring_cq_advance(ring, count);
Jens Axboef2ee0432019-10-17 17:21:25 -0600173 if (done)
174 goto err;
175 }
176
177out:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600178 close(p_fd[0]);
179 close(p_fd[1]);
Jens Axboecfddbbf2020-09-05 13:30:28 -0600180 close(recv_s0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600181 return 0;
182err:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600183 close(p_fd[0]);
184 close(p_fd[1]);
Jens Axboecfddbbf2020-09-05 13:30:28 -0600185 close(recv_s0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600186 return 1;
187}
Jens Axboea9bb08d2019-10-18 08:20:31 -0600188
Jens Axboed974c9f2019-10-24 13:43:33 -0600189static void sig_alrm(int sig)
190{
191 exit(0);
192}
193
Jens Axboec6aa23e2019-11-10 09:49:47 -0700194static int test_accept_pending_on_exit(void)
195{
196 struct io_uring m_io_uring;
197 struct io_uring_cqe *cqe;
198 struct io_uring_sqe *sqe;
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000199 int fd, ret;
Jens Axboec6aa23e2019-11-10 09:49:47 -0700200
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000201 ret = io_uring_queue_init(32, &m_io_uring, 0);
202 assert(ret >= 0);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700203
Jens Axboec1177122019-11-10 21:23:56 -0700204 fd = start_accept_listen(NULL, 0);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700205
Jens Axboed974c9f2019-10-24 13:43:33 -0600206 sqe = io_uring_get_sqe(&m_io_uring);
207 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000208 ret = io_uring_submit(&m_io_uring);
209 assert(ret != -1);
Jens Axboed974c9f2019-10-24 13:43:33 -0600210
211 signal(SIGALRM, sig_alrm);
212 alarm(1);
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000213 ret = io_uring_wait_cqe(&m_io_uring, &cqe);
214 assert(!ret);
Jens Axboed974c9f2019-10-24 13:43:33 -0600215 io_uring_cqe_seen(&m_io_uring, cqe);
216
217 io_uring_queue_exit(&m_io_uring);
218 return 0;
219}
220
Jens Axboec1177122019-11-10 21:23:56 -0700221/*
222 * Test issue many accepts and see if we handle cancellation on exit
223 */
224static int test_accept_many(unsigned nr, unsigned usecs)
225{
226 struct io_uring m_io_uring;
227 struct io_uring_cqe *cqe;
228 struct io_uring_sqe *sqe;
229 unsigned long cur_lim;
230 struct rlimit rlim;
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000231 int *fds, i, ret;
Jens Axboec1177122019-11-10 21:23:56 -0700232
233 if (getrlimit(RLIMIT_NPROC, &rlim) < 0) {
234 perror("getrlimit");
235 return 1;
236 }
237
238 cur_lim = rlim.rlim_cur;
239 rlim.rlim_cur = nr / 4;
240
241 if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
242 perror("setrlimit");
243 return 1;
244 }
245
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000246 ret = io_uring_queue_init(2 * nr, &m_io_uring, 0);
247 assert(ret >= 0);
Jens Axboec1177122019-11-10 21:23:56 -0700248
249 fds = calloc(nr, sizeof(int));
250
251 for (i = 0; i < nr; i++)
252 fds[i] = start_accept_listen(NULL, i);
253
254 for (i = 0; i < nr; i++) {
255 sqe = io_uring_get_sqe(&m_io_uring);
256 io_uring_prep_accept(sqe, fds[i], NULL, NULL, 0);
257 sqe->user_data = 1 + i;
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000258 ret = io_uring_submit(&m_io_uring);
259 assert(ret == 1);
Jens Axboec1177122019-11-10 21:23:56 -0700260 }
261
262 if (usecs)
263 usleep(usecs);
264
265 for (i = 0; i < nr; i++) {
266 if (io_uring_peek_cqe(&m_io_uring, &cqe))
267 break;
268 if (cqe->res != -ECANCELED) {
269 fprintf(stderr, "Expected cqe to be cancelled\n");
270 goto err;
271 }
272 io_uring_cqe_seen(&m_io_uring, cqe);
273 }
274out:
275 rlim.rlim_cur = cur_lim;
276 if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
277 perror("setrlimit");
278 return 1;
279 }
280
281 free(fds);
282 io_uring_queue_exit(&m_io_uring);
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000283 return 0;
Jens Axboec1177122019-11-10 21:23:56 -0700284err:
285 ret = 1;
286 goto out;
287}
288
Jens Axboec6aa23e2019-11-10 09:49:47 -0700289static int test_accept_cancel(unsigned usecs)
290{
291 struct io_uring m_io_uring;
292 struct io_uring_cqe *cqe;
293 struct io_uring_sqe *sqe;
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000294 int fd, i, ret;
Jens Axboec6aa23e2019-11-10 09:49:47 -0700295
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000296 ret = io_uring_queue_init(32, &m_io_uring, 0);
297 assert(ret >= 0);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700298
Jens Axboec1177122019-11-10 21:23:56 -0700299 fd = start_accept_listen(NULL, 0);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700300
301 sqe = io_uring_get_sqe(&m_io_uring);
302 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
303 sqe->user_data = 1;
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000304 ret = io_uring_submit(&m_io_uring);
305 assert(ret == 1);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700306
307 if (usecs)
308 usleep(usecs);
309
310 sqe = io_uring_get_sqe(&m_io_uring);
311 io_uring_prep_cancel(sqe, (void *) 1, 0);
312 sqe->user_data = 2;
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000313 ret = io_uring_submit(&m_io_uring);
314 assert(ret == 1);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700315
316 for (i = 0; i < 2; i++) {
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000317 ret = io_uring_wait_cqe(&m_io_uring, &cqe);
318 assert(!ret);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700319 /*
320 * Two cases here:
321 *
322 * 1) We cancel the accept4() before it got started, we should
323 * get '0' for the cancel request and '-ECANCELED' for the
324 * accept request.
325 * 2) We cancel the accept4() after it's already running, we
326 * should get '-EALREADY' for the cancel request and
327 * '-EINTR' for the accept request.
328 */
329 if (cqe->user_data == 1) {
330 if (cqe->res != -EINTR && cqe->res != -ECANCELED) {
331 fprintf(stderr, "Cancelled accept got %d\n", cqe->res);
332 goto err;
333 }
334 } else if (cqe->user_data == 2) {
335 if (cqe->res != -EALREADY && cqe->res != 0) {
336 fprintf(stderr, "Cancel got %d\n", cqe->res);
337 goto err;
338 }
339 }
340 io_uring_cqe_seen(&m_io_uring, cqe);
341 }
342
343 io_uring_queue_exit(&m_io_uring);
344 return 0;
345err:
346 io_uring_queue_exit(&m_io_uring);
347 return 1;
348}
349
Jens Axboea9bb08d2019-10-18 08:20:31 -0600350static int test_accept(void)
351{
352 struct io_uring m_io_uring;
353 int ret;
354
Ryan Sharpellettie3adbfc2020-10-27 21:04:11 +0000355 ret = io_uring_queue_init(32, &m_io_uring, 0);
356 assert(ret >= 0);
Jens Axboea9bb08d2019-10-18 08:20:31 -0600357 ret = test(&m_io_uring, 0);
358 io_uring_queue_exit(&m_io_uring);
359 return ret;
360}
361
362static int test_accept_sqpoll(void)
363{
364 struct io_uring m_io_uring;
Jens Axboe27b44792020-09-05 12:00:09 -0600365 struct io_uring_params p = { };
366 int ret, should_fail;
Jens Axboea9bb08d2019-10-18 08:20:31 -0600367
Jens Axboe27b44792020-09-05 12:00:09 -0600368 p.flags = IORING_SETUP_SQPOLL;
369 ret = io_uring_queue_init_params(32, &m_io_uring, &p);
Jens Axboe9fca8692019-11-10 09:48:47 -0700370 if (ret && geteuid()) {
371 printf("%s: skipped, not root\n", __FUNCTION__);
372 return 0;
373 } else if (ret)
374 return ret;
375
Jens Axboe27b44792020-09-05 12:00:09 -0600376 should_fail = 1;
377 if (p.features & IORING_FEAT_SQPOLL_NONFIXED)
378 should_fail = 0;
379
380 ret = test(&m_io_uring, should_fail);
Jens Axboea9bb08d2019-10-18 08:20:31 -0600381 io_uring_queue_exit(&m_io_uring);
382 return ret;
383}
384
385int main(int argc, char *argv[])
386{
387 int ret;
388
Jens Axboea2141fc2020-05-19 17:36:19 -0600389 if (argc > 1)
390 return 0;
391
Jens Axboea9bb08d2019-10-18 08:20:31 -0600392 ret = test_accept();
393 if (ret) {
394 fprintf(stderr, "test_accept failed\n");
395 return ret;
396 }
397 if (no_accept)
398 return 0;
399
400 ret = test_accept_sqpoll();
401 if (ret) {
402 fprintf(stderr, "test_accept_sqpoll failed\n");
403 return ret;
404 }
405
Jens Axboec6aa23e2019-11-10 09:49:47 -0700406 ret = test_accept_cancel(0);
Jens Axboed974c9f2019-10-24 13:43:33 -0600407 if (ret) {
Jens Axboec6aa23e2019-11-10 09:49:47 -0700408 fprintf(stderr, "test_accept_cancel nodelay failed\n");
409 return ret;
410 }
411
412 ret = test_accept_cancel(10000);
413 if (ret) {
414 fprintf(stderr, "test_accept_cancel delay failed\n");
415 return ret;
416 }
417
Jens Axboec1177122019-11-10 21:23:56 -0700418 ret = test_accept_many(128, 0);
419 if (ret) {
420 fprintf(stderr, "test_accept_many failed\n");
421 return ret;
422 }
423
424 ret = test_accept_many(128, 100000);
425 if (ret) {
426 fprintf(stderr, "test_accept_many failed\n");
427 return ret;
428 }
429
Jens Axboec6aa23e2019-11-10 09:49:47 -0700430 ret = test_accept_pending_on_exit();
431 if (ret) {
432 fprintf(stderr, "test_accept_pending_on_exit failed\n");
Jens Axboed974c9f2019-10-24 13:43:33 -0600433 return ret;
434 }
435
Jens Axboea9bb08d2019-10-18 08:20:31 -0600436 return 0;
437}