File Index
Files and directories
Sign in
FILE

msg_oob.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/net/af_unix/msg_oob.c C
  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, bool is_sender)
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		int index = is_sender ? i * 2 : i * 2 + 1;
225
226		ret[i] = recv(self->fd[index], recv_buf[i], buf_len, flags);
227		recv_errno[i] = errno;
228	}
229
230	if (expected_len < 0) {
231		expected_errno = -expected_len;
232		expected_len = -1;
233	}
234
235	if (ret[0] != expected_len || recv_errno[0] != expected_errno) {
236		TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
237		TH_LOG("Expected:%s", expected_errno ? strerror(expected_errno) : expected_buf);
238
239		ASSERT_EQ(ret[0], expected_len);
240		ASSERT_EQ(recv_errno[0], expected_errno);
241	}
242
243	if (ret[0] != ret[1] || recv_errno[0] != recv_errno[1]) {
244		TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
245		TH_LOG("TCP     :%s", ret[1] < 0 ? strerror(recv_errno[1]) : recv_buf[1]);
246
247		printed = true;
248
249		if (self->tcp_compliant) {
250			ASSERT_EQ(ret[0], ret[1]);
251			ASSERT_EQ(recv_errno[0], recv_errno[1]);
252		}
253	}
254
255	if (expected_len >= 0) {
256		int cmp;
257
258		cmp = strncmp(expected_buf, recv_buf[0], expected_len);
259		if (cmp) {
260			TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
261			TH_LOG("Expected:%s", expected_errno ? strerror(expected_errno) : expected_buf);
262
263			ASSERT_EQ(cmp, 0);
264		}
265
266		cmp = strncmp(recv_buf[0], recv_buf[1], expected_len);
267		if (cmp) {
268			if (!printed) {
269				TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);
270				TH_LOG("TCP     :%s", ret[1] < 0 ? strerror(recv_errno[1]) : recv_buf[1]);
271			}
272
273			if (self->tcp_compliant)
274				ASSERT_EQ(cmp, 0);
275		}
276	}
277}
278
279static void __setinlinepair(struct __test_metadata *_metadata,
280			    FIXTURE_DATA(msg_oob) *self)
281{
282	int i, oob_inline = 1;
283
284	for (i = 0; i < 2; i++) {
285		int ret;
286
287		ret = setsockopt(self->fd[i * 2 + 1], SOL_SOCKET, SO_OOBINLINE,
288				 &oob_inline, sizeof(oob_inline));
289		ASSERT_EQ(ret, 0);
290	}
291}
292
293static void __siocatmarkpair(struct __test_metadata *_metadata,
294			     FIXTURE_DATA(msg_oob) *self,
295			     bool oob_head)
296{
297	int answ[2] = {};
298	int i;
299
300	for (i = 0; i < 2; i++) {
301		int ret;
302
303		ret = ioctl(self->fd[i * 2 + 1], SIOCATMARK, &answ[i]);
304		ASSERT_EQ(ret, 0);
305	}
306
307	ASSERT_EQ(answ[0], oob_head);
308
309	if (self->tcp_compliant)
310		ASSERT_EQ(answ[0], answ[1]);
311}
312
313static void __resetpair(struct __test_metadata *_metadata,
314			FIXTURE_DATA(msg_oob) *self,
315			const FIXTURE_VARIANT(msg_oob) *variant,
316			bool reset)
317{
318	int i;
319
320	for (i = 0; i < 2; i++)
321		close(self->fd[i * 2 + 1]);
322
323	__recvpair(_metadata, self, "", reset ? -ECONNRESET : 0, 1,
324		   variant->peek ? MSG_PEEK : 0, true);
325}
326
327#define sendpair(buf, len, flags)					\
328	__sendpair(_metadata, self, buf, len, flags)
329
330#define recvpair(expected_buf, expected_len, buf_len, flags)		\
331	do {								\
332		if (variant->peek)					\
333			__recvpair(_metadata, self,			\
334				   expected_buf, expected_len,		\
335				   buf_len, (flags) | MSG_PEEK, false);	\
336		__recvpair(_metadata, self,				\
337			   expected_buf, expected_len,			\
338			   buf_len, flags, false);			\
339	} while (0)
340
341#define epollpair(oob_remaining)					\
342	__epollpair(_metadata, self, oob_remaining)
343
344#define siocatmarkpair(oob_head)					\
345	__siocatmarkpair(_metadata, self, oob_head)
346
347#define setinlinepair()							\
348	__setinlinepair(_metadata, self)
349
350#define resetpair(reset)						\
351	__resetpair(_metadata, self, variant, reset)
352
353#define tcp_incompliant							\
354	for (self->tcp_compliant = false;				\
355	     self->tcp_compliant == false;				\
356	     self->tcp_compliant = true)
357
358TEST_F(msg_oob, non_oob)
359{
360	sendpair("x", 1, 0);
361	epollpair(false);
362	siocatmarkpair(false);
363
364	recvpair("", -EINVAL, 1, MSG_OOB);
365	epollpair(false);
366	siocatmarkpair(false);
367
368	resetpair(true);
369}
370
371TEST_F(msg_oob, non_oob_no_reset)
372{
373	sendpair("x", 1, 0);
374	epollpair(false);
375	siocatmarkpair(false);
376
377	recvpair("x", 1, 1, 0);
378	epollpair(false);
379	siocatmarkpair(false);
380
381	resetpair(false);
382}
383
384TEST_F(msg_oob, oob)
385{
386	sendpair("x", 1, MSG_OOB);
387	epollpair(true);
388	siocatmarkpair(true);
389
390	recvpair("x", 1, 1, MSG_OOB);
391	epollpair(false);
392	siocatmarkpair(true);
393
394	tcp_incompliant {
395		resetpair(false);		/* TCP sets -ECONNRESET for ex-OOB. */
396	}
397}
398
399TEST_F(msg_oob, oob_reset)
400{
401	sendpair("x", 1, MSG_OOB);
402	epollpair(true);
403	siocatmarkpair(true);
404
405	resetpair(true);
406}
407
408TEST_F(msg_oob, oob_drop)
409{
410	sendpair("x", 1, MSG_OOB);
411	epollpair(true);
412	siocatmarkpair(true);
413
414	recvpair("", -EAGAIN, 1, 0);		/* Drop OOB. */
415	epollpair(false);
416	siocatmarkpair(false);
417
418	recvpair("", -EINVAL, 1, MSG_OOB);
419	epollpair(false);
420	siocatmarkpair(false);
421
422	resetpair(false);
423}
424
425TEST_F(msg_oob, oob_ahead)
426{
427	sendpair("hello", 5, MSG_OOB);
428	epollpair(true);
429	siocatmarkpair(false);
430
431	recvpair("o", 1, 1, MSG_OOB);
432	epollpair(false);
433	siocatmarkpair(false);
434
435	recvpair("hell", 4, 4, 0);
436	epollpair(false);
437	siocatmarkpair(true);
438
439	tcp_incompliant {
440		resetpair(false);		/* TCP sets -ECONNRESET for ex-OOB. */
441	}
442}
443
444TEST_F(msg_oob, oob_break)
445{
446	sendpair("hello", 5, MSG_OOB);
447	epollpair(true);
448	siocatmarkpair(false);
449
450	recvpair("hell", 4, 5, 0);		/* Break at OOB even with enough buffer. */
451	epollpair(true);
452	siocatmarkpair(true);
453
454	recvpair("o", 1, 1, MSG_OOB);
455	epollpair(false);
456	siocatmarkpair(true);
457
458	recvpair("", -EAGAIN, 1, 0);
459	siocatmarkpair(false);
460
461	resetpair(false);
462}
463
464TEST_F(msg_oob, oob_ahead_break)
465{
466	sendpair("hello", 5, MSG_OOB);
467	epollpair(true);
468	siocatmarkpair(false);
469
470	sendpair("world", 5, 0);
471	epollpair(true);
472	siocatmarkpair(false);
473
474	recvpair("o", 1, 1, MSG_OOB);
475	epollpair(false);
476	siocatmarkpair(false);
477
478	recvpair("hell", 4, 9, 0);		/* Break at OOB even after it's recv()ed. */
479	epollpair(false);
480	siocatmarkpair(true);
481
482	recvpair("world", 5, 5, 0);
483	epollpair(false);
484	siocatmarkpair(false);
485
486	resetpair(false);
487}
488
489TEST_F(msg_oob, oob_break_drop)
490{
491	sendpair("hello", 5, MSG_OOB);
492	epollpair(true);
493	siocatmarkpair(false);
494
495	sendpair("world", 5, 0);
496	epollpair(true);
497	siocatmarkpair(false);
498
499	recvpair("hell", 4, 10, 0);		/* Break at OOB even with enough buffer. */
500	epollpair(true);
501	siocatmarkpair(true);
502
503	recvpair("world", 5, 10, 0);		/* Drop OOB and recv() the next skb. */
504	epollpair(false);
505	siocatmarkpair(false);
506
507	recvpair("", -EINVAL, 1, MSG_OOB);
508	epollpair(false);
509	siocatmarkpair(false);
510
511	resetpair(false);
512}
513
514TEST_F(msg_oob, ex_oob_break)
515{
516	sendpair("hello", 5, MSG_OOB);
517	epollpair(true);
518	siocatmarkpair(false);
519
520	sendpair("wor", 3, MSG_OOB);
521	epollpair(true);
522	siocatmarkpair(false);
523
524	sendpair("ld", 2, 0);
525	epollpair(true);
526	siocatmarkpair(false);
527
528	recvpair("hellowo", 7, 10, 0);		/* Break at OOB but not at ex-OOB. */
529	epollpair(true);
530	siocatmarkpair(true);
531
532	recvpair("r", 1, 1, MSG_OOB);
533	epollpair(false);
534	siocatmarkpair(true);
535
536	recvpair("ld", 2, 2, 0);
537	epollpair(false);
538	siocatmarkpair(false);
539
540	resetpair(false);
541}
542
543TEST_F(msg_oob, ex_oob_drop)
544{
545	sendpair("x", 1, MSG_OOB);
546	epollpair(true);
547	siocatmarkpair(true);
548
549	sendpair("y", 1, MSG_OOB);		/* TCP drops "x" at this moment. */
550	epollpair(true);
551
552	tcp_incompliant {
553		siocatmarkpair(false);
554
555		recvpair("x", 1, 1, 0);		/* TCP drops "y" by passing through it. */
556		epollpair(true);
557		siocatmarkpair(true);
558
559		recvpair("y", 1, 1, MSG_OOB);	/* TCP returns -EINVAL. */
560		epollpair(false);
561		siocatmarkpair(true);
562	}
563
564	resetpair(false);
565}
566
567TEST_F(msg_oob, ex_oob_drop_2)
568{
569	sendpair("x", 1, MSG_OOB);
570	epollpair(true);
571	siocatmarkpair(true);
572
573	sendpair("y", 1, MSG_OOB);		/* TCP drops "x" at this moment. */
574	epollpair(true);
575
576	tcp_incompliant {
577		siocatmarkpair(false);
578	}
579
580	recvpair("y", 1, 1, MSG_OOB);
581	epollpair(false);
582
583	tcp_incompliant {
584		siocatmarkpair(false);
585
586		recvpair("x", 1, 1, 0);		/* TCP returns -EAGAIN. */
587		epollpair(false);
588		siocatmarkpair(true);
589	}
590
591	resetpair(false);
592}
593
594TEST_F(msg_oob, ex_oob_oob)
595{
596	sendpair("x", 1, MSG_OOB);
597	epollpair(true);
598	siocatmarkpair(true);
599
600	recvpair("x", 1, 1, MSG_OOB);
601	epollpair(false);
602	siocatmarkpair(true);
603
604	sendpair("y", 1, MSG_OOB);
605	epollpair(true);
606	siocatmarkpair(true);
607
608	recvpair("", -EAGAIN, 1, 0);
609	epollpair(false);
610	siocatmarkpair(false);
611
612	recvpair("", -EINVAL, 1, MSG_OOB);
613	epollpair(false);
614	siocatmarkpair(false);
615
616	resetpair(false);
617}
618
619TEST_F(msg_oob, ex_oob_ex_oob)
620{
621	sendpair("x", 1, MSG_OOB);
622	epollpair(true);
623	siocatmarkpair(true);
624
625	recvpair("x", 1, 1, MSG_OOB);
626	epollpair(false);
627	siocatmarkpair(true);
628
629	sendpair("y", 1, MSG_OOB);
630	epollpair(true);
631	siocatmarkpair(true);
632
633	recvpair("y", 1, 1, MSG_OOB);
634	epollpair(false);
635	siocatmarkpair(true);
636
637	tcp_incompliant {
638		resetpair(false);		/* TCP sets -ECONNRESET for ex-OOB. */
639	}
640}
641
642TEST_F(msg_oob, ex_oob_ex_oob_oob)
643{
644	sendpair("x", 1, MSG_OOB);
645	epollpair(true);
646	siocatmarkpair(true);
647
648	recvpair("x", 1, 1, MSG_OOB);
649	epollpair(false);
650	siocatmarkpair(true);
651
652	sendpair("y", 1, MSG_OOB);
653	epollpair(true);
654	siocatmarkpair(true);
655
656	recvpair("y", 1, 1, MSG_OOB);
657	epollpair(false);
658	siocatmarkpair(true);
659
660	sendpair("z", 1, MSG_OOB);
661	epollpair(true);
662	siocatmarkpair(true);
663}
664
665TEST_F(msg_oob, ex_oob_ahead_break)
666{
667	sendpair("hello", 5, MSG_OOB);
668	epollpair(true);
669	siocatmarkpair(false);
670
671	sendpair("wor", 3, MSG_OOB);
672	epollpair(true);
673	siocatmarkpair(false);
674
675	recvpair("r", 1, 1, MSG_OOB);
676	epollpair(false);
677	siocatmarkpair(false);
678
679	sendpair("ld", 2, MSG_OOB);
680	epollpair(true);
681	siocatmarkpair(false);
682
683	tcp_incompliant {
684		recvpair("hellowol", 8, 10, 0);	/* TCP recv()s "helloworl", why "r" ?? */
685	}
686
687	epollpair(true);
688	siocatmarkpair(true);
689
690	recvpair("d", 1, 1, MSG_OOB);
691	epollpair(false);
692	siocatmarkpair(true);
693
694	tcp_incompliant {
695		resetpair(false);		/* TCP sets -ECONNRESET for ex-OOB. */
696	}
697}
698
699TEST_F(msg_oob, ex_oob_siocatmark)
700{
701	sendpair("hello", 5, MSG_OOB);
702	epollpair(true);
703	siocatmarkpair(false);
704
705	recvpair("o", 1, 1, MSG_OOB);
706	epollpair(false);
707	siocatmarkpair(false);
708
709	sendpair("world", 5, MSG_OOB);
710	epollpair(true);
711	siocatmarkpair(false);
712
713	recvpair("hell", 4, 4, 0);		/* Intentionally stop at ex-OOB. */
714	epollpair(true);
715	siocatmarkpair(false);
716
717	resetpair(true);
718}
719
720TEST_F(msg_oob, inline_oob)
721{
722	setinlinepair();
723
724	sendpair("x", 1, MSG_OOB);
725	epollpair(true);
726	siocatmarkpair(true);
727
728	recvpair("", -EINVAL, 1, MSG_OOB);
729	epollpair(true);
730	siocatmarkpair(true);
731
732	recvpair("x", 1, 1, 0);
733	epollpair(false);
734	siocatmarkpair(false);
735
736	resetpair(false);
737}
738
739TEST_F(msg_oob, inline_oob_break)
740{
741	setinlinepair();
742
743	sendpair("hello", 5, MSG_OOB);
744	epollpair(true);
745	siocatmarkpair(false);
746
747	recvpair("", -EINVAL, 1, MSG_OOB);
748	epollpair(true);
749	siocatmarkpair(false);
750
751	recvpair("hell", 4, 5, 0);		/* Break at OOB but not at ex-OOB. */
752	epollpair(true);
753	siocatmarkpair(true);
754
755	recvpair("o", 1, 1, 0);
756	epollpair(false);
757	siocatmarkpair(false);
758
759	resetpair(false);
760}
761
762TEST_F(msg_oob, inline_oob_ahead_break)
763{
764	sendpair("hello", 5, MSG_OOB);
765	epollpair(true);
766	siocatmarkpair(false);
767
768	sendpair("world", 5, 0);
769	epollpair(true);
770	siocatmarkpair(false);
771
772	recvpair("o", 1, 1, MSG_OOB);
773	epollpair(false);
774	siocatmarkpair(false);
775
776	setinlinepair();
777
778	recvpair("hell", 4, 9, 0);		/* Break at OOB even with enough buffer. */
779	epollpair(false);
780	siocatmarkpair(true);
781
782	tcp_incompliant {
783		recvpair("world", 5, 6, 0);	/* TCP recv()s "oworld", ... "o" ??? */
784	}
785
786	epollpair(false);
787	siocatmarkpair(false);
788
789	resetpair(false);
790}
791
792TEST_F(msg_oob, inline_ex_oob_break)
793{
794	sendpair("hello", 5, MSG_OOB);
795	epollpair(true);
796	siocatmarkpair(false);
797
798	sendpair("wor", 3, MSG_OOB);
799	epollpair(true);
800	siocatmarkpair(false);
801
802	sendpair("ld", 2, 0);
803	epollpair(true);
804	siocatmarkpair(false);
805
806	setinlinepair();
807
808	recvpair("hellowo", 7, 10, 0);		/* Break at OOB but not at ex-OOB. */
809	epollpair(true);
810	siocatmarkpair(true);
811
812	recvpair("rld", 3, 3, 0);
813	epollpair(false);
814	siocatmarkpair(false);
815
816	resetpair(false);
817}
818
819TEST_F(msg_oob, inline_ex_oob_no_drop)
820{
821	sendpair("x", 1, MSG_OOB);
822	epollpair(true);
823	siocatmarkpair(true);
824
825	setinlinepair();
826
827	sendpair("y", 1, MSG_OOB);		/* TCP does NOT drops "x" at this moment. */
828	epollpair(true);
829	siocatmarkpair(false);
830
831	recvpair("x", 1, 1, 0);
832	epollpair(true);
833	siocatmarkpair(true);
834
835	recvpair("y", 1, 1, 0);
836	epollpair(false);
837	siocatmarkpair(false);
838
839	resetpair(false);
840}
841
842TEST_F(msg_oob, inline_ex_oob_drop)
843{
844	sendpair("x", 1, MSG_OOB);
845	epollpair(true);
846	siocatmarkpair(true);
847
848	sendpair("y", 1, MSG_OOB);		/* TCP drops "x" at this moment. */
849	epollpair(true);
850
851	setinlinepair();
852
853	tcp_incompliant {
854		siocatmarkpair(false);
855
856		recvpair("x", 1, 1, 0);		/* TCP recv()s "y". */
857		epollpair(true);
858		siocatmarkpair(true);
859
860		recvpair("y", 1, 1, 0);		/* TCP returns -EAGAIN. */
861		epollpair(false);
862		siocatmarkpair(false);
863	}
864
865	resetpair(false);
866}
867
868TEST_F(msg_oob, inline_ex_oob_siocatmark)
869{
870	sendpair("hello", 5, MSG_OOB);
871	epollpair(true);
872	siocatmarkpair(false);
873
874	recvpair("o", 1, 1, MSG_OOB);
875	epollpair(false);
876	siocatmarkpair(false);
877
878	setinlinepair();
879
880	sendpair("world", 5, MSG_OOB);
881	epollpair(true);
882	siocatmarkpair(false);
883
884	recvpair("hell", 4, 4, 0);		/* Intentionally stop at ex-OOB. */
885	epollpair(true);
886	siocatmarkpair(false);
887
888	resetpair(true);
889}
890
891TEST_HARNESS_MAIN
~/ Read-only file preview.