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 __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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 913 TEST_F(msg_oob, zero_buf_oob) 914 { 915 sendpair("a", 1, MSG_OOB); 916 recvpair("", 0, 0, 0); 917 } 918 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 926 TEST_F(msg_oob, zero_buf_non_oob_oob) 927 { 928 sendpair("ab", 2, MSG_OOB); 929 recvpair("", 0, 0, 0); 930 } 931 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 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 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