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