blob: faf81d6ffaa086032677487734e1399cee050d3c [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
65 assert(io_uring_submit(ring) != -1);
66
67 assert(!io_uring_wait_cqe(ring, &cqe));
68 ret = cqe->res;
69 io_uring_cqe_seen(ring, cqe);
70 return ret;
71}
72
Jens Axboec1177122019-11-10 21:23:56 -070073static int start_accept_listen(struct sockaddr_in *addr, int port_off)
Jens Axboe7de62532019-11-10 10:09:36 -070074{
75 int fd;
76
77 fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
78
79 int32_t val = 1;
80 assert(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) != -1);
81 assert(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
82
83 struct sockaddr_in laddr;
84
85 if (!addr)
86 addr = &laddr;
87
88 addr->sin_family = AF_INET;
Jens Axboec1177122019-11-10 21:23:56 -070089 addr->sin_port = 0x1235 + port_off;
Jens Axboe7de62532019-11-10 10:09:36 -070090 addr->sin_addr.s_addr = 0x0100007fU;
91
92 assert(bind(fd, (struct sockaddr*)addr, sizeof(*addr)) != -1);
93 assert(listen(fd, 128) != -1);
94
95 return fd;
96}
97
Jens Axboe6b998552019-10-18 11:12:26 -060098static int test(struct io_uring *ring, int accept_should_error)
Jens Axboef2ee0432019-10-17 17:21:25 -060099{
Jens Axboef2ee0432019-10-17 17:21:25 -0600100 struct io_uring_cqe *cqe;
Jens Axboe7de62532019-11-10 10:09:36 -0700101 struct sockaddr_in addr;
Jens Axboef2ee0432019-10-17 17:21:25 -0600102 uint32_t head;
103 uint32_t count = 0;
104 int done = 0;
105 int p_fd[2];
106
Jens Axboec1177122019-11-10 21:23:56 -0700107 int32_t val, recv_s0 = start_accept_listen(&addr, 0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600108
109 p_fd[1] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
110
111 val = 1;
112 assert(setsockopt(p_fd[1], IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) != -1);
113
114 int32_t flags = fcntl(p_fd[1], F_GETFL, 0);
115 assert(flags != -1);
116
117 flags |= O_NONBLOCK;
118 assert(fcntl(p_fd[1], F_SETFL, flags) != -1);
119
120 assert(connect(p_fd[1], (struct sockaddr*)&addr, sizeof(addr)) == -1);
121
122 flags = fcntl(p_fd[1], F_GETFL, 0);
123 assert(flags != -1);
124
125 flags &= ~O_NONBLOCK;
126 assert(fcntl(p_fd[1], F_SETFL, flags) != -1);
127
Jens Axboea9bb08d2019-10-18 08:20:31 -0600128 p_fd[0] = accept_conn(ring, recv_s0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600129 if (p_fd[0] == -EINVAL) {
Jens Axboe6b998552019-10-18 11:12:26 -0600130 if (accept_should_error)
Jens Axboea9bb08d2019-10-18 08:20:31 -0600131 goto out;
Jens Axboef2ee0432019-10-17 17:21:25 -0600132 fprintf(stdout, "Accept not supported, skipping\n");
Jens Axboea9bb08d2019-10-18 08:20:31 -0600133 no_accept = 1;
Jens Axboef2ee0432019-10-17 17:21:25 -0600134 goto out;
Jens Axboe6b998552019-10-18 11:12:26 -0600135 } else if (p_fd[0] < 0) {
136 if (accept_should_error &&
137 (p_fd[0] == -EBADF || p_fd[0] == -EINVAL))
138 goto out;
139 fprintf(stderr, "Accept got %d\n", p_fd[0]);
140 goto err;
Jens Axboef2ee0432019-10-17 17:21:25 -0600141 }
Jens Axboef2ee0432019-10-17 17:21:25 -0600142
Jens Axboea9bb08d2019-10-18 08:20:31 -0600143 queue_send(ring, p_fd[1]);
144 queue_recv(ring, p_fd[0]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600145
Jens Axboea9bb08d2019-10-18 08:20:31 -0600146 assert(io_uring_submit_and_wait(ring, 2) != -1);
Jens Axboef2ee0432019-10-17 17:21:25 -0600147
148 while (count < 2) {
Jens Axboea9bb08d2019-10-18 08:20:31 -0600149 io_uring_for_each_cqe(ring, head, cqe) {
Jens Axboef2ee0432019-10-17 17:21:25 -0600150 if (cqe->res < 0) {
151 fprintf(stderr, "Got cqe res %d\n", cqe->res);
152 done = 1;
153 break;
154 }
155 assert(cqe->res == 128);
156 count++;
157 }
158
159 assert(count <= 2);
Jens Axboea9bb08d2019-10-18 08:20:31 -0600160 io_uring_cq_advance(ring, count);
Jens Axboef2ee0432019-10-17 17:21:25 -0600161 if (done)
162 goto err;
163 }
164
165out:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600166 close(p_fd[0]);
167 close(p_fd[1]);
Jens Axboecfddbbf2020-09-05 13:30:28 -0600168 close(recv_s0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600169 return 0;
170err:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600171 close(p_fd[0]);
172 close(p_fd[1]);
Jens Axboecfddbbf2020-09-05 13:30:28 -0600173 close(recv_s0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600174 return 1;
175}
Jens Axboea9bb08d2019-10-18 08:20:31 -0600176
Jens Axboed974c9f2019-10-24 13:43:33 -0600177static void sig_alrm(int sig)
178{
179 exit(0);
180}
181
Jens Axboec6aa23e2019-11-10 09:49:47 -0700182static int test_accept_pending_on_exit(void)
183{
184 struct io_uring m_io_uring;
185 struct io_uring_cqe *cqe;
186 struct io_uring_sqe *sqe;
187 int fd;
188
189 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
190
Jens Axboec1177122019-11-10 21:23:56 -0700191 fd = start_accept_listen(NULL, 0);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700192
Jens Axboed974c9f2019-10-24 13:43:33 -0600193 sqe = io_uring_get_sqe(&m_io_uring);
194 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
195 assert(io_uring_submit(&m_io_uring) != -1);
196
197 signal(SIGALRM, sig_alrm);
198 alarm(1);
199 assert(!io_uring_wait_cqe(&m_io_uring, &cqe));
200 io_uring_cqe_seen(&m_io_uring, cqe);
201
202 io_uring_queue_exit(&m_io_uring);
203 return 0;
204}
205
Jens Axboec1177122019-11-10 21:23:56 -0700206/*
207 * Test issue many accepts and see if we handle cancellation on exit
208 */
209static int test_accept_many(unsigned nr, unsigned usecs)
210{
211 struct io_uring m_io_uring;
212 struct io_uring_cqe *cqe;
213 struct io_uring_sqe *sqe;
214 unsigned long cur_lim;
215 struct rlimit rlim;
216 int *fds, i, ret = 0;
217
218 if (getrlimit(RLIMIT_NPROC, &rlim) < 0) {
219 perror("getrlimit");
220 return 1;
221 }
222
223 cur_lim = rlim.rlim_cur;
224 rlim.rlim_cur = nr / 4;
225
226 if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
227 perror("setrlimit");
228 return 1;
229 }
230
231 assert(io_uring_queue_init(2 * nr, &m_io_uring, 0) >= 0);
232
233 fds = calloc(nr, sizeof(int));
234
235 for (i = 0; i < nr; i++)
236 fds[i] = start_accept_listen(NULL, i);
237
238 for (i = 0; i < nr; i++) {
239 sqe = io_uring_get_sqe(&m_io_uring);
240 io_uring_prep_accept(sqe, fds[i], NULL, NULL, 0);
241 sqe->user_data = 1 + i;
242 assert(io_uring_submit(&m_io_uring) == 1);
243 }
244
245 if (usecs)
246 usleep(usecs);
247
248 for (i = 0; i < nr; i++) {
249 if (io_uring_peek_cqe(&m_io_uring, &cqe))
250 break;
251 if (cqe->res != -ECANCELED) {
252 fprintf(stderr, "Expected cqe to be cancelled\n");
253 goto err;
254 }
255 io_uring_cqe_seen(&m_io_uring, cqe);
256 }
257out:
258 rlim.rlim_cur = cur_lim;
259 if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
260 perror("setrlimit");
261 return 1;
262 }
263
264 free(fds);
265 io_uring_queue_exit(&m_io_uring);
266 return ret;
267err:
268 ret = 1;
269 goto out;
270}
271
Jens Axboec6aa23e2019-11-10 09:49:47 -0700272static int test_accept_cancel(unsigned usecs)
273{
274 struct io_uring m_io_uring;
275 struct io_uring_cqe *cqe;
276 struct io_uring_sqe *sqe;
277 int fd, i;
278
279 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
280
Jens Axboec1177122019-11-10 21:23:56 -0700281 fd = start_accept_listen(NULL, 0);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700282
283 sqe = io_uring_get_sqe(&m_io_uring);
284 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
285 sqe->user_data = 1;
286 assert(io_uring_submit(&m_io_uring) == 1);
287
288 if (usecs)
289 usleep(usecs);
290
291 sqe = io_uring_get_sqe(&m_io_uring);
292 io_uring_prep_cancel(sqe, (void *) 1, 0);
293 sqe->user_data = 2;
294 assert(io_uring_submit(&m_io_uring) == 1);
295
296 for (i = 0; i < 2; i++) {
297 assert(!io_uring_wait_cqe(&m_io_uring, &cqe));
298 /*
299 * Two cases here:
300 *
301 * 1) We cancel the accept4() before it got started, we should
302 * get '0' for the cancel request and '-ECANCELED' for the
303 * accept request.
304 * 2) We cancel the accept4() after it's already running, we
305 * should get '-EALREADY' for the cancel request and
306 * '-EINTR' for the accept request.
307 */
308 if (cqe->user_data == 1) {
309 if (cqe->res != -EINTR && cqe->res != -ECANCELED) {
310 fprintf(stderr, "Cancelled accept got %d\n", cqe->res);
311 goto err;
312 }
313 } else if (cqe->user_data == 2) {
314 if (cqe->res != -EALREADY && cqe->res != 0) {
315 fprintf(stderr, "Cancel got %d\n", cqe->res);
316 goto err;
317 }
318 }
319 io_uring_cqe_seen(&m_io_uring, cqe);
320 }
321
322 io_uring_queue_exit(&m_io_uring);
323 return 0;
324err:
325 io_uring_queue_exit(&m_io_uring);
326 return 1;
327}
328
Jens Axboea9bb08d2019-10-18 08:20:31 -0600329static int test_accept(void)
330{
331 struct io_uring m_io_uring;
332 int ret;
333
334 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
335 ret = test(&m_io_uring, 0);
336 io_uring_queue_exit(&m_io_uring);
337 return ret;
338}
339
340static int test_accept_sqpoll(void)
341{
342 struct io_uring m_io_uring;
Jens Axboe27b44792020-09-05 12:00:09 -0600343 struct io_uring_params p = { };
344 int ret, should_fail;
Jens Axboea9bb08d2019-10-18 08:20:31 -0600345
Jens Axboe27b44792020-09-05 12:00:09 -0600346 p.flags = IORING_SETUP_SQPOLL;
347 ret = io_uring_queue_init_params(32, &m_io_uring, &p);
Jens Axboe9fca8692019-11-10 09:48:47 -0700348 if (ret && geteuid()) {
349 printf("%s: skipped, not root\n", __FUNCTION__);
350 return 0;
351 } else if (ret)
352 return ret;
353
Jens Axboe27b44792020-09-05 12:00:09 -0600354 should_fail = 1;
355 if (p.features & IORING_FEAT_SQPOLL_NONFIXED)
356 should_fail = 0;
357
358 ret = test(&m_io_uring, should_fail);
Jens Axboea9bb08d2019-10-18 08:20:31 -0600359 io_uring_queue_exit(&m_io_uring);
360 return ret;
361}
362
363int main(int argc, char *argv[])
364{
365 int ret;
366
Jens Axboea2141fc2020-05-19 17:36:19 -0600367 if (argc > 1)
368 return 0;
369
Jens Axboea9bb08d2019-10-18 08:20:31 -0600370 ret = test_accept();
371 if (ret) {
372 fprintf(stderr, "test_accept failed\n");
373 return ret;
374 }
375 if (no_accept)
376 return 0;
377
378 ret = test_accept_sqpoll();
379 if (ret) {
380 fprintf(stderr, "test_accept_sqpoll failed\n");
381 return ret;
382 }
383
Jens Axboec6aa23e2019-11-10 09:49:47 -0700384 ret = test_accept_cancel(0);
Jens Axboed974c9f2019-10-24 13:43:33 -0600385 if (ret) {
Jens Axboec6aa23e2019-11-10 09:49:47 -0700386 fprintf(stderr, "test_accept_cancel nodelay failed\n");
387 return ret;
388 }
389
390 ret = test_accept_cancel(10000);
391 if (ret) {
392 fprintf(stderr, "test_accept_cancel delay failed\n");
393 return ret;
394 }
395
Jens Axboec1177122019-11-10 21:23:56 -0700396 ret = test_accept_many(128, 0);
397 if (ret) {
398 fprintf(stderr, "test_accept_many failed\n");
399 return ret;
400 }
401
402 ret = test_accept_many(128, 100000);
403 if (ret) {
404 fprintf(stderr, "test_accept_many failed\n");
405 return ret;
406 }
407
Jens Axboec6aa23e2019-11-10 09:49:47 -0700408 ret = test_accept_pending_on_exit();
409 if (ret) {
410 fprintf(stderr, "test_accept_pending_on_exit failed\n");
Jens Axboed974c9f2019-10-24 13:43:33 -0600411 return ret;
412 }
413
Jens Axboea9bb08d2019-10-18 08:20:31 -0600414 return 0;
415}