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