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
16static int pipefd[2];
17static int signal_recvd;
18static pid_t producer_id;
19static char sock_name[32];
20
21static void sig_hand(int sn, siginfo_t *si, void *p)
22{
23 signal_recvd = sn;
24}
25
26static 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
37static 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
48static void signal_producer(int fd)
49{
50 char cmd;
51
52 cmd = 'S';
53 write(fd, &cmd, sizeof(cmd));
54}
55
56static void wait_for_signal(int fd)
57{
58 char buf[5];
59
60 read(fd, buf, 5);
61}
62
63static void die(int status)
64{
65 fflush(NULL);
66 unlink(sock_name);
67 kill(producer_id, SIGTERM);
68 exit(status);
69}
70
71int 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
83void 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
94int 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
107static 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
116void 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(fd: pipefd[0]);
126 if (connect(cfd, (struct sockaddr *)consumer_addr,
127 sizeof(*consumer_addr)) != 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(fd: pipefd[0]);
136 memset(buf, 'x', sizeof(buf));
137 buf[63] = '@';
138 send(cfd, buf, sizeof(buf), MSG_OOB);
139
140 wait_for_signal(fd: 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(fd: 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(fd: 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
174int
175main(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 atmark;
184
185 lfd = socket(AF_UNIX, SOCK_STREAM, 0);
186 memset(&consumer_addr, 0, sizeof(consumer_addr));
187 consumer_addr.sun_family = AF_UNIX;
188 sprintf(sock_name, "unix_oob_%d", getpid());
189 unlink(sock_name);
190 strcpy(consumer_addr.sun_path, sock_name);
191
192 if ((bind(lfd, (struct sockaddr *)&consumer_addr,
193 sizeof(consumer_addr))) != 0) {
194 perror("socket bind failed");
195 exit(1);
196 }
197
198 pipe(pipefd);
199
200 listen(lfd, 1);
201
202 producer_id = fork();
203 if (producer_id == 0) {
204 producer(consumer_addr: &consumer_addr);
205 exit(0);
206 }
207
208 set_sig_handler(SIGURG);
209 signal_producer(fd: pipefd[1]);
210
211 pfd = accept(lfd, (struct sockaddr *) &paddr, &len);
212 fcntl(pfd, F_SETOWN, getpid());
213
214 signal_recvd = 0;
215 signal_producer(fd: pipefd[1]);
216
217 /* Test 1:
218 * veriyf that SIGURG is
219 * delivered, 63 bytes are
220 * read, oob is '@', and POLLPRI works.
221 */
222 wait_for_data(pfd, POLLPRI);
223 read_oob(fd: pfd, c: &oob);
224 len = read_data(pfd, buf, 1024);
225 if (!signal_recvd || len != 63 || oob != '@') {
226 fprintf(stderr, "Test 1 failed sigurg %d len %d %c\n",
227 signal_recvd, len, oob);
228 die(status: 1);
229 }
230
231 signal_recvd = 0;
232 signal_producer(fd: pipefd[1]);
233
234 /* Test 2:
235 * Verify that the first OOB is over written by
236 * the 2nd one and the first OOB is returned as
237 * part of the read, and sigurg is received.
238 */
239 wait_for_data(pfd, POLLIN | POLLPRI);
240 len = 0;
241 while (len < 70)
242 len = recv(pfd, buf, 1024, MSG_PEEK);
243 len = read_data(pfd, buf, 1024);
244 read_oob(fd: pfd, c: &oob);
245 if (!signal_recvd || len != 127 || oob != '#') {
246 fprintf(stderr, "Test 2 failed, sigurg %d len %d OOB %c\n",
247 signal_recvd, len, oob);
248 die(status: 1);
249 }
250
251 signal_recvd = 0;
252 signal_producer(fd: pipefd[1]);
253
254 /* Test 3:
255 * verify that 2nd oob over writes
256 * the first one and read breaks at
257 * oob boundary returning 127 bytes
258 * and sigurg is received and atmark
259 * is set.
260 * oob is '%' and second read returns
261 * 64 bytes.
262 */
263 len = 0;
264 wait_for_data(pfd, POLLIN | POLLPRI);
265 while (len < 150)
266 len = recv(pfd, buf, 1024, MSG_PEEK);
267 len = read_data(pfd, buf, 1024);
268 atmark = is_sioctatmark(fd: pfd);
269 read_oob(fd: pfd, c: &oob);
270
271 if (!signal_recvd || len != 127 || oob != '%' || atmark != 1) {
272 fprintf(stderr,
273 "Test 3 failed, sigurg %d len %d OOB %c atmark %d\n",
274 signal_recvd, len, oob, atmark);
275 die(status: 1);
276 }
277
278 signal_recvd = 0;
279
280 len = read_data(pfd, buf, 1024);
281 if (len != 64) {
282 fprintf(stderr, "Test 3.1 failed, sigurg %d len %d OOB %c\n",
283 signal_recvd, len, oob);
284 die(status: 1);
285 }
286
287 signal_recvd = 0;
288 signal_producer(fd: pipefd[1]);
289
290 /* Test 4:
291 * verify that a single byte
292 * oob message is delivered.
293 * set non blocking mode and
294 * check proper error is
295 * returned and sigurg is
296 * received and correct
297 * oob is read.
298 */
299
300 set_filemode(fd: pfd, set: 0);
301
302 wait_for_data(pfd, POLLIN | POLLPRI);
303 len = read_data(pfd, buf, 1024);
304 if ((len == -1) && (errno == 11))
305 len = 0;
306
307 read_oob(fd: pfd, c: &oob);
308
309 if (!signal_recvd || len != 0 || oob != '@') {
310 fprintf(stderr, "Test 4 failed, sigurg %d len %d OOB %c\n",
311 signal_recvd, len, oob);
312 die(status: 1);
313 }
314
315 set_filemode(fd: pfd, set: 1);
316
317 /* Inline Testing */
318
319 on = 1;
320 if (setsockopt(pfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))) {
321 perror("SO_OOBINLINE");
322 die(status: 1);
323 }
324
325 signal_recvd = 0;
326 signal_producer(fd: pipefd[1]);
327
328 /* Test 1 -- Inline:
329 * Check that SIGURG is
330 * delivered and 63 bytes are
331 * read and oob is '@'
332 */
333
334 wait_for_data(pfd, POLLIN | POLLPRI);
335 len = read_data(pfd, buf, 1024);
336
337 if (!signal_recvd || len != 63) {
338 fprintf(stderr, "Test 1 Inline failed, sigurg %d len %d\n",
339 signal_recvd, len);
340 die(status: 1);
341 }
342
343 len = read_data(pfd, buf, 1024);
344
345 if (len != 1) {
346 fprintf(stderr,
347 "Test 1.1 Inline failed, sigurg %d len %d oob %c\n",
348 signal_recvd, len, oob);
349 die(status: 1);
350 }
351
352 signal_recvd = 0;
353 signal_producer(fd: pipefd[1]);
354
355 /* Test 2 -- Inline:
356 * Verify that the first OOB is over written by
357 * the 2nd one and read breaks correctly on
358 * 2nd OOB boundary with the first OOB returned as
359 * part of the read, and sigurg is delivered and
360 * siocatmark returns true.
361 * next read returns one byte, the oob byte
362 * and siocatmark returns false.
363 */
364 len = 0;
365 wait_for_data(pfd, POLLIN | POLLPRI);
366 while (len < 70)
367 len = recv(pfd, buf, 1024, MSG_PEEK);
368 len = read_data(pfd, buf, 1024);
369 atmark = is_sioctatmark(fd: pfd);
370 if (len != 127 || atmark != 1 || !signal_recvd) {
371 fprintf(stderr, "Test 2 Inline failed, len %d atmark %d\n",
372 len, atmark);
373 die(status: 1);
374 }
375
376 len = read_data(pfd, buf, 1024);
377 atmark = is_sioctatmark(fd: pfd);
378 if (len != 1 || buf[0] != '#' || atmark == 1) {
379 fprintf(stderr, "Test 2.1 Inline failed, len %d data %c atmark %d\n",
380 len, buf[0], atmark);
381 die(status: 1);
382 }
383
384 signal_recvd = 0;
385 signal_producer(fd: pipefd[1]);
386
387 /* Test 3 -- Inline:
388 * verify that 2nd oob over writes
389 * the first one and read breaks at
390 * oob boundary returning 127 bytes
391 * and sigurg is received and siocatmark
392 * is true after the read.
393 * subsequent read returns 65 bytes
394 * because of oob which should be '%'.
395 */
396 len = 0;
397 wait_for_data(pfd, POLLIN | POLLPRI);
398 while (len < 126)
399 len = recv(pfd, buf, 1024, MSG_PEEK);
400 len = read_data(pfd, buf, 1024);
401 atmark = is_sioctatmark(fd: pfd);
402 if (!signal_recvd || len != 127 || !atmark) {
403 fprintf(stderr,
404 "Test 3 Inline failed, sigurg %d len %d data %c\n",
405 signal_recvd, len, buf[0]);
406 die(status: 1);
407 }
408
409 len = read_data(pfd, buf, 1024);
410 atmark = is_sioctatmark(fd: pfd);
411 if (len != 65 || buf[0] != '%' || atmark != 0) {
412 fprintf(stderr,
413 "Test 3.1 Inline failed, len %d oob %c atmark %d\n",
414 len, buf[0], atmark);
415 die(status: 1);
416 }
417
418 signal_recvd = 0;
419 signal_producer(fd: pipefd[1]);
420
421 /* Test 4 -- Inline:
422 * verify that a single
423 * byte oob message is delivered
424 * and read returns one byte, the oob
425 * byte and sigurg is received
426 */
427 wait_for_data(pfd, POLLIN | POLLPRI);
428 len = read_data(pfd, buf, 1024);
429 if (!signal_recvd || len != 1 || buf[0] != '@') {
430 fprintf(stderr,
431 "Test 4 Inline failed, signal %d len %d data %c\n",
432 signal_recvd, len, buf[0]);
433 die(status: 1);
434 }
435 die(status: 0);
436}
437

source code of linux/tools/testing/selftests/net/af_unix/test_unix_oob.c