xref: /linux/tools/testing/selftests/net/af_unix/msg_oob.c (revision e34a79b96ab9d49ed8b605fee11099cf3efbb428)
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 
FIXTURE(msg_oob)18 FIXTURE(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 
FIXTURE_VARIANT(msg_oob)32 FIXTURE_VARIANT(msg_oob)
33 {
34 	bool peek;
35 };
36 
FIXTURE_VARIANT_ADD(msg_oob,no_peek)37 FIXTURE_VARIANT_ADD(msg_oob, no_peek)
38 {
39 	.peek = false,
40 };
41 
FIXTURE_VARIANT_ADD(msg_oob,peek)42 FIXTURE_VARIANT_ADD(msg_oob, peek)
43 {
44 	.peek = true
45 };
46 
create_unix_socketpair(struct __test_metadata * _metadata,FIXTURE_DATA (msg_oob)* self)47 static 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 
create_tcp_socketpair(struct __test_metadata * _metadata,FIXTURE_DATA (msg_oob)* self)56 static 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 
setup_sigurg(struct __test_metadata * _metadata,FIXTURE_DATA (msg_oob)* self)87 static 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 
setup_epollpri(struct __test_metadata * _metadata,FIXTURE_DATA (msg_oob)* self)116 static 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 
close_sockets(FIXTURE_DATA (msg_oob)* self)135 static 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 
FIXTURE_SETUP(msg_oob)143 FIXTURE_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 
FIXTURE_TEARDOWN(msg_oob)154 FIXTURE_TEARDOWN(msg_oob)
155 {
156 	close_sockets(self);
157 }
158 
__epollpair(struct __test_metadata * _metadata,FIXTURE_DATA (msg_oob)* self,bool oob_remaining)159 static 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 
__sendpair(struct __test_metadata * _metadata,FIXTURE_DATA (msg_oob)* self,const void * buf,size_t len,int flags)182 static 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 
__recvpair(struct __test_metadata * _metadata,FIXTURE_DATA (msg_oob)* self,const char * expected_buf,int expected_len,int buf_len,int flags,bool is_sender)210 static 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 
__setinlinepair(struct __test_metadata * _metadata,FIXTURE_DATA (msg_oob)* self)279 static 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 
__siocatmarkpair(struct __test_metadata * _metadata,FIXTURE_DATA (msg_oob)* self,bool oob_head)293 static 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 
__resetpair(struct __test_metadata * _metadata,FIXTURE_DATA (msg_oob)* self,const FIXTURE_VARIANT (msg_oob)* variant,bool reset)313 static 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 
TEST_F(msg_oob,non_oob)358 TEST_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 
TEST_F(msg_oob,non_oob_no_reset)371 TEST_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 
TEST_F(msg_oob,oob)384 TEST_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 
TEST_F(msg_oob,oob_reset)399 TEST_F(msg_oob, oob_reset)
400 {
401 	sendpair("x", 1, MSG_OOB);
402 	epollpair(true);
403 	siocatmarkpair(true);
404 
405 	resetpair(true);
406 }
407 
TEST_F(msg_oob,oob_drop)408 TEST_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 
TEST_F(msg_oob,oob_ahead)425 TEST_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 
TEST_F(msg_oob,oob_break)444 TEST_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 
TEST_F(msg_oob,oob_ahead_break)464 TEST_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 
TEST_F(msg_oob,oob_break_drop)489 TEST_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 
TEST_F(msg_oob,ex_oob_break)514 TEST_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 
TEST_F(msg_oob,ex_oob_drop)543 TEST_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 
TEST_F(msg_oob,ex_oob_drop_2)567 TEST_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 
TEST_F(msg_oob,ex_oob_oob)594 TEST_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 
TEST_F(msg_oob,ex_oob_ex_oob)619 TEST_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 
TEST_F(msg_oob,ex_oob_ex_oob_oob)642 TEST_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 
TEST_F(msg_oob,ex_oob_ahead_break)665 TEST_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 
TEST_F(msg_oob,ex_oob_siocatmark)699 TEST_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 
TEST_F(msg_oob,inline_oob)720 TEST_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 
TEST_F(msg_oob,inline_oob_break)739 TEST_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 
TEST_F(msg_oob,inline_oob_ahead_break)762 TEST_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 
TEST_F(msg_oob,inline_ex_oob_break)792 TEST_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 
TEST_F(msg_oob,inline_ex_oob_no_drop)819 TEST_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 
TEST_F(msg_oob,inline_ex_oob_drop)842 TEST_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 
TEST_F(msg_oob,inline_ex_oob_siocatmark)868 TEST_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 
891 TEST_HARNESS_MAIN
892