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