• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
sig_hand(int sn,siginfo_t * si,void * p)21 static void sig_hand(int sn, siginfo_t *si, void *p)
22 {
23 	signal_recvd = sn;
24 }
25 
set_sig_handler(int signal)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 
set_filemode(int fd,int set)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 
signal_producer(int fd)48 static void signal_producer(int fd)
49 {
50 	char cmd;
51 
52 	cmd = 'S';
53 	write(fd, &cmd, sizeof(cmd));
54 }
55 
wait_for_signal(int fd)56 static void wait_for_signal(int fd)
57 {
58 	char buf[5];
59 
60 	read(fd, buf, 5);
61 }
62 
die(int status)63 static void die(int status)
64 {
65 	fflush(NULL);
66 	unlink(sock_name);
67 	kill(producer_id, SIGTERM);
68 	exit(status);
69 }
70 
is_sioctatmark(int fd)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 
read_oob(int fd,char * c)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 
read_data(int pfd,char * buf,int size)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 
wait_for_data(int pfd,int event)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 
producer(struct sockaddr_un * consumer_addr)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(*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(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
main(int argc,char ** argv)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 }
439