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