• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params, 0, sizeof(params));
48 	ret = t_io_uring_init_sqarray(4, &io_uring, &params);
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