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