1 /* $OpenBSD: select_iocond.c,v 1.2 2021/12/08 13:22:53 visa Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Visa Hankala 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Test select(2) with various I/O conditions. 21 */ 22 23 #include <sys/types.h> 24 #include <sys/ioctl.h> 25 #include <sys/select.h> 26 #include <sys/socket.h> 27 #include <sys/stat.h> 28 #include <sys/wait.h> 29 #include <netinet/in.h> 30 #include <netinet/tcp.h> 31 #include <arpa/inet.h> 32 33 #include <assert.h> 34 #include <err.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #if defined(__OpenBSD__) 43 /* for pty */ 44 #include <termios.h> 45 #include <util.h> 46 #endif 47 48 #if !defined(__linux__) 49 #define HAVE_SOCKADDR_LEN 1 50 #endif 51 52 #define MIN(a, b) ((a) <= (b) ? (a) : (b)) 53 54 #define TEST_FIFO_NAME "iocond_fifo" 55 56 enum filetype { 57 FTYPE_NONE, 58 FTYPE_FIFO, 59 FTYPE_PIPE, 60 FTYPE_PTY, 61 FTYPE_SOCKET_TCP, 62 FTYPE_SOCKET_UDP, 63 FTYPE_SOCKET_UNIX, 64 }; 65 66 static struct { 67 const char *name; 68 enum filetype type; 69 } filetypes[] = { 70 { "fifo", FTYPE_FIFO }, 71 { "pipe", FTYPE_PIPE }, 72 #if defined(__OpenBSD__) 73 { "pty", FTYPE_PTY }, 74 #endif 75 { "socket-tcp", FTYPE_SOCKET_TCP }, 76 { "socket-udp", FTYPE_SOCKET_UDP }, 77 { "socket-unix", FTYPE_SOCKET_UNIX }, 78 }; 79 80 static enum filetype filetype = FTYPE_NONE; 81 82 static void cleanup(void); 83 static void proc_barrier(int); 84 static void proc_child(int, int); 85 static void proc_parent(int, int); 86 87 int 88 main(int argc, char *argv[]) 89 { 90 const char *ftname; 91 int bfd[2], fds[2]; 92 int child_fd = -1; 93 int parent_fd = -1; 94 int sock = -1; 95 unsigned int i; 96 pid_t pid; 97 98 /* Enforce test timeout. */ 99 alarm(10); 100 101 if (argc != 2) { 102 fprintf(stderr, "usage: %s filetype\n", argv[0]); 103 return 1; 104 } 105 ftname = argv[1]; 106 107 for (i = 0; i < sizeof(filetypes) / sizeof(filetypes[0]); i++) { 108 if (strcmp(ftname, filetypes[i].name) == 0) { 109 filetype = filetypes[i].type; 110 break; 111 } 112 } 113 if (filetype == FTYPE_NONE) 114 errx(1, "unknown filetype"); 115 116 /* Open barrier sockets. */ 117 if (socketpair(AF_UNIX, SOCK_STREAM, 0, bfd) == -1) 118 err(1, "socketpair"); 119 120 atexit(cleanup); 121 122 switch (filetype) { 123 case FTYPE_FIFO: 124 (void)unlink(TEST_FIFO_NAME); 125 if (mkfifo(TEST_FIFO_NAME, 0644) == -1) 126 err(1, "mkfifo"); 127 break; 128 case FTYPE_PIPE: 129 if (pipe(fds) == -1) 130 err(1, "pipe"); 131 parent_fd = fds[0]; 132 child_fd = fds[1]; 133 break; 134 #if defined(__OpenBSD__) 135 case FTYPE_PTY: 136 if (openpty(&parent_fd, &child_fd, NULL, NULL, NULL) == -1) 137 err(1, "openpty"); 138 break; 139 #endif 140 case FTYPE_SOCKET_TCP: { 141 struct sockaddr_in inaddr; 142 143 sock = socket(AF_INET, SOCK_STREAM, 0); 144 145 memset(&inaddr, 0, sizeof(inaddr)); 146 #ifdef HAVE_SOCKADDR_LEN 147 inaddr.sin_len = sizeof(inaddr); 148 #endif 149 inaddr.sin_family = AF_INET; 150 inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 151 if (bind(sock, (struct sockaddr *)&inaddr, 152 sizeof(inaddr)) == -1) 153 err(1, "bind"); 154 if (listen(sock, 1) == -1) 155 err(1, "listen"); 156 break; 157 } 158 case FTYPE_SOCKET_UDP: { 159 struct sockaddr_in inaddr; 160 161 sock = socket(AF_INET, SOCK_DGRAM, 0); 162 163 memset(&inaddr, 0, sizeof(inaddr)); 164 #ifdef HAVE_SOCKADDR_LEN 165 inaddr.sin_len = sizeof(inaddr); 166 #endif 167 inaddr.sin_family = AF_INET; 168 inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 169 if (bind(sock, (struct sockaddr *)&inaddr, 170 sizeof(inaddr)) == -1) 171 err(1, "bind"); 172 break; 173 } 174 case FTYPE_SOCKET_UNIX: 175 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) 176 err(1, "socketpair"); 177 parent_fd = fds[0]; 178 child_fd = fds[1]; 179 break; 180 default: 181 errx(1, "unhandled filetype"); 182 } 183 184 pid = fork(); 185 switch (pid) { 186 case -1: 187 err(1, "fork"); 188 case 0: 189 switch (filetype) { 190 case FTYPE_FIFO: 191 child_fd = open(TEST_FIFO_NAME, O_WRONLY); 192 if (child_fd == -1) 193 err(1, "child: open"); 194 break; 195 case FTYPE_SOCKET_TCP: { 196 struct sockaddr_in inaddr; 197 socklen_t inaddrlen; 198 int on = 1; 199 200 /* Get the bound address. */ 201 inaddrlen = sizeof(inaddr); 202 if (getsockname(sock, (struct sockaddr *)&inaddr, 203 &inaddrlen) == -1) 204 err(1, "child: getsockname"); 205 206 child_fd = socket(AF_INET, SOCK_STREAM, 0); 207 if (child_fd == -1) 208 err(1, "child: socket"); 209 if (connect(child_fd, (struct sockaddr *)&inaddr, 210 sizeof(inaddr)) == -1) 211 err(1, "child: connect"); 212 if (setsockopt(child_fd, IPPROTO_TCP, TCP_NODELAY, 213 &on, sizeof(on)) == -1) 214 err(1, "child: setsockopt(TCP_NODELAY)"); 215 break; 216 } 217 case FTYPE_SOCKET_UDP: { 218 struct sockaddr_in inaddr; 219 socklen_t inaddrlen; 220 221 /* Get the bound address. */ 222 inaddrlen = sizeof(inaddr); 223 if (getsockname(sock, (struct sockaddr *)&inaddr, 224 &inaddrlen) == -1) 225 err(1, "child: getsockname"); 226 227 child_fd = socket(AF_INET, SOCK_DGRAM, 0); 228 if (child_fd == -1) 229 err(1, "child: socket"); 230 if (connect(child_fd, (struct sockaddr *)&inaddr, 231 sizeof(inaddr)) == -1) 232 err(1, "child: connect"); 233 break; 234 } 235 default: 236 break; 237 } 238 if (parent_fd != -1) { 239 close(parent_fd); 240 parent_fd = -1; 241 } 242 if (sock != -1) { 243 close(sock); 244 sock = -1; 245 } 246 proc_child(child_fd, bfd[1]); 247 _exit(0); 248 default: 249 switch (filetype) { 250 case FTYPE_FIFO: 251 parent_fd = open(TEST_FIFO_NAME, O_RDONLY); 252 if (parent_fd == -1) 253 err(1, "parent: open"); 254 break; 255 case FTYPE_SOCKET_TCP: { 256 int on = 1; 257 258 parent_fd = accept(sock, NULL, NULL); 259 if (parent_fd == -1) 260 err(1, "parent: accept"); 261 if (setsockopt(parent_fd, IPPROTO_TCP, TCP_NODELAY, 262 &on, sizeof(on)) == -1) 263 err(1, "parent: setsockopt(TCP_NODELAY)"); 264 break; 265 } 266 case FTYPE_SOCKET_UDP: 267 parent_fd = sock; 268 sock = -1; 269 break; 270 default: 271 break; 272 } 273 if (child_fd != -1) { 274 close(child_fd); 275 child_fd = -1; 276 } 277 if (sock != -1) { 278 close(sock); 279 sock = -1; 280 } 281 proc_parent(parent_fd, bfd[0]); 282 break; 283 } 284 285 if (waitpid(pid, NULL, 0) == -1) 286 err(1, "waitpid"); 287 288 return 0; 289 } 290 291 static void 292 cleanup(void) 293 { 294 if (filetype == FTYPE_FIFO) 295 (void)unlink(TEST_FIFO_NAME); 296 } 297 298 static void 299 proc_barrier(int fd) 300 { 301 int ret; 302 char b = 0; 303 304 ret = write(fd, &b, 1); 305 assert(ret == 1); 306 ret = read(fd, &b, 1); 307 assert(ret == 1); 308 } 309 310 static void 311 fdset_init(fd_set *rfd, fd_set *wfd, fd_set *efd, int fd) 312 { 313 FD_ZERO(rfd); 314 FD_ZERO(wfd); 315 FD_ZERO(efd); 316 FD_SET(fd, rfd); 317 FD_SET(fd, wfd); 318 FD_SET(fd, efd); 319 } 320 321 static void 322 proc_child(int fd, int bfd) 323 { 324 char buf[1024]; 325 fd_set efd, rfd, wfd; 326 struct timeval tv = { 0, 1 }; 327 struct timeval zerotv = { 0, 0 }; 328 size_t nbytes; 329 int ret; 330 char b = 0; 331 332 proc_barrier(bfd); 333 334 fdset_init(&rfd, &wfd, &efd, fd); 335 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 336 assert(ret == 1); 337 assert(FD_ISSET(fd, &rfd) == 0); 338 assert(FD_ISSET(fd, &wfd) != 0); 339 assert(FD_ISSET(fd, &efd) == 0); 340 341 proc_barrier(bfd); 342 343 ret = write(fd, &b, 1); 344 assert(ret == 1); 345 346 proc_barrier(bfd); 347 348 fdset_init(&rfd, &wfd, &efd, fd); 349 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 350 assert(ret == 1); 351 assert(FD_ISSET(fd, &rfd) == 0); 352 assert(FD_ISSET(fd, &wfd) != 0); 353 assert(FD_ISSET(fd, &efd) == 0); 354 355 proc_barrier(bfd); 356 357 /* parent: read */ 358 359 proc_barrier(bfd); 360 361 if (filetype != FTYPE_SOCKET_UDP) { 362 /* write until full */ 363 memset(buf, 0, sizeof(buf)); 364 nbytes = 0; 365 for (;;) { 366 FD_ZERO(&wfd); 367 FD_SET(fd, &wfd); 368 ret = select(fd + 1, NULL, &wfd, NULL, &zerotv); 369 if (ret == 0) 370 break; 371 assert(ret == 1); 372 assert(FD_ISSET(fd, &wfd) != 0); 373 ret = write(fd, buf, sizeof(buf)); 374 assert(ret > 0); 375 nbytes += ret; 376 } 377 ret = write(bfd, &nbytes, sizeof(nbytes)); 378 assert(ret == sizeof(nbytes)); 379 380 proc_barrier(bfd); 381 382 /* parent: read until empty */ 383 } 384 385 proc_barrier(bfd); 386 387 /* Test out-of-band data. */ 388 switch (filetype) { 389 #if defined(__OpenBSD__) 390 case FTYPE_PTY: { 391 /* parent: enable user ioctl command mode */ 392 393 proc_barrier(bfd); 394 395 ret = write(fd, &b, 1); 396 assert(ret == 1); 397 398 if (ioctl(fd, UIOCCMD(42), NULL) == -1) 399 err(1, "child: ioctl(UIOCCMD)"); 400 401 ret = write(fd, &b, 1); 402 assert(ret == 1); 403 404 proc_barrier(bfd); 405 406 /* parent: read, and disable user ioctl command mode */ 407 408 proc_barrier(bfd); 409 break; 410 } 411 #endif /* __OpenBSD__ */ 412 413 case FTYPE_SOCKET_TCP: 414 ret = send(fd, &b, 2, 0); 415 assert(ret == 2); 416 417 ret = send(fd, &b, 1, MSG_OOB); 418 assert(ret == 1); 419 420 ret = send(fd, &b, 3, 0); 421 assert(ret == 3); 422 423 proc_barrier(bfd); 424 425 /* parent: read */ 426 427 proc_barrier(bfd); 428 break; 429 430 default: 431 break; 432 } 433 434 /* Test socket shutdown. */ 435 switch (filetype) { 436 case FTYPE_SOCKET_TCP: 437 case FTYPE_SOCKET_UNIX: 438 ret = write(fd, &b, 1); 439 assert(ret == 1); 440 441 ret = shutdown(fd, SHUT_WR); 442 assert(ret == 0); 443 444 proc_barrier(bfd); 445 446 /* parent: read and shutdown */ 447 448 proc_barrier(bfd); 449 450 /* Let inet sockets take their time. */ 451 if (filetype == FTYPE_SOCKET_TCP) 452 usleep(10000); 453 454 fdset_init(&rfd, &wfd, &efd, fd); 455 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 456 assert(ret == 2); 457 assert(FD_ISSET(fd, &rfd) != 0); 458 assert(FD_ISSET(fd, &wfd) != 0); 459 assert(FD_ISSET(fd, &efd) == 0); 460 break; 461 462 case FTYPE_FIFO: 463 case FTYPE_PIPE: 464 case FTYPE_PTY: 465 case FTYPE_SOCKET_UDP: 466 default: 467 break; 468 } 469 470 proc_barrier(bfd); 471 472 close(fd); 473 474 proc_barrier(bfd); 475 476 fdset_init(&rfd, &wfd, &efd, fd); 477 ret = select(fd + 1, &rfd, &wfd, &efd, NULL); 478 assert(ret == -1); 479 assert(errno == EBADF); 480 } 481 482 static void 483 proc_parent(int fd, int bfd) 484 { 485 char buf[1024]; 486 fd_set efd, rfd, wfd; 487 struct timeval tv = { 0, 1 }; 488 struct timeval zerotv = { 0, 0 }; 489 size_t nbytes; 490 int ret, retries; 491 char b = 0; 492 493 proc_barrier(bfd); 494 495 fdset_init(&rfd, &wfd, &efd, fd); 496 if (filetype == FTYPE_FIFO || filetype == FTYPE_PIPE) 497 FD_CLR(fd, &wfd); 498 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 499 switch (filetype) { 500 case FTYPE_FIFO: 501 case FTYPE_PIPE: 502 assert(ret == 0); 503 assert(FD_ISSET(fd, &rfd) == 0); 504 assert(FD_ISSET(fd, &wfd) == 0); 505 assert(FD_ISSET(fd, &efd) == 0); 506 break; 507 default: 508 assert(ret == 1); 509 assert(FD_ISSET(fd, &rfd) == 0); 510 assert(FD_ISSET(fd, &wfd) != 0); 511 assert(FD_ISSET(fd, &efd) == 0); 512 break; 513 } 514 515 proc_barrier(bfd); 516 517 /* child: write */ 518 519 proc_barrier(bfd); 520 521 /* Let inet sockets take their time. */ 522 if (filetype == FTYPE_SOCKET_TCP || 523 filetype == FTYPE_SOCKET_UDP) 524 usleep(10000); 525 526 fdset_init(&rfd, &wfd, &efd, fd); 527 if (filetype == FTYPE_FIFO || filetype == FTYPE_PIPE) 528 FD_CLR(fd, &wfd); 529 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 530 switch (filetype) { 531 case FTYPE_FIFO: 532 case FTYPE_PIPE: 533 assert(ret == 1); 534 assert(FD_ISSET(fd, &rfd) != 0); 535 assert(FD_ISSET(fd, &wfd) == 0); 536 assert(FD_ISSET(fd, &efd) == 0); 537 break; 538 case FTYPE_PTY: 539 case FTYPE_SOCKET_TCP: 540 case FTYPE_SOCKET_UDP: 541 case FTYPE_SOCKET_UNIX: 542 assert(ret == 2); 543 assert(FD_ISSET(fd, &rfd) != 0); 544 assert(FD_ISSET(fd, &wfd) != 0); 545 assert(FD_ISSET(fd, &efd) == 0); 546 break; 547 default: 548 assert(0); 549 } 550 551 proc_barrier(bfd); 552 553 ret = read(fd, &b, 1); 554 assert(ret == 1); 555 556 fdset_init(&rfd, &wfd, &efd, fd); 557 ret = select(fd + 1, &rfd, NULL, NULL, &tv); 558 assert(ret == 0); 559 560 proc_barrier(bfd); 561 562 if (filetype != FTYPE_SOCKET_UDP) { 563 /* child: write until full */ 564 nbytes = 0; 565 ret = read(bfd, &nbytes, sizeof(nbytes)); 566 assert(ret == sizeof(nbytes)); 567 568 proc_barrier(bfd); 569 570 /* read until empty */ 571 retries = 5; 572 while (retries > 0) { 573 FD_ZERO(&rfd); 574 FD_SET(fd, &rfd); 575 ret = select(fd + 1, &rfd, NULL, NULL, &zerotv); 576 if (ret == 0) { 577 retries--; 578 /* Let inet sockets take their time. */ 579 if (nbytes > 0 && retries > 0) 580 usleep(10000); 581 continue; 582 } 583 assert(ret == 1); 584 assert(FD_ISSET(fd, &rfd) != 0); 585 assert(nbytes > 0); 586 ret = read(fd, buf, MIN(sizeof(buf), nbytes)); 587 assert(ret > 0); 588 nbytes -= ret; 589 } 590 assert(nbytes == 0); 591 } 592 593 proc_barrier(bfd); 594 595 /* Test out-of-band data. */ 596 switch (filetype) { 597 #if defined(__OpenBSD__) 598 case FTYPE_PTY: { 599 int off = 0; 600 int on = 1; 601 602 if (ioctl(fd, TIOCUCNTL, &on) == -1) 603 err(1, "parent: ioctl(TIOCUCNTL, 1)"); 604 605 proc_barrier(bfd); 606 607 /* child: write */ 608 609 proc_barrier(bfd); 610 611 fdset_init(&rfd, &wfd, &efd, fd); 612 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 613 assert(ret == 3); 614 assert(FD_ISSET(fd, &rfd) != 0); 615 assert(FD_ISSET(fd, &wfd) != 0); 616 assert(FD_ISSET(fd, &efd) != 0); 617 618 /* Read out-of-band data. */ 619 ret = read(fd, buf, sizeof(buf)); 620 assert(ret == 1); 621 622 fdset_init(&rfd, &wfd, &efd, fd); 623 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 624 assert(ret == 2); 625 assert(FD_ISSET(fd, &rfd) != 0); 626 assert(FD_ISSET(fd, &wfd) != 0); 627 assert(FD_ISSET(fd, &efd) == 0); 628 629 /* Read normal data. */ 630 ret = read(fd, buf, sizeof(buf)); 631 assert(ret == 3); 632 633 fdset_init(&rfd, &wfd, &efd, fd); 634 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 635 assert(ret == 1); 636 assert(FD_ISSET(fd, &rfd) == 0); 637 assert(FD_ISSET(fd, &wfd) != 0); 638 assert(FD_ISSET(fd, &efd) == 0); 639 640 if (ioctl(fd, TIOCUCNTL, &off) == -1) 641 err(1, "parent: ioctl(TIOCUCNTL, 0)"); 642 643 proc_barrier(bfd); 644 break; 645 } 646 #endif /* __OpenBSD__ */ 647 648 case FTYPE_SOCKET_TCP: { 649 int atmark; 650 int on = 1; 651 652 /* child: write */ 653 654 if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &on, 655 sizeof(on)) == -1) 656 err(1, "parent: setsockopt(SO_OOBINLINE)"); 657 658 proc_barrier(bfd); 659 660 fdset_init(&rfd, &wfd, &efd, fd); 661 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 662 assert(ret == 3); 663 assert(FD_ISSET(fd, &rfd) != 0); 664 assert(FD_ISSET(fd, &wfd) != 0); 665 assert(FD_ISSET(fd, &efd) != 0); 666 667 /* Read normal data. */ 668 atmark = 0; 669 if (ioctl(fd, SIOCATMARK, &atmark) == -1) 670 err(1, "parent: ioctl(SIOCATMARK)"); 671 assert(atmark == 0); 672 ret = recv(fd, buf, sizeof(buf), 0); 673 assert(ret == 2); 674 675 fdset_init(&rfd, &wfd, &efd, fd); 676 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 677 assert(ret == 3); 678 assert(FD_ISSET(fd, &rfd) != 0); 679 assert(FD_ISSET(fd, &wfd) != 0); 680 assert(FD_ISSET(fd, &efd) != 0); 681 682 /* Read out-of-band data. */ 683 atmark = 0; 684 if (ioctl(fd, SIOCATMARK, &atmark) == -1) 685 err(1, "parent: ioctl(SIOCATMARK)"); 686 assert(atmark != 0); 687 ret = recv(fd, &b, 1, 0); 688 assert(ret == 1); 689 690 fdset_init(&rfd, &wfd, &efd, fd); 691 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 692 assert(ret == 2); 693 assert(FD_ISSET(fd, &rfd) != 0); 694 assert(FD_ISSET(fd, &wfd) != 0); 695 assert(FD_ISSET(fd, &efd) == 0); 696 697 /* Read normal data. */ 698 atmark = 0; 699 if (ioctl(fd, SIOCATMARK, &atmark) == -1) 700 err(1, "parent: ioctl(SIOCATMARK)"); 701 assert(atmark == 0); 702 ret = recv(fd, buf, sizeof(buf), 0); 703 assert(ret == 3); 704 705 fdset_init(&rfd, &wfd, &efd, fd); 706 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 707 assert(ret == 1); 708 assert(FD_ISSET(fd, &rfd) == 0); 709 assert(FD_ISSET(fd, &wfd) != 0); 710 assert(FD_ISSET(fd, &efd) == 0); 711 712 proc_barrier(bfd); 713 break; 714 } 715 716 default: 717 break; 718 } 719 720 /* Test socket shutdown. */ 721 switch (filetype) { 722 case FTYPE_SOCKET_TCP: 723 case FTYPE_SOCKET_UNIX: 724 /* child: write and shutdown */ 725 726 proc_barrier(bfd); 727 728 /* Let inet sockets take their time. */ 729 if (filetype == FTYPE_SOCKET_TCP) 730 usleep(10000); 731 732 fdset_init(&rfd, &wfd, &efd, fd); 733 ret = select(fd + 1, &rfd, NULL, NULL, &tv); 734 assert(ret == 1); 735 assert(FD_ISSET(fd, &rfd) != 0); 736 737 ret = read(fd, &b, 1); 738 assert(ret == 1); 739 740 fdset_init(&rfd, &wfd, &efd, fd); 741 ret = select(fd + 1, &rfd, NULL, NULL, &tv); 742 assert(ret == 1); 743 assert(FD_ISSET(fd, &rfd) != 0); 744 745 ret = read(fd, &b, 1); 746 assert(ret == 0); 747 748 ret = shutdown(fd, SHUT_WR); 749 assert(ret == 0); 750 751 proc_barrier(bfd); 752 753 fdset_init(&rfd, &wfd, &efd, fd); 754 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 755 assert(ret == 2); 756 assert(FD_ISSET(fd, &rfd) != 0); 757 assert(FD_ISSET(fd, &wfd) != 0); 758 assert(FD_ISSET(fd, &efd) == 0); 759 break; 760 761 case FTYPE_FIFO: 762 case FTYPE_PIPE: 763 case FTYPE_PTY: 764 case FTYPE_SOCKET_UDP: 765 default: 766 break; 767 } 768 769 proc_barrier(bfd); 770 771 /* child: close */ 772 773 proc_barrier(bfd); 774 775 fdset_init(&rfd, &wfd, &efd, fd); 776 if (filetype == FTYPE_FIFO || filetype == FTYPE_PIPE) 777 FD_CLR(fd, &wfd); 778 ret = select(fd + 1, &rfd, &wfd, &efd, &tv); 779 switch (filetype) { 780 case FTYPE_FIFO: 781 case FTYPE_PIPE: 782 assert(ret == 1); 783 assert(FD_ISSET(fd, &rfd) != 0); 784 assert(FD_ISSET(fd, &wfd) == 0); 785 assert(FD_ISSET(fd, &efd) == 0); 786 break; 787 case FTYPE_PTY: 788 case FTYPE_SOCKET_TCP: 789 case FTYPE_SOCKET_UNIX: 790 assert(ret == 2); 791 assert(FD_ISSET(fd, &rfd) != 0); 792 assert(FD_ISSET(fd, &wfd) != 0); 793 assert(FD_ISSET(fd, &efd) == 0); 794 break; 795 case FTYPE_SOCKET_UDP: 796 assert(ret == 1); 797 assert(FD_ISSET(fd, &rfd) == 0); 798 assert(FD_ISSET(fd, &wfd) != 0); 799 assert(FD_ISSET(fd, &efd) == 0); 800 break; 801 default: 802 assert(0); 803 } 804 805 close(fd); 806 } 807