blob: 9aca97822e84a9f0c25864a2f0ed00eb352edfab [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 Axboe6b998552019-10-18 11:12:26 -060065static int test(struct io_uring *ring, int accept_should_error)
Jens Axboef2ee0432019-10-17 17:21:25 -060066{
Jens Axboef2ee0432019-10-17 17:21:25 -060067 struct io_uring_cqe *cqe;
68 uint32_t head;
69 uint32_t count = 0;
70 int done = 0;
71 int p_fd[2];
72
73 int32_t recv_s0 = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
74
75 int32_t val = 1;
76 assert(setsockopt(recv_s0, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) != -1);
77 assert(setsockopt(recv_s0, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
78
79 struct sockaddr_in addr;
80
81 addr.sin_family = AF_INET;
82 addr.sin_port = 0x1235;
83 addr.sin_addr.s_addr = 0x0100007fU;
84
85 assert(bind(recv_s0, (struct sockaddr*)&addr, sizeof(addr)) != -1);
86 assert(listen(recv_s0, 128) != -1);
87
88 p_fd[1] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
89
90 val = 1;
91 assert(setsockopt(p_fd[1], IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) != -1);
92
93 int32_t flags = fcntl(p_fd[1], F_GETFL, 0);
94 assert(flags != -1);
95
96 flags |= O_NONBLOCK;
97 assert(fcntl(p_fd[1], F_SETFL, flags) != -1);
98
99 assert(connect(p_fd[1], (struct sockaddr*)&addr, sizeof(addr)) == -1);
100
101 flags = fcntl(p_fd[1], F_GETFL, 0);
102 assert(flags != -1);
103
104 flags &= ~O_NONBLOCK;
105 assert(fcntl(p_fd[1], F_SETFL, flags) != -1);
106
Jens Axboea9bb08d2019-10-18 08:20:31 -0600107 p_fd[0] = accept_conn(ring, recv_s0);
Jens Axboef2ee0432019-10-17 17:21:25 -0600108 if (p_fd[0] == -EINVAL) {
Jens Axboe6b998552019-10-18 11:12:26 -0600109 if (accept_should_error)
Jens Axboea9bb08d2019-10-18 08:20:31 -0600110 goto out;
Jens Axboef2ee0432019-10-17 17:21:25 -0600111 fprintf(stdout, "Accept not supported, skipping\n");
Jens Axboea9bb08d2019-10-18 08:20:31 -0600112 no_accept = 1;
Jens Axboef2ee0432019-10-17 17:21:25 -0600113 goto out;
Jens Axboe6b998552019-10-18 11:12:26 -0600114 } else if (p_fd[0] < 0) {
115 if (accept_should_error &&
116 (p_fd[0] == -EBADF || p_fd[0] == -EINVAL))
117 goto out;
118 fprintf(stderr, "Accept got %d\n", p_fd[0]);
119 goto err;
Jens Axboef2ee0432019-10-17 17:21:25 -0600120 }
Jens Axboef2ee0432019-10-17 17:21:25 -0600121
Jens Axboea9bb08d2019-10-18 08:20:31 -0600122 queue_send(ring, p_fd[1]);
123 queue_recv(ring, p_fd[0]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600124
Jens Axboea9bb08d2019-10-18 08:20:31 -0600125 assert(io_uring_submit_and_wait(ring, 2) != -1);
Jens Axboef2ee0432019-10-17 17:21:25 -0600126
127 while (count < 2) {
Jens Axboea9bb08d2019-10-18 08:20:31 -0600128 io_uring_for_each_cqe(ring, head, cqe) {
Jens Axboef2ee0432019-10-17 17:21:25 -0600129 if (cqe->res < 0) {
130 fprintf(stderr, "Got cqe res %d\n", cqe->res);
131 done = 1;
132 break;
133 }
134 assert(cqe->res == 128);
135 count++;
136 }
137
138 assert(count <= 2);
Jens Axboea9bb08d2019-10-18 08:20:31 -0600139 io_uring_cq_advance(ring, count);
Jens Axboef2ee0432019-10-17 17:21:25 -0600140 if (done)
141 goto err;
142 }
143
144out:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600145 close(p_fd[0]);
146 close(p_fd[1]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600147 return 0;
148err:
Jens Axboea9bb08d2019-10-18 08:20:31 -0600149 close(p_fd[0]);
150 close(p_fd[1]);
Jens Axboef2ee0432019-10-17 17:21:25 -0600151 return 1;
152}
Jens Axboea9bb08d2019-10-18 08:20:31 -0600153
Jens Axboed974c9f2019-10-24 13:43:33 -0600154static void sig_alrm(int sig)
155{
156 exit(0);
157}
158
Jens Axboec6aa23e2019-11-10 09:49:47 -0700159static int start_accept_listen(void)
Jens Axboed974c9f2019-10-24 13:43:33 -0600160{
Jens Axboed974c9f2019-10-24 13:43:33 -0600161 int fd;
162
Jens Axboed974c9f2019-10-24 13:43:33 -0600163 fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
164
165 int32_t val = 1;
166 assert(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) != -1);
167 assert(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
168
169 struct sockaddr_in addr;
170
171 addr.sin_family = AF_INET;
172 addr.sin_port = 0x1235;
173 addr.sin_addr.s_addr = 0x0100007fU;
174
175 assert(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) != -1);
176 assert(listen(fd, 128) != -1);
177
Jens Axboec6aa23e2019-11-10 09:49:47 -0700178 return fd;
179}
180
181static int test_accept_pending_on_exit(void)
182{
183 struct io_uring m_io_uring;
184 struct io_uring_cqe *cqe;
185 struct io_uring_sqe *sqe;
186 int fd;
187
188 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
189
190 fd = start_accept_listen();
191
Jens Axboed974c9f2019-10-24 13:43:33 -0600192 sqe = io_uring_get_sqe(&m_io_uring);
193 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
194 assert(io_uring_submit(&m_io_uring) != -1);
195
196 signal(SIGALRM, sig_alrm);
197 alarm(1);
198 assert(!io_uring_wait_cqe(&m_io_uring, &cqe));
199 io_uring_cqe_seen(&m_io_uring, cqe);
200
201 io_uring_queue_exit(&m_io_uring);
202 return 0;
203}
204
Jens Axboec6aa23e2019-11-10 09:49:47 -0700205static int test_accept_cancel(unsigned usecs)
206{
207 struct io_uring m_io_uring;
208 struct io_uring_cqe *cqe;
209 struct io_uring_sqe *sqe;
210 int fd, i;
211
212 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
213
214 fd = start_accept_listen();
215
216 sqe = io_uring_get_sqe(&m_io_uring);
217 io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
218 sqe->user_data = 1;
219 assert(io_uring_submit(&m_io_uring) == 1);
220
221 if (usecs)
222 usleep(usecs);
223
224 sqe = io_uring_get_sqe(&m_io_uring);
225 io_uring_prep_cancel(sqe, (void *) 1, 0);
226 sqe->user_data = 2;
227 assert(io_uring_submit(&m_io_uring) == 1);
228
229 for (i = 0; i < 2; i++) {
230 assert(!io_uring_wait_cqe(&m_io_uring, &cqe));
231 /*
232 * Two cases here:
233 *
234 * 1) We cancel the accept4() before it got started, we should
235 * get '0' for the cancel request and '-ECANCELED' for the
236 * accept request.
237 * 2) We cancel the accept4() after it's already running, we
238 * should get '-EALREADY' for the cancel request and
239 * '-EINTR' for the accept request.
240 */
241 if (cqe->user_data == 1) {
242 if (cqe->res != -EINTR && cqe->res != -ECANCELED) {
243 fprintf(stderr, "Cancelled accept got %d\n", cqe->res);
244 goto err;
245 }
246 } else if (cqe->user_data == 2) {
247 if (cqe->res != -EALREADY && cqe->res != 0) {
248 fprintf(stderr, "Cancel got %d\n", cqe->res);
249 goto err;
250 }
251 }
252 io_uring_cqe_seen(&m_io_uring, cqe);
253 }
254
255 io_uring_queue_exit(&m_io_uring);
256 return 0;
257err:
258 io_uring_queue_exit(&m_io_uring);
259 return 1;
260}
261
Jens Axboea9bb08d2019-10-18 08:20:31 -0600262static int test_accept(void)
263{
264 struct io_uring m_io_uring;
265 int ret;
266
267 assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0);
268 ret = test(&m_io_uring, 0);
269 io_uring_queue_exit(&m_io_uring);
270 return ret;
271}
272
273static int test_accept_sqpoll(void)
274{
275 struct io_uring m_io_uring;
276 int ret;
277
Jens Axboe9fca8692019-11-10 09:48:47 -0700278 ret = io_uring_queue_init(32, &m_io_uring, IORING_SETUP_SQPOLL);
279 if (ret && geteuid()) {
280 printf("%s: skipped, not root\n", __FUNCTION__);
281 return 0;
282 } else if (ret)
283 return ret;
284
Jens Axboea9bb08d2019-10-18 08:20:31 -0600285 ret = test(&m_io_uring, 1);
286 io_uring_queue_exit(&m_io_uring);
287 return ret;
288}
289
290int main(int argc, char *argv[])
291{
292 int ret;
293
294 ret = test_accept();
295 if (ret) {
296 fprintf(stderr, "test_accept failed\n");
297 return ret;
298 }
299 if (no_accept)
300 return 0;
301
302 ret = test_accept_sqpoll();
303 if (ret) {
304 fprintf(stderr, "test_accept_sqpoll failed\n");
305 return ret;
306 }
307
Jens Axboec6aa23e2019-11-10 09:49:47 -0700308 ret = test_accept_cancel(0);
Jens Axboed974c9f2019-10-24 13:43:33 -0600309 if (ret) {
Jens Axboec6aa23e2019-11-10 09:49:47 -0700310 fprintf(stderr, "test_accept_cancel nodelay failed\n");
311 return ret;
312 }
313
314 ret = test_accept_cancel(10000);
315 if (ret) {
316 fprintf(stderr, "test_accept_cancel delay failed\n");
317 return ret;
318 }
319
320 ret = test_accept_pending_on_exit();
321 if (ret) {
322 fprintf(stderr, "test_accept_pending_on_exit failed\n");
Jens Axboed974c9f2019-10-24 13:43:33 -0600323 return ret;
324 }
325
Jens Axboea9bb08d2019-10-18 08:20:31 -0600326 return 0;
327}