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