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 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 32 FIXTURE_VARIANT(msg_oob) 33 { 34 bool peek; 35 }; 36 37 FIXTURE_VARIANT_ADD(msg_oob, no_peek) 38 { 39 .peek = false, 40 }; 41 42 FIXTURE_VARIANT_ADD(msg_oob, peek) 43 { 44 .peek = true 45 }; 46 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 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 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 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 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 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 154 FIXTURE_TEARDOWN(msg_oob) 155 { 156 close_sockets(self); 157 } 158 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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