blob: edb7bc2b46fe532ae24e78b17dd8bfef455dd521 [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 Axboef2ee0432019-10-17 17:21:25 -060024static void queue_send(struct io_uring *ring, int fd)
25{
26 struct io_uring_sqe *sqe;
27 char send_buff[128];
28 struct iovec iov;
29
30 iov.iov_base = send_buff;
31 iov.iov_len = sizeof(send_buff);
32
33 sqe = io_uring_get_sqe(ring);
34 io_uring_prep_writev(sqe, fd, &iov, 1, 0);
35}
36
37static void queue_recv(struct io_uring *ring, int fd)
38{
39 struct io_uring_sqe *sqe;
40 char recv_buff[128];
41 struct iovec iov;
42
43 iov.iov_base = recv_buff;
44 iov.iov_len = sizeof(recv_buff);
45
46 sqe = io_uring_get_sqe(ring);
47 io_uring_prep_readv(sqe, fd, &iov, 1, 0);
48}
49
50static int accept_conn(struct io_uring *ring, int fd)
51{
52 struct io_uring_sqe *sqe;
53 struct io_uring_cqe *cqe;
54 int ret;
55
56 sqe = io_uring_get_sqe(ring);
57 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
58
59 assert(io_uring_submit(ring) != -1);
60
61 assert(!io_uring_wait_cqe(ring, &cqe));
62 ret = cqe->res;
63 io_uring_cqe_seen(ring, cqe);
64 return ret;
65}
66
Jens Axboec1177122019-11-10 21:23:56 -070067static int start_accept_listen(struct sockaddr_in *addr, int port_off)
Jens Axboe7de62532019-11-10 10:09:36 -070068{
69 int fd;
70
71 fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
72
73 int32_t val = 1;
74 assert(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) != -1);
75 assert(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
76
77 struct sockaddr_in laddr;
78
79 if (!addr)
80 addr = &laddr;
81
82 addr->sin_family = AF_INET;
Jens Axboec1177122019-11-10 21:23:56 -070083 addr->sin_port = 0x1235 + port_off;
Jens Axboe7de62532019-11-10 10:09:36 -070084 addr->sin_addr.s_addr = 0x0100007fU;
85
86 assert(bind(fd, (struct sockaddr*)addr, sizeof(*addr)) != -1);
87 assert(listen(fd, 128) != -1);
88
89 return fd;
90}
91
Jens Axboe6b998552019-10-18 11:12:26 -060092static int test(struct io_uring *ring, int accept_should_error)
Jens Axboef2ee0432019-10-17 17:21:25 -060093{
Jens Axboef2ee0432019-10-17 17:21:25 -060094 struct io_uring_cqe *cqe;
Jens Axboe7de62532019-11-10 10:09:36 -070095 struct sockaddr_in addr;
Jens Axboef2ee0432019-10-17 17:21:25 -060096 uint32_t head;
97 uint32_t count = 0;
98 int done = 0;
99 int p_fd[2];
100
Jens Axboec1177122019-11-10 21:23:56 -0700101 int32_t val, recv_s0 = start_accept_listen(&addr, 0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600102
103 p_fd[1] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
104
105 val = 1;
106 assert(setsockopt(p_fd[1], IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) != -1);
107
108 int32_t flags = fcntl(p_fd[1], F_GETFL, 0);
109 assert(flags != -1);
110
111 flags |= O_NONBLOCK;
112 assert(fcntl(p_fd[1], F_SETFL, flags) != -1);
113
114 assert(connect(p_fd[1], (struct sockaddr*)&addr, sizeof(addr)) == -1);
115
116 flags = fcntl(p_fd[1], F_GETFL, 0);
117 assert(flags != -1);
118
119 flags &= ~O_NONBLOCK;
120 assert(fcntl(p_fd[1], F_SETFL, flags) != -1);
121
Jens Axboea9bb08d2019-10-18 08:20:31 -0600122 p_fd[0] = accept_conn(ring, recv_s0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600123 if (p_fd[0] == -EINVAL) {
Jens Axboe6b998552019-10-18 11:12:26 -0600124 if (accept_should_error)
Jens Axboea9bb08d2019-10-18 08:20:31 -0600125 goto out;
Jens Axboef2ee0432019-10-17 17:21:25 -0600126 fprintf(stdout, "Accept not supported, skipping\n");
Jens Axboea9bb08d2019-10-18 08:20:31 -0600127 no_accept = 1;
Jens Axboef2ee0432019-10-17 17:21:25 -0600128 goto out;
Jens Axboe6b998552019-10-18 11:12:26 -0600129 } else if (p_fd[0] < 0) {
130 if (accept_should_error &&
131 (p_fd[0] == -EBADF || p_fd[0] == -EINVAL))
132 goto out;
133 fprintf(stderr, "Accept got %d\n", p_fd[0]);
134 goto err;
Jens Axboef2ee0432019-10-17 17:21:25 -0600135 }
Jens Axboef2ee0432019-10-17 17:21:25 -0600136
Jens Axboea9bb08d2019-10-18 08:20:31 -0600137 queue_send(ring, p_fd[1]);
138 queue_recv(ring, p_fd[0]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600139
Jens Axboea9bb08d2019-10-18 08:20:31 -0600140 assert(io_uring_submit_and_wait(ring, 2) != -1);
Jens Axboef2ee0432019-10-17 17:21:25 -0600141
142 while (count < 2) {
Jens Axboea9bb08d2019-10-18 08:20:31 -0600143 io_uring_for_each_cqe(ring, head, cqe) {
Jens Axboef2ee0432019-10-17 17:21:25 -0600144 if (cqe->res < 0) {
145 fprintf(stderr, "Got cqe res %d\n", cqe->res);
146 done = 1;
147 break;
148 }
149 assert(cqe->res == 128);
150 count++;
151 }
152
153 assert(count <= 2);
Jens Axboea9bb08d2019-10-18 08:20:31 -0600154 io_uring_cq_advance(ring, count);
Jens Axboef2ee0432019-10-17 17:21:25 -0600155 if (done)
156 goto err;
157 }
158
159out:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600160 close(p_fd[0]);
161 close(p_fd[1]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600162 return 0;
163err:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600164 close(p_fd[0]);
165 close(p_fd[1]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600166 return 1;
167}
Jens Axboea9bb08d2019-10-18 08:20:31 -0600168
Jens Axboed974c9f2019-10-24 13:43:33 -0600169static void sig_alrm(int sig)
170{
171 exit(0);
172}
173
Jens Axboec6aa23e2019-11-10 09:49:47 -0700174static int test_accept_pending_on_exit(void)
175{
176 struct io_uring m_io_uring;
177 struct io_uring_cqe *cqe;
178 struct io_uring_sqe *sqe;
179 int fd;
180
181 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
182
Jens Axboec1177122019-11-10 21:23:56 -0700183 fd = start_accept_listen(NULL, 0);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700184
Jens Axboed974c9f2019-10-24 13:43:33 -0600185 sqe = io_uring_get_sqe(&m_io_uring);
186 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
187 assert(io_uring_submit(&m_io_uring) != -1);
188
189 signal(SIGALRM, sig_alrm);
190 alarm(1);
191 assert(!io_uring_wait_cqe(&m_io_uring, &cqe));
192 io_uring_cqe_seen(&m_io_uring, cqe);
193
194 io_uring_queue_exit(&m_io_uring);
195 return 0;
196}
197
Jens Axboec1177122019-11-10 21:23:56 -0700198/*
199 * Test issue many accepts and see if we handle cancellation on exit
200 */
201static int test_accept_many(unsigned nr, unsigned usecs)
202{
203 struct io_uring m_io_uring;
204 struct io_uring_cqe *cqe;
205 struct io_uring_sqe *sqe;
206 unsigned long cur_lim;
207 struct rlimit rlim;
208 int *fds, i, ret = 0;
209
210 if (getrlimit(RLIMIT_NPROC, &rlim) < 0) {
211 perror("getrlimit");
212 return 1;
213 }
214
215 cur_lim = rlim.rlim_cur;
216 rlim.rlim_cur = nr / 4;
217
218 if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
219 perror("setrlimit");
220 return 1;
221 }
222
223 assert(io_uring_queue_init(2 * nr, &m_io_uring, 0) >= 0);
224
225 fds = calloc(nr, sizeof(int));
226
227 for (i = 0; i < nr; i++)
228 fds[i] = start_accept_listen(NULL, i);
229
230 for (i = 0; i < nr; i++) {
231 sqe = io_uring_get_sqe(&m_io_uring);
232 io_uring_prep_accept(sqe, fds[i], NULL, NULL, 0);
233 sqe->user_data = 1 + i;
234 assert(io_uring_submit(&m_io_uring) == 1);
235 }
236
237 if (usecs)
238 usleep(usecs);
239
240 for (i = 0; i < nr; i++) {
241 if (io_uring_peek_cqe(&m_io_uring, &cqe))
242 break;
243 if (cqe->res != -ECANCELED) {
244 fprintf(stderr, "Expected cqe to be cancelled\n");
245 goto err;
246 }
247 io_uring_cqe_seen(&m_io_uring, cqe);
248 }
249out:
250 rlim.rlim_cur = cur_lim;
251 if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
252 perror("setrlimit");
253 return 1;
254 }
255
256 free(fds);
257 io_uring_queue_exit(&m_io_uring);
258 return ret;
259err:
260 ret = 1;
261 goto out;
262}
263
Jens Axboec6aa23e2019-11-10 09:49:47 -0700264static int test_accept_cancel(unsigned usecs)
265{
266 struct io_uring m_io_uring;
267 struct io_uring_cqe *cqe;
268 struct io_uring_sqe *sqe;
269 int fd, i;
270
271 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
272
Jens Axboec1177122019-11-10 21:23:56 -0700273 fd = start_accept_listen(NULL, 0);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700274
275 sqe = io_uring_get_sqe(&m_io_uring);
276 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
277 sqe->user_data = 1;
278 assert(io_uring_submit(&m_io_uring) == 1);
279
280 if (usecs)
281 usleep(usecs);
282
283 sqe = io_uring_get_sqe(&m_io_uring);
284 io_uring_prep_cancel(sqe, (void *) 1, 0);
285 sqe->user_data = 2;
286 assert(io_uring_submit(&m_io_uring) == 1);
287
288 for (i = 0; i < 2; i++) {
289 assert(!io_uring_wait_cqe(&m_io_uring, &cqe));
290 /*
291 * Two cases here:
292 *
293 * 1) We cancel the accept4() before it got started, we should
294 * get '0' for the cancel request and '-ECANCELED' for the
295 * accept request.
296 * 2) We cancel the accept4() after it's already running, we
297 * should get '-EALREADY' for the cancel request and
298 * '-EINTR' for the accept request.
299 */
300 if (cqe->user_data == 1) {
301 if (cqe->res != -EINTR && cqe->res != -ECANCELED) {
302 fprintf(stderr, "Cancelled accept got %d\n", cqe->res);
303 goto err;
304 }
305 } else if (cqe->user_data == 2) {
306 if (cqe->res != -EALREADY && cqe->res != 0) {
307 fprintf(stderr, "Cancel got %d\n", cqe->res);
308 goto err;
309 }
310 }
311 io_uring_cqe_seen(&m_io_uring, cqe);
312 }
313
314 io_uring_queue_exit(&m_io_uring);
315 return 0;
316err:
317 io_uring_queue_exit(&m_io_uring);
318 return 1;
319}
320
Jens Axboea9bb08d2019-10-18 08:20:31 -0600321static int test_accept(void)
322{
323 struct io_uring m_io_uring;
324 int ret;
325
326 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
327 ret = test(&m_io_uring, 0);
328 io_uring_queue_exit(&m_io_uring);
329 return ret;
330}
331
332static int test_accept_sqpoll(void)
333{
334 struct io_uring m_io_uring;
335 int ret;
336
Jens Axboe9fca8692019-11-10 09:48:47 -0700337 ret = io_uring_queue_init(32, &m_io_uring, IORING_SETUP_SQPOLL);
338 if (ret && geteuid()) {
339 printf("%s: skipped, not root\n", __FUNCTION__);
340 return 0;
341 } else if (ret)
342 return ret;
343
Jens Axboea9bb08d2019-10-18 08:20:31 -0600344 ret = test(&m_io_uring, 1);
345 io_uring_queue_exit(&m_io_uring);
346 return ret;
347}
348
349int main(int argc, char *argv[])
350{
351 int ret;
352
353 ret = test_accept();
354 if (ret) {
355 fprintf(stderr, "test_accept failed\n");
356 return ret;
357 }
358 if (no_accept)
359 return 0;
360
361 ret = test_accept_sqpoll();
362 if (ret) {
363 fprintf(stderr, "test_accept_sqpoll failed\n");
364 return ret;
365 }
366
Jens Axboec6aa23e2019-11-10 09:49:47 -0700367 ret = test_accept_cancel(0);
Jens Axboed974c9f2019-10-24 13:43:33 -0600368 if (ret) {
Jens Axboec6aa23e2019-11-10 09:49:47 -0700369 fprintf(stderr, "test_accept_cancel nodelay failed\n");
370 return ret;
371 }
372
373 ret = test_accept_cancel(10000);
374 if (ret) {
375 fprintf(stderr, "test_accept_cancel delay failed\n");
376 return ret;
377 }
378
Jens Axboec1177122019-11-10 21:23:56 -0700379 ret = test_accept_many(128, 0);
380 if (ret) {
381 fprintf(stderr, "test_accept_many failed\n");
382 return ret;
383 }
384
385 ret = test_accept_many(128, 100000);
386 if (ret) {
387 fprintf(stderr, "test_accept_many failed\n");
388 return ret;
389 }
390
Jens Axboec6aa23e2019-11-10 09:49:47 -0700391 ret = test_accept_pending_on_exit();
392 if (ret) {
393 fprintf(stderr, "test_accept_pending_on_exit failed\n");
Jens Axboed974c9f2019-10-24 13:43:33 -0600394 return ret;
395 }
396
Jens Axboea9bb08d2019-10-18 08:20:31 -0600397 return 0;
398}