]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - tools/testing/selftests/net/af_unix/test_unix_oob.c
af_unix: Support POLLPRI for OOB.
[mirror_ubuntu-jammy-kernel.git] / tools / testing / selftests / net / af_unix / test_unix_oob.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <sys/socket.h>
5 #include <arpa/inet.h>
6 #include <unistd.h>
7 #include <string.h>
8 #include <fcntl.h>
9 #include <sys/ioctl.h>
10 #include <errno.h>
11 #include <netinet/tcp.h>
12 #include <sys/un.h>
13 #include <sys/signal.h>
14 #include <sys/poll.h>
15
16 static int pipefd[2];
17 static int signal_recvd;
18 static pid_t producer_id;
19 static char sock_name[32];
20
21 static void sig_hand(int sn, siginfo_t *si, void *p)
22 {
23 signal_recvd = sn;
24 }
25
26 static int set_sig_handler(int signal)
27 {
28 struct sigaction sa;
29
30 sa.sa_sigaction = sig_hand;
31 sigemptyset(&sa.sa_mask);
32 sa.sa_flags = SA_SIGINFO | SA_RESTART;
33
34 return sigaction(signal, &sa, NULL);
35 }
36
37 static void set_filemode(int fd, int set)
38 {
39 int flags = fcntl(fd, F_GETFL, 0);
40
41 if (set)
42 flags &= ~O_NONBLOCK;
43 else
44 flags |= O_NONBLOCK;
45 fcntl(fd, F_SETFL, flags);
46 }
47
48 static void signal_producer(int fd)
49 {
50 char cmd;
51
52 cmd = 'S';
53 write(fd, &cmd, sizeof(cmd));
54 }
55
56 static void wait_for_signal(int fd)
57 {
58 char buf[5];
59
60 read(fd, buf, 5);
61 }
62
63 static void die(int status)
64 {
65 fflush(NULL);
66 unlink(sock_name);
67 kill(producer_id, SIGTERM);
68 exit(status);
69 }
70
71 int is_sioctatmark(int fd)
72 {
73 int ans = -1;
74
75 if (ioctl(fd, SIOCATMARK, &ans, sizeof(ans)) < 0) {
76 #ifdef DEBUG
77 perror("SIOCATMARK Failed");
78 #endif
79 }
80 return ans;
81 }
82
83 void read_oob(int fd, char *c)
84 {
85
86 *c = ' ';
87 if (recv(fd, c, sizeof(*c), MSG_OOB) < 0) {
88 #ifdef DEBUG
89 perror("Reading MSG_OOB Failed");
90 #endif
91 }
92 }
93
94 int read_data(int pfd, char *buf, int size)
95 {
96 int len = 0;
97
98 memset(buf, size, '0');
99 len = read(pfd, buf, size);
100 #ifdef DEBUG
101 if (len < 0)
102 perror("read failed");
103 #endif
104 return len;
105 }
106
107 static void wait_for_data(int pfd, int event)
108 {
109 struct pollfd pfds[1];
110
111 pfds[0].fd = pfd;
112 pfds[0].events = event;
113 poll(pfds, 1, -1);
114 }
115
116 void producer(struct sockaddr_un *consumer_addr)
117 {
118 int cfd;
119 char buf[64];
120 int i;
121
122 memset(buf, 'x', sizeof(buf));
123 cfd = socket(AF_UNIX, SOCK_STREAM, 0);
124
125 wait_for_signal(pipefd[0]);
126 if (connect(cfd, (struct sockaddr *)consumer_addr,
127 sizeof(struct sockaddr)) != 0) {
128 perror("Connect failed");
129 kill(0, SIGTERM);
130 exit(1);
131 }
132
133 for (i = 0; i < 2; i++) {
134 /* Test 1: Test for SIGURG and OOB */
135 wait_for_signal(pipefd[0]);
136 memset(buf, 'x', sizeof(buf));
137 buf[63] = '@';
138 send(cfd, buf, sizeof(buf), MSG_OOB);
139
140 wait_for_signal(pipefd[0]);
141
142 /* Test 2: Test for OOB being overwitten */
143 memset(buf, 'x', sizeof(buf));
144 buf[63] = '%';
145 send(cfd, buf, sizeof(buf), MSG_OOB);
146
147 memset(buf, 'x', sizeof(buf));
148 buf[63] = '#';
149 send(cfd, buf, sizeof(buf), MSG_OOB);
150
151 wait_for_signal(pipefd[0]);
152
153 /* Test 3: Test for SIOCATMARK */
154 memset(buf, 'x', sizeof(buf));
155 buf[63] = '@';
156 send(cfd, buf, sizeof(buf), MSG_OOB);
157
158 memset(buf, 'x', sizeof(buf));
159 buf[63] = '%';
160 send(cfd, buf, sizeof(buf), MSG_OOB);
161
162 memset(buf, 'x', sizeof(buf));
163 send(cfd, buf, sizeof(buf), 0);
164
165 wait_for_signal(pipefd[0]);
166
167 /* Test 4: Test for 1byte OOB msg */
168 memset(buf, 'x', sizeof(buf));
169 buf[0] = '@';
170 send(cfd, buf, 1, MSG_OOB);
171 }
172 }
173
174 int
175 main(int argc, char **argv)
176 {
177 int lfd, pfd;
178 struct sockaddr_un consumer_addr, paddr;
179 socklen_t len = sizeof(consumer_addr);
180 char buf[1024];
181 int on = 0;
182 char oob;
183 int flags;
184 int atmark;
185 char *tmp_file;
186
187 lfd = socket(AF_UNIX, SOCK_STREAM, 0);
188 memset(&consumer_addr, 0, sizeof(consumer_addr));
189 consumer_addr.sun_family = AF_UNIX;
190 sprintf(sock_name, "unix_oob_%d", getpid());
191 unlink(sock_name);
192 strcpy(consumer_addr.sun_path, sock_name);
193
194 if ((bind(lfd, (struct sockaddr *)&consumer_addr,
195 sizeof(consumer_addr))) != 0) {
196 perror("socket bind failed");
197 exit(1);
198 }
199
200 pipe(pipefd);
201
202 listen(lfd, 1);
203
204 producer_id = fork();
205 if (producer_id == 0) {
206 producer(&consumer_addr);
207 exit(0);
208 }
209
210 set_sig_handler(SIGURG);
211 signal_producer(pipefd[1]);
212
213 pfd = accept(lfd, (struct sockaddr *) &paddr, &len);
214 fcntl(pfd, F_SETOWN, getpid());
215
216 signal_recvd = 0;
217 signal_producer(pipefd[1]);
218
219 /* Test 1:
220 * veriyf that SIGURG is
221 * delivered, 63 bytes are
222 * read, oob is '@', and POLLPRI works.
223 */
224 wait_for_data(pfd, POLLPRI);
225 read_oob(pfd, &oob);
226 len = read_data(pfd, buf, 1024);
227 if (!signal_recvd || len != 63 || oob != '@') {
228 fprintf(stderr, "Test 1 failed sigurg %d len %d %c\n",
229 signal_recvd, len, oob);
230 die(1);
231 }
232
233 signal_recvd = 0;
234 signal_producer(pipefd[1]);
235
236 /* Test 2:
237 * Verify that the first OOB is over written by
238 * the 2nd one and the first OOB is returned as
239 * part of the read, and sigurg is received.
240 */
241 wait_for_data(pfd, POLLIN | POLLPRI);
242 len = 0;
243 while (len < 70)
244 len = recv(pfd, buf, 1024, MSG_PEEK);
245 len = read_data(pfd, buf, 1024);
246 read_oob(pfd, &oob);
247 if (!signal_recvd || len != 127 || oob != '#') {
248 fprintf(stderr, "Test 2 failed, sigurg %d len %d OOB %c\n",
249 signal_recvd, len, oob);
250 die(1);
251 }
252
253 signal_recvd = 0;
254 signal_producer(pipefd[1]);
255
256 /* Test 3:
257 * verify that 2nd oob over writes
258 * the first one and read breaks at
259 * oob boundary returning 127 bytes
260 * and sigurg is received and atmark
261 * is set.
262 * oob is '%' and second read returns
263 * 64 bytes.
264 */
265 len = 0;
266 wait_for_data(pfd, POLLIN | POLLPRI);
267 while (len < 150)
268 len = recv(pfd, buf, 1024, MSG_PEEK);
269 len = read_data(pfd, buf, 1024);
270 atmark = is_sioctatmark(pfd);
271 read_oob(pfd, &oob);
272
273 if (!signal_recvd || len != 127 || oob != '%' || atmark != 1) {
274 fprintf(stderr,
275 "Test 3 failed, sigurg %d len %d OOB %c atmark %d\n",
276 signal_recvd, len, oob, atmark);
277 die(1);
278 }
279
280 signal_recvd = 0;
281
282 len = read_data(pfd, buf, 1024);
283 if (len != 64) {
284 fprintf(stderr, "Test 3.1 failed, sigurg %d len %d OOB %c\n",
285 signal_recvd, len, oob);
286 die(1);
287 }
288
289 signal_recvd = 0;
290 signal_producer(pipefd[1]);
291
292 /* Test 4:
293 * verify that a single byte
294 * oob message is delivered.
295 * set non blocking mode and
296 * check proper error is
297 * returned and sigurg is
298 * received and correct
299 * oob is read.
300 */
301
302 set_filemode(pfd, 0);
303
304 wait_for_data(pfd, POLLIN | POLLPRI);
305 len = read_data(pfd, buf, 1024);
306 if ((len == -1) && (errno == 11))
307 len = 0;
308
309 read_oob(pfd, &oob);
310
311 if (!signal_recvd || len != 0 || oob != '@') {
312 fprintf(stderr, "Test 4 failed, sigurg %d len %d OOB %c\n",
313 signal_recvd, len, oob);
314 die(1);
315 }
316
317 set_filemode(pfd, 1);
318
319 /* Inline Testing */
320
321 on = 1;
322 if (setsockopt(pfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))) {
323 perror("SO_OOBINLINE");
324 die(1);
325 }
326
327 signal_recvd = 0;
328 signal_producer(pipefd[1]);
329
330 /* Test 1 -- Inline:
331 * Check that SIGURG is
332 * delivered and 63 bytes are
333 * read and oob is '@'
334 */
335
336 wait_for_data(pfd, POLLIN | POLLPRI);
337 len = read_data(pfd, buf, 1024);
338
339 if (!signal_recvd || len != 63) {
340 fprintf(stderr, "Test 1 Inline failed, sigurg %d len %d\n",
341 signal_recvd, len);
342 die(1);
343 }
344
345 len = read_data(pfd, buf, 1024);
346
347 if (len != 1) {
348 fprintf(stderr,
349 "Test 1.1 Inline failed, sigurg %d len %d oob %c\n",
350 signal_recvd, len, oob);
351 die(1);
352 }
353
354 signal_recvd = 0;
355 signal_producer(pipefd[1]);
356
357 /* Test 2 -- Inline:
358 * Verify that the first OOB is over written by
359 * the 2nd one and read breaks correctly on
360 * 2nd OOB boundary with the first OOB returned as
361 * part of the read, and sigurg is delivered and
362 * siocatmark returns true.
363 * next read returns one byte, the oob byte
364 * and siocatmark returns false.
365 */
366 len = 0;
367 wait_for_data(pfd, POLLIN | POLLPRI);
368 while (len < 70)
369 len = recv(pfd, buf, 1024, MSG_PEEK);
370 len = read_data(pfd, buf, 1024);
371 atmark = is_sioctatmark(pfd);
372 if (len != 127 || atmark != 1 || !signal_recvd) {
373 fprintf(stderr, "Test 2 Inline failed, len %d atmark %d\n",
374 len, atmark);
375 die(1);
376 }
377
378 len = read_data(pfd, buf, 1024);
379 atmark = is_sioctatmark(pfd);
380 if (len != 1 || buf[0] != '#' || atmark == 1) {
381 fprintf(stderr, "Test 2.1 Inline failed, len %d data %c atmark %d\n",
382 len, buf[0], atmark);
383 die(1);
384 }
385
386 signal_recvd = 0;
387 signal_producer(pipefd[1]);
388
389 /* Test 3 -- Inline:
390 * verify that 2nd oob over writes
391 * the first one and read breaks at
392 * oob boundary returning 127 bytes
393 * and sigurg is received and siocatmark
394 * is true after the read.
395 * subsequent read returns 65 bytes
396 * because of oob which should be '%'.
397 */
398 len = 0;
399 wait_for_data(pfd, POLLIN | POLLPRI);
400 while (len < 126)
401 len = recv(pfd, buf, 1024, MSG_PEEK);
402 len = read_data(pfd, buf, 1024);
403 atmark = is_sioctatmark(pfd);
404 if (!signal_recvd || len != 127 || !atmark) {
405 fprintf(stderr,
406 "Test 3 Inline failed, sigurg %d len %d data %c\n",
407 signal_recvd, len, buf[0]);
408 die(1);
409 }
410
411 len = read_data(pfd, buf, 1024);
412 atmark = is_sioctatmark(pfd);
413 if (len != 65 || buf[0] != '%' || atmark != 0) {
414 fprintf(stderr,
415 "Test 3.1 Inline failed, len %d oob %c atmark %d\n",
416 len, buf[0], atmark);
417 die(1);
418 }
419
420 signal_recvd = 0;
421 signal_producer(pipefd[1]);
422
423 /* Test 4 -- Inline:
424 * verify that a single
425 * byte oob message is delivered
426 * and read returns one byte, the oob
427 * byte and sigurg is received
428 */
429 wait_for_data(pfd, POLLIN | POLLPRI);
430 len = read_data(pfd, buf, 1024);
431 if (!signal_recvd || len != 1 || buf[0] != '@') {
432 fprintf(stderr,
433 "Test 4 Inline failed, signal %d len %d data %c\n",
434 signal_recvd, len, buf[0]);
435 die(1);
436 }
437 die(0);
438 }