• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Check that CMD operations on sockets are consistent.
4  */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <assert.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <linux/sockios.h>
12 #include <sys/ioctl.h>
13 
14 #include "liburing.h"
15 #include "helpers.h"
16 
17 #define USERDATA 0x1234
18 #define MSG "foobarbaz"
19 
20 static int no_io_cmd;
21 
22 struct fds {
23 	int tx;
24 	int rx;
25 };
26 
27 /* Create 2 sockets (tx, rx) given the socket type */
create_sockets(bool stream)28 static struct fds create_sockets(bool stream)
29 {
30 	struct fds retval;
31 	int fd[2];
32 
33 	t_create_socket_pair(fd, stream);
34 
35 	retval.tx = fd[0];
36 	retval.rx = fd[1];
37 
38 	return retval;
39 }
40 
create_sqe_and_submit(struct io_uring * ring,int32_t fd,int op)41 static int create_sqe_and_submit(struct io_uring *ring, int32_t fd, int op)
42 {
43 	struct io_uring_sqe *sqe;
44 	int ret;
45 
46 	assert(fd > 0);
47 	sqe = io_uring_get_sqe(ring);
48 	assert(sqe != NULL);
49 
50 	io_uring_prep_cmd_sock(sqe, op, fd, 0, 0, NULL, 0);
51 	sqe->user_data = USERDATA;
52 
53 	/* Submitting SQE */
54 	ret = io_uring_submit_and_wait(ring, 1);
55 	if (ret <= 0)
56 		return ret;
57 
58 	return 0;
59 }
60 
receive_cqe(struct io_uring * ring)61 static int receive_cqe(struct io_uring *ring)
62 {
63 	struct io_uring_cqe *cqe;
64 	int err;
65 
66 	err = io_uring_wait_cqe(ring, &cqe);
67 	assert(err ==  0);
68 	assert(cqe->user_data == USERDATA);
69 	err = cqe->res;
70 	io_uring_cqe_seen(ring, cqe);
71 
72 	/* Return the result of the operation */
73 	return err;
74 }
75 
send_data(struct fds * s,char * str)76 static ssize_t send_data(struct fds *s, char *str)
77 {
78 	size_t written_bytes;
79 
80 	written_bytes = write(s->tx, str, strlen(str));
81 	assert(written_bytes == strlen(MSG));
82 
83 	return written_bytes;
84 }
85 
run_test(bool stream)86 static int run_test(bool stream)
87 {
88 	struct fds sockfds;
89 	ssize_t bytes_in, bytes_out;
90 	struct io_uring ring;
91 	size_t written_bytes;
92 	int error;
93 
94 	/* Create three sockets */
95 	sockfds = create_sockets(stream);
96 	assert(sockfds.tx > 0);
97 	assert(sockfds.rx > 0);
98 	/* Send data sing the sockfds->send */
99 	written_bytes = send_data(&sockfds, MSG);
100 
101 	/* Simply io_uring ring creation */
102 	error = t_create_ring(1, &ring, 0);
103 	if (error == T_SETUP_SKIP)
104 		return error;
105 	else if (error != T_SETUP_OK)
106 		return T_EXIT_FAIL;
107 
108 	error = create_sqe_and_submit(&ring, sockfds.rx,
109 				      SOCKET_URING_OP_SIOCINQ);
110 	if (error)
111 		return T_EXIT_FAIL;
112 	bytes_in = receive_cqe(&ring);
113 	if (bytes_in < 0) {
114 		if (bytes_in == -EINVAL || bytes_in == -EOPNOTSUPP) {
115 			no_io_cmd = 1;
116 			return T_EXIT_SKIP;
117 		}
118 		fprintf(stderr, "Bad return value %ld\n", (long) bytes_in);
119 		return T_EXIT_FAIL;
120 	}
121 
122 	error = create_sqe_and_submit(&ring, sockfds.tx,
123 				      SOCKET_URING_OP_SIOCOUTQ);
124 	if (error)
125 		return T_EXIT_FAIL;
126 
127 	bytes_out = receive_cqe(&ring);
128 	if (bytes_in == -ENOTSUP || bytes_out == -ENOTSUP) {
129 		fprintf(stderr, "Skipping tests. -ENOTSUP returned\n");
130 		return T_EXIT_SKIP;
131 	}
132 
133 	/*
134 	 * Assert the number of written bytes are either in the socket buffer
135 	 * or on the receive side
136 	 */
137 	if (bytes_in + bytes_out != written_bytes) {
138 		fprintf(stderr, "values does not match: %zu+%zu != %zu\n",
139 			bytes_in, bytes_out, written_bytes);
140 		return T_EXIT_FAIL;
141 	}
142 
143 	io_uring_queue_exit(&ring);
144 
145 	return T_EXIT_PASS;
146 }
147 
148 /*
149  * Make sure that siocoutq and siocinq returns the same value
150  * using ioctl(2) and uring commands for raw sockets
151  */
run_test_raw(void)152 static int run_test_raw(void)
153 {
154 	int ioctl_siocoutq, ioctl_siocinq;
155 	int uring_siocoutq, uring_siocinq;
156 	struct io_uring ring;
157 	int retry = 0, sock, error;
158 
159 	sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
160 	if (sock == -1)  {
161 		/* You need root to create raw socket */
162 		perror("Not able to create a raw socket");
163 		return T_EXIT_SKIP;
164 	}
165 
166 	/* Get the same operation using uring cmd */
167 	error = t_create_ring(1, &ring, 0);
168 	if (error == T_SETUP_SKIP)
169 		return error;
170 	else if (error != T_SETUP_OK)
171 		return T_EXIT_FAIL;
172 
173 again:
174 	/* Simple SIOCOUTQ using ioctl */
175 	error = ioctl(sock, SIOCOUTQ, &ioctl_siocoutq);
176 	if (error < 0) {
177 		fprintf(stderr, "Failed to run ioctl(SIOCOUTQ): %d\n", error);
178 		return T_EXIT_FAIL;
179 	}
180 
181 	error = ioctl(sock, SIOCINQ, &ioctl_siocinq);
182 	if (error < 0) {
183 		fprintf(stderr, "Failed to run ioctl(SIOCINQ): %d\n", error);
184 		return T_EXIT_FAIL;
185 	}
186 
187 	create_sqe_and_submit(&ring, sock, SOCKET_URING_OP_SIOCOUTQ);
188 	uring_siocoutq = receive_cqe(&ring);
189 
190 	create_sqe_and_submit(&ring, sock, SOCKET_URING_OP_SIOCINQ);
191 	uring_siocinq = receive_cqe(&ring);
192 
193 	/* Compare that both values (ioctl and uring CMD) should be similar */
194 	if (uring_siocoutq != ioctl_siocoutq) {
195 		if (!retry) {
196 			retry = 1;
197 			goto again;
198 		}
199 		fprintf(stderr, "values does not match: %d != %d\n",
200 			uring_siocoutq, ioctl_siocoutq);
201 		return T_EXIT_FAIL;
202 	}
203 	if (uring_siocinq != ioctl_siocinq) {
204 		if (!retry) {
205 			retry = 1;
206 			goto again;
207 		}
208 		fprintf(stderr, "values does not match: %d != %d\n",
209 			uring_siocinq, ioctl_siocinq);
210 		return T_EXIT_FAIL;
211 	}
212 
213 	return T_EXIT_PASS;
214 }
215 
main(int argc,char * argv[])216 int main(int argc, char *argv[])
217 {
218 	int err;
219 
220 	if (argc > 1)
221 		return 0;
222 
223 	/* Test SOCK_STREAM */
224 	err = run_test(true);
225 	if (err)
226 		return err;
227 	if (no_io_cmd)
228 		return T_EXIT_SKIP;
229 
230 	/* Test SOCK_DGRAM */
231 	err = run_test(false);
232 	if (err)
233 		return err;
234 
235 	/* Test raw sockets */
236 	return run_test_raw();
237 }
238