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