1 /* SPDX-License-Identifier: MIT */
2 #include <netdb.h>
3 #include <string.h>
4 #include <sys/socket.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7 #include <stdio.h>
8 #include <errno.h>
9 #include "liburing.h"
10 #include "helpers.h"
11 #include "../src/syscall.h"
12
13 static struct io_uring io_uring;
14
sys_io_uring_enter(const int fd,const unsigned to_submit,const unsigned min_complete,const unsigned flags,sigset_t * const sig)15 static int sys_io_uring_enter(const int fd, const unsigned to_submit,
16 const unsigned min_complete,
17 const unsigned flags, sigset_t * const sig)
18 {
19 return __sys_io_uring_enter(fd, to_submit, min_complete, flags, sig);
20 }
21
submit_sqe(void)22 static int submit_sqe(void)
23 {
24 struct io_uring_sq *sq = &io_uring.sq;
25 const unsigned tail = *sq->ktail;
26
27 sq->array[tail & sq->ring_mask] = 0;
28 io_uring_smp_store_release(sq->ktail, tail + 1);
29
30 return sys_io_uring_enter(io_uring.ring_fd, 1, 0, 0, NULL);
31 }
32
main(int argc,char ** argv)33 int main(int argc, char **argv)
34 {
35 struct addrinfo *addr_info_list = NULL;
36 struct addrinfo *ai, *addr_info = NULL;
37 struct io_uring_params params;
38 struct io_uring_sqe *sqe;
39 struct addrinfo hints;
40 struct sockaddr sa;
41 socklen_t sa_size = sizeof(sa);
42 int ret, listen_fd, connect_fd, val, i;
43
44 if (argc > 1)
45 return T_EXIT_SKIP;
46
47 memset(¶ms, 0, sizeof(params));
48 ret = t_io_uring_init_sqarray(4, &io_uring, ¶ms);
49 if (ret) {
50 fprintf(stderr, "io_uring_init_failed: %d\n", ret);
51 return T_EXIT_FAIL;
52 }
53 if (!(params.features & IORING_FEAT_SUBMIT_STABLE)) {
54 fprintf(stdout, "FEAT_SUBMIT_STABLE not there, skipping\n");
55 return T_EXIT_SKIP;
56 }
57
58 memset(&hints, 0, sizeof(hints));
59 hints.ai_family = AF_UNSPEC;
60 hints.ai_socktype = SOCK_STREAM;
61 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
62
63 ret = getaddrinfo(NULL, "12345", &hints, &addr_info_list);
64 if (ret < 0) {
65 perror("getaddrinfo");
66 return T_EXIT_FAIL;
67 }
68
69 for (ai = addr_info_list; ai; ai = ai->ai_next) {
70 if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
71 addr_info = ai;
72 break;
73 }
74 }
75 if (!addr_info) {
76 fprintf(stderr, "addrinfo not found\n");
77 return T_EXIT_FAIL;
78 }
79
80 sqe = &io_uring.sq.sqes[0];
81 listen_fd = -1;
82
83 ret = socket(addr_info->ai_family, SOCK_STREAM,
84 addr_info->ai_protocol);
85 if (ret < 0) {
86 perror("socket");
87 return T_EXIT_FAIL;
88 }
89 listen_fd = ret;
90
91 val = 1;
92 setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int));
93 setsockopt(listen_fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(int));
94
95 ret = bind(listen_fd, addr_info->ai_addr, addr_info->ai_addrlen);
96 if (ret < 0) {
97 perror("bind");
98 return T_EXIT_FAIL;
99 }
100
101 ret = listen(listen_fd, SOMAXCONN);
102 if (ret < 0) {
103 perror("listen");
104 return T_EXIT_FAIL;
105 }
106
107 memset(&sa, 0, sizeof(sa));
108
109 io_uring_prep_accept(sqe, listen_fd, &sa, &sa_size, 0);
110 sqe->user_data = 1;
111 ret = submit_sqe();
112 if (ret != 1) {
113 fprintf(stderr, "submit failed: %d\n", ret);
114 return T_EXIT_FAIL;
115 }
116
117 connect_fd = -1;
118 ret = socket(addr_info->ai_family, SOCK_STREAM, addr_info->ai_protocol);
119 if (ret < 0) {
120 perror("socket");
121 return T_EXIT_FAIL;
122 }
123 connect_fd = ret;
124
125 io_uring_prep_connect(sqe, connect_fd, addr_info->ai_addr,
126 addr_info->ai_addrlen);
127 sqe->user_data = 2;
128 ret = submit_sqe();
129 if (ret != 1) {
130 fprintf(stderr, "submit failed: %d\n", ret);
131 return T_EXIT_FAIL;
132 }
133
134 for (i = 0; i < 2; i++) {
135 struct io_uring_cqe *cqe = NULL;
136
137 ret = io_uring_wait_cqe(&io_uring, &cqe);
138 if (ret) {
139 fprintf(stderr, "io_uring_wait_cqe: %d\n", ret);
140 return T_EXIT_FAIL;
141 }
142
143 switch (cqe->user_data) {
144 case 1:
145 if (cqe->res < 0) {
146 fprintf(stderr, "accept failed: %d\n", cqe->res);
147 return T_EXIT_FAIL;
148 }
149 break;
150 case 2:
151 if (cqe->res) {
152 fprintf(stderr, "connect failed: %d\n", cqe->res);
153 return T_EXIT_FAIL;
154 }
155 break;
156 }
157 io_uring_cq_advance(&io_uring, 1);
158 }
159
160 freeaddrinfo(addr_info_list);
161 io_uring_queue_exit(&io_uring);
162 return T_EXIT_PASS;
163 }
164