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(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
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);
205		exit(0);
206	}
207
208	set_sig_handler(SIGURG);
209	signal_producer(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(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(pfd, &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(1);
229	}
230
231	signal_recvd = 0;
232	signal_producer(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(pfd, &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(1);
249	}
250
251	signal_recvd = 0;
252	signal_producer(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(pfd);
269	read_oob(pfd, &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(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(1);
285	}
286
287	signal_recvd = 0;
288	signal_producer(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(pfd, 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(pfd, &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(1);
313	}
314
315	set_filemode(pfd, 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(1);
323	}
324
325	signal_recvd = 0;
326	signal_producer(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(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(1);
350	}
351
352	signal_recvd = 0;
353	signal_producer(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(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(1);
374	}
375
376	len = read_data(pfd, buf, 1024);
377	atmark = is_sioctatmark(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(1);
382	}
383
384	signal_recvd = 0;
385	signal_producer(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(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(1);
407	}
408
409	len = read_data(pfd, buf, 1024);
410	atmark = is_sioctatmark(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(1);
416	}
417
418	signal_recvd = 0;
419	signal_producer(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(1);
434	}
435	die(0);
436}
437