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