1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1988, 1990, 1993 8 * The Regents of the University of California. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 */ 39 40 #ifndef lint 41 static char sccsid[] = "@(#)sys_bsd.c 8.1 (Berkeley) 6/6/93"; 42 #endif /* not lint */ 43 44 /* 45 * The following routines try to encapsulate what is system dependent 46 * (at least between 4.x and dos) which is used in telnet.c. 47 */ 48 49 50 #include <fcntl.h> 51 #include <sys/types.h> 52 #include <sys/time.h> 53 #include <sys/socket.h> 54 #include <sys/uio.h> 55 #include <signal.h> 56 #include <errno.h> 57 #include <arpa/telnet.h> 58 59 #include "ring.h" 60 61 #include "defines.h" 62 #include "externs.h" 63 #include "types.h" 64 65 #define SIG_FUNC_RET void 66 67 int tout; /* Output file descriptor */ 68 static int tin; /* Input file descriptor */ 69 int net = -1; 70 71 72 #ifndef USE_TERMIO 73 struct tchars otc = { 0 }, ntc = { 0 }; 74 struct ltchars oltc = { 0 }, nltc = { 0 }; 75 struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 76 int olmode = 0; 77 #define cfgetispeed(ptr) (ptr)->sg_ispeed 78 #define cfgetospeed(ptr) (ptr)->sg_ospeed 79 #define old_tc ottyb 80 81 #else /* USE_TERMIO */ 82 static struct termio old_tc = { 0 }; 83 extern struct termio new_tc; 84 #endif /* USE_TERMIO */ 85 86 static fd_set ibits, obits, xbits; 87 88 static SIG_FUNC_RET susp(int); 89 void fatal_tty_error(char *doing_what); 90 91 92 void 93 init_sys() 94 { 95 tout = fileno(stdout); 96 tin = fileno(stdin); 97 FD_ZERO(&ibits); 98 FD_ZERO(&obits); 99 FD_ZERO(&xbits); 100 101 errno = 0; 102 } 103 104 105 int 106 TerminalWrite(buf, n) 107 char *buf; 108 int n; 109 { 110 return (write(tout, buf, n)); 111 } 112 113 static int 114 TerminalRead(buf, n) 115 char *buf; 116 int n; 117 { 118 return (read(tin, buf, n)); 119 } 120 121 #ifdef KLUDGELINEMODE 122 extern int kludgelinemode; 123 #endif 124 /* 125 * TerminalSpecialChars() 126 * 127 * Look at an input character to see if it is a special character 128 * and decide what to do. 129 * 130 * Output: 131 * 132 * 0 Don't add this character. 133 * 1 Do add this character 134 */ 135 int 136 TerminalSpecialChars(c) 137 int c; 138 { 139 /* 140 * Don't check for signal characters here. If MODE_TRAPSIG is on, 141 * then the various signal handlers will catch the characters. If 142 * the character in question gets here, then it must have been LNEXTed 143 */ 144 if (c == termQuitChar) { 145 #ifdef KLUDGELINEMODE 146 if (kludgelinemode) { 147 if (sendbrk() == -1) { 148 /* This won't return. */ 149 fatal_tty_error("write"); 150 } 151 return (0); 152 } 153 #endif 154 } else if (c == termFlushChar) { 155 /* Transmit Abort Output */ 156 if (xmitAO() == -1) { 157 /* This won't return. */ 158 fatal_tty_error("write"); 159 } 160 return (0); 161 } else if (!MODE_LOCAL_CHARS(globalmode)) { 162 if (c == termKillChar) { 163 xmitEL(); 164 return (0); 165 } else if (c == termEraseChar) { 166 xmitEC(); /* Transmit Erase Character */ 167 return (0); 168 } 169 } 170 return (1); 171 } 172 173 174 /* 175 * Flush output to the terminal 176 */ 177 178 void 179 TerminalFlushOutput() 180 { 181 if (isatty(fileno(stdout))) { 182 (void) ioctl(fileno(stdout), TIOCFLUSH, NULL); 183 } 184 } 185 186 void 187 TerminalSaveState() 188 { 189 #ifndef USE_TERMIO 190 (void) ioctl(0, TIOCGETP, &ottyb); 191 (void) ioctl(0, TIOCGETC, &otc); 192 (void) ioctl(0, TIOCGLTC, &oltc); 193 (void) ioctl(0, TIOCLGET, &olmode); 194 195 ntc = otc; 196 nltc = oltc; 197 nttyb = ottyb; 198 199 #else /* USE_TERMIO */ 200 (void) tcgetattr(0, &old_tc); 201 202 new_tc = old_tc; 203 termAytChar = CONTROL('T'); 204 #endif /* USE_TERMIO */ 205 } 206 207 cc_t * 208 tcval(func) 209 register int func; 210 { 211 switch (func) { 212 case SLC_IP: return (&termIntChar); 213 case SLC_ABORT: return (&termQuitChar); 214 case SLC_EOF: return (&termEofChar); 215 case SLC_EC: return (&termEraseChar); 216 case SLC_EL: return (&termKillChar); 217 case SLC_XON: return (&termStartChar); 218 case SLC_XOFF: return (&termStopChar); 219 case SLC_FORW1: return (&termForw1Char); 220 #ifdef USE_TERMIO 221 case SLC_FORW2: return (&termForw2Char); 222 case SLC_AO: return (&termFlushChar); 223 case SLC_SUSP: return (&termSuspChar); 224 case SLC_EW: return (&termWerasChar); 225 case SLC_RP: return (&termRprntChar); 226 case SLC_LNEXT: return (&termLiteralNextChar); 227 #endif 228 229 case SLC_SYNCH: 230 case SLC_BRK: 231 case SLC_EOR: 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 (void) memcpy(new_tc.c_cc, old_tc.c_cc, sizeof (old_tc.c_cc)); 247 termAytChar = CONTROL('T'); 248 #endif /* USE_TERMIO */ 249 } 250 251 /* 252 * TerminalNewMode - set up terminal to a specific mode. 253 * MODE_ECHO: do local terminal echo 254 * MODE_FLOW: do local flow control 255 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 256 * MODE_EDIT: do local line editing 257 * 258 * Command mode: 259 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 260 * local echo 261 * local editing 262 * local xon/xoff 263 * local signal mapping 264 * 265 * Linemode: 266 * local/no editing 267 * Both Linemode and Single Character mode: 268 * local/remote echo 269 * local/no xon/xoff 270 * local/no signal mapping 271 */ 272 273 274 void 275 TerminalNewMode(f) 276 register int f; 277 { 278 static int prevmode = -2; /* guaranteed unique */ 279 #ifndef USE_TERMIO 280 struct tchars tc; 281 struct ltchars ltc; 282 struct sgttyb sb; 283 int lmode; 284 #else /* USE_TERMIO */ 285 struct termio tmp_tc; 286 #endif /* USE_TERMIO */ 287 int onoff; 288 int old; 289 cc_t esc; 290 sigset_t nset; 291 292 globalmode = f&~MODE_FORCE; 293 if (prevmode == f) 294 return; 295 296 /* 297 * Write any outstanding data before switching modes 298 * ttyflush() returns 0 only when there was no data 299 * to write out; it returns -1 if it couldn't do 300 * anything at all, returns -2 if there was a write 301 * error (other than EWOULDBLOCK), and otherwise it 302 * returns 1 + the number of characters left to write. 303 */ 304 #ifndef USE_TERMIO 305 /* 306 * We would really like ask the kernel to wait for the output 307 * to drain, like we can do with the TCSADRAIN, but we don't have 308 * that option. The only ioctl that waits for the output to 309 * drain, TIOCSETP, also flushes the input queue, which is NOT 310 * what we want(TIOCSETP is like TCSADFLUSH). 311 */ 312 #endif 313 old = ttyflush(SYNCHing|flushout); 314 if (old == -1 || old > 1) { 315 #ifdef USE_TERMIO 316 (void) tcgetattr(tin, &tmp_tc); 317 #endif /* USE_TERMIO */ 318 do { 319 /* 320 * Wait for data to drain, then flush again. 321 */ 322 #ifdef USE_TERMIO 323 (void) tcsetattr(tin, TCSADRAIN, &tmp_tc); 324 #endif /* USE_TERMIO */ 325 old = ttyflush(SYNCHing|flushout); 326 } while (old == -1 || old > 1); 327 } 328 329 old = prevmode; 330 prevmode = f&~MODE_FORCE; 331 #ifndef USE_TERMIO 332 sb = nttyb; 333 tc = ntc; 334 ltc = nltc; 335 lmode = olmode; 336 #else 337 tmp_tc = new_tc; 338 #endif 339 340 if (f&MODE_ECHO) { 341 #ifndef USE_TERMIO 342 sb.sg_flags |= ECHO; 343 #else 344 tmp_tc.c_lflag |= ECHO; 345 tmp_tc.c_oflag |= ONLCR; 346 if (crlf) 347 tmp_tc.c_iflag |= ICRNL; 348 #endif 349 } else { 350 #ifndef USE_TERMIO 351 sb.sg_flags &= ~ECHO; 352 #else 353 tmp_tc.c_lflag &= ~ECHO; 354 tmp_tc.c_oflag &= ~ONLCR; 355 #ifdef notdef 356 if (crlf) 357 tmp_tc.c_iflag &= ~ICRNL; 358 #endif 359 #endif 360 } 361 362 if ((f&MODE_FLOW) == 0) { 363 #ifndef USE_TERMIO 364 tc.t_startc = _POSIX_VDISABLE; 365 tc.t_stopc = _POSIX_VDISABLE; 366 #else 367 tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */ 368 } else { 369 if (restartany < 0) { 370 /* Leave the IXANY bit alone */ 371 tmp_tc.c_iflag |= IXOFF|IXON; 372 } else if (restartany > 0) { 373 tmp_tc.c_iflag |= IXOFF|IXON|IXANY; 374 } else { 375 tmp_tc.c_iflag |= IXOFF|IXON; 376 tmp_tc.c_iflag &= ~IXANY; 377 } 378 #endif 379 } 380 381 if ((f&MODE_TRAPSIG) == 0) { 382 #ifndef USE_TERMIO 383 tc.t_intrc = _POSIX_VDISABLE; 384 tc.t_quitc = _POSIX_VDISABLE; 385 tc.t_eofc = _POSIX_VDISABLE; 386 ltc.t_suspc = _POSIX_VDISABLE; 387 ltc.t_dsuspc = _POSIX_VDISABLE; 388 #else 389 tmp_tc.c_lflag &= ~ISIG; 390 #endif 391 localchars = 0; 392 } else { 393 #ifdef USE_TERMIO 394 tmp_tc.c_lflag |= ISIG; 395 #endif 396 localchars = 1; 397 } 398 399 if (f&MODE_EDIT) { 400 #ifndef USE_TERMIO 401 sb.sg_flags &= ~CBREAK; 402 sb.sg_flags |= CRMOD; 403 #else 404 tmp_tc.c_lflag |= ICANON; 405 #endif 406 } else { 407 #ifndef USE_TERMIO 408 sb.sg_flags |= CBREAK; 409 if (f&MODE_ECHO) 410 sb.sg_flags |= CRMOD; 411 else 412 sb.sg_flags &= ~CRMOD; 413 #else 414 tmp_tc.c_lflag &= ~ICANON; 415 tmp_tc.c_iflag &= ~ICRNL; 416 tmp_tc.c_cc[VMIN] = 1; 417 tmp_tc.c_cc[VTIME] = 0; 418 #endif 419 } 420 421 if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { 422 #ifndef USE_TERMIO 423 ltc.t_lnextc = _POSIX_VDISABLE; 424 #else 425 tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE); 426 #endif 427 } 428 429 if (f&MODE_SOFT_TAB) { 430 #ifndef USE_TERMIO 431 sb.sg_flags |= XTABS; 432 #else 433 tmp_tc.c_oflag &= ~TABDLY; 434 tmp_tc.c_oflag |= TAB3; 435 #endif 436 } else { 437 #ifndef USE_TERMIO 438 sb.sg_flags &= ~XTABS; 439 #else 440 tmp_tc.c_oflag &= ~TABDLY; 441 #endif 442 } 443 444 if (f&MODE_LIT_ECHO) { 445 #ifndef USE_TERMIO 446 lmode &= ~LCTLECH; 447 #else 448 tmp_tc.c_lflag &= ~ECHOCTL; 449 #endif 450 } else { 451 #ifndef USE_TERMIO 452 lmode |= LCTLECH; 453 #else 454 tmp_tc.c_lflag |= ECHOCTL; 455 #endif 456 } 457 458 if (f == -1) { 459 onoff = 0; 460 } else { 461 #ifndef USE_TERMIO 462 if (f & MODE_OUTBIN) 463 lmode |= LLITOUT; 464 else 465 lmode &= ~LLITOUT; 466 #else 467 if (f & MODE_OUTBIN) { 468 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 469 tmp_tc.c_cflag |= CS8; 470 tmp_tc.c_oflag &= ~OPOST; 471 } else { 472 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 473 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB); 474 tmp_tc.c_oflag |= OPOST; 475 } 476 #endif 477 onoff = 1; 478 } 479 480 if (f != -1) { 481 482 (void) signal(SIGTSTP, susp); 483 484 #if defined(USE_TERMIO) && defined(NOKERNINFO) 485 tmp_tc.c_lflag |= NOKERNINFO; 486 #endif 487 /* 488 * We don't want to process ^Y here. It's just another 489 * character that we'll pass on to the back end. It has 490 * to process it because it will be processed when the 491 * user attempts to read it, not when we send it. 492 */ 493 #ifndef USE_TERMIO 494 ltc.t_dsuspc = _POSIX_VDISABLE; 495 #else 496 tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE); 497 #endif 498 #ifdef USE_TERMIO 499 /* 500 * If the VEOL character is already set, then use VEOL2, 501 * otherwise use VEOL. 502 */ 503 esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape; 504 if ((tmp_tc.c_cc[VEOL] != esc) 505 /* XXX */ && 506 (tmp_tc.c_cc[VEOL2] != esc) 507 /* XXX */) { 508 if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE)) 509 tmp_tc.c_cc[VEOL] = esc; 510 else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE)) 511 tmp_tc.c_cc[VEOL2] = esc; 512 } 513 #else 514 if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE)) 515 tc.t_brkc = esc; 516 #endif 517 } else { 518 (void) signal(SIGTSTP, SIG_DFL); 519 (void) sigemptyset(&nset); 520 (void) sigaddset(&nset, SIGTSTP); 521 (void) sigprocmask(SIG_UNBLOCK, &nset, 0); 522 #ifndef USE_TERMIO 523 ltc = oltc; 524 tc = otc; 525 sb = ottyb; 526 lmode = olmode; 527 #else 528 tmp_tc = old_tc; 529 #endif 530 } 531 if (isatty(tin)) { 532 #ifndef USE_TERMIO 533 (void) ioctl(tin, TIOCLSET, &lmode); 534 (void) ioctl(tin, TIOCSLTC, <c); 535 (void) ioctl(tin, TIOCSETC, &tc); 536 (void) ioctl(tin, TIOCSETN, &sb); 537 #else 538 if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) 539 (void) tcsetattr(tin, TCSANOW, &tmp_tc); 540 #endif 541 (void) ioctl(tin, FIONBIO, &onoff); 542 (void) ioctl(tout, FIONBIO, &onoff); 543 } 544 545 } 546 547 /* 548 * This code assumes that the values B0, B50, B75... 549 * are in ascending order. They do not have to be 550 * contiguous. 551 */ 552 static struct termspeeds { 553 int speed; 554 int value; 555 } termspeeds[] = { 556 { 0, B0 }, { 50, B50 }, { 75, B75 }, 557 { 110, B110 }, { 134, B134 }, { 150, B150 }, 558 { 200, B200 }, { 300, B300 }, { 600, B600 }, 559 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 560 { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 }, 561 { 38400, B38400 }, { 57600, B57600 }, { 76800, B76800 }, 562 { 115200, B115200 }, { 153600, B153600 }, { 230400, B230400 }, 563 { 307200, B307200 }, { 460800, B460800 }, { 921600, B921600 }, 564 { -1, B0 } 565 }; 566 567 void 568 TerminalSpeeds(ispeed, ospeed) 569 int *ispeed; 570 int *ospeed; 571 { 572 register struct termspeeds *tp; 573 register int in, out; 574 575 out = cfgetospeed(&old_tc); 576 in = cfgetispeed(&old_tc); 577 if (in == 0) 578 in = out; 579 580 tp = termspeeds; 581 while ((tp->speed != -1) && (tp->value < in)) { 582 tp++; 583 } 584 if (tp->speed == -1) 585 tp--; /* back up to fastest defined speed */ 586 *ispeed = tp->speed; 587 588 tp = termspeeds; 589 while ((tp->speed != -1) && (tp->value < out)) { 590 tp++; 591 } 592 if (tp->speed == -1) 593 tp--; 594 *ospeed = tp->speed; 595 } 596 597 int 598 TerminalWindowSize(rows, cols) 599 unsigned short *rows, *cols; 600 { 601 struct winsize ws; 602 603 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) { 604 *rows = ws.ws_row; 605 *cols = ws.ws_col; 606 return (1); 607 } 608 return (0); 609 } 610 611 static void 612 NetNonblockingIO(fd, onoff) 613 int fd; 614 int onoff; 615 { 616 (void) ioctl(fd, FIONBIO, &onoff); 617 } 618 619 /* 620 * Various signal handling routines. 621 */ 622 623 /* ARGSUSED */ 624 static SIG_FUNC_RET 625 deadpeer(sig) 626 int sig; 627 { 628 /* 629 * Once is all we should catch SIGPIPE. If we get it again, 630 * it means we tried to put still more data out to a pipe 631 * which has disappeared. In that case, telnet will exit. 632 */ 633 (void) signal(SIGPIPE, SIG_IGN); 634 flushout = 1; 635 setcommandmode(); 636 longjmp(peerdied, -1); 637 } 638 639 boolean_t intr_happened = B_FALSE; 640 boolean_t intr_waiting = B_FALSE; 641 642 /* ARGSUSED */ 643 static SIG_FUNC_RET 644 intr(sig) 645 int sig; 646 { 647 if (intr_waiting) { 648 intr_happened = 1; 649 return; 650 } 651 (void) signal(SIGINT, intr); 652 if (localchars) { 653 intp(); 654 return; 655 } 656 setcommandmode(); 657 longjmp(toplevel, -1); 658 } 659 660 /* ARGSUSED */ 661 static SIG_FUNC_RET 662 intr2(sig) 663 int sig; 664 { 665 (void) signal(SIGQUIT, intr2); 666 if (localchars) { 667 /* 668 * Ignore return to the next two function calls 669 * since we're doing SIGQUIT 670 */ 671 #ifdef KLUDGELINEMODE 672 if (kludgelinemode) { 673 (void) sendbrk(); 674 } 675 else 676 #endif 677 sendabort(); 678 return; 679 } 680 } 681 682 /* ARGSUSED */ 683 static SIG_FUNC_RET 684 susp(sig) 685 int sig; 686 { 687 (void) signal(SIGTSTP, susp); 688 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) 689 return; 690 if (localchars) 691 sendsusp(); 692 } 693 694 /* ARGSUSED */ 695 static SIG_FUNC_RET 696 sendwin(sig) 697 int sig; 698 { 699 (void) signal(SIGWINCH, sendwin); 700 if (connected) { 701 sendnaws(); 702 } 703 } 704 705 void 706 sys_telnet_init() 707 { 708 (void) signal(SIGINT, intr); 709 (void) signal(SIGQUIT, intr2); 710 (void) signal(SIGPIPE, deadpeer); 711 (void) signal(SIGWINCH, sendwin); 712 (void) signal(SIGTSTP, susp); 713 714 setconnmode(0); 715 716 NetNonblockingIO(net, 1); 717 718 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 719 perror("SetSockOpt"); 720 } 721 } 722 723 724 /* 725 * fatal_tty_error - 726 * Handle case where there is an unrecoverable error on the tty 727 * connections. Print an error, reset the terminal settings 728 * and get out as painlessly as possible. 729 */ 730 void 731 fatal_tty_error(char *doing_what) 732 { 733 TerminalNewMode(-1); 734 (void) fprintf(stderr, "Error processing %s: %s\n", doing_what, 735 strerror(errno)); 736 exit(1); 737 } 738 739 740 /* 741 * Process rings - 742 * 743 * This routine tries to fill up/empty our various rings. 744 * 745 * The parameter specifies whether this is a poll operation, 746 * or a block-until-something-happens operation. 747 * 748 * The return value is 1 if something happened, 0 if not. 749 */ 750 751 int 752 process_rings(netin, netout, netex, ttyin, ttyout, poll) 753 int poll; /* If 0, then block until something to do */ 754 { 755 register int c; 756 /* 757 * One wants to be a bit careful about setting returnValue 758 * to one, since a one implies we did some useful work, 759 * and therefore probably won't be called to block next 760 * time (TN3270 mode only). 761 */ 762 int returnValue = 0; 763 static struct timeval TimeValue = { 0 }; 764 int i; 765 766 if (netout) { 767 FD_SET(net, &obits); 768 } 769 if (ttyout) { 770 FD_SET(tout, &obits); 771 } 772 if (ttyin) { 773 FD_SET(tin, &ibits); 774 } 775 if (netin) { 776 FD_SET(net, &ibits); 777 } 778 if (netex) { 779 FD_SET(net, &xbits); 780 } 781 if ((c = select(16, &ibits, &obits, &xbits, 782 (poll == 0) ? NULL : &TimeValue)) < 0) { 783 if (c == -1) { 784 /* 785 * we can get EINTR if we are in line mode, 786 * and the user does an escape (TSTP), or 787 * some other signal generator. 788 */ 789 if (errno == EINTR) { 790 return (0); 791 } 792 /* I don't like this, does it ever happen? */ 793 (void) printf("sleep(5) from telnet, after select\r\n"); 794 (void) sleep(5); 795 } 796 return (0); 797 } 798 799 /* 800 * Any urgent data? 801 */ 802 if (FD_ISSET(net, &xbits)) { 803 FD_CLR(net, &xbits); 804 SYNCHing = 1; 805 806 /* flush any data that is already enqueued */ 807 i = ttyflush(1); 808 if (i == -2) { 809 /* This will not return. */ 810 fatal_tty_error("write"); 811 } 812 } 813 814 /* 815 * Something to read from the network... 816 */ 817 if (FD_ISSET(net, &ibits)) { 818 int canread; 819 820 FD_CLR(net, &ibits); 821 canread = ring_empty_consecutive(&netiring); 822 c = recv(net, netiring.supply, canread, 0); 823 if (c < 0 && errno == EWOULDBLOCK) { 824 c = 0; 825 } else if (c <= 0) { 826 return (-1); 827 } 828 if (netdata) { 829 Dump('<', netiring.supply, c); 830 } 831 if (c) 832 ring_supplied(&netiring, c); 833 returnValue = 1; 834 } 835 836 /* 837 * Something to read from the tty... 838 */ 839 if (FD_ISSET(tin, &ibits)) { 840 FD_CLR(tin, &ibits); 841 c = TerminalRead((char *)ttyiring.supply, 842 ring_empty_consecutive(&ttyiring)); 843 if (c < 0) { 844 if (errno != EWOULDBLOCK) { 845 /* This will not return. */ 846 fatal_tty_error("read"); 847 } 848 c = 0; 849 } else { 850 /* EOF detection for line mode!!!! */ 851 if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && 852 isatty(tin)) { 853 /* must be an EOF... */ 854 eof_pending = 1; 855 return (1); 856 } 857 if (c <= 0) { 858 returnValue = -1; 859 goto next; 860 } 861 if (termdata) { 862 Dump('<', ttyiring.supply, c); 863 } 864 ring_supplied(&ttyiring, c); 865 } 866 returnValue = 1; /* did something useful */ 867 } 868 869 next: 870 if (FD_ISSET(net, &obits)) { 871 FD_CLR(net, &obits); 872 returnValue |= netflush(); 873 } 874 if (FD_ISSET(tout, &obits)) { 875 FD_CLR(tout, &obits); 876 i = ttyflush(SYNCHing|flushout); 877 if (i == -2) { 878 /* This will not return. */ 879 fatal_tty_error("write"); 880 } 881 returnValue |= (i > 0); 882 } 883 884 return (returnValue); 885 } 886