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(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 | |
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 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 | |