xref: /linux/tools/testing/selftests/net/af_unix/msg_oob.c (revision b94038d841a91d0e3f59cfe4d073e210910366ee)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright Amazon.com Inc. or its affiliates. */
3 
4 #include <fcntl.h>
5 #include <string.h>
6 #include <unistd.h>
7 
8 #include <netinet/in.h>
9 #include <sys/socket.h>
10 
11 #include "../../kselftest_harness.h"
12 
13 #define BUF_SZ	32
14 
15 FIXTURE(msg_oob)
16 {
17 	int fd[4];		/* 0: AF_UNIX sender
18 				 * 1: AF_UNIX receiver
19 				 * 2: TCP sender
20 				 * 3: TCP receiver
21 				 */
22 };
23 
24 FIXTURE_VARIANT(msg_oob)
25 {
26 	bool peek;
27 };
28 
29 FIXTURE_VARIANT_ADD(msg_oob, no_peek)
30 {
31 	.peek = false,
32 };
33 
34 FIXTURE_VARIANT_ADD(msg_oob, peek)
35 {
36 	.peek = true
37 };
38 
39 static void create_unix_socketpair(struct __test_metadata *_metadata,
40 				   FIXTURE_DATA(msg_oob) *self)
41 {
42 	int ret;
43 
44 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, self->fd);
45 	ASSERT_EQ(ret, 0);
46 }
47 
48 static void create_tcp_socketpair(struct __test_metadata *_metadata,
49 				  FIXTURE_DATA(msg_oob) *self)
50 {
51 	struct sockaddr_in addr;
52 	socklen_t addrlen;
53 	int listen_fd;
54 	int ret;
55 
56 	listen_fd = socket(AF_INET, SOCK_STREAM, 0);
57 	ASSERT_GE(listen_fd, 0);
58 
59 	ret = listen(listen_fd, -1);
60 	ASSERT_EQ(ret, 0);
61 
62 	addrlen = sizeof(addr);
63 	ret = getsockname(listen_fd, (struct sockaddr *)&addr, &addrlen);
64 	ASSERT_EQ(ret, 0);
65 
66 	self->fd[2] = socket(AF_INET, SOCK_STREAM, 0);
67 	ASSERT_GE(self->fd[2], 0);
68 
69 	ret = connect(self->fd[2], (struct sockaddr *)&addr, addrlen);
70 	ASSERT_EQ(ret, 0);
71 
72 	self->fd[3] = accept(listen_fd, (struct sockaddr *)&addr, &addrlen);
73 	ASSERT_GE(self->fd[3], 0);
74 
75 	ret = fcntl(self->fd[3], F_SETFL, O_NONBLOCK);
76 	ASSERT_EQ(ret, 0);
77 }
78 
79 static void close_sockets(FIXTURE_DATA(msg_oob) *self)
80 {
81 	int i;
82 
83 	for (i = 0; i < 4; i++)
84 		close(self->fd[i]);
85 }
86 
87 FIXTURE_SETUP(msg_oob)
88 {
89 	create_unix_socketpair(_metadata, self);
90 	create_tcp_socketpair(_metadata, self);
91 }
92 
93 FIXTURE_TEARDOWN(msg_oob)
94 {
95 	close_sockets(self);
96 }
97 
98 static void __sendpair(struct __test_metadata *_metadata,
99 		       FIXTURE_DATA(msg_oob) *self,
100 		       const void *buf, size_t len, int flags)
101 {
102 	int i, ret[2];
103 
104 	for (i = 0; i < 2; i++)
105 		ret[i] = send(self->fd[i * 2], buf, len, flags);
106 
107 	ASSERT_EQ(ret[0], len);
108 	ASSERT_EQ(ret[0], ret[1]);
109 }
110 
111 static void __recvpair(struct __test_metadata *_metadata,
112 		       FIXTURE_DATA(msg_oob) *self,
113 		       const void *expected_buf, int expected_len,
114 		       int buf_len, int flags)
115 {
116 	int i, ret[2], recv_errno[2], expected_errno = 0;
117 	char recv_buf[2][BUF_SZ] = {};
118 
119 	ASSERT_GE(BUF_SZ, buf_len);
120 
121 	errno = 0;
122 
123 	for (i = 0; i < 2; i++) {
124 		ret[i] = recv(self->fd[i * 2 + 1], recv_buf[i], buf_len, flags);
125 		recv_errno[i] = errno;
126 	}
127 
128 	if (expected_len < 0) {
129 		expected_errno = -expected_len;
130 		expected_len = -1;
131 	}
132 
133 	if (ret[0] != expected_len || recv_errno[0] != expected_errno) {
134 		TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
135 		TH_LOG("Expected:%s", expected_errno ? strerror(expected_errno) : expected_buf);
136 
137 		ASSERT_EQ(ret[0], expected_len);
138 		ASSERT_EQ(recv_errno[0], expected_errno);
139 	}
140 
141 	if (ret[0] != ret[1] || recv_errno[0] != recv_errno[1]) {
142 		TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
143 		TH_LOG("TCP     :%s", ret[1] < 0 ? strerror(recv_errno[1]) : recv_buf[1]);
144 
145 		ASSERT_EQ(ret[0], ret[1]);
146 		ASSERT_EQ(recv_errno[0], recv_errno[1]);
147 	}
148 
149 	if (expected_len >= 0) {
150 		int cmp;
151 
152 		cmp = strncmp(expected_buf, recv_buf[0], expected_len);
153 		if (cmp) {
154 			TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
155 			TH_LOG("Expected:%s", expected_errno ? strerror(expected_errno) : expected_buf);
156 
157 			ASSERT_EQ(cmp, 0);
158 		}
159 
160 		cmp = strncmp(recv_buf[0], recv_buf[1], expected_len);
161 		if (cmp) {
162 			TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
163 			TH_LOG("TCP     :%s", ret[1] < 0 ? strerror(recv_errno[1]) : recv_buf[1]);
164 
165 			ASSERT_EQ(cmp, 0);
166 		}
167 	}
168 }
169 
170 #define sendpair(buf, len, flags)					\
171 	__sendpair(_metadata, self, buf, len, flags)
172 
173 #define recvpair(expected_buf, expected_len, buf_len, flags)		\
174 	do {								\
175 		if (variant->peek)					\
176 			__recvpair(_metadata, self,			\
177 				   expected_buf, expected_len,		\
178 				   buf_len, (flags) | MSG_PEEK);	\
179 		__recvpair(_metadata, self,				\
180 			   expected_buf, expected_len, buf_len, flags);	\
181 	} while (0)
182 
183 TEST_F(msg_oob, non_oob)
184 {
185 	sendpair("x", 1, 0);
186 
187 	recvpair("", -EINVAL, 1, MSG_OOB);
188 }
189 
190 TEST_F(msg_oob, oob)
191 {
192 	sendpair("x", 1, MSG_OOB);
193 
194 	recvpair("x", 1, 1, MSG_OOB);
195 }
196 
197 TEST_F(msg_oob, oob_drop)
198 {
199 	sendpair("x", 1, MSG_OOB);
200 
201 	recvpair("", -EAGAIN, 1, 0);		/* Drop OOB. */
202 	recvpair("", -EINVAL, 1, MSG_OOB);
203 }
204 
205 TEST_F(msg_oob, oob_ahead)
206 {
207 	sendpair("hello", 5, MSG_OOB);
208 
209 	recvpair("o", 1, 1, MSG_OOB);
210 	recvpair("hell", 4, 4, 0);
211 }
212 
213 TEST_F(msg_oob, oob_break)
214 {
215 	sendpair("hello", 5, MSG_OOB);
216 
217 	recvpair("hell", 4, 5, 0);		/* Break at OOB even with enough buffer. */
218 	recvpair("o", 1, 1, MSG_OOB);
219 }
220 
221 TEST_F(msg_oob, oob_ahead_break)
222 {
223 	sendpair("hello", 5, MSG_OOB);
224 	sendpair("world", 5, 0);
225 
226 	recvpair("o", 1, 1, MSG_OOB);
227 	recvpair("hell", 4, 9, 0);		/* Break at OOB even after it's recv()ed. */
228 	recvpair("world", 5, 5, 0);
229 }
230 
231 TEST_F(msg_oob, oob_break_drop)
232 {
233 	sendpair("hello", 5, MSG_OOB);
234 	sendpair("world", 5, 0);
235 
236 	recvpair("hell", 4, 10, 0);		/* Break at OOB even with enough buffer. */
237 	recvpair("world", 5, 10, 0);		/* Drop OOB and recv() the next skb. */
238 	recvpair("", -EINVAL, 1, MSG_OOB);
239 }
240 
241 TEST_HARNESS_MAIN
242