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