1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)sys_bsd.c 1.25 (Berkeley) 06/01/90"; 10 #endif /* not lint */ 11 12 /* 13 * The following routines try to encapsulate what is system dependent 14 * (at least between 4.x and dos) which is used in telnet.c. 15 */ 16 17 18 #include <fcntl.h> 19 #include <sys/types.h> 20 #include <sys/time.h> 21 #include <sys/socket.h> 22 #include <signal.h> 23 #include <errno.h> 24 #include <arpa/telnet.h> 25 26 #include "ring.h" 27 28 #include "fdset.h" 29 30 #include "defines.h" 31 #include "externs.h" 32 #include "types.h" 33 34 #if defined(CRAY) 35 #define SIG_FUNC_RET void 36 #else 37 #define SIG_FUNC_RET int 38 #endif 39 40 int 41 tout, /* Output file descriptor */ 42 tin, /* Input file descriptor */ 43 net; 44 45 #ifndef USE_TERMIO 46 struct tchars otc = { 0 }, ntc = { 0 }; 47 struct ltchars oltc = { 0 }, nltc = { 0 }; 48 struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 49 int olmode = 0; 50 51 #else /* USE_TERMIO */ 52 struct termio old_tc = { 0 }; 53 extern struct termio new_tc; 54 55 #ifndef TCGETA 56 #define TCGETA TIOCGETA 57 #define TCSETA TIOCSETA 58 #define TCSETAW TIOCSETAW 59 #endif /* TCGETA */ 60 #endif /* USE_TERMIO */ 61 62 static fd_set ibits, obits, xbits; 63 64 65 init_sys() 66 { 67 tout = fileno(stdout); 68 tin = fileno(stdin); 69 FD_ZERO(&ibits); 70 FD_ZERO(&obits); 71 FD_ZERO(&xbits); 72 73 errno = 0; 74 } 75 76 77 TerminalWrite(buf, n) 78 char *buf; 79 int n; 80 { 81 return write(tout, buf, n); 82 } 83 84 TerminalRead(buf, n) 85 char *buf; 86 int n; 87 { 88 return read(tin, buf, n); 89 } 90 91 /* 92 * 93 */ 94 95 int 96 TerminalAutoFlush() 97 { 98 #if defined(LNOFLSH) 99 int flush; 100 101 ioctl(0, TIOCLGET, (char *)&flush); 102 return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ 103 #else /* LNOFLSH */ 104 return 1; 105 #endif /* LNOFLSH */ 106 } 107 108 #ifdef KLUDGELINEMODE 109 extern int kludgelinemode; 110 #endif 111 /* 112 * TerminalSpecialChars() 113 * 114 * Look at an input character to see if it is a special character 115 * and decide what to do. 116 * 117 * Output: 118 * 119 * 0 Don't add this character. 120 * 1 Do add this character 121 */ 122 123 int 124 TerminalSpecialChars(c) 125 int c; 126 { 127 void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); 128 129 if (c == termIntChar) { 130 intp(); 131 return 0; 132 } else if (c == termQuitChar) { 133 #ifdef KLUDGELINEMODE 134 if (kludgelinemode) 135 sendbrk(); 136 else 137 #endif 138 sendabort(); 139 return 0; 140 } else if (c == termEofChar) { 141 if (my_want_state_is_will(TELOPT_LINEMODE)) { 142 sendeof(); 143 return 0; 144 } 145 return 1; 146 } else if (c == termSuspChar) { 147 sendsusp(); 148 return(0); 149 } else if (c == termFlushChar) { 150 xmitAO(); /* Transmit Abort Output */ 151 return 0; 152 } else if (!MODE_LOCAL_CHARS(globalmode)) { 153 if (c == termKillChar) { 154 xmitEL(); 155 return 0; 156 } else if (c == termEraseChar) { 157 xmitEC(); /* Transmit Erase Character */ 158 return 0; 159 } 160 } 161 return 1; 162 } 163 164 165 /* 166 * Flush output to the terminal 167 */ 168 169 void 170 TerminalFlushOutput() 171 { 172 #ifdef TIOCFLUSH 173 (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 174 #else 175 (void) ioctl(fileno(stdout), TCFLSH, (char *) 0); 176 #endif 177 } 178 179 void 180 TerminalSaveState() 181 { 182 #ifndef USE_TERMIO 183 ioctl(0, TIOCGETP, (char *)&ottyb); 184 ioctl(0, TIOCGETC, (char *)&otc); 185 ioctl(0, TIOCGLTC, (char *)&oltc); 186 ioctl(0, TIOCLGET, (char *)&olmode); 187 188 ntc = otc; 189 nltc = oltc; 190 nttyb = ottyb; 191 192 #else /* USE_TERMIO */ 193 ioctl(0, TCGETA, &old_tc); 194 195 new_tc = old_tc; 196 197 termFlushChar = 'O'&0x37; 198 termWerasChar = 'W'&0x37; 199 termRprntChar = 'R'&0x37; 200 termLiteralNextChar = 'V'&0x37; 201 termStartChar = 'Q'&0x37; 202 termStopChar = 'S'&0x37; 203 #endif /* USE_TERMIO */ 204 } 205 206 cc_t * 207 tcval(func) 208 register int func; 209 { 210 switch(func) { 211 case SLC_IP: return(&termIntChar); 212 case SLC_ABORT: return(&termQuitChar); 213 case SLC_EOF: return(&termEofChar); 214 case SLC_EC: return(&termEraseChar); 215 case SLC_EL: return(&termKillChar); 216 case SLC_XON: return(&termStartChar); 217 case SLC_XOFF: return(&termStopChar); 218 #ifndef SYSV_TERMIO 219 case SLC_AO: return(&termFlushChar); 220 case SLC_SUSP: return(&termSuspChar); 221 case SLC_EW: return(&termWerasChar); 222 case SLC_RP: return(&termRprntChar); 223 case SLC_LNEXT: return(&termLiteralNextChar); 224 #endif /* SYSV_TERMIO */ 225 226 case SLC_SYNCH: 227 case SLC_BRK: 228 case SLC_AYT: 229 case SLC_EOR: 230 case SLC_FORW1: 231 case SLC_FORW2: 232 default: 233 return((cc_t *)0); 234 } 235 } 236 237 void 238 TerminalDefaultChars() 239 { 240 #ifndef USE_TERMIO 241 ntc = otc; 242 nltc = oltc; 243 nttyb.sg_kill = ottyb.sg_kill; 244 nttyb.sg_erase = ottyb.sg_erase; 245 #else /* USE_TERMIO */ 246 memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); 247 # ifndef VFLUSHO 248 termFlushChar = 'O'&0x37; 249 # endif 250 # ifndef VWERASE 251 termWerasChar = 'W'&0x37; 252 # endif 253 # ifndef VREPRINT 254 termRprntChar = 'R'&0x37; 255 # endif 256 # ifndef VLNEXT 257 termLiteralNextChar = 'V'&0x37; 258 # endif 259 # ifndef VSTART 260 termStartChar = 'Q'&0x37; 261 # endif 262 # ifndef VSTOP 263 termStopChar = 'S'&0x37; 264 # endif 265 #endif /* USE_TERMIO */ 266 } 267 268 void 269 TerminalRestoreState() 270 { 271 } 272 273 /* 274 * TerminalNewMode - set up terminal to a specific mode. 275 * MODE_ECHO: do local terminal echo 276 * MODE_FLOW: do local flow control 277 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 278 * MODE_EDIT: do local line editing 279 * 280 * Command mode: 281 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 282 * local echo 283 * local editing 284 * local xon/xoff 285 * local signal mapping 286 * 287 * Linemode: 288 * local/no editing 289 * Both Linemode and Single Character mode: 290 * local/remote echo 291 * local/no xon/xoff 292 * local/no signal mapping 293 */ 294 295 296 void 297 TerminalNewMode(f) 298 register int f; 299 { 300 static int prevmode = 0; 301 #ifndef USE_TERMIO 302 struct tchars tc; 303 struct ltchars ltc; 304 struct sgttyb sb; 305 int lmode; 306 #else /* USE_TERMIO */ 307 struct termio tmp_tc; 308 #endif /* USE_TERMIO */ 309 int onoff; 310 int old; 311 312 globalmode = f&~MODE_FORCE; 313 if (prevmode == f) 314 return; 315 316 /* 317 * Write any outstanding data before switching modes 318 * ttyflush() returns 0 only when there is no more data 319 * left to write out, it returns -1 if it couldn't do 320 * anything at all, otherwise it returns 1 + the number 321 * of characters left to write. 322 */ 323 old = ttyflush(SYNCHing|flushout); 324 if (old < 0 || old > 1) { 325 #ifndef USE_TERMIO 326 ioctl(tin, TIOCGETP, (char *)&sb); 327 #else /* USE_TERMIO */ 328 ioctl(tin, TCGETA, (char *)&tmp_tc); 329 #endif /* USE_TERMIO */ 330 do { 331 /* 332 * Wait for data to drain, then flush again. 333 */ 334 #ifndef USE_TERMIO 335 ioctl(tin, TIOCSETP, (char *)&sb); 336 #else /* USE_TERMIO */ 337 ioctl(tin, TCSETAW, (char *)&tmp_tc); 338 #endif /* USE_TERMIO */ 339 old = ttyflush(SYNCHing|flushout); 340 } while (old < 0 || old > 1); 341 } 342 343 old = prevmode; 344 prevmode = f&~MODE_FORCE; 345 #ifndef USE_TERMIO 346 sb = nttyb; 347 tc = ntc; 348 ltc = nltc; 349 lmode = olmode; 350 #else 351 tmp_tc = new_tc; 352 #endif 353 354 if (f&MODE_ECHO) { 355 #ifndef USE_TERMIO 356 sb.sg_flags |= ECHO; 357 #else 358 tmp_tc.c_lflag |= ECHO; 359 tmp_tc.c_oflag |= ONLCR; 360 # ifdef notdef 361 tmp_tc.c_iflag |= ICRNL; 362 # endif 363 #endif 364 } else { 365 #ifndef USE_TERMIO 366 sb.sg_flags &= ~ECHO; 367 #else 368 tmp_tc.c_lflag &= ~ECHO; 369 tmp_tc.c_oflag &= ~ONLCR; 370 # ifdef notdef 371 tmp_tc.c_iflag &= ~ICRNL; 372 # endif 373 #endif 374 } 375 376 if ((f&MODE_FLOW) == 0) { 377 #ifndef USE_TERMIO 378 tc.t_startc = -1; 379 tc.t_stopc = -1; 380 #else 381 tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON); 382 } else { 383 tmp_tc.c_iflag |= IXANY|IXOFF|IXON; 384 #endif 385 } 386 387 if ((f&MODE_TRAPSIG) == 0) { 388 #ifndef USE_TERMIO 389 tc.t_intrc = -1; 390 tc.t_quitc = -1; 391 tc.t_eofc = -1; 392 ltc.t_suspc = -1; 393 ltc.t_dsuspc = -1; 394 #else 395 tmp_tc.c_lflag &= ~ISIG; 396 #endif 397 localchars = 0; 398 } else { 399 #ifdef USE_TERMIO 400 tmp_tc.c_lflag |= ISIG; 401 #endif 402 localchars = 1; 403 } 404 405 if (f&MODE_EDIT) { 406 #ifndef USE_TERMIO 407 sb.sg_flags &= ~CBREAK; 408 sb.sg_flags |= CRMOD; 409 #else 410 tmp_tc.c_lflag |= ICANON; 411 #endif 412 } else { 413 #ifndef USE_TERMIO 414 sb.sg_flags |= CBREAK; 415 if (f&MODE_ECHO) 416 sb.sg_flags |= CRMOD; 417 else 418 sb.sg_flags &= ~CRMOD; 419 #else 420 tmp_tc.c_lflag &= ~ICANON; 421 tmp_tc.c_iflag &= ~ICRNL; 422 tmp_tc.c_cc[VMIN] = 1; 423 tmp_tc.c_cc[VTIME] = 0; 424 #endif 425 } 426 427 if (f == -1) { 428 onoff = 0; 429 } else { 430 #ifndef USE_TERMIO 431 if (f & MODE_OUTBIN) 432 lmode |= LLITOUT; 433 else 434 lmode &= ~LLITOUT; 435 436 if (f & MODE_INBIN) 437 lmode |= LPASS8; 438 else 439 lmode &= ~LPASS8; 440 #else 441 if (f & MODE_OUTBIN) 442 tmp_tc.c_lflag &= ~ISTRIP; 443 else 444 tmp_tc.c_lflag |= ISTRIP; 445 if (f & MODE_INBIN) { 446 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 447 tmp_tc.c_cflag |= CS8; 448 tmp_tc.c_cflag &= ~OPOST; 449 } else { 450 tmp_tc.c_cflag &= ~CSIZE; 451 tmp_tc.c_cflag |= CS7|PARENB; 452 tmp_tc.c_cflag |= OPOST; 453 } 454 #endif 455 onoff = 1; 456 } 457 458 if (f != -1) { 459 #ifdef SIGTSTP 460 void susp(); 461 462 (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp); 463 #endif /* SIGTSTP */ 464 #ifdef USE_TERMIO 465 #ifdef VEOL2 466 /* 467 * If the VEOL character is already set, then use VEOL2, 468 * otherwise use VEOL. 469 */ 470 if (tmp_tc.c_cc[VEOL] != (cc_t)(-1)) 471 tmp_tc.c_cc[VEOL2] = escape; 472 else 473 #endif 474 tmp_tc.c_cc[VEOL] = escape; 475 #else 476 tc.t_brkc = escape; 477 #endif 478 } else { 479 #ifdef SIGTSTP 480 (void) signal(SIGTSTP, SIG_DFL); 481 sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 482 #endif /* SIGTSTP */ 483 #ifndef USE_TERMIO 484 ltc = oltc; 485 tc = otc; 486 sb = ottyb; 487 #endif 488 } 489 #ifndef USE_TERMIO 490 ioctl(tin, TIOCLSET, (char *)&lmode); 491 ioctl(tin, TIOCSLTC, (char *)<c); 492 ioctl(tin, TIOCSETC, (char *)&tc); 493 ioctl(tin, TIOCSETP, (char *)&sb); 494 #else 495 if (ioctl(tin, TCSETAW, &tmp_tc) < 0) 496 ioctl(tin, TCSETA, &tmp_tc); 497 #endif 498 499 #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 500 ioctl(tin, FIONBIO, (char *)&onoff); 501 ioctl(tout, FIONBIO, (char *)&onoff); 502 #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 503 #if defined(TN3270) 504 if (noasynchtty == 0) { 505 ioctl(tin, FIOASYNC, (char *)&onoff); 506 } 507 #endif /* defined(TN3270) */ 508 } 509 510 #ifndef B19200 511 # define B19200 B9600 512 #endif 513 514 #ifndef B38400 515 # define B38400 B19200 516 #endif 517 518 /* 519 * This code assumes that the values B0, B50, B75... 520 * are in ascending order. They do not have to be 521 * contiguous. 522 */ 523 struct termspeeds { 524 long speed; 525 long value; 526 } termspeeds[] = { 527 { 0, B0 }, { 50, B50 }, { 75, B75 }, 528 { 110, B110 }, { 134, B134 }, { 150, B150 }, 529 { 200, B200 }, { 300, B300 }, { 600, B600 }, 530 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 531 { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 }, 532 { 38400, B38400 }, { -1, B38400 } 533 }; 534 535 #ifndef USE_TERMIO 536 # define ISPEED ottyb.sg_ispeed 537 # define OSPEED ottyb.sg_ospeed 538 #else 539 # ifdef SYSV_TERMIO 540 # define ISPEED (old_tc.c_cflag&CBAUD) 541 # define OSPEED ISPEED 542 # else 543 # define ISPEED old_tc.c_ispeed 544 # define OSPEED old_tc.c_ospeed 545 # endif 546 #endif 547 548 void 549 TerminalSpeeds(ispeed, ospeed) 550 long *ispeed; 551 long *ospeed; 552 { 553 register struct termspeeds *tp; 554 555 tp = termspeeds; 556 while ((tp->speed != -1) && (tp->value < ISPEED)) 557 tp++; 558 *ispeed = tp->speed; 559 560 tp = termspeeds; 561 while ((tp->speed != -1) && (tp->value < OSPEED)) 562 tp++; 563 *ospeed = tp->speed; 564 } 565 566 int 567 TerminalWindowSize(rows, cols) 568 long *rows, *cols; 569 { 570 #ifdef TIOCGWINSZ 571 struct winsize ws; 572 573 if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 574 *rows = ws.ws_row; 575 *cols = ws.ws_col; 576 return 1; 577 } 578 #endif /* TIOCGWINSZ */ 579 return 0; 580 } 581 582 int 583 NetClose(fd) 584 int fd; 585 { 586 return close(fd); 587 } 588 589 590 void 591 NetNonblockingIO(fd, onoff) 592 int 593 fd, 594 onoff; 595 { 596 ioctl(fd, FIONBIO, (char *)&onoff); 597 } 598 599 #if defined(TN3270) 600 void 601 NetSigIO(fd, onoff) 602 int 603 fd, 604 onoff; 605 { 606 ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ 607 } 608 609 void 610 NetSetPgrp(fd) 611 int fd; 612 { 613 int myPid; 614 615 myPid = getpid(); 616 fcntl(fd, F_SETOWN, myPid); 617 } 618 #endif /*defined(TN3270)*/ 619 620 /* 621 * Various signal handling routines. 622 */ 623 624 static void 625 deadpeer() 626 { 627 setcommandmode(); 628 longjmp(peerdied, -1); 629 } 630 631 static void 632 intr() 633 { 634 if (localchars) { 635 intp(); 636 return; 637 } 638 setcommandmode(); 639 longjmp(toplevel, -1); 640 } 641 642 static void 643 intr2() 644 { 645 if (localchars) { 646 #ifdef KLUDGELINEMODE 647 if (kludgelinemode) 648 sendbrk(); 649 else 650 #endif 651 sendabort(); 652 return; 653 } 654 } 655 656 static void 657 susp() 658 { 659 if (localchars) 660 sendsusp(); 661 } 662 663 static void 664 sendwin() 665 { 666 if (connected) { 667 sendnaws(); 668 } 669 } 670 671 static void 672 doescape() 673 { 674 command(0, 0, 0); 675 } 676 677 void 678 sys_telnet_init() 679 { 680 (void) signal(SIGINT, (SIG_FUNC_RET (*)())intr); 681 (void) signal(SIGQUIT, (SIG_FUNC_RET (*)())intr2); 682 (void) signal(SIGPIPE, (SIG_FUNC_RET (*)())deadpeer); 683 #ifdef SIGWINCH 684 (void) signal(SIGWINCH, (SIG_FUNC_RET (*)())sendwin); 685 #endif 686 #ifdef SIGTSTP 687 (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp); 688 #endif 689 690 setconnmode(0); 691 692 NetNonblockingIO(net, 1); 693 694 #if defined(TN3270) 695 if (noasynchnet == 0) { /* DBX can't handle! */ 696 NetSigIO(net, 1); 697 NetSetPgrp(net); 698 } 699 #endif /* defined(TN3270) */ 700 701 #if defined(SO_OOBINLINE) 702 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 703 perror("SetSockOpt"); 704 } 705 #endif /* defined(SO_OOBINLINE) */ 706 } 707 708 /* 709 * Process rings - 710 * 711 * This routine tries to fill up/empty our various rings. 712 * 713 * The parameter specifies whether this is a poll operation, 714 * or a block-until-something-happens operation. 715 * 716 * The return value is 1 if something happened, 0 if not. 717 */ 718 719 int 720 process_rings(netin, netout, netex, ttyin, ttyout, poll) 721 int poll; /* If 0, then block until something to do */ 722 { 723 register int c; 724 /* One wants to be a bit careful about setting returnValue 725 * to one, since a one implies we did some useful work, 726 * and therefore probably won't be called to block next 727 * time (TN3270 mode only). 728 */ 729 int returnValue = 0; 730 static struct timeval TimeValue = { 0 }; 731 732 if (netout) { 733 FD_SET(net, &obits); 734 } 735 if (ttyout) { 736 FD_SET(tout, &obits); 737 } 738 #if defined(TN3270) 739 if (ttyin) { 740 FD_SET(tin, &ibits); 741 } 742 #else /* defined(TN3270) */ 743 if (ttyin) { 744 FD_SET(tin, &ibits); 745 } 746 #endif /* defined(TN3270) */ 747 #if defined(TN3270) 748 if (netin) { 749 FD_SET(net, &ibits); 750 } 751 # else /* !defined(TN3270) */ 752 if (netin) { 753 FD_SET(net, &ibits); 754 } 755 # endif /* !defined(TN3270) */ 756 if (netex) { 757 FD_SET(net, &xbits); 758 } 759 if ((c = select(16, &ibits, &obits, &xbits, 760 (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { 761 if (c == -1) { 762 /* 763 * we can get EINTR if we are in line mode, 764 * and the user does an escape (TSTP), or 765 * some other signal generator. 766 */ 767 if (errno == EINTR) { 768 return 0; 769 } 770 # if defined(TN3270) 771 /* 772 * we can get EBADF if we were in transparent 773 * mode, and the transcom process died. 774 */ 775 if (errno == EBADF) { 776 /* 777 * zero the bits (even though kernel does it) 778 * to make sure we are selecting on the right 779 * ones. 780 */ 781 FD_ZERO(&ibits); 782 FD_ZERO(&obits); 783 FD_ZERO(&xbits); 784 return 0; 785 } 786 # endif /* defined(TN3270) */ 787 /* I don't like this, does it ever happen? */ 788 printf("sleep(5) from telnet, after select\r\n"); 789 sleep(5); 790 } 791 return 0; 792 } 793 794 /* 795 * Any urgent data? 796 */ 797 if (FD_ISSET(net, &xbits)) { 798 FD_CLR(net, &xbits); 799 SYNCHing = 1; 800 ttyflush(1); /* flush already enqueued data */ 801 } 802 803 /* 804 * Something to read from the network... 805 */ 806 if (FD_ISSET(net, &ibits)) { 807 int canread; 808 809 FD_CLR(net, &ibits); 810 canread = ring_empty_consecutive(&netiring); 811 #if !defined(SO_OOBINLINE) 812 /* 813 * In 4.2 (and some early 4.3) systems, the 814 * OOB indication and data handling in the kernel 815 * is such that if two separate TCP Urgent requests 816 * come in, one byte of TCP data will be overlaid. 817 * This is fatal for Telnet, but we try to live 818 * with it. 819 * 820 * In addition, in 4.2 (and...), a special protocol 821 * is needed to pick up the TCP Urgent data in 822 * the correct sequence. 823 * 824 * What we do is: if we think we are in urgent 825 * mode, we look to see if we are "at the mark". 826 * If we are, we do an OOB receive. If we run 827 * this twice, we will do the OOB receive twice, 828 * but the second will fail, since the second 829 * time we were "at the mark", but there wasn't 830 * any data there (the kernel doesn't reset 831 * "at the mark" until we do a normal read). 832 * Once we've read the OOB data, we go ahead 833 * and do normal reads. 834 * 835 * There is also another problem, which is that 836 * since the OOB byte we read doesn't put us 837 * out of OOB state, and since that byte is most 838 * likely the TELNET DM (data mark), we would 839 * stay in the TELNET SYNCH (SYNCHing) state. 840 * So, clocks to the rescue. If we've "just" 841 * received a DM, then we test for the 842 * presence of OOB data when the receive OOB 843 * fails (and AFTER we did the normal mode read 844 * to clear "at the mark"). 845 */ 846 if (SYNCHing) { 847 int atmark; 848 static int bogus_oob = 0, first = 1; 849 850 ioctl(net, SIOCATMARK, (char *)&atmark); 851 if (atmark) { 852 c = recv(net, netiring.supply, canread, MSG_OOB); 853 if ((c == -1) && (errno == EINVAL)) { 854 c = recv(net, netiring.supply, canread, 0); 855 if (clocks.didnetreceive < clocks.gotDM) { 856 SYNCHing = stilloob(net); 857 } 858 } else if (first && c > 0) { 859 /* 860 * Bogosity check. Systems based on 4.2BSD 861 * do not return an error if you do a second 862 * recv(MSG_OOB). So, we do one. If it 863 * succeeds and returns exactly the same 864 * data, then assume that we are running 865 * on a broken system and set the bogus_oob 866 * flag. (If the data was different, then 867 * we probably got some valid new data, so 868 * increment the count...) 869 */ 870 int i; 871 i = recv(net, netiring.supply + c, canread - c, MSG_OOB); 872 if (i == c && 873 bcmp(netiring.supply, netiring.supply + c, i) == 0) { 874 bogus_oob = 1; 875 first = 0; 876 } else if (i < 0) { 877 bogus_oob = 0; 878 first = 0; 879 } else 880 c += i; 881 } 882 if (bogus_oob && c > 0) { 883 int i; 884 /* 885 * Bogosity. We have to do the read 886 * to clear the atmark to get out of 887 * an infinate loop. 888 */ 889 i = read(net, netiring.supply + c, canread - c); 890 if (i > 0) 891 c += i; 892 } 893 } else { 894 c = recv(net, netiring.supply, canread, 0); 895 } 896 } else { 897 c = recv(net, netiring.supply, canread, 0); 898 } 899 settimer(didnetreceive); 900 #else /* !defined(SO_OOBINLINE) */ 901 c = recv(net, netiring.supply, canread, 0); 902 #endif /* !defined(SO_OOBINLINE) */ 903 if (c < 0 && errno == EWOULDBLOCK) { 904 c = 0; 905 } else if (c <= 0) { 906 return -1; 907 } 908 if (netdata) { 909 Dump('<', netiring.supply, c); 910 } 911 if (c) 912 ring_supplied(&netiring, c); 913 returnValue = 1; 914 } 915 916 /* 917 * Something to read from the tty... 918 */ 919 if (FD_ISSET(tin, &ibits)) { 920 FD_CLR(tin, &ibits); 921 c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 922 if (c < 0 && errno == EWOULDBLOCK) { 923 c = 0; 924 } else { 925 /* EOF detection for line mode!!!! */ 926 if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 927 /* must be an EOF... */ 928 *ttyiring.supply = termEofChar; 929 c = 1; 930 } 931 if (c <= 0) { 932 return -1; 933 } 934 if (termdata) { 935 Dump('<', ttyiring.supply, c); 936 } 937 ring_supplied(&ttyiring, c); 938 } 939 returnValue = 1; /* did something useful */ 940 } 941 942 if (FD_ISSET(net, &obits)) { 943 FD_CLR(net, &obits); 944 returnValue |= netflush(); 945 } 946 if (FD_ISSET(tout, &obits)) { 947 FD_CLR(tout, &obits); 948 returnValue |= (ttyflush(SYNCHing|flushout) > 0); 949 } 950 951 return returnValue; 952 } 953