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