blob: 3de975fbe37bdd949e9d4db39a9d1fab8e08e965 [file] [log] [blame]
Jens Axboef2ee0432019-10-17 17:21:25 -06001/*
2 * Check that IORING_OP_ACCEPT works, and send some data across to verify we
3 * didn't get a junk fd.
4 */
5#include <stdio.h>
6#include <stdlib.h>
7#include <stdint.h>
8#include <assert.h>
9
10#include <errno.h>
11#include <fcntl.h>
12#include <unistd.h>
13#include <sys/socket.h>
Jens Axboec1177122019-11-10 21:23:56 -070014#include <sys/time.h>
15#include <sys/resource.h>
Jens Axboef2ee0432019-10-17 17:21:25 -060016#include <sys/un.h>
17#include <netinet/tcp.h>
18#include <netinet/in.h>
19
Jens Axboea8f85362019-11-12 12:30:38 -070020#include "liburing.h"
Jens Axboef2ee0432019-10-17 17:21:25 -060021
Jens Axboea9bb08d2019-10-18 08:20:31 -060022static int no_accept;
23
Jens Axboea80dabe2019-12-24 10:25:45 -070024struct data {
25 char buf[128];
26 struct iovec iov;
27};
28
Jens Axboef2ee0432019-10-17 17:21:25 -060029static void queue_send(struct io_uring *ring, int fd)
30{
31 struct io_uring_sqe *sqe;
Jens Axboea80dabe2019-12-24 10:25:45 -070032 struct data *d;
Jens Axboef2ee0432019-10-17 17:21:25 -060033
Jens Axboea80dabe2019-12-24 10:25:45 -070034 d = malloc(sizeof(*d));
35 d->iov.iov_base = d->buf;
36 d->iov.iov_len = sizeof(d->buf);
Jens Axboef2ee0432019-10-17 17:21:25 -060037
38 sqe = io_uring_get_sqe(ring);
Jens Axboea80dabe2019-12-24 10:25:45 -070039 io_uring_prep_writev(sqe, fd, &d->iov, 1, 0);
Jens Axboef2ee0432019-10-17 17:21:25 -060040}
41
42static void queue_recv(struct io_uring *ring, int fd)
43{
44 struct io_uring_sqe *sqe;
Jens Axboea80dabe2019-12-24 10:25:45 -070045 struct data *d;
Jens Axboef2ee0432019-10-17 17:21:25 -060046
Jens Axboea80dabe2019-12-24 10:25:45 -070047 d = malloc(sizeof(*d));
48 d->iov.iov_base = d->buf;
49 d->iov.iov_len = sizeof(d->buf);
Jens Axboef2ee0432019-10-17 17:21:25 -060050
51 sqe = io_uring_get_sqe(ring);
Jens Axboea80dabe2019-12-24 10:25:45 -070052 io_uring_prep_readv(sqe, fd, &d->iov, 1, 0);
Jens Axboef2ee0432019-10-17 17:21:25 -060053}
54
55static int accept_conn(struct io_uring *ring, int fd)
56{
57 struct io_uring_sqe *sqe;
58 struct io_uring_cqe *cqe;
59 int ret;
60
61 sqe = io_uring_get_sqe(ring);
62 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
63
64 assert(io_uring_submit(ring) != -1);
65
66 assert(!io_uring_wait_cqe(ring, &cqe));
67 ret = cqe->res;
68 io_uring_cqe_seen(ring, cqe);
69 return ret;
70}
71
Jens Axboec1177122019-11-10 21:23:56 -070072static int start_accept_listen(struct sockaddr_in *addr, int port_off)
Jens Axboe7de62532019-11-10 10:09:36 -070073{
74 int fd;
75
76 fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
77
78 int32_t val = 1;
79 assert(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) != -1);
80 assert(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
81
82 struct sockaddr_in laddr;
83
84 if (!addr)
85 addr = &laddr;
86
87 addr->sin_family = AF_INET;
Jens Axboec1177122019-11-10 21:23:56 -070088 addr->sin_port = 0x1235 + port_off;
Jens Axboe7de62532019-11-10 10:09:36 -070089 addr->sin_addr.s_addr = 0x0100007fU;
90
91 assert(bind(fd, (struct sockaddr*)addr, sizeof(*addr)) != -1);
92 assert(listen(fd, 128) != -1);
93
94 return fd;
95}
96
Jens Axboe6b998552019-10-18 11:12:26 -060097static int test(struct io_uring *ring, int accept_should_error)
Jens Axboef2ee0432019-10-17 17:21:25 -060098{
Jens Axboef2ee0432019-10-17 17:21:25 -060099 struct io_uring_cqe *cqe;
Jens Axboe7de62532019-11-10 10:09:36 -0700100 struct sockaddr_in addr;
Jens Axboef2ee0432019-10-17 17:21:25 -0600101 uint32_t head;
102 uint32_t count = 0;
103 int done = 0;
104 int p_fd[2];
105
Jens Axboec1177122019-11-10 21:23:56 -0700106 int32_t val, recv_s0 = start_accept_listen(&addr, 0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600107
108 p_fd[1] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
109
110 val = 1;
111 assert(setsockopt(p_fd[1], IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) != -1);
112
113 int32_t flags = fcntl(p_fd[1], F_GETFL, 0);
114 assert(flags != -1);
115
116 flags |= O_NONBLOCK;
117 assert(fcntl(p_fd[1], F_SETFL, flags) != -1);
118
119 assert(connect(p_fd[1], (struct sockaddr*)&addr, sizeof(addr)) == -1);
120
121 flags = fcntl(p_fd[1], F_GETFL, 0);
122 assert(flags != -1);
123
124 flags &= ~O_NONBLOCK;
125 assert(fcntl(p_fd[1], F_SETFL, flags) != -1);
126
Jens Axboea9bb08d2019-10-18 08:20:31 -0600127 p_fd[0] = accept_conn(ring, recv_s0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600128 if (p_fd[0] == -EINVAL) {
Jens Axboe6b998552019-10-18 11:12:26 -0600129 if (accept_should_error)
Jens Axboea9bb08d2019-10-18 08:20:31 -0600130 goto out;
Jens Axboef2ee0432019-10-17 17:21:25 -0600131 fprintf(stdout, "Accept not supported, skipping\n");
Jens Axboea9bb08d2019-10-18 08:20:31 -0600132 no_accept = 1;
Jens Axboef2ee0432019-10-17 17:21:25 -0600133 goto out;
Jens Axboe6b998552019-10-18 11:12:26 -0600134 } else if (p_fd[0] < 0) {
135 if (accept_should_error &&
136 (p_fd[0] == -EBADF || p_fd[0] == -EINVAL))
137 goto out;
138 fprintf(stderr, "Accept got %d\n", p_fd[0]);
139 goto err;
Jens Axboef2ee0432019-10-17 17:21:25 -0600140 }
Jens Axboef2ee0432019-10-17 17:21:25 -0600141
Jens Axboea9bb08d2019-10-18 08:20:31 -0600142 queue_send(ring, p_fd[1]);
143 queue_recv(ring, p_fd[0]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600144
Jens Axboea9bb08d2019-10-18 08:20:31 -0600145 assert(io_uring_submit_and_wait(ring, 2) != -1);
Jens Axboef2ee0432019-10-17 17:21:25 -0600146
147 while (count < 2) {
Jens Axboea9bb08d2019-10-18 08:20:31 -0600148 io_uring_for_each_cqe(ring, head, cqe) {
Jens Axboef2ee0432019-10-17 17:21:25 -0600149 if (cqe->res < 0) {
150 fprintf(stderr, "Got cqe res %d\n", cqe->res);
151 done = 1;
152 break;
153 }
154 assert(cqe->res == 128);
155 count++;
156 }
157
158 assert(count <= 2);
Jens Axboea9bb08d2019-10-18 08:20:31 -0600159 io_uring_cq_advance(ring, count);
Jens Axboef2ee0432019-10-17 17:21:25 -0600160 if (done)
161 goto err;
162 }
163
164out:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600165 close(p_fd[0]);
166 close(p_fd[1]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600167 return 0;
168err:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600169 close(p_fd[0]);
170 close(p_fd[1]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600171 return 1;
172}
Jens Axboea9bb08d2019-10-18 08:20:31 -0600173
Jens Axboed974c9f2019-10-24 13:43:33 -0600174static void sig_alrm(int sig)
175{
176 exit(0);
177}
178
Jens Axboec6aa23e2019-11-10 09:49:47 -0700179static int test_accept_pending_on_exit(void)
180{
181 struct io_uring m_io_uring;
182 struct io_uring_cqe *cqe;
183 struct io_uring_sqe *sqe;
184 int fd;
185
186 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
187
Jens Axboec1177122019-11-10 21:23:56 -0700188 fd = start_accept_listen(NULL, 0);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700189
Jens Axboed974c9f2019-10-24 13:43:33 -0600190 sqe = io_uring_get_sqe(&m_io_uring);
191 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
192 assert(io_uring_submit(&m_io_uring) != -1);
193
194 signal(SIGALRM, sig_alrm);
195 alarm(1);
196 assert(!io_uring_wait_cqe(&m_io_uring, &cqe));
197 io_uring_cqe_seen(&m_io_uring, cqe);
198
199 io_uring_queue_exit(&m_io_uring);
200 return 0;
201}
202
Jens Axboec1177122019-11-10 21:23:56 -0700203/*
204 * Test issue many accepts and see if we handle cancellation on exit
205 */
206static int test_accept_many(unsigned nr, unsigned usecs)
207{
208 struct io_uring m_io_uring;
209 struct io_uring_cqe *cqe;
210 struct io_uring_sqe *sqe;
211 unsigned long cur_lim;
212 struct rlimit rlim;
213 int *fds, i, ret = 0;
214
215 if (getrlimit(RLIMIT_NPROC, &rlim) < 0) {
216 perror("getrlimit");
217 return 1;
218 }
219
220 cur_lim = rlim.rlim_cur;
221 rlim.rlim_cur = nr / 4;
222
223 if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
224 perror("setrlimit");
225 return 1;
226 }
227
228 assert(io_uring_queue_init(2 * nr, &m_io_uring, 0) >= 0);
229
230 fds = calloc(nr, sizeof(int));
231
232 for (i = 0; i < nr; i++)
233 fds[i] = start_accept_listen(NULL, i);
234
235 for (i = 0; i < nr; i++) {
236 sqe = io_uring_get_sqe(&m_io_uring);
237 io_uring_prep_accept(sqe, fds[i], NULL, NULL, 0);
238 sqe->user_data = 1 + i;
239 assert(io_uring_submit(&m_io_uring) == 1);
240 }
241
242 if (usecs)
243 usleep(usecs);
244
245 for (i = 0; i < nr; i++) {
246 if (io_uring_peek_cqe(&m_io_uring, &cqe))
247 break;
248 if (cqe->res != -ECANCELED) {
249 fprintf(stderr, "Expected cqe to be cancelled\n");
250 goto err;
251 }
252 io_uring_cqe_seen(&m_io_uring, cqe);
253 }
254out:
255 rlim.rlim_cur = cur_lim;
256 if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
257 perror("setrlimit");
258 return 1;
259 }
260
261 free(fds);
262 io_uring_queue_exit(&m_io_uring);
263 return ret;
264err:
265 ret = 1;
266 goto out;
267}
268
Jens Axboec6aa23e2019-11-10 09:49:47 -0700269static int test_accept_cancel(unsigned usecs)
270{
271 struct io_uring m_io_uring;
272 struct io_uring_cqe *cqe;
273 struct io_uring_sqe *sqe;
274 int fd, i;
275
276 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
277
Jens Axboec1177122019-11-10 21:23:56 -0700278 fd = start_accept_listen(NULL, 0);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700279
280 sqe = io_uring_get_sqe(&m_io_uring);
281 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
282 sqe->user_data = 1;
283 assert(io_uring_submit(&m_io_uring) == 1);
284
285 if (usecs)
286 usleep(usecs);
287
288 sqe = io_uring_get_sqe(&m_io_uring);
289 io_uring_prep_cancel(sqe, (void *) 1, 0);
290 sqe->user_data = 2;
291 assert(io_uring_submit(&m_io_uring) == 1);
292
293 for (i = 0; i < 2; i++) {
294 assert(!io_uring_wait_cqe(&m_io_uring, &cqe));
295 /*
296 * Two cases here:
297 *
298 * 1) We cancel the accept4() before it got started, we should
299 * get '0' for the cancel request and '-ECANCELED' for the
300 * accept request.
301 * 2) We cancel the accept4() after it's already running, we
302 * should get '-EALREADY' for the cancel request and
303 * '-EINTR' for the accept request.
304 */
305 if (cqe->user_data == 1) {
306 if (cqe->res != -EINTR && cqe->res != -ECANCELED) {
307 fprintf(stderr, "Cancelled accept got %d\n", cqe->res);
308 goto err;
309 }
310 } else if (cqe->user_data == 2) {
311 if (cqe->res != -EALREADY && cqe->res != 0) {
312 fprintf(stderr, "Cancel got %d\n", cqe->res);
313 goto err;
314 }
315 }
316 io_uring_cqe_seen(&m_io_uring, cqe);
317 }
318
319 io_uring_queue_exit(&m_io_uring);
320 return 0;
321err:
322 io_uring_queue_exit(&m_io_uring);
323 return 1;
324}
325
Jens Axboea9bb08d2019-10-18 08:20:31 -0600326static int test_accept(void)
327{
328 struct io_uring m_io_uring;
329 int ret;
330
331 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
332 ret = test(&m_io_uring, 0);
333 io_uring_queue_exit(&m_io_uring);
334 return ret;
335}
336
337static int test_accept_sqpoll(void)
338{
339 struct io_uring m_io_uring;
340 int ret;
341
Jens Axboe9fca8692019-11-10 09:48:47 -0700342 ret = io_uring_queue_init(32, &m_io_uring, IORING_SETUP_SQPOLL);
343 if (ret && geteuid()) {
344 printf("%s: skipped, not root\n", __FUNCTION__);
345 return 0;
346 } else if (ret)
347 return ret;
348
Jens Axboea9bb08d2019-10-18 08:20:31 -0600349 ret = test(&m_io_uring, 1);
350 io_uring_queue_exit(&m_io_uring);
351 return ret;
352}
353
354int main(int argc, char *argv[])
355{
356 int ret;
357
358 ret = test_accept();
359 if (ret) {
360 fprintf(stderr, "test_accept failed\n");
361 return ret;
362 }
363 if (no_accept)
364 return 0;
365
366 ret = test_accept_sqpoll();
367 if (ret) {
368 fprintf(stderr, "test_accept_sqpoll failed\n");
369 return ret;
370 }
371
Jens Axboec6aa23e2019-11-10 09:49:47 -0700372 ret = test_accept_cancel(0);
Jens Axboed974c9f2019-10-24 13:43:33 -0600373 if (ret) {
Jens Axboec6aa23e2019-11-10 09:49:47 -0700374 fprintf(stderr, "test_accept_cancel nodelay failed\n");
375 return ret;
376 }
377
378 ret = test_accept_cancel(10000);
379 if (ret) {
380 fprintf(stderr, "test_accept_cancel delay failed\n");
381 return ret;
382 }
383
Jens Axboec1177122019-11-10 21:23:56 -0700384 ret = test_accept_many(128, 0);
385 if (ret) {
386 fprintf(stderr, "test_accept_many failed\n");
387 return ret;
388 }
389
390 ret = test_accept_many(128, 100000);
391 if (ret) {
392 fprintf(stderr, "test_accept_many failed\n");
393 return ret;
394 }
395
Jens Axboec6aa23e2019-11-10 09:49:47 -0700396 ret = test_accept_pending_on_exit();
397 if (ret) {
398 fprintf(stderr, "test_accept_pending_on_exit failed\n");
Jens Axboed974c9f2019-10-24 13:43:33 -0600399 return ret;
400 }
401
Jens Axboea9bb08d2019-10-18 08:20:31 -0600402 return 0;
403}