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