Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright Amazon.com Inc. or its affiliates. */
  3
  4#include <fcntl.h>
  5#include <string.h>
  6#include <unistd.h>
  7
  8#include <netinet/in.h>
  9#include <sys/epoll.h>
 10#include <sys/ioctl.h>
 11#include <sys/signalfd.h>
 12#include <sys/socket.h>
 13
 14#include "../../kselftest_harness.h"
 15
 16#define BUF_SZ	32
 17
 18FIXTURE(msg_oob)
 19{
 20	int fd[4];		/* 0: AF_UNIX sender
 21				 * 1: AF_UNIX receiver
 22				 * 2: TCP sender
 23				 * 3: TCP receiver
 24				 */
 25	int signal_fd;
 26	int epoll_fd[2];	/* 0: AF_UNIX receiver
 27				 * 1: TCP receiver
 28				 */
 29	bool tcp_compliant;
 30};
 31
 32FIXTURE_VARIANT(msg_oob)
 33{
 34	bool peek;
 35};
 36
 37FIXTURE_VARIANT_ADD(msg_oob, no_peek)
 38{
 39	.peek = false,
 40};
 41
 42FIXTURE_VARIANT_ADD(msg_oob, peek)
 43{
 44	.peek = true
 45};
 46
 47static void create_unix_socketpair(struct __test_metadata *_metadata,
 48				   FIXTURE_DATA(msg_oob) *self)
 49{
 50	int ret;
 51
 52	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, self->fd);
 53	ASSERT_EQ(ret, 0);
 54}
 55
 56static void create_tcp_socketpair(struct __test_metadata *_metadata,
 57				  FIXTURE_DATA(msg_oob) *self)
 58{
 59	struct sockaddr_in addr;
 60	socklen_t addrlen;
 61	int listen_fd;
 62	int ret;
 63
 64	listen_fd = socket(AF_INET, SOCK_STREAM, 0);
 65	ASSERT_GE(listen_fd, 0);
 66
 67	ret = listen(listen_fd, -1);
 68	ASSERT_EQ(ret, 0);
 69
 70	addrlen = sizeof(addr);
 71	ret = getsockname(listen_fd, (struct sockaddr *)&addr, &addrlen);
 72	ASSERT_EQ(ret, 0);
 73
 74	self->fd[2] = socket(AF_INET, SOCK_STREAM, 0);
 75	ASSERT_GE(self->fd[2], 0);
 76
 77	ret = connect(self->fd[2], (struct sockaddr *)&addr, addrlen);
 78	ASSERT_EQ(ret, 0);
 79
 80	self->fd[3] = accept(listen_fd, (struct sockaddr *)&addr, &addrlen);
 81	ASSERT_GE(self->fd[3], 0);
 82
 83	ret = fcntl(self->fd[3], F_SETFL, O_NONBLOCK);
 84	ASSERT_EQ(ret, 0);
 85}
 86
 87static void setup_sigurg(struct __test_metadata *_metadata,
 88			 FIXTURE_DATA(msg_oob) *self)
 89{
 90	struct signalfd_siginfo siginfo;
 91	int pid = getpid();
 92	sigset_t mask;
 93	int i, ret;
 94
 95	for (i = 0; i < 2; i++) {
 96		ret = ioctl(self->fd[i * 2 + 1], FIOSETOWN, &pid);
 97		ASSERT_EQ(ret, 0);
 98	}
 99
100	ret = sigemptyset(&mask);
101	ASSERT_EQ(ret, 0);
102
103	ret = sigaddset(&mask, SIGURG);
104	ASSERT_EQ(ret, 0);
105
106	ret = sigprocmask(SIG_BLOCK, &mask, NULL);
107	ASSERT_EQ(ret, 0);
108
109	self->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK);
110	ASSERT_GE(self->signal_fd, 0);
111
112	ret = read(self->signal_fd, &siginfo, sizeof(siginfo));
113	ASSERT_EQ(ret, -1);
114}
115
116static void setup_epollpri(struct __test_metadata *_metadata,
117			   FIXTURE_DATA(msg_oob) *self)
118{
119	struct epoll_event event = {
120		.events = EPOLLPRI,
121	};
122	int i;
123
124	for (i = 0; i < 2; i++) {
125		int ret;
126
127		self->epoll_fd[i] = epoll_create1(0);
128		ASSERT_GE(self->epoll_fd[i], 0);
129
130		ret = epoll_ctl(self->epoll_fd[i], EPOLL_CTL_ADD, self->fd[i * 2 + 1], &event);
131		ASSERT_EQ(ret, 0);
132	}
133}
134
135static void close_sockets(FIXTURE_DATA(msg_oob) *self)
136{
137	int i;
138
139	for (i = 0; i < 4; i++)
140		close(self->fd[i]);
141}
142
143FIXTURE_SETUP(msg_oob)
144{
145	create_unix_socketpair(_metadata, self);
146	create_tcp_socketpair(_metadata, self);
147
148	setup_sigurg(_metadata, self);
149	setup_epollpri(_metadata, self);
150
151	self->tcp_compliant = true;
152}
153
154FIXTURE_TEARDOWN(msg_oob)
155{
156	close_sockets(self);
157}
158
159static void __epollpair(struct __test_metadata *_metadata,
160			FIXTURE_DATA(msg_oob) *self,
161			bool oob_remaining)
162{
163	struct epoll_event event[2] = {};
164	int i, ret[2];
165
166	for (i = 0; i < 2; i++)
167		ret[i] = epoll_wait(self->epoll_fd[i], &event[i], 1, 0);
168
169	ASSERT_EQ(ret[0], oob_remaining);
170
171	if (self->tcp_compliant)
172		ASSERT_EQ(ret[0], ret[1]);
173
174	if (oob_remaining) {
175		ASSERT_EQ(event[0].events, EPOLLPRI);
176
177		if (self->tcp_compliant)
178			ASSERT_EQ(event[0].events, event[1].events);
179	}
180}
181
182static void __sendpair(struct __test_metadata *_metadata,
183		       FIXTURE_DATA(msg_oob) *self,
184		       const void *buf, size_t len, int flags)
185{
186	int i, ret[2];
187
188	for (i = 0; i < 2; i++) {
189		struct signalfd_siginfo siginfo = {};
190		int bytes;
191
192		ret[i] = send(self->fd[i * 2], buf, len, flags);
193
194		bytes = read(self->signal_fd, &siginfo, sizeof(siginfo));
195
196		if (flags & MSG_OOB) {
197			ASSERT_EQ(bytes, sizeof(siginfo));
198			ASSERT_EQ(siginfo.ssi_signo, SIGURG);
199
200			bytes = read(self->signal_fd, &siginfo, sizeof(siginfo));
201		}
202
203		ASSERT_EQ(bytes, -1);
204	}
205
206	ASSERT_EQ(ret[0], len);
207	ASSERT_EQ(ret[0], ret[1]);
208}
209
210static void __recvpair(struct __test_metadata *_metadata,
211		       FIXTURE_DATA(msg_oob) *self,
212		       const char *expected_buf, int expected_len,
213		       int buf_len, int flags)
214{
215	int i, ret[2], recv_errno[2], expected_errno = 0;
216	char recv_buf[2][BUF_SZ] = {};
217	bool printed = false;
218
219	ASSERT_GE(BUF_SZ, buf_len);
220
221	errno = 0;
222
223	for (i = 0; i < 2; i++) {
224		ret[i] = recv(self->fd[i * 2 + 1], recv_buf[i], buf_len, flags);
225		recv_errno[i] = errno;
226	}
227
228	if (expected_len < 0) {
229		expected_errno = -expected_len;
230		expected_len = -1;
231	}
232
233	if (ret[0] != expected_len || recv_errno[0] != expected_errno) {
234		TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
235		TH_LOG("Expected:%s", expected_errno ? strerror(expected_errno) : expected_buf);
236
237		ASSERT_EQ(ret[0], expected_len);
238		ASSERT_EQ(recv_errno[0], expected_errno);
239	}
240
241	if (ret[0] != ret[1] || recv_errno[0] != recv_errno[1]) {
242		TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
243		TH_LOG("TCP     :%s", ret[1] < 0 ? strerror(recv_errno[1]) : recv_buf[1]);
244
245		printed = true;
246
247		if (self->tcp_compliant) {
248			ASSERT_EQ(ret[0], ret[1]);
249			ASSERT_EQ(recv_errno[0], recv_errno[1]);
250		}
251	}
252
253	if (expected_len >= 0) {
254		int cmp;
255
256		cmp = strncmp(expected_buf, recv_buf[0], expected_len);
257		if (cmp) {
258			TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
259			TH_LOG("Expected:%s", expected_errno ? strerror(expected_errno) : expected_buf);
260
261			ASSERT_EQ(cmp, 0);
262		}
263
264		cmp = strncmp(recv_buf[0], recv_buf[1], expected_len);
265		if (cmp) {
266			if (!printed) {
267				TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
268				TH_LOG("TCP     :%s", ret[1] < 0 ? strerror(recv_errno[1]) : recv_buf[1]);
269			}
270
271			if (self->tcp_compliant)
272				ASSERT_EQ(cmp, 0);
273		}
274	}
275}
276
277static void __setinlinepair(struct __test_metadata *_metadata,
278			    FIXTURE_DATA(msg_oob) *self)
279{
280	int i, oob_inline = 1;
281
282	for (i = 0; i < 2; i++) {
283		int ret;
284
285		ret = setsockopt(self->fd[i * 2 + 1], SOL_SOCKET, SO_OOBINLINE,
286				 &oob_inline, sizeof(oob_inline));
287		ASSERT_EQ(ret, 0);
288	}
289}
290
291static void __siocatmarkpair(struct __test_metadata *_metadata,
292			     FIXTURE_DATA(msg_oob) *self,
293			     bool oob_head)
294{
295	int answ[2] = {};
296	int i;
297
298	for (i = 0; i < 2; i++) {
299		int ret;
300
301		ret = ioctl(self->fd[i * 2 + 1], SIOCATMARK, &answ[i]);
302		ASSERT_EQ(ret, 0);
303	}
304
305	ASSERT_EQ(answ[0], oob_head);
306
307	if (self->tcp_compliant)
308		ASSERT_EQ(answ[0], answ[1]);
309}
310
311#define sendpair(buf, len, flags)					\
312	__sendpair(_metadata, self, buf, len, flags)
313
314#define recvpair(expected_buf, expected_len, buf_len, flags)		\
315	do {								\
316		if (variant->peek)					\
317			__recvpair(_metadata, self,			\
318				   expected_buf, expected_len,		\
319				   buf_len, (flags) | MSG_PEEK);	\
320		__recvpair(_metadata, self,				\
321			   expected_buf, expected_len, buf_len, flags);	\
322	} while (0)
323
324#define epollpair(oob_remaining)					\
325	__epollpair(_metadata, self, oob_remaining)
326
327#define siocatmarkpair(oob_head)					\
328	__siocatmarkpair(_metadata, self, oob_head)
329
330#define setinlinepair()							\
331	__setinlinepair(_metadata, self)
332
333#define tcp_incompliant							\
334	for (self->tcp_compliant = false;				\
335	     self->tcp_compliant == false;				\
336	     self->tcp_compliant = true)
337
338TEST_F(msg_oob, non_oob)
339{
340	sendpair("x", 1, 0);
341	epollpair(false);
342	siocatmarkpair(false);
343
344	recvpair("", -EINVAL, 1, MSG_OOB);
345	epollpair(false);
346	siocatmarkpair(false);
347}
348
349TEST_F(msg_oob, oob)
350{
351	sendpair("x", 1, MSG_OOB);
352	epollpair(true);
353	siocatmarkpair(true);
354
355	recvpair("x", 1, 1, MSG_OOB);
356	epollpair(false);
357	siocatmarkpair(true);
358}
359
360TEST_F(msg_oob, oob_drop)
361{
362	sendpair("x", 1, MSG_OOB);
363	epollpair(true);
364	siocatmarkpair(true);
365
366	recvpair("", -EAGAIN, 1, 0);		/* Drop OOB. */
367	epollpair(false);
368	siocatmarkpair(false);
369
370	recvpair("", -EINVAL, 1, MSG_OOB);
371	epollpair(false);
372	siocatmarkpair(false);
373}
374
375TEST_F(msg_oob, oob_ahead)
376{
377	sendpair("hello", 5, MSG_OOB);
378	epollpair(true);
379	siocatmarkpair(false);
380
381	recvpair("o", 1, 1, MSG_OOB);
382	epollpair(false);
383	siocatmarkpair(false);
384
385	recvpair("hell", 4, 4, 0);
386	epollpair(false);
387	siocatmarkpair(true);
388}
389
390TEST_F(msg_oob, oob_break)
391{
392	sendpair("hello", 5, MSG_OOB);
393	epollpair(true);
394	siocatmarkpair(false);
395
396	recvpair("hell", 4, 5, 0);		/* Break at OOB even with enough buffer. */
397	epollpair(true);
398	siocatmarkpair(true);
399
400	recvpair("o", 1, 1, MSG_OOB);
401	epollpair(false);
402	siocatmarkpair(true);
403
404	recvpair("", -EAGAIN, 1, 0);
405	siocatmarkpair(false);
406}
407
408TEST_F(msg_oob, oob_ahead_break)
409{
410	sendpair("hello", 5, MSG_OOB);
411	epollpair(true);
412	siocatmarkpair(false);
413
414	sendpair("world", 5, 0);
415	epollpair(true);
416	siocatmarkpair(false);
417
418	recvpair("o", 1, 1, MSG_OOB);
419	epollpair(false);
420	siocatmarkpair(false);
421
422	recvpair("hell", 4, 9, 0);		/* Break at OOB even after it's recv()ed. */
423	epollpair(false);
424	siocatmarkpair(true);
425
426	recvpair("world", 5, 5, 0);
427	epollpair(false);
428	siocatmarkpair(false);
429}
430
431TEST_F(msg_oob, oob_break_drop)
432{
433	sendpair("hello", 5, MSG_OOB);
434	epollpair(true);
435	siocatmarkpair(false);
436
437	sendpair("world", 5, 0);
438	epollpair(true);
439	siocatmarkpair(false);
440
441	recvpair("hell", 4, 10, 0);		/* Break at OOB even with enough buffer. */
442	epollpair(true);
443	siocatmarkpair(true);
444
445	recvpair("world", 5, 10, 0);		/* Drop OOB and recv() the next skb. */
446	epollpair(false);
447	siocatmarkpair(false);
448
449	recvpair("", -EINVAL, 1, MSG_OOB);
450	epollpair(false);
451	siocatmarkpair(false);
452}
453
454TEST_F(msg_oob, ex_oob_break)
455{
456	sendpair("hello", 5, MSG_OOB);
457	epollpair(true);
458	siocatmarkpair(false);
459
460	sendpair("wor", 3, MSG_OOB);
461	epollpair(true);
462	siocatmarkpair(false);
463
464	sendpair("ld", 2, 0);
465	epollpair(true);
466	siocatmarkpair(false);
467
468	recvpair("hellowo", 7, 10, 0);		/* Break at OOB but not at ex-OOB. */
469	epollpair(true);
470	siocatmarkpair(true);
471
472	recvpair("r", 1, 1, MSG_OOB);
473	epollpair(false);
474	siocatmarkpair(true);
475
476	recvpair("ld", 2, 2, 0);
477	epollpair(false);
478	siocatmarkpair(false);
479}
480
481TEST_F(msg_oob, ex_oob_drop)
482{
483	sendpair("x", 1, MSG_OOB);
484	epollpair(true);
485	siocatmarkpair(true);
486
487	sendpair("y", 1, MSG_OOB);		/* TCP drops "x" at this moment. */
488	epollpair(true);
489
490	tcp_incompliant {
491		siocatmarkpair(false);
492
493		recvpair("x", 1, 1, 0);		/* TCP drops "y" by passing through it. */
494		epollpair(true);
495		siocatmarkpair(true);
496
497		recvpair("y", 1, 1, MSG_OOB);	/* TCP returns -EINVAL. */
498		epollpair(false);
499		siocatmarkpair(true);
500	}
501}
502
503TEST_F(msg_oob, ex_oob_drop_2)
504{
505	sendpair("x", 1, MSG_OOB);
506	epollpair(true);
507	siocatmarkpair(true);
508
509	sendpair("y", 1, MSG_OOB);		/* TCP drops "x" at this moment. */
510	epollpair(true);
511
512	tcp_incompliant {
513		siocatmarkpair(false);
514	}
515
516	recvpair("y", 1, 1, MSG_OOB);
517	epollpair(false);
518
519	tcp_incompliant {
520		siocatmarkpair(false);
521
522		recvpair("x", 1, 1, 0);		/* TCP returns -EAGAIN. */
523		epollpair(false);
524		siocatmarkpair(true);
525	}
526}
527
528TEST_F(msg_oob, ex_oob_oob)
529{
530	sendpair("x", 1, MSG_OOB);
531	epollpair(true);
532	siocatmarkpair(true);
533
534	recvpair("x", 1, 1, MSG_OOB);
535	epollpair(false);
536	siocatmarkpair(true);
537
538	sendpair("y", 1, MSG_OOB);
539	epollpair(true);
540	siocatmarkpair(true);
541
542	recvpair("", -EAGAIN, 1, 0);
543	epollpair(false);
544	siocatmarkpair(false);
545
546	recvpair("", -EINVAL, 1, MSG_OOB);
547	epollpair(false);
548	siocatmarkpair(false);
549}
550
551TEST_F(msg_oob, ex_oob_ahead_break)
552{
553	sendpair("hello", 5, MSG_OOB);
554	epollpair(true);
555	siocatmarkpair(false);
556
557	sendpair("wor", 3, MSG_OOB);
558	epollpair(true);
559	siocatmarkpair(false);
560
561	recvpair("r", 1, 1, MSG_OOB);
562	epollpair(false);
563	siocatmarkpair(false);
564
565	sendpair("ld", 2, MSG_OOB);
566	epollpair(true);
567	siocatmarkpair(false);
568
569	tcp_incompliant {
570		recvpair("hellowol", 8, 10, 0);	/* TCP recv()s "helloworl", why "r" ?? */
571	}
572
573	epollpair(true);
574	siocatmarkpair(true);
575
576	recvpair("d", 1, 1, MSG_OOB);
577	epollpair(false);
578	siocatmarkpair(true);
579}
580
581TEST_F(msg_oob, ex_oob_siocatmark)
582{
583	sendpair("hello", 5, MSG_OOB);
584	epollpair(true);
585	siocatmarkpair(false);
586
587	recvpair("o", 1, 1, MSG_OOB);
588	epollpair(false);
589	siocatmarkpair(false);
590
591	sendpair("world", 5, MSG_OOB);
592	epollpair(true);
593	siocatmarkpair(false);
594
595	recvpair("hell", 4, 4, 0);		/* Intentionally stop at ex-OOB. */
596	epollpair(true);
597	siocatmarkpair(false);
598}
599
600TEST_F(msg_oob, inline_oob)
601{
602	setinlinepair();
603
604	sendpair("x", 1, MSG_OOB);
605	epollpair(true);
606	siocatmarkpair(true);
607
608	recvpair("", -EINVAL, 1, MSG_OOB);
609	epollpair(true);
610	siocatmarkpair(true);
611
612	recvpair("x", 1, 1, 0);
613	epollpair(false);
614	siocatmarkpair(false);
615}
616
617TEST_F(msg_oob, inline_oob_break)
618{
619	setinlinepair();
620
621	sendpair("hello", 5, MSG_OOB);
622	epollpair(true);
623	siocatmarkpair(false);
624
625	recvpair("", -EINVAL, 1, MSG_OOB);
626	epollpair(true);
627	siocatmarkpair(false);
628
629	recvpair("hell", 4, 5, 0);		/* Break at OOB but not at ex-OOB. */
630	epollpair(true);
631	siocatmarkpair(true);
632
633	recvpair("o", 1, 1, 0);
634	epollpair(false);
635	siocatmarkpair(false);
636}
637
638TEST_F(msg_oob, inline_oob_ahead_break)
639{
640	sendpair("hello", 5, MSG_OOB);
641	epollpair(true);
642	siocatmarkpair(false);
643
644	sendpair("world", 5, 0);
645	epollpair(true);
646	siocatmarkpair(false);
647
648	recvpair("o", 1, 1, MSG_OOB);
649	epollpair(false);
650	siocatmarkpair(false);
651
652	setinlinepair();
653
654	recvpair("hell", 4, 9, 0);		/* Break at OOB even with enough buffer. */
655	epollpair(false);
656	siocatmarkpair(true);
657
658	tcp_incompliant {
659		recvpair("world", 5, 6, 0);	/* TCP recv()s "oworld", ... "o" ??? */
660	}
661
662	epollpair(false);
663	siocatmarkpair(false);
664}
665
666TEST_F(msg_oob, inline_ex_oob_break)
667{
668	sendpair("hello", 5, MSG_OOB);
669	epollpair(true);
670	siocatmarkpair(false);
671
672	sendpair("wor", 3, MSG_OOB);
673	epollpair(true);
674	siocatmarkpair(false);
675
676	sendpair("ld", 2, 0);
677	epollpair(true);
678	siocatmarkpair(false);
679
680	setinlinepair();
681
682	recvpair("hellowo", 7, 10, 0);		/* Break at OOB but not at ex-OOB. */
683	epollpair(true);
684	siocatmarkpair(true);
685
686	recvpair("rld", 3, 3, 0);
687	epollpair(false);
688	siocatmarkpair(false);
689}
690
691TEST_F(msg_oob, inline_ex_oob_no_drop)
692{
693	sendpair("x", 1, MSG_OOB);
694	epollpair(true);
695	siocatmarkpair(true);
696
697	setinlinepair();
698
699	sendpair("y", 1, MSG_OOB);		/* TCP does NOT drops "x" at this moment. */
700	epollpair(true);
701	siocatmarkpair(false);
702
703	recvpair("x", 1, 1, 0);
704	epollpair(true);
705	siocatmarkpair(true);
706
707	recvpair("y", 1, 1, 0);
708	epollpair(false);
709	siocatmarkpair(false);
710}
711
712TEST_F(msg_oob, inline_ex_oob_drop)
713{
714	sendpair("x", 1, MSG_OOB);
715	epollpair(true);
716	siocatmarkpair(true);
717
718	sendpair("y", 1, MSG_OOB);		/* TCP drops "x" at this moment. */
719	epollpair(true);
720
721	setinlinepair();
722
723	tcp_incompliant {
724		siocatmarkpair(false);
725
726		recvpair("x", 1, 1, 0);		/* TCP recv()s "y". */
727		epollpair(true);
728		siocatmarkpair(true);
729
730		recvpair("y", 1, 1, 0);		/* TCP returns -EAGAIN. */
731		epollpair(false);
732		siocatmarkpair(false);
733	}
734}
735
736TEST_F(msg_oob, inline_ex_oob_siocatmark)
737{
738	sendpair("hello", 5, MSG_OOB);
739	epollpair(true);
740	siocatmarkpair(false);
741
742	recvpair("o", 1, 1, MSG_OOB);
743	epollpair(false);
744	siocatmarkpair(false);
745
746	setinlinepair();
747
748	sendpair("world", 5, MSG_OOB);
749	epollpair(true);
750	siocatmarkpair(false);
751
752	recvpair("hell", 4, 4, 0);		/* Intentionally stop at ex-OOB. */
753	epollpair(true);
754	siocatmarkpair(false);
755}
756
757TEST_HARNESS_MAIN