1 /* $OpenBSD: sys_bsd.c,v 1.8 2000/10/10 15:41:10 millert 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. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include "telnet_locl.h" 38 #include <err.h> 39 40 /* 41 * The following routines try to encapsulate what is system dependent 42 * (at least between 4.x and dos) which is used in telnet.c. 43 */ 44 45 int 46 tout, /* Output file descriptor */ 47 tin, /* Input file descriptor */ 48 net; 49 50 #ifndef USE_TERMIO 51 struct tchars otc = { 0 }, ntc = { 0 }; 52 struct ltchars oltc = { 0 }, nltc = { 0 }; 53 struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 54 int olmode = 0; 55 # define cfgetispeed(ptr) (ptr)->sg_ispeed 56 # define cfgetospeed(ptr) (ptr)->sg_ospeed 57 # define old_tc ottyb 58 59 #else /* USE_TERMIO */ 60 struct termios old_tc = { 0 }; 61 extern struct termios new_tc; 62 63 # ifndef TCSANOW 64 # ifdef TCSETS 65 # define TCSANOW TCSETS 66 # define TCSADRAIN TCSETSW 67 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) 68 # else 69 # ifdef TCSETA 70 # define TCSANOW TCSETA 71 # define TCSADRAIN TCSETAW 72 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) 73 # else 74 # define TCSANOW TIOCSETA 75 # define TCSADRAIN TIOCSETAW 76 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) 77 # endif 78 # endif 79 # define tcsetattr(f, a, t) ioctl(f, a, (char *)t) 80 # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD) 81 # ifdef CIBAUD 82 # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT) 83 # else 84 # define cfgetispeed(ptr) cfgetospeed(ptr) 85 # endif 86 # endif /* TCSANOW */ 87 # ifdef sysV88 88 # define TIOCFLUSH TC_PX_DRAIN 89 # endif 90 #endif /* USE_TERMIO */ 91 92 fd_set *ibitsp, *obitsp, *xbitsp; 93 int fdsn; 94 95 void 96 init_sys() 97 { 98 tout = fileno(stdout); 99 tin = fileno(stdin); 100 101 errno = 0; 102 } 103 104 105 int 106 TerminalWrite(buf, n) 107 char *buf; 108 int n; 109 { 110 return write(tout, buf, n); 111 } 112 113 int 114 TerminalRead(buf, n) 115 unsigned char *buf; 116 int n; 117 { 118 return read(tin, buf, n); 119 } 120 121 /* 122 * 123 */ 124 125 int 126 TerminalAutoFlush() 127 { 128 #if defined(LNOFLSH) 129 int flush; 130 131 ioctl(0, TIOCLGET, (char *)&flush); 132 return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ 133 #else /* LNOFLSH */ 134 return 1; 135 #endif /* LNOFLSH */ 136 } 137 138 #ifdef KLUDGELINEMODE 139 extern int kludgelinemode; 140 #endif 141 /* 142 * TerminalSpecialChars() 143 * 144 * Look at an input character to see if it is a special character 145 * and decide what to do. 146 * 147 * Output: 148 * 149 * 0 Don't add this character. 150 * 1 Do add this character 151 */ 152 153 extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); 154 155 int 156 TerminalSpecialChars(c) 157 int c; 158 { 159 if (c == termIntChar) { 160 intp(); 161 return 0; 162 } else if (c == termQuitChar) { 163 #ifdef KLUDGELINEMODE 164 if (kludgelinemode) 165 sendbrk(); 166 else 167 #endif 168 sendabort(); 169 return 0; 170 } else if (c == termEofChar) { 171 if (my_want_state_is_will(TELOPT_LINEMODE)) { 172 sendeof(); 173 return 0; 174 } 175 return 1; 176 } else if (c == termSuspChar) { 177 sendsusp(); 178 return(0); 179 } else if (c == termFlushChar) { 180 xmitAO(); /* Transmit Abort Output */ 181 return 0; 182 } else if (!MODE_LOCAL_CHARS(globalmode)) { 183 if (c == termKillChar) { 184 xmitEL(); 185 return 0; 186 } else if (c == termEraseChar) { 187 xmitEC(); /* Transmit Erase Character */ 188 return 0; 189 } 190 } 191 return 1; 192 } 193 194 195 /* 196 * Flush output to the terminal 197 */ 198 199 void 200 TerminalFlushOutput() 201 { 202 #ifdef TIOCFLUSH 203 int com = FWRITE; 204 (void) ioctl(fileno(stdout), TIOCFLUSH, (int *) &com); 205 #else 206 (void) ioctl(fileno(stdout), TCFLSH, (int *) 0); 207 #endif 208 } 209 210 void 211 TerminalSaveState() 212 { 213 #ifndef USE_TERMIO 214 ioctl(0, TIOCGETP, (char *)&ottyb); 215 ioctl(0, TIOCGETC, (char *)&otc); 216 ioctl(0, TIOCGLTC, (char *)&oltc); 217 ioctl(0, TIOCLGET, (char *)&olmode); 218 219 ntc = otc; 220 nltc = oltc; 221 nttyb = ottyb; 222 223 #else /* USE_TERMIO */ 224 tcgetattr(0, &old_tc); 225 226 new_tc = old_tc; 227 228 #ifndef VDISCARD 229 termFlushChar = CONTROL('O'); 230 #endif 231 #ifndef VWERASE 232 termWerasChar = CONTROL('W'); 233 #endif 234 #ifndef VREPRINT 235 termRprntChar = CONTROL('R'); 236 #endif 237 #ifndef VLNEXT 238 termLiteralNextChar = CONTROL('V'); 239 #endif 240 #ifndef VSTART 241 termStartChar = CONTROL('Q'); 242 #endif 243 #ifndef VSTOP 244 termStopChar = CONTROL('S'); 245 #endif 246 #ifndef VSTATUS 247 termAytChar = CONTROL('T'); 248 #endif 249 #endif /* USE_TERMIO */ 250 } 251 252 cc_t * 253 tcval(func) 254 register int func; 255 { 256 switch(func) { 257 case SLC_IP: return(&termIntChar); 258 case SLC_ABORT: return(&termQuitChar); 259 case SLC_EOF: return(&termEofChar); 260 case SLC_EC: return(&termEraseChar); 261 case SLC_EL: return(&termKillChar); 262 case SLC_XON: return(&termStartChar); 263 case SLC_XOFF: return(&termStopChar); 264 case SLC_FORW1: return(&termForw1Char); 265 #ifdef USE_TERMIO 266 case SLC_FORW2: return(&termForw2Char); 267 # ifdef VDISCARD 268 case SLC_AO: return(&termFlushChar); 269 # endif 270 # ifdef VSUSP 271 case SLC_SUSP: return(&termSuspChar); 272 # endif 273 # ifdef VWERASE 274 case SLC_EW: return(&termWerasChar); 275 # endif 276 # ifdef VREPRINT 277 case SLC_RP: return(&termRprntChar); 278 # endif 279 # ifdef VLNEXT 280 case SLC_LNEXT: return(&termLiteralNextChar); 281 # endif 282 # ifdef VSTATUS 283 case SLC_AYT: return(&termAytChar); 284 # endif 285 #endif 286 287 case SLC_SYNCH: 288 case SLC_BRK: 289 case SLC_EOR: 290 default: 291 return((cc_t *)0); 292 } 293 } 294 295 void 296 TerminalDefaultChars() 297 { 298 #ifndef USE_TERMIO 299 ntc = otc; 300 nltc = oltc; 301 nttyb.sg_kill = ottyb.sg_kill; 302 nttyb.sg_erase = ottyb.sg_erase; 303 #else /* USE_TERMIO */ 304 memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); 305 # ifndef VDISCARD 306 termFlushChar = CONTROL('O'); 307 # endif 308 # ifndef VWERASE 309 termWerasChar = CONTROL('W'); 310 # endif 311 # ifndef VREPRINT 312 termRprntChar = CONTROL('R'); 313 # endif 314 # ifndef VLNEXT 315 termLiteralNextChar = CONTROL('V'); 316 # endif 317 # ifndef VSTART 318 termStartChar = CONTROL('Q'); 319 # endif 320 # ifndef VSTOP 321 termStopChar = CONTROL('S'); 322 # endif 323 # ifndef VSTATUS 324 termAytChar = CONTROL('T'); 325 # endif 326 #endif /* USE_TERMIO */ 327 } 328 329 #ifdef notdef 330 void 331 TerminalRestoreState() 332 { 333 } 334 #endif 335 336 /* 337 * TerminalNewMode - set up terminal to a specific mode. 338 * MODE_ECHO: do local terminal echo 339 * MODE_FLOW: do local flow control 340 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 341 * MODE_EDIT: do local line editing 342 * 343 * Command mode: 344 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 345 * local echo 346 * local editing 347 * local xon/xoff 348 * local signal mapping 349 * 350 * Linemode: 351 * local/no editing 352 * Both Linemode and Single Character mode: 353 * local/remote echo 354 * local/no xon/xoff 355 * local/no signal mapping 356 */ 357 358 #ifdef SIGTSTP 359 static void susp(); 360 #endif /* SIGTSTP */ 361 #ifdef SIGINFO 362 static void ayt(); 363 #endif 364 365 void 366 TerminalNewMode(f) 367 register 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 termios 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 # ifdef notdef 443 if (crlf) 444 tmp_tc.c_iflag &= ~ICRNL; 445 # endif 446 #endif 447 } 448 449 if ((f&MODE_FLOW) == 0) { 450 #ifndef USE_TERMIO 451 tc.t_startc = _POSIX_VDISABLE; 452 tc.t_stopc = _POSIX_VDISABLE; 453 #else 454 tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */ 455 } else { 456 if (restartany < 0) { 457 tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */ 458 } else if (restartany > 0) { 459 tmp_tc.c_iflag |= IXOFF|IXON|IXANY; 460 } else { 461 tmp_tc.c_iflag |= IXOFF|IXON; 462 tmp_tc.c_iflag &= ~IXANY; 463 } 464 #endif 465 } 466 467 if ((f&MODE_TRAPSIG) == 0) { 468 #ifndef USE_TERMIO 469 tc.t_intrc = _POSIX_VDISABLE; 470 tc.t_quitc = _POSIX_VDISABLE; 471 tc.t_eofc = _POSIX_VDISABLE; 472 ltc.t_suspc = _POSIX_VDISABLE; 473 ltc.t_dsuspc = _POSIX_VDISABLE; 474 #else 475 tmp_tc.c_lflag &= ~ISIG; 476 #endif 477 localchars = 0; 478 } else { 479 #ifdef USE_TERMIO 480 tmp_tc.c_lflag |= ISIG; 481 #endif 482 localchars = 1; 483 } 484 485 if (f&MODE_EDIT) { 486 #ifndef USE_TERMIO 487 sb.sg_flags &= ~CBREAK; 488 sb.sg_flags |= CRMOD; 489 #else 490 tmp_tc.c_lflag |= ICANON; 491 #endif 492 } else { 493 #ifndef USE_TERMIO 494 sb.sg_flags |= CBREAK; 495 if (f&MODE_ECHO) 496 sb.sg_flags |= CRMOD; 497 else 498 sb.sg_flags &= ~CRMOD; 499 #else 500 tmp_tc.c_lflag &= ~ICANON; 501 tmp_tc.c_iflag &= ~ICRNL; 502 tmp_tc.c_cc[VMIN] = 1; 503 tmp_tc.c_cc[VTIME] = 0; 504 #endif 505 } 506 507 if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { 508 #ifndef USE_TERMIO 509 ltc.t_lnextc = _POSIX_VDISABLE; 510 #else 511 tmp_tc.c_lflag &= ~IEXTEN; 512 #endif 513 } 514 515 if (f&MODE_SOFT_TAB) { 516 #ifndef USE_TERMIO 517 sb.sg_flags |= XTABS; 518 #else 519 # ifdef OXTABS 520 tmp_tc.c_oflag |= OXTABS; 521 # endif 522 # ifdef TABDLY 523 tmp_tc.c_oflag &= ~TABDLY; 524 tmp_tc.c_oflag |= TAB3; 525 # endif 526 #endif 527 } else { 528 #ifndef USE_TERMIO 529 sb.sg_flags &= ~XTABS; 530 #else 531 # ifdef OXTABS 532 tmp_tc.c_oflag &= ~OXTABS; 533 # endif 534 # ifdef TABDLY 535 tmp_tc.c_oflag &= ~TABDLY; 536 # endif 537 #endif 538 } 539 540 if (f&MODE_LIT_ECHO) { 541 #ifndef USE_TERMIO 542 lmode &= ~LCTLECH; 543 #else 544 # ifdef ECHOCTL 545 tmp_tc.c_lflag &= ~ECHOCTL; 546 # endif 547 #endif 548 } else { 549 #ifndef USE_TERMIO 550 lmode |= LCTLECH; 551 #else 552 # ifdef ECHOCTL 553 tmp_tc.c_lflag |= ECHOCTL; 554 # endif 555 #endif 556 } 557 558 if (f == -1) { 559 onoff = 0; 560 } else { 561 #ifndef USE_TERMIO 562 if (f & MODE_OUTBIN) 563 lmode |= LLITOUT; 564 else 565 lmode &= ~LLITOUT; 566 567 if (f & MODE_INBIN) 568 lmode |= LPASS8; 569 else 570 lmode &= ~LPASS8; 571 #else 572 if (f & MODE_INBIN) 573 tmp_tc.c_iflag &= ~ISTRIP; 574 else 575 tmp_tc.c_iflag |= ISTRIP; 576 if ((f & MODE_OUTBIN) || (f & MODE_OUT8)) { 577 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 578 tmp_tc.c_cflag |= CS8; 579 if(f & MODE_OUTBIN) 580 tmp_tc.c_oflag &= ~OPOST; 581 else 582 tmp_tc.c_oflag |= OPOST; 583 584 } else { 585 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 586 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB); 587 tmp_tc.c_oflag |= OPOST; 588 } 589 #endif 590 onoff = 1; 591 } 592 593 if (f != -1) { 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 ayt_status(); 641 642 (void) signal(SIGINFO, (void (*)(int))ayt_status); 643 #endif 644 #ifdef SIGTSTP 645 (void) signal(SIGTSTP, SIG_DFL); 646 # ifndef SOLARIS 647 (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 648 # else SOLARIS 649 (void) sigrelse(SIGTSTP); 650 # endif SOLARIS 651 #endif /* SIGTSTP */ 652 #ifndef USE_TERMIO 653 ltc = oltc; 654 tc = otc; 655 sb = ottyb; 656 lmode = olmode; 657 #else 658 tmp_tc = old_tc; 659 #endif 660 } 661 #ifndef USE_TERMIO 662 ioctl(tin, TIOCLSET, (char *)&lmode); 663 ioctl(tin, TIOCSLTC, (char *)<c); 664 ioctl(tin, TIOCSETC, (char *)&tc); 665 ioctl(tin, TIOCSETN, (char *)&sb); 666 #else 667 if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) 668 tcsetattr(tin, TCSANOW, &tmp_tc); 669 #endif 670 671 #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 672 # if !defined(sysV88) 673 ioctl(tin, FIONBIO, (char *)&onoff); 674 ioctl(tout, FIONBIO, (char *)&onoff); 675 # endif 676 #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 677 #if defined(TN3270) 678 if (noasynchtty == 0) { 679 ioctl(tin, FIOASYNC, (char *)&onoff); 680 } 681 #endif /* defined(TN3270) */ 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(ispeed, ospeed) 752 long *ispeed; 753 long *ospeed; 754 { 755 #ifdef DECODE_BAUD 756 register struct termspeeds *tp; 757 #endif /* DECODE_BAUD */ 758 register long in, out; 759 760 out = cfgetospeed(&old_tc); 761 in = cfgetispeed(&old_tc); 762 if (in == 0) 763 in = out; 764 765 #ifdef DECODE_BAUD 766 tp = termspeeds; 767 while ((tp->speed != -1) && (tp->value < in)) 768 tp++; 769 *ispeed = tp->speed; 770 771 tp = termspeeds; 772 while ((tp->speed != -1) && (tp->value < out)) 773 tp++; 774 *ospeed = tp->speed; 775 #else /* DECODE_BAUD */ 776 *ispeed = in; 777 *ospeed = out; 778 #endif /* DECODE_BAUD */ 779 } 780 781 int 782 TerminalWindowSize(rows, cols) 783 long *rows, *cols; 784 { 785 #ifdef TIOCGWINSZ 786 struct winsize ws; 787 788 if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 789 *rows = ws.ws_row; 790 *cols = ws.ws_col; 791 return 1; 792 } 793 #endif /* TIOCGWINSZ */ 794 return 0; 795 } 796 797 int 798 NetClose(fd) 799 int fd; 800 { 801 return close(fd); 802 } 803 804 805 void 806 NetNonblockingIO(fd, onoff) 807 int fd; 808 int onoff; 809 { 810 ioctl(fd, FIONBIO, (char *)&onoff); 811 } 812 813 #if defined(TN3270) 814 void 815 NetSigIO(fd, onoff) 816 int fd; 817 int onoff; 818 { 819 ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ 820 } 821 822 void 823 NetSetPgrp(fd) 824 int fd; 825 { 826 int myPid; 827 828 myPid = getpid(); 829 fcntl(fd, F_SETOWN, myPid); 830 } 831 #endif /*defined(TN3270)*/ 832 833 /* 834 * Various signal handling routines. 835 */ 836 837 /* ARGSUSED */ 838 void 839 deadpeer(sig) 840 int sig; 841 { 842 setcommandmode(); 843 longjmp(peerdied, -1); 844 } 845 846 /* ARGSUSED */ 847 void 848 intr(sig) 849 int sig; 850 { 851 if (localchars) { 852 intp(); 853 return; 854 } 855 setcommandmode(); 856 longjmp(toplevel, -1); 857 } 858 859 /* ARGSUSED */ 860 void 861 intr2(sig) 862 int sig; 863 { 864 if (localchars) { 865 #ifdef KLUDGELINEMODE 866 if (kludgelinemode) 867 sendbrk(); 868 else 869 #endif 870 sendabort(); 871 return; 872 } 873 } 874 875 #ifdef SIGTSTP 876 /* ARGSUSED */ 877 void 878 susp(sig) 879 int sig; 880 { 881 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) 882 return; 883 if (localchars) 884 sendsusp(); 885 } 886 #endif 887 888 #ifdef SIGWINCH 889 /* ARGSUSED */ 890 void 891 sendwin(sig) 892 int sig; 893 { 894 if (connected) { 895 sendnaws(); 896 } 897 } 898 #endif 899 900 #ifdef SIGINFO 901 /* ARGSUSED */ 902 void 903 ayt(sig) 904 int sig; 905 { 906 if (connected) 907 sendayt(); 908 else 909 ayt_status(); 910 } 911 #endif 912 913 914 void 915 sys_telnet_init() 916 { 917 (void) signal(SIGINT, intr); 918 (void) signal(SIGQUIT, intr2); 919 (void) signal(SIGPIPE, deadpeer); 920 #ifdef SIGWINCH 921 (void) signal(SIGWINCH, sendwin); 922 #endif 923 #ifdef SIGTSTP 924 (void) signal(SIGTSTP, susp); 925 #endif 926 #ifdef SIGINFO 927 (void) signal(SIGINFO, ayt); 928 #endif 929 930 setconnmode(0); 931 932 NetNonblockingIO(net, 1); 933 934 #if defined(TN3270) 935 if (noasynchnet == 0) { /* DBX can't handle! */ 936 NetSigIO(net, 1); 937 NetSetPgrp(net); 938 } 939 #endif /* defined(TN3270) */ 940 941 #if defined(SO_OOBINLINE) 942 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 943 perror("SetSockOpt"); 944 } 945 #endif /* defined(SO_OOBINLINE) */ 946 } 947 948 /* 949 * Process rings - 950 * 951 * This routine tries to fill up/empty our various rings. 952 * 953 * The parameter specifies whether this is a poll operation, 954 * or a block-until-something-happens operation. 955 * 956 * The return value is 1 if something happened, 0 if not. 957 */ 958 959 int 960 process_rings(netin, netout, netex, ttyin, ttyout, poll) 961 int poll; /* If 0, then block until something to do */ 962 { 963 register int c; 964 /* One wants to be a bit careful about setting returnValue 965 * to one, since a one implies we did some useful work, 966 * and therefore probably won't be called to block next 967 * time (TN3270 mode only). 968 */ 969 int returnValue = 0; 970 static struct timeval TimeValue = { 0 }; 971 int maxfd = -1; 972 int tmp; 973 974 if ((netout || netin || netex) && net > maxfd) 975 maxfd = net; 976 if (ttyout && tout > maxfd) 977 maxfd = tout; 978 if (ttyin && tin > maxfd) 979 maxfd = tin; 980 tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask); 981 if (tmp > fdsn) { 982 if (ibitsp) 983 free(ibitsp); 984 if (obitsp) 985 free(obitsp); 986 if (xbitsp) 987 free(xbitsp); 988 fdsn = tmp; 989 if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL) 990 err(1, "malloc"); 991 if ((obitsp = (fd_set *)malloc(fdsn)) == NULL) 992 err(1, "malloc"); 993 if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL) 994 err(1, "malloc"); 995 memset(ibitsp, 0, fdsn); 996 memset(obitsp, 0, fdsn); 997 memset(xbitsp, 0, fdsn); 998 } 999 1000 if (netout) 1001 FD_SET(net, obitsp); 1002 if (ttyout) 1003 FD_SET(tout, obitsp); 1004 if (ttyin) 1005 FD_SET(tin, ibitsp); 1006 if (netin) 1007 FD_SET(net, ibitsp); 1008 if (netex) 1009 FD_SET(net, xbitsp); 1010 1011 if ((c = select(maxfd+1, ibitsp, obitsp, xbitsp, 1012 (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { 1013 if (c == -1) { 1014 /* 1015 * we can get EINTR if we are in line mode, 1016 * and the user does an escape (TSTP), or 1017 * some other signal generator. 1018 */ 1019 if (errno == EINTR) { 1020 return 0; 1021 } 1022 # if defined(TN3270) 1023 /* 1024 * we can get EBADF if we were in transparent 1025 * mode, and the transcom process died. 1026 */ 1027 if (errno == EBADF) { 1028 /* 1029 * zero the bits (even though kernel does it) 1030 * to make sure we are selecting on the right 1031 * ones. 1032 */ 1033 memset(ibitsp, 0, fdsn); 1034 memset(obitsp, 0, fdsn); 1035 memset(xbitsp, 0, fdsn); 1036 return 0; 1037 } 1038 # endif /* defined(TN3270) */ 1039 /* I don't like this, does it ever happen? */ 1040 printf("sleep(5) from telnet, after select\r\n"); 1041 sleep(5); 1042 } 1043 return 0; 1044 } 1045 1046 /* 1047 * Any urgent data? 1048 */ 1049 if (FD_ISSET(net, xbitsp)) { 1050 FD_CLR(net, xbitsp); 1051 SYNCHing = 1; 1052 (void) ttyflush(1); /* flush already enqueued data */ 1053 } 1054 1055 /* 1056 * Something to read from the network... 1057 */ 1058 if (FD_ISSET(net, ibitsp)) { 1059 int canread; 1060 1061 FD_CLR(net, ibitsp); 1062 canread = ring_empty_consecutive(&netiring); 1063 #if !defined(SO_OOBINLINE) 1064 /* 1065 * In 4.2 (and some early 4.3) systems, the 1066 * OOB indication and data handling in the kernel 1067 * is such that if two separate TCP Urgent requests 1068 * come in, one byte of TCP data will be overlaid. 1069 * This is fatal for Telnet, but we try to live 1070 * with it. 1071 * 1072 * In addition, in 4.2 (and...), a special protocol 1073 * is needed to pick up the TCP Urgent data in 1074 * the correct sequence. 1075 * 1076 * What we do is: if we think we are in urgent 1077 * mode, we look to see if we are "at the mark". 1078 * If we are, we do an OOB receive. If we run 1079 * this twice, we will do the OOB receive twice, 1080 * but the second will fail, since the second 1081 * time we were "at the mark", but there wasn't 1082 * any data there (the kernel doesn't reset 1083 * "at the mark" until we do a normal read). 1084 * Once we've read the OOB data, we go ahead 1085 * and do normal reads. 1086 * 1087 * There is also another problem, which is that 1088 * since the OOB byte we read doesn't put us 1089 * out of OOB state, and since that byte is most 1090 * likely the TELNET DM (data mark), we would 1091 * stay in the TELNET SYNCH (SYNCHing) state. 1092 * So, clocks to the rescue. If we've "just" 1093 * received a DM, then we test for the 1094 * presence of OOB data when the receive OOB 1095 * fails (and AFTER we did the normal mode read 1096 * to clear "at the mark"). 1097 */ 1098 if (SYNCHing) { 1099 int atmark; 1100 static int bogus_oob = 0, first = 1; 1101 1102 ioctl(net, SIOCATMARK, (char *)&atmark); 1103 if (atmark) { 1104 c = recv(net, netiring.supply, canread, MSG_OOB); 1105 if ((c == -1) && (errno == EINVAL)) { 1106 c = recv(net, netiring.supply, canread, 0); 1107 if (clocks.didnetreceive < clocks.gotDM) { 1108 SYNCHing = stilloob(net); 1109 } 1110 } else if (first && c > 0) { 1111 /* 1112 * Bogosity check. Systems based on 4.2BSD 1113 * do not return an error if you do a second 1114 * recv(MSG_OOB). So, we do one. If it 1115 * succeeds and returns exactly the same 1116 * data, then assume that we are running 1117 * on a broken system and set the bogus_oob 1118 * flag. (If the data was different, then 1119 * we probably got some valid new data, so 1120 * increment the count...) 1121 */ 1122 int i; 1123 i = recv(net, netiring.supply + c, canread - c, MSG_OOB); 1124 if (i == c && 1125 memcmp(netiring.supply, netiring.supply + c, i) == 0) { 1126 bogus_oob = 1; 1127 first = 0; 1128 } else if (i < 0) { 1129 bogus_oob = 0; 1130 first = 0; 1131 } else 1132 c += i; 1133 } 1134 if (bogus_oob && c > 0) { 1135 int i; 1136 /* 1137 * Bogosity. We have to do the read 1138 * to clear the atmark to get out of 1139 * an infinate loop. 1140 */ 1141 i = read(net, netiring.supply + c, canread - c); 1142 if (i > 0) 1143 c += i; 1144 } 1145 } else { 1146 c = recv(net, netiring.supply, canread, 0); 1147 } 1148 } else { 1149 c = recv(net, netiring.supply, canread, 0); 1150 } 1151 settimer(didnetreceive); 1152 #else /* !defined(SO_OOBINLINE) */ 1153 c = recv(net, (char *)netiring.supply, canread, 0); 1154 #endif /* !defined(SO_OOBINLINE) */ 1155 if (c < 0 && errno == EWOULDBLOCK) { 1156 c = 0; 1157 } else if (c <= 0) { 1158 return -1; 1159 } 1160 if (netdata) { 1161 Dump('<', netiring.supply, c); 1162 } 1163 if (c) 1164 ring_supplied(&netiring, c); 1165 returnValue = 1; 1166 } 1167 1168 /* 1169 * Something to read from the tty... 1170 */ 1171 if (FD_ISSET(tin, ibitsp)) { 1172 FD_CLR(tin, ibitsp); 1173 c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 1174 if (c < 0 && errno == EIO) 1175 c = 0; 1176 if (c < 0 && errno == EWOULDBLOCK) { 1177 c = 0; 1178 } else { 1179 /* EOF detection for line mode!!!! */ 1180 if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 1181 /* must be an EOF... */ 1182 *ttyiring.supply = termEofChar; 1183 c = 1; 1184 } 1185 if (c <= 0) { 1186 return -1; 1187 } 1188 if (termdata) { 1189 Dump('<', ttyiring.supply, c); 1190 } 1191 ring_supplied(&ttyiring, c); 1192 } 1193 returnValue = 1; /* did something useful */ 1194 } 1195 1196 if (FD_ISSET(net, obitsp)) { 1197 FD_CLR(net, obitsp); 1198 returnValue |= netflush(); 1199 } 1200 if (FD_ISSET(tout, obitsp)) { 1201 FD_CLR(tout, obitsp); 1202 returnValue |= (ttyflush(SYNCHing|flushout) > 0); 1203 } 1204 1205 return returnValue; 1206 } 1207