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