Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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