xref: /aosp_15_r20/external/liburing/test/send_recv.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker /*
3*25da2beaSAndroid Build Coastguard Worker  * Simple test case showing using send and recv through io_uring
4*25da2beaSAndroid Build Coastguard Worker  */
5*25da2beaSAndroid Build Coastguard Worker #include <errno.h>
6*25da2beaSAndroid Build Coastguard Worker #include <stdio.h>
7*25da2beaSAndroid Build Coastguard Worker #include <stdlib.h>
8*25da2beaSAndroid Build Coastguard Worker #include <string.h>
9*25da2beaSAndroid Build Coastguard Worker #include <unistd.h>
10*25da2beaSAndroid Build Coastguard Worker #include <arpa/inet.h>
11*25da2beaSAndroid Build Coastguard Worker #include <sys/types.h>
12*25da2beaSAndroid Build Coastguard Worker #include <sys/socket.h>
13*25da2beaSAndroid Build Coastguard Worker #include <pthread.h>
14*25da2beaSAndroid Build Coastguard Worker 
15*25da2beaSAndroid Build Coastguard Worker #include "liburing.h"
16*25da2beaSAndroid Build Coastguard Worker #include "helpers.h"
17*25da2beaSAndroid Build Coastguard Worker 
18*25da2beaSAndroid Build Coastguard Worker static char str[] = "This is a test of send and recv over io_uring!";
19*25da2beaSAndroid Build Coastguard Worker 
20*25da2beaSAndroid Build Coastguard Worker #define MAX_MSG	128
21*25da2beaSAndroid Build Coastguard Worker 
22*25da2beaSAndroid Build Coastguard Worker #define PORT	10202
23*25da2beaSAndroid Build Coastguard Worker #define HOST	"127.0.0.1"
24*25da2beaSAndroid Build Coastguard Worker 
recv_prep(struct io_uring * ring,struct iovec * iov,int * sock,int registerfiles)25*25da2beaSAndroid Build Coastguard Worker static int recv_prep(struct io_uring *ring, struct iovec *iov, int *sock,
26*25da2beaSAndroid Build Coastguard Worker 		     int registerfiles)
27*25da2beaSAndroid Build Coastguard Worker {
28*25da2beaSAndroid Build Coastguard Worker 	struct sockaddr_in saddr;
29*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_sqe *sqe;
30*25da2beaSAndroid Build Coastguard Worker 	int sockfd, ret, val, use_fd;
31*25da2beaSAndroid Build Coastguard Worker 
32*25da2beaSAndroid Build Coastguard Worker 	memset(&saddr, 0, sizeof(saddr));
33*25da2beaSAndroid Build Coastguard Worker 	saddr.sin_family = AF_INET;
34*25da2beaSAndroid Build Coastguard Worker 	saddr.sin_addr.s_addr = htonl(INADDR_ANY);
35*25da2beaSAndroid Build Coastguard Worker 	saddr.sin_port = htons(PORT);
36*25da2beaSAndroid Build Coastguard Worker 
37*25da2beaSAndroid Build Coastguard Worker 	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
38*25da2beaSAndroid Build Coastguard Worker 	if (sockfd < 0) {
39*25da2beaSAndroid Build Coastguard Worker 		perror("socket");
40*25da2beaSAndroid Build Coastguard Worker 		return 1;
41*25da2beaSAndroid Build Coastguard Worker 	}
42*25da2beaSAndroid Build Coastguard Worker 
43*25da2beaSAndroid Build Coastguard Worker 	val = 1;
44*25da2beaSAndroid Build Coastguard Worker 	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
45*25da2beaSAndroid Build Coastguard Worker 
46*25da2beaSAndroid Build Coastguard Worker 	ret = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
47*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0) {
48*25da2beaSAndroid Build Coastguard Worker 		perror("bind");
49*25da2beaSAndroid Build Coastguard Worker 		goto err;
50*25da2beaSAndroid Build Coastguard Worker 	}
51*25da2beaSAndroid Build Coastguard Worker 
52*25da2beaSAndroid Build Coastguard Worker 	if (registerfiles) {
53*25da2beaSAndroid Build Coastguard Worker 		ret = io_uring_register_files(ring, &sockfd, 1);
54*25da2beaSAndroid Build Coastguard Worker 		if (ret) {
55*25da2beaSAndroid Build Coastguard Worker 			fprintf(stderr, "file reg failed\n");
56*25da2beaSAndroid Build Coastguard Worker 			goto err;
57*25da2beaSAndroid Build Coastguard Worker 		}
58*25da2beaSAndroid Build Coastguard Worker 		use_fd = 0;
59*25da2beaSAndroid Build Coastguard Worker 	} else {
60*25da2beaSAndroid Build Coastguard Worker 		use_fd = sockfd;
61*25da2beaSAndroid Build Coastguard Worker 	}
62*25da2beaSAndroid Build Coastguard Worker 
63*25da2beaSAndroid Build Coastguard Worker 	sqe = io_uring_get_sqe(ring);
64*25da2beaSAndroid Build Coastguard Worker 	io_uring_prep_recv(sqe, use_fd, iov->iov_base, iov->iov_len, 0);
65*25da2beaSAndroid Build Coastguard Worker 	if (registerfiles)
66*25da2beaSAndroid Build Coastguard Worker 		sqe->flags |= IOSQE_FIXED_FILE;
67*25da2beaSAndroid Build Coastguard Worker 	sqe->user_data = 2;
68*25da2beaSAndroid Build Coastguard Worker 
69*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_submit(ring);
70*25da2beaSAndroid Build Coastguard Worker 	if (ret <= 0) {
71*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "submit failed: %d\n", ret);
72*25da2beaSAndroid Build Coastguard Worker 		goto err;
73*25da2beaSAndroid Build Coastguard Worker 	}
74*25da2beaSAndroid Build Coastguard Worker 
75*25da2beaSAndroid Build Coastguard Worker 	*sock = sockfd;
76*25da2beaSAndroid Build Coastguard Worker 	return 0;
77*25da2beaSAndroid Build Coastguard Worker err:
78*25da2beaSAndroid Build Coastguard Worker 	close(sockfd);
79*25da2beaSAndroid Build Coastguard Worker 	return 1;
80*25da2beaSAndroid Build Coastguard Worker }
81*25da2beaSAndroid Build Coastguard Worker 
do_recv(struct io_uring * ring,struct iovec * iov)82*25da2beaSAndroid Build Coastguard Worker static int do_recv(struct io_uring *ring, struct iovec *iov)
83*25da2beaSAndroid Build Coastguard Worker {
84*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_cqe *cqe;
85*25da2beaSAndroid Build Coastguard Worker 	int ret;
86*25da2beaSAndroid Build Coastguard Worker 
87*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_wait_cqe(ring, &cqe);
88*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
89*25da2beaSAndroid Build Coastguard Worker 		fprintf(stdout, "wait_cqe: %d\n", ret);
90*25da2beaSAndroid Build Coastguard Worker 		goto err;
91*25da2beaSAndroid Build Coastguard Worker 	}
92*25da2beaSAndroid Build Coastguard Worker 	if (cqe->res == -EINVAL) {
93*25da2beaSAndroid Build Coastguard Worker 		fprintf(stdout, "recv not supported, skipping\n");
94*25da2beaSAndroid Build Coastguard Worker 		return 0;
95*25da2beaSAndroid Build Coastguard Worker 	}
96*25da2beaSAndroid Build Coastguard Worker 	if (cqe->res < 0) {
97*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "failed cqe: %d\n", cqe->res);
98*25da2beaSAndroid Build Coastguard Worker 		goto err;
99*25da2beaSAndroid Build Coastguard Worker 	}
100*25da2beaSAndroid Build Coastguard Worker 
101*25da2beaSAndroid Build Coastguard Worker 	if (cqe->res -1 != strlen(str)) {
102*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "got wrong length: %d/%d\n", cqe->res,
103*25da2beaSAndroid Build Coastguard Worker 							(int) strlen(str) + 1);
104*25da2beaSAndroid Build Coastguard Worker 		goto err;
105*25da2beaSAndroid Build Coastguard Worker 	}
106*25da2beaSAndroid Build Coastguard Worker 
107*25da2beaSAndroid Build Coastguard Worker 	if (strcmp(str, iov->iov_base)) {
108*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "string mismatch\n");
109*25da2beaSAndroid Build Coastguard Worker 		goto err;
110*25da2beaSAndroid Build Coastguard Worker 	}
111*25da2beaSAndroid Build Coastguard Worker 
112*25da2beaSAndroid Build Coastguard Worker 	return 0;
113*25da2beaSAndroid Build Coastguard Worker err:
114*25da2beaSAndroid Build Coastguard Worker 	return 1;
115*25da2beaSAndroid Build Coastguard Worker }
116*25da2beaSAndroid Build Coastguard Worker 
117*25da2beaSAndroid Build Coastguard Worker struct recv_data {
118*25da2beaSAndroid Build Coastguard Worker 	pthread_mutex_t mutex;
119*25da2beaSAndroid Build Coastguard Worker 	int use_sqthread;
120*25da2beaSAndroid Build Coastguard Worker 	int registerfiles;
121*25da2beaSAndroid Build Coastguard Worker };
122*25da2beaSAndroid Build Coastguard Worker 
recv_fn(void * data)123*25da2beaSAndroid Build Coastguard Worker static void *recv_fn(void *data)
124*25da2beaSAndroid Build Coastguard Worker {
125*25da2beaSAndroid Build Coastguard Worker 	struct recv_data *rd = data;
126*25da2beaSAndroid Build Coastguard Worker 	char buf[MAX_MSG + 1];
127*25da2beaSAndroid Build Coastguard Worker 	struct iovec iov = {
128*25da2beaSAndroid Build Coastguard Worker 		.iov_base = buf,
129*25da2beaSAndroid Build Coastguard Worker 		.iov_len = sizeof(buf) - 1,
130*25da2beaSAndroid Build Coastguard Worker 	};
131*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_params p = { };
132*25da2beaSAndroid Build Coastguard Worker 	struct io_uring ring;
133*25da2beaSAndroid Build Coastguard Worker 	int ret, sock;
134*25da2beaSAndroid Build Coastguard Worker 
135*25da2beaSAndroid Build Coastguard Worker 	if (rd->use_sqthread)
136*25da2beaSAndroid Build Coastguard Worker 		p.flags = IORING_SETUP_SQPOLL;
137*25da2beaSAndroid Build Coastguard Worker 	ret = t_create_ring_params(1, &ring, &p);
138*25da2beaSAndroid Build Coastguard Worker 	if (ret == T_SETUP_SKIP) {
139*25da2beaSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&rd->mutex);
140*25da2beaSAndroid Build Coastguard Worker 		ret = 0;
141*25da2beaSAndroid Build Coastguard Worker 		goto err;
142*25da2beaSAndroid Build Coastguard Worker 	} else if (ret < 0) {
143*25da2beaSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&rd->mutex);
144*25da2beaSAndroid Build Coastguard Worker 		goto err;
145*25da2beaSAndroid Build Coastguard Worker 	}
146*25da2beaSAndroid Build Coastguard Worker 
147*25da2beaSAndroid Build Coastguard Worker 	if (rd->use_sqthread && !rd->registerfiles) {
148*25da2beaSAndroid Build Coastguard Worker 		if (!(p.features & IORING_FEAT_SQPOLL_NONFIXED)) {
149*25da2beaSAndroid Build Coastguard Worker 			fprintf(stdout, "Non-registered SQPOLL not available, skipping\n");
150*25da2beaSAndroid Build Coastguard Worker 			pthread_mutex_unlock(&rd->mutex);
151*25da2beaSAndroid Build Coastguard Worker 			goto err;
152*25da2beaSAndroid Build Coastguard Worker 		}
153*25da2beaSAndroid Build Coastguard Worker 	}
154*25da2beaSAndroid Build Coastguard Worker 
155*25da2beaSAndroid Build Coastguard Worker 	ret = recv_prep(&ring, &iov, &sock, rd->registerfiles);
156*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
157*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "recv_prep failed: %d\n", ret);
158*25da2beaSAndroid Build Coastguard Worker 		goto err;
159*25da2beaSAndroid Build Coastguard Worker 	}
160*25da2beaSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&rd->mutex);
161*25da2beaSAndroid Build Coastguard Worker 	ret = do_recv(&ring, &iov);
162*25da2beaSAndroid Build Coastguard Worker 
163*25da2beaSAndroid Build Coastguard Worker 	close(sock);
164*25da2beaSAndroid Build Coastguard Worker 	io_uring_queue_exit(&ring);
165*25da2beaSAndroid Build Coastguard Worker err:
166*25da2beaSAndroid Build Coastguard Worker 	return (void *)(intptr_t)ret;
167*25da2beaSAndroid Build Coastguard Worker }
168*25da2beaSAndroid Build Coastguard Worker 
do_send(void)169*25da2beaSAndroid Build Coastguard Worker static int do_send(void)
170*25da2beaSAndroid Build Coastguard Worker {
171*25da2beaSAndroid Build Coastguard Worker 	struct sockaddr_in saddr;
172*25da2beaSAndroid Build Coastguard Worker 	struct iovec iov = {
173*25da2beaSAndroid Build Coastguard Worker 		.iov_base = str,
174*25da2beaSAndroid Build Coastguard Worker 		.iov_len = sizeof(str),
175*25da2beaSAndroid Build Coastguard Worker 	};
176*25da2beaSAndroid Build Coastguard Worker 	struct io_uring ring;
177*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_cqe *cqe;
178*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_sqe *sqe;
179*25da2beaSAndroid Build Coastguard Worker 	int sockfd, ret;
180*25da2beaSAndroid Build Coastguard Worker 
181*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_queue_init(1, &ring, 0);
182*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
183*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "queue init failed: %d\n", ret);
184*25da2beaSAndroid Build Coastguard Worker 		return 1;
185*25da2beaSAndroid Build Coastguard Worker 	}
186*25da2beaSAndroid Build Coastguard Worker 
187*25da2beaSAndroid Build Coastguard Worker 	memset(&saddr, 0, sizeof(saddr));
188*25da2beaSAndroid Build Coastguard Worker 	saddr.sin_family = AF_INET;
189*25da2beaSAndroid Build Coastguard Worker 	saddr.sin_port = htons(PORT);
190*25da2beaSAndroid Build Coastguard Worker 	inet_pton(AF_INET, HOST, &saddr.sin_addr);
191*25da2beaSAndroid Build Coastguard Worker 
192*25da2beaSAndroid Build Coastguard Worker 	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
193*25da2beaSAndroid Build Coastguard Worker 	if (sockfd < 0) {
194*25da2beaSAndroid Build Coastguard Worker 		perror("socket");
195*25da2beaSAndroid Build Coastguard Worker 		return 1;
196*25da2beaSAndroid Build Coastguard Worker 	}
197*25da2beaSAndroid Build Coastguard Worker 
198*25da2beaSAndroid Build Coastguard Worker 	ret = connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
199*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0) {
200*25da2beaSAndroid Build Coastguard Worker 		perror("connect");
201*25da2beaSAndroid Build Coastguard Worker 		return 1;
202*25da2beaSAndroid Build Coastguard Worker 	}
203*25da2beaSAndroid Build Coastguard Worker 
204*25da2beaSAndroid Build Coastguard Worker 	sqe = io_uring_get_sqe(&ring);
205*25da2beaSAndroid Build Coastguard Worker 	io_uring_prep_send(sqe, sockfd, iov.iov_base, iov.iov_len, 0);
206*25da2beaSAndroid Build Coastguard Worker 	sqe->user_data = 1;
207*25da2beaSAndroid Build Coastguard Worker 
208*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_submit(&ring);
209*25da2beaSAndroid Build Coastguard Worker 	if (ret <= 0) {
210*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "submit failed: %d\n", ret);
211*25da2beaSAndroid Build Coastguard Worker 		goto err;
212*25da2beaSAndroid Build Coastguard Worker 	}
213*25da2beaSAndroid Build Coastguard Worker 
214*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_wait_cqe(&ring, &cqe);
215*25da2beaSAndroid Build Coastguard Worker 	if (cqe->res == -EINVAL) {
216*25da2beaSAndroid Build Coastguard Worker 		fprintf(stdout, "send not supported, skipping\n");
217*25da2beaSAndroid Build Coastguard Worker 		close(sockfd);
218*25da2beaSAndroid Build Coastguard Worker 		return 0;
219*25da2beaSAndroid Build Coastguard Worker 	}
220*25da2beaSAndroid Build Coastguard Worker 	if (cqe->res != iov.iov_len) {
221*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "failed cqe: %d\n", cqe->res);
222*25da2beaSAndroid Build Coastguard Worker 		goto err;
223*25da2beaSAndroid Build Coastguard Worker 	}
224*25da2beaSAndroid Build Coastguard Worker 
225*25da2beaSAndroid Build Coastguard Worker 	close(sockfd);
226*25da2beaSAndroid Build Coastguard Worker 	return 0;
227*25da2beaSAndroid Build Coastguard Worker err:
228*25da2beaSAndroid Build Coastguard Worker 	close(sockfd);
229*25da2beaSAndroid Build Coastguard Worker 	return 1;
230*25da2beaSAndroid Build Coastguard Worker }
231*25da2beaSAndroid Build Coastguard Worker 
test(int use_sqthread,int regfiles)232*25da2beaSAndroid Build Coastguard Worker static int test(int use_sqthread, int regfiles)
233*25da2beaSAndroid Build Coastguard Worker {
234*25da2beaSAndroid Build Coastguard Worker 	pthread_mutexattr_t attr;
235*25da2beaSAndroid Build Coastguard Worker 	pthread_t recv_thread;
236*25da2beaSAndroid Build Coastguard Worker 	struct recv_data rd;
237*25da2beaSAndroid Build Coastguard Worker 	int ret;
238*25da2beaSAndroid Build Coastguard Worker 	void *retval;
239*25da2beaSAndroid Build Coastguard Worker 
240*25da2beaSAndroid Build Coastguard Worker 	pthread_mutexattr_init(&attr);
241*25da2beaSAndroid Build Coastguard Worker 	pthread_mutexattr_setpshared(&attr, 1);
242*25da2beaSAndroid Build Coastguard Worker 	pthread_mutex_init(&rd.mutex, &attr);
243*25da2beaSAndroid Build Coastguard Worker 	pthread_mutex_lock(&rd.mutex);
244*25da2beaSAndroid Build Coastguard Worker 	rd.use_sqthread = use_sqthread;
245*25da2beaSAndroid Build Coastguard Worker 	rd.registerfiles = regfiles;
246*25da2beaSAndroid Build Coastguard Worker 
247*25da2beaSAndroid Build Coastguard Worker 	ret = pthread_create(&recv_thread, NULL, recv_fn, &rd);
248*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
249*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "Thread create failed: %d\n", ret);
250*25da2beaSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&rd.mutex);
251*25da2beaSAndroid Build Coastguard Worker 		return 1;
252*25da2beaSAndroid Build Coastguard Worker 	}
253*25da2beaSAndroid Build Coastguard Worker 
254*25da2beaSAndroid Build Coastguard Worker 	pthread_mutex_lock(&rd.mutex);
255*25da2beaSAndroid Build Coastguard Worker 	do_send();
256*25da2beaSAndroid Build Coastguard Worker 	pthread_join(recv_thread, &retval);
257*25da2beaSAndroid Build Coastguard Worker 	return (intptr_t)retval;
258*25da2beaSAndroid Build Coastguard Worker }
259*25da2beaSAndroid Build Coastguard Worker 
main(int argc,char * argv[])260*25da2beaSAndroid Build Coastguard Worker int main(int argc, char *argv[])
261*25da2beaSAndroid Build Coastguard Worker {
262*25da2beaSAndroid Build Coastguard Worker 	int ret;
263*25da2beaSAndroid Build Coastguard Worker 
264*25da2beaSAndroid Build Coastguard Worker 	if (argc > 1)
265*25da2beaSAndroid Build Coastguard Worker 		return 0;
266*25da2beaSAndroid Build Coastguard Worker 
267*25da2beaSAndroid Build Coastguard Worker 	ret = test(0, 0);
268*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
269*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "test sqthread=0 failed\n");
270*25da2beaSAndroid Build Coastguard Worker 		return ret;
271*25da2beaSAndroid Build Coastguard Worker 	}
272*25da2beaSAndroid Build Coastguard Worker 
273*25da2beaSAndroid Build Coastguard Worker 	ret = test(1, 1);
274*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
275*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "test sqthread=1 reg=1 failed\n");
276*25da2beaSAndroid Build Coastguard Worker 		return ret;
277*25da2beaSAndroid Build Coastguard Worker 	}
278*25da2beaSAndroid Build Coastguard Worker 
279*25da2beaSAndroid Build Coastguard Worker 	ret = test(1, 0);
280*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
281*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "test sqthread=1 reg=0 failed\n");
282*25da2beaSAndroid Build Coastguard Worker 		return ret;
283*25da2beaSAndroid Build Coastguard Worker 	}
284*25da2beaSAndroid Build Coastguard Worker 
285*25da2beaSAndroid Build Coastguard Worker 	return 0;
286*25da2beaSAndroid Build Coastguard Worker }
287