blob: 0953be65689d559919933b37af5e70699ece2177 [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>
14#include <sys/un.h>
15#include <netinet/tcp.h>
16#include <netinet/in.h>
17
18#include <liburing.h>
19
Jens Axboea9bb08d2019-10-18 08:20:31 -060020static int no_accept;
21
Jens Axboef2ee0432019-10-17 17:21:25 -060022static void queue_send(struct io_uring *ring, int fd)
23{
24 struct io_uring_sqe *sqe;
25 char send_buff[128];
26 struct iovec iov;
27
28 iov.iov_base = send_buff;
29 iov.iov_len = sizeof(send_buff);
30
31 sqe = io_uring_get_sqe(ring);
32 io_uring_prep_writev(sqe, fd, &iov, 1, 0);
33}
34
35static void queue_recv(struct io_uring *ring, int fd)
36{
37 struct io_uring_sqe *sqe;
38 char recv_buff[128];
39 struct iovec iov;
40
41 iov.iov_base = recv_buff;
42 iov.iov_len = sizeof(recv_buff);
43
44 sqe = io_uring_get_sqe(ring);
45 io_uring_prep_readv(sqe, fd, &iov, 1, 0);
46}
47
48static int accept_conn(struct io_uring *ring, int fd)
49{
50 struct io_uring_sqe *sqe;
51 struct io_uring_cqe *cqe;
52 int ret;
53
54 sqe = io_uring_get_sqe(ring);
55 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
56
57 assert(io_uring_submit(ring) != -1);
58
59 assert(!io_uring_wait_cqe(ring, &cqe));
60 ret = cqe->res;
61 io_uring_cqe_seen(ring, cqe);
62 return ret;
63}
64
Jens Axboe7de62532019-11-10 10:09:36 -070065static int start_accept_listen(struct sockaddr_in *addr)
66{
67 int fd;
68
69 fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
70
71 int32_t val = 1;
72 assert(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) != -1);
73 assert(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
74
75 struct sockaddr_in laddr;
76
77 if (!addr)
78 addr = &laddr;
79
80 addr->sin_family = AF_INET;
81 addr->sin_port = 0x1235;
82 addr->sin_addr.s_addr = 0x0100007fU;
83
84 assert(bind(fd, (struct sockaddr*)addr, sizeof(*addr)) != -1);
85 assert(listen(fd, 128) != -1);
86
87 return fd;
88}
89
Jens Axboe6b998552019-10-18 11:12:26 -060090static int test(struct io_uring *ring, int accept_should_error)
Jens Axboef2ee0432019-10-17 17:21:25 -060091{
Jens Axboef2ee0432019-10-17 17:21:25 -060092 struct io_uring_cqe *cqe;
Jens Axboe7de62532019-11-10 10:09:36 -070093 struct sockaddr_in addr;
Jens Axboef2ee0432019-10-17 17:21:25 -060094 uint32_t head;
95 uint32_t count = 0;
96 int done = 0;
97 int p_fd[2];
98
Jens Axboe7de62532019-11-10 10:09:36 -070099 int32_t val, recv_s0 = start_accept_listen(&addr);
Jens Axboef2ee0432019-10-17 17:21:25 -0600100
101 p_fd[1] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
102
103 val = 1;
104 assert(setsockopt(p_fd[1], IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) != -1);
105
106 int32_t flags = fcntl(p_fd[1], F_GETFL, 0);
107 assert(flags != -1);
108
109 flags |= O_NONBLOCK;
110 assert(fcntl(p_fd[1], F_SETFL, flags) != -1);
111
112 assert(connect(p_fd[1], (struct sockaddr*)&addr, sizeof(addr)) == -1);
113
114 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
Jens Axboea9bb08d2019-10-18 08:20:31 -0600120 p_fd[0] = accept_conn(ring, recv_s0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600121 if (p_fd[0] == -EINVAL) {
Jens Axboe6b998552019-10-18 11:12:26 -0600122 if (accept_should_error)
Jens Axboea9bb08d2019-10-18 08:20:31 -0600123 goto out;
Jens Axboef2ee0432019-10-17 17:21:25 -0600124 fprintf(stdout, "Accept not supported, skipping\n");
Jens Axboea9bb08d2019-10-18 08:20:31 -0600125 no_accept = 1;
Jens Axboef2ee0432019-10-17 17:21:25 -0600126 goto out;
Jens Axboe6b998552019-10-18 11:12:26 -0600127 } else if (p_fd[0] < 0) {
128 if (accept_should_error &&
129 (p_fd[0] == -EBADF || p_fd[0] == -EINVAL))
130 goto out;
131 fprintf(stderr, "Accept got %d\n", p_fd[0]);
132 goto err;
Jens Axboef2ee0432019-10-17 17:21:25 -0600133 }
Jens Axboef2ee0432019-10-17 17:21:25 -0600134
Jens Axboea9bb08d2019-10-18 08:20:31 -0600135 queue_send(ring, p_fd[1]);
136 queue_recv(ring, p_fd[0]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600137
Jens Axboea9bb08d2019-10-18 08:20:31 -0600138 assert(io_uring_submit_and_wait(ring, 2) != -1);
Jens Axboef2ee0432019-10-17 17:21:25 -0600139
140 while (count < 2) {
Jens Axboea9bb08d2019-10-18 08:20:31 -0600141 io_uring_for_each_cqe(ring, head, cqe) {
Jens Axboef2ee0432019-10-17 17:21:25 -0600142 if (cqe->res < 0) {
143 fprintf(stderr, "Got cqe res %d\n", cqe->res);
144 done = 1;
145 break;
146 }
147 assert(cqe->res == 128);
148 count++;
149 }
150
151 assert(count <= 2);
Jens Axboea9bb08d2019-10-18 08:20:31 -0600152 io_uring_cq_advance(ring, count);
Jens Axboef2ee0432019-10-17 17:21:25 -0600153 if (done)
154 goto err;
155 }
156
157out:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600158 close(p_fd[0]);
159 close(p_fd[1]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600160 return 0;
161err:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600162 close(p_fd[0]);
163 close(p_fd[1]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600164 return 1;
165}
Jens Axboea9bb08d2019-10-18 08:20:31 -0600166
Jens Axboed974c9f2019-10-24 13:43:33 -0600167static void sig_alrm(int sig)
168{
169 exit(0);
170}
171
Jens Axboec6aa23e2019-11-10 09:49:47 -0700172static int test_accept_pending_on_exit(void)
173{
174 struct io_uring m_io_uring;
175 struct io_uring_cqe *cqe;
176 struct io_uring_sqe *sqe;
177 int fd;
178
179 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
180
Jens Axboe7de62532019-11-10 10:09:36 -0700181 fd = start_accept_listen(NULL);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700182
Jens Axboed974c9f2019-10-24 13:43:33 -0600183 sqe = io_uring_get_sqe(&m_io_uring);
184 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
185 assert(io_uring_submit(&m_io_uring) != -1);
186
187 signal(SIGALRM, sig_alrm);
188 alarm(1);
189 assert(!io_uring_wait_cqe(&m_io_uring, &cqe));
190 io_uring_cqe_seen(&m_io_uring, cqe);
191
192 io_uring_queue_exit(&m_io_uring);
193 return 0;
194}
195
Jens Axboec6aa23e2019-11-10 09:49:47 -0700196static int test_accept_cancel(unsigned usecs)
197{
198 struct io_uring m_io_uring;
199 struct io_uring_cqe *cqe;
200 struct io_uring_sqe *sqe;
201 int fd, i;
202
203 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
204
Jens Axboe7de62532019-11-10 10:09:36 -0700205 fd = start_accept_listen(NULL);
Jens Axboec6aa23e2019-11-10 09:49:47 -0700206
207 sqe = io_uring_get_sqe(&m_io_uring);
208 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
209 sqe->user_data = 1;
210 assert(io_uring_submit(&m_io_uring) == 1);
211
212 if (usecs)
213 usleep(usecs);
214
215 sqe = io_uring_get_sqe(&m_io_uring);
216 io_uring_prep_cancel(sqe, (void *) 1, 0);
217 sqe->user_data = 2;
218 assert(io_uring_submit(&m_io_uring) == 1);
219
220 for (i = 0; i < 2; i++) {
221 assert(!io_uring_wait_cqe(&m_io_uring, &cqe));
222 /*
223 * Two cases here:
224 *
225 * 1) We cancel the accept4() before it got started, we should
226 * get '0' for the cancel request and '-ECANCELED' for the
227 * accept request.
228 * 2) We cancel the accept4() after it's already running, we
229 * should get '-EALREADY' for the cancel request and
230 * '-EINTR' for the accept request.
231 */
232 if (cqe->user_data == 1) {
233 if (cqe->res != -EINTR && cqe->res != -ECANCELED) {
234 fprintf(stderr, "Cancelled accept got %d\n", cqe->res);
235 goto err;
236 }
237 } else if (cqe->user_data == 2) {
238 if (cqe->res != -EALREADY && cqe->res != 0) {
239 fprintf(stderr, "Cancel got %d\n", cqe->res);
240 goto err;
241 }
242 }
243 io_uring_cqe_seen(&m_io_uring, cqe);
244 }
245
246 io_uring_queue_exit(&m_io_uring);
247 return 0;
248err:
249 io_uring_queue_exit(&m_io_uring);
250 return 1;
251}
252
Jens Axboea9bb08d2019-10-18 08:20:31 -0600253static int test_accept(void)
254{
255 struct io_uring m_io_uring;
256 int ret;
257
258 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
259 ret = test(&m_io_uring, 0);
260 io_uring_queue_exit(&m_io_uring);
261 return ret;
262}
263
264static int test_accept_sqpoll(void)
265{
266 struct io_uring m_io_uring;
267 int ret;
268
Jens Axboe9fca8692019-11-10 09:48:47 -0700269 ret = io_uring_queue_init(32, &m_io_uring, IORING_SETUP_SQPOLL);
270 if (ret && geteuid()) {
271 printf("%s: skipped, not root\n", __FUNCTION__);
272 return 0;
273 } else if (ret)
274 return ret;
275
Jens Axboea9bb08d2019-10-18 08:20:31 -0600276 ret = test(&m_io_uring, 1);
277 io_uring_queue_exit(&m_io_uring);
278 return ret;
279}
280
281int main(int argc, char *argv[])
282{
283 int ret;
284
285 ret = test_accept();
286 if (ret) {
287 fprintf(stderr, "test_accept failed\n");
288 return ret;
289 }
290 if (no_accept)
291 return 0;
292
293 ret = test_accept_sqpoll();
294 if (ret) {
295 fprintf(stderr, "test_accept_sqpoll failed\n");
296 return ret;
297 }
298
Jens Axboec6aa23e2019-11-10 09:49:47 -0700299 ret = test_accept_cancel(0);
Jens Axboed974c9f2019-10-24 13:43:33 -0600300 if (ret) {
Jens Axboec6aa23e2019-11-10 09:49:47 -0700301 fprintf(stderr, "test_accept_cancel nodelay failed\n");
302 return ret;
303 }
304
305 ret = test_accept_cancel(10000);
306 if (ret) {
307 fprintf(stderr, "test_accept_cancel delay failed\n");
308 return ret;
309 }
310
311 ret = test_accept_pending_on_exit();
312 if (ret) {
313 fprintf(stderr, "test_accept_pending_on_exit failed\n");
Jens Axboed974c9f2019-10-24 13:43:33 -0600314 return ret;
315 }
316
Jens Axboea9bb08d2019-10-18 08:20:31 -0600317 return 0;
318}