1 /* $NetBSD: sys_bsd.c,v 1.22 2002/09/23 12:48:04 mycroft 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.22 2002/09/23 12:48:04 mycroft 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 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 } while (old < 0 || old > 1); 447 } 448 449 old = prevmode; 450 prevmode = f&~MODE_FORCE; 451 #ifndef USE_TERMIO 452 sb = nttyb; 453 tc = ntc; 454 ltc = nltc; 455 lmode = olmode; 456 #else 457 tmp_tc = new_tc; 458 #endif 459 460 if (f&MODE_ECHO) { 461 #ifndef USE_TERMIO 462 sb.sg_flags |= ECHO; 463 #else 464 tmp_tc.c_lflag |= ECHO; 465 tmp_tc.c_oflag |= ONLCR; 466 if (crlf) 467 tmp_tc.c_iflag |= ICRNL; 468 #endif 469 } else { 470 #ifndef USE_TERMIO 471 sb.sg_flags &= ~ECHO; 472 #else 473 tmp_tc.c_lflag &= ~ECHO; 474 tmp_tc.c_oflag &= ~ONLCR; 475 # ifdef notdef 476 if (crlf) 477 tmp_tc.c_iflag &= ~ICRNL; 478 # endif 479 #endif 480 } 481 482 if ((f&MODE_FLOW) == 0) { 483 #ifndef USE_TERMIO 484 tc.t_startc = _POSIX_VDISABLE; 485 tc.t_stopc = _POSIX_VDISABLE; 486 #else 487 tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */ 488 } else { 489 if (restartany < 0) { 490 tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */ 491 } else if (restartany > 0) { 492 tmp_tc.c_iflag |= IXOFF|IXON|IXANY; 493 } else { 494 tmp_tc.c_iflag |= IXOFF|IXON; 495 tmp_tc.c_iflag &= ~IXANY; 496 } 497 #endif 498 } 499 500 if ((f&MODE_TRAPSIG) == 0) { 501 #ifndef USE_TERMIO 502 tc.t_intrc = _POSIX_VDISABLE; 503 tc.t_quitc = _POSIX_VDISABLE; 504 tc.t_eofc = _POSIX_VDISABLE; 505 ltc.t_suspc = _POSIX_VDISABLE; 506 ltc.t_dsuspc = _POSIX_VDISABLE; 507 #else 508 tmp_tc.c_lflag &= ~ISIG; 509 #endif 510 localchars = 0; 511 } else { 512 #ifdef USE_TERMIO 513 tmp_tc.c_lflag |= ISIG; 514 #endif 515 localchars = 1; 516 } 517 518 if (f&MODE_EDIT) { 519 #ifndef USE_TERMIO 520 sb.sg_flags &= ~CBREAK; 521 sb.sg_flags |= CRMOD; 522 #else 523 tmp_tc.c_lflag |= ICANON; 524 #endif 525 } else { 526 #ifndef USE_TERMIO 527 sb.sg_flags |= CBREAK; 528 if (f&MODE_ECHO) 529 sb.sg_flags |= CRMOD; 530 else 531 sb.sg_flags &= ~CRMOD; 532 #else 533 tmp_tc.c_lflag &= ~ICANON; 534 tmp_tc.c_iflag &= ~ICRNL; 535 tmp_tc.c_cc[VMIN] = 1; 536 tmp_tc.c_cc[VTIME] = 0; 537 #endif 538 } 539 540 if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { 541 #ifndef USE_TERMIO 542 ltc.t_lnextc = _POSIX_VDISABLE; 543 #else 544 tmp_tc.c_lflag &= ~IEXTEN; 545 #endif 546 } 547 548 if (f&MODE_SOFT_TAB) { 549 #ifndef USE_TERMIO 550 sb.sg_flags |= XTABS; 551 #else 552 # ifdef OXTABS 553 tmp_tc.c_oflag |= OXTABS; 554 # endif 555 # ifdef TABDLY 556 tmp_tc.c_oflag &= ~TABDLY; 557 tmp_tc.c_oflag |= TAB3; 558 # endif 559 #endif 560 } else { 561 #ifndef USE_TERMIO 562 sb.sg_flags &= ~XTABS; 563 #else 564 # ifdef OXTABS 565 tmp_tc.c_oflag &= ~OXTABS; 566 # endif 567 # ifdef TABDLY 568 tmp_tc.c_oflag &= ~TABDLY; 569 # endif 570 #endif 571 } 572 573 if (f&MODE_LIT_ECHO) { 574 #ifndef USE_TERMIO 575 lmode &= ~LCTLECH; 576 #else 577 # ifdef ECHOCTL 578 tmp_tc.c_lflag &= ~ECHOCTL; 579 # endif 580 #endif 581 } else { 582 #ifndef USE_TERMIO 583 lmode |= LCTLECH; 584 #else 585 # ifdef ECHOCTL 586 tmp_tc.c_lflag |= ECHOCTL; 587 # endif 588 #endif 589 } 590 591 if (f == -1) { 592 onoff = 0; 593 } else { 594 #ifndef USE_TERMIO 595 if (f & MODE_OUTBIN) 596 lmode |= LLITOUT; 597 else 598 lmode &= ~LLITOUT; 599 600 if (f & MODE_INBIN) 601 lmode |= LPASS8; 602 else 603 lmode &= ~LPASS8; 604 #else 605 if (f & MODE_INBIN) 606 tmp_tc.c_iflag &= ~ISTRIP; 607 else 608 tmp_tc.c_iflag |= ISTRIP; 609 if (f & MODE_OUTBIN) { 610 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 611 tmp_tc.c_cflag |= CS8; 612 tmp_tc.c_oflag &= ~OPOST; 613 } else { 614 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 615 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB); 616 tmp_tc.c_oflag |= OPOST; 617 } 618 #endif 619 onoff = 1; 620 } 621 622 if (f != -1) { 623 #ifdef SIGTSTP 624 (void) signal(SIGTSTP, susp); 625 #endif /* SIGTSTP */ 626 #ifdef SIGINFO 627 (void) signal(SIGINFO, ayt); 628 #endif 629 #if defined(USE_TERMIO) && defined(NOKERNINFO) 630 tmp_tc.c_lflag |= NOKERNINFO; 631 #endif 632 /* 633 * We don't want to process ^Y here. It's just another 634 * character that we'll pass on to the back end. It has 635 * to process it because it will be processed when the 636 * user attempts to read it, not when we send it. 637 */ 638 #ifndef USE_TERMIO 639 ltc.t_dsuspc = _POSIX_VDISABLE; 640 #else 641 # ifdef VDSUSP 642 tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE); 643 # endif 644 #endif 645 #ifdef USE_TERMIO 646 /* 647 * If the VEOL character is already set, then use VEOL2, 648 * otherwise use VEOL. 649 */ 650 esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape; 651 if ((tmp_tc.c_cc[VEOL] != esc) 652 # ifdef VEOL2 653 && (tmp_tc.c_cc[VEOL2] != esc) 654 # endif 655 ) { 656 if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE)) 657 tmp_tc.c_cc[VEOL] = esc; 658 # ifdef VEOL2 659 else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE)) 660 tmp_tc.c_cc[VEOL2] = esc; 661 # endif 662 } 663 #else 664 if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE)) 665 tc.t_brkc = esc; 666 #endif 667 } else { 668 #ifdef SIGINFO 669 (void) signal(SIGINFO, (void (*)(int)) ayt_status); 670 #endif 671 #ifdef SIGTSTP 672 (void) signal(SIGTSTP, SIG_DFL); 673 # ifndef SOLARIS 674 (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 675 # else /* SOLARIS */ 676 (void) sigrelse(SIGTSTP); 677 # endif /* SOLARIS */ 678 #endif /* SIGTSTP */ 679 #ifndef USE_TERMIO 680 ltc = oltc; 681 tc = otc; 682 sb = ottyb; 683 lmode = olmode; 684 #else 685 tmp_tc = old_tc; 686 #endif 687 } 688 #ifndef USE_TERMIO 689 ioctl(tin, TIOCLSET, (char *)&lmode); 690 ioctl(tin, TIOCSLTC, (char *)<c); 691 ioctl(tin, TIOCSETC, (char *)&tc); 692 ioctl(tin, TIOCSETN, (char *)&sb); 693 #else 694 if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) 695 tcsetattr(tin, TCSANOW, &tmp_tc); 696 #endif 697 698 #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 699 # if !defined(sysV88) 700 ioctl(tin, FIONBIO, (char *)&onoff); 701 ioctl(tout, FIONBIO, (char *)&onoff); 702 # endif 703 #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 704 #if defined(TN3270) 705 if (noasynchtty == 0) { 706 ioctl(tin, FIOASYNC, (char *)&onoff); 707 } 708 #endif /* defined(TN3270) */ 709 710 } 711 712 /* 713 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). 714 */ 715 #if B4800 != 4800 716 #define DECODE_BAUD 717 #endif 718 719 #ifdef DECODE_BAUD 720 #ifndef B7200 721 #define B7200 B4800 722 #endif 723 724 #ifndef B14400 725 #define B14400 B9600 726 #endif 727 728 #ifndef B19200 729 # define B19200 B14400 730 #endif 731 732 #ifndef B28800 733 #define B28800 B19200 734 #endif 735 736 #ifndef B38400 737 # define B38400 B28800 738 #endif 739 740 #ifndef B57600 741 #define B57600 B38400 742 #endif 743 744 #ifndef B76800 745 #define B76800 B57600 746 #endif 747 748 #ifndef B115200 749 #define B115200 B76800 750 #endif 751 752 #ifndef B230400 753 #define B230400 B115200 754 #endif 755 756 757 /* 758 * This code assumes that the values B0, B50, B75... 759 * are in ascending order. They do not have to be 760 * contiguous. 761 */ 762 struct termspeeds { 763 long speed; 764 long value; 765 } termspeeds[] = { 766 { 0, B0 }, { 50, B50 }, { 75, B75 }, 767 { 110, B110 }, { 134, B134 }, { 150, B150 }, 768 { 200, B200 }, { 300, B300 }, { 600, B600 }, 769 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 770 { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 }, 771 { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 }, 772 { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 }, 773 { 230400, B230400 }, { -1, B230400 } 774 }; 775 #endif /* DECODE_BAUD */ 776 777 void 778 TerminalSpeeds(ispeed, ospeed) 779 long *ispeed; 780 long *ospeed; 781 { 782 #ifdef DECODE_BAUD 783 struct termspeeds *tp; 784 #endif /* DECODE_BAUD */ 785 long in, out; 786 787 out = cfgetospeed(&old_tc); 788 in = cfgetispeed(&old_tc); 789 if (in == 0) 790 in = out; 791 792 #ifdef DECODE_BAUD 793 tp = termspeeds; 794 while ((tp->speed != -1) && (tp->value < in)) 795 tp++; 796 *ispeed = tp->speed; 797 798 tp = termspeeds; 799 while ((tp->speed != -1) && (tp->value < out)) 800 tp++; 801 *ospeed = tp->speed; 802 #else /* DECODE_BAUD */ 803 *ispeed = in; 804 *ospeed = out; 805 #endif /* DECODE_BAUD */ 806 } 807 808 int 809 TerminalWindowSize(rows, cols) 810 long *rows, *cols; 811 { 812 #ifdef TIOCGWINSZ 813 struct winsize ws; 814 815 if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 816 *rows = ws.ws_row; 817 *cols = ws.ws_col; 818 return 1; 819 } 820 #endif /* TIOCGWINSZ */ 821 return 0; 822 } 823 824 int 825 NetClose(fd) 826 int fd; 827 { 828 return close(fd); 829 } 830 831 832 void 833 NetNonblockingIO(fd, onoff) 834 int fd; 835 int onoff; 836 { 837 ioctl(fd, FIONBIO, (char *)&onoff); 838 } 839 840 #if defined(TN3270) 841 void 842 NetSigIO(fd, onoff) 843 int fd; 844 int onoff; 845 { 846 ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ 847 } 848 849 void 850 NetSetPgrp(fd) 851 int fd; 852 { 853 int myPid; 854 855 myPid = getpid(); 856 fcntl(fd, F_SETOWN, myPid); 857 } 858 #endif /*defined(TN3270)*/ 859 860 /* 861 * Various signal handling routines. 862 */ 863 864 /* ARGSUSED */ 865 SIG_FUNC_RET 866 deadpeer(sig) 867 int sig; 868 { 869 setcommandmode(); 870 longjmp(peerdied, -1); 871 } 872 873 /* ARGSUSED */ 874 SIG_FUNC_RET 875 intr(sig) 876 int sig; 877 { 878 if (localchars) { 879 intp(); 880 return; 881 } 882 setcommandmode(); 883 longjmp(toplevel, -1); 884 } 885 886 /* ARGSUSED */ 887 SIG_FUNC_RET 888 intr2(sig) 889 int sig; 890 { 891 if (localchars) { 892 #ifdef KLUDGELINEMODE 893 if (kludgelinemode) 894 sendbrk(); 895 else 896 #endif 897 sendabort(); 898 return; 899 } 900 } 901 902 #ifdef SIGTSTP 903 /* ARGSUSED */ 904 SIG_FUNC_RET 905 susp(sig) 906 int sig; 907 { 908 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) 909 return; 910 if (localchars) 911 sendsusp(); 912 } 913 #endif 914 915 #ifdef SIGWINCH 916 /* ARGSUSED */ 917 SIG_FUNC_RET 918 sendwin(sig) 919 int sig; 920 { 921 if (connected) { 922 sendnaws(); 923 } 924 } 925 #endif 926 927 #ifdef SIGINFO 928 /* ARGSUSED */ 929 SIG_FUNC_RET 930 ayt(sig) 931 int sig; 932 { 933 if (connected) 934 sendayt(); 935 else 936 ayt_status(); 937 } 938 #endif 939 940 941 void 942 sys_telnet_init() 943 { 944 (void) signal(SIGINT, intr); 945 (void) signal(SIGQUIT, intr2); 946 (void) signal(SIGPIPE, deadpeer); 947 #ifdef SIGWINCH 948 (void) signal(SIGWINCH, sendwin); 949 #endif 950 #ifdef SIGTSTP 951 (void) signal(SIGTSTP, susp); 952 #endif 953 #ifdef SIGINFO 954 (void) signal(SIGINFO, ayt); 955 #endif 956 957 setconnmode(0); 958 959 NetNonblockingIO(net, 1); 960 961 #if defined(TN3270) 962 if (noasynchnet == 0) { /* DBX can't handle! */ 963 NetSigIO(net, 1); 964 NetSetPgrp(net); 965 } 966 #endif /* defined(TN3270) */ 967 968 #if defined(SO_OOBINLINE) 969 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 970 perror("SetSockOpt"); 971 } 972 #endif /* defined(SO_OOBINLINE) */ 973 } 974 975 /* 976 * Process rings - 977 * 978 * This routine tries to fill up/empty our various rings. 979 * 980 * The parameter specifies whether this is a poll operation, 981 * or a block-until-something-happens operation. 982 * 983 * The return value is 1 if something happened, 0 if not. 984 */ 985 986 int 987 process_rings(netin, netout, netex, ttyin, ttyout, dopoll) 988 int netin, netout, netex, ttyin, ttyout; 989 int dopoll; /* If 0, then block until something to do */ 990 { 991 struct pollfd set[3]; 992 int c; 993 /* One wants to be a bit careful about setting returnValue 994 * to one, since a one implies we did some useful work, 995 * and therefore probably won't be called to block next 996 * time (TN3270 mode only). 997 */ 998 int returnValue = 0; 999 1000 set[0].fd = net; 1001 set[0].events = (netout ? POLLOUT : 0) | (netin ? POLLIN : 0) | 1002 (netex ? POLLPRI : 0); 1003 set[1].fd = tout; 1004 set[1].events = ttyout ? POLLOUT : 0; 1005 set[2].fd = tin; 1006 set[2].events = ttyin ? POLLIN : 0; 1007 1008 if ((c = poll(set, 3, dopoll ? 0 : INFTIM)) < 0) { 1009 if (c == -1) { 1010 /* 1011 * we can get EINTR if we are in line mode, 1012 * and the user does an escape (TSTP), or 1013 * some other signal generator. 1014 */ 1015 if (errno == EINTR) { 1016 return 0; 1017 } 1018 # if defined(TN3270) 1019 /* 1020 * we can get EBADF if we were in transparent 1021 * mode, and the transcom process died. 1022 */ 1023 if (errno == EBADF) 1024 return 0; 1025 # endif /* defined(TN3270) */ 1026 /* I don't like this, does it ever happen? */ 1027 printf("sleep(5) from telnet, after select\r\n"); 1028 sleep(5); 1029 } 1030 return 0; 1031 } 1032 1033 /* 1034 * Any urgent data? 1035 */ 1036 if (set[0].revents & POLLPRI) { 1037 SYNCHing = 1; 1038 (void) ttyflush(1); /* flush already enqueued data */ 1039 } 1040 1041 /* 1042 * Something to read from the network... 1043 */ 1044 if (set[0].revents & POLLIN) { 1045 int canread; 1046 1047 canread = ring_empty_consecutive(&netiring); 1048 #if !defined(SO_OOBINLINE) 1049 /* 1050 * In 4.2 (and some early 4.3) systems, the 1051 * OOB indication and data handling in the kernel 1052 * is such that if two separate TCP Urgent requests 1053 * come in, one byte of TCP data will be overlaid. 1054 * This is fatal for Telnet, but we try to live 1055 * with it. 1056 * 1057 * In addition, in 4.2 (and...), a special protocol 1058 * is needed to pick up the TCP Urgent data in 1059 * the correct sequence. 1060 * 1061 * What we do is: if we think we are in urgent 1062 * mode, we look to see if we are "at the mark". 1063 * If we are, we do an OOB receive. If we run 1064 * this twice, we will do the OOB receive twice, 1065 * but the second will fail, since the second 1066 * time we were "at the mark", but there wasn't 1067 * any data there (the kernel doesn't reset 1068 * "at the mark" until we do a normal read). 1069 * Once we've read the OOB data, we go ahead 1070 * and do normal reads. 1071 * 1072 * There is also another problem, which is that 1073 * since the OOB byte we read doesn't put us 1074 * out of OOB state, and since that byte is most 1075 * likely the TELNET DM (data mark), we would 1076 * stay in the TELNET SYNCH (SYNCHing) state. 1077 * So, clocks to the rescue. If we've "just" 1078 * received a DM, then we test for the 1079 * presence of OOB data when the receive OOB 1080 * fails (and AFTER we did the normal mode read 1081 * to clear "at the mark"). 1082 */ 1083 if (SYNCHing) { 1084 int atmark; 1085 static int bogus_oob = 0, first = 1; 1086 1087 ioctl(net, SIOCATMARK, (char *)&atmark); 1088 if (atmark) { 1089 c = recv(net, netiring.supply, canread, MSG_OOB); 1090 if ((c == -1) && (errno == EINVAL)) { 1091 c = recv(net, netiring.supply, canread, 0); 1092 if (clocks.didnetreceive < clocks.gotDM) { 1093 SYNCHing = stilloob(net); 1094 } 1095 } else if (first && c > 0) { 1096 /* 1097 * Bogosity check. Systems based on 4.2BSD 1098 * do not return an error if you do a second 1099 * recv(MSG_OOB). So, we do one. If it 1100 * succeeds and returns exactly the same 1101 * data, then assume that we are running 1102 * on a broken system and set the bogus_oob 1103 * flag. (If the data was different, then 1104 * we probably got some valid new data, so 1105 * increment the count...) 1106 */ 1107 int i; 1108 i = recv(net, netiring.supply + c, canread - c, MSG_OOB); 1109 if (i == c && 1110 memcmp(netiring.supply, netiring.supply + c, i) == 0) { 1111 bogus_oob = 1; 1112 first = 0; 1113 } else if (i < 0) { 1114 bogus_oob = 0; 1115 first = 0; 1116 } else 1117 c += i; 1118 } 1119 if (bogus_oob && c > 0) { 1120 int i; 1121 /* 1122 * Bogosity. We have to do the read 1123 * to clear the atmark to get out of 1124 * an infinite loop. 1125 */ 1126 i = read(net, netiring.supply + c, canread - c); 1127 if (i > 0) 1128 c += i; 1129 } 1130 } else { 1131 c = recv(net, netiring.supply, canread, 0); 1132 } 1133 } else { 1134 c = recv(net, netiring.supply, canread, 0); 1135 } 1136 settimer(didnetreceive); 1137 #else /* !defined(SO_OOBINLINE) */ 1138 c = recv(net, (char *)netiring.supply, canread, 0); 1139 #endif /* !defined(SO_OOBINLINE) */ 1140 if (c < 0 && errno == EWOULDBLOCK) { 1141 c = 0; 1142 } else if (c <= 0) { 1143 return -1; 1144 } 1145 if (netdata) { 1146 Dump('<', netiring.supply, c); 1147 } 1148 if (c) 1149 ring_supplied(&netiring, c); 1150 returnValue = 1; 1151 } 1152 1153 /* 1154 * Something to read from the tty... 1155 */ 1156 if (set[2].revents & POLLIN) { 1157 c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 1158 if (c < 0 && errno == EIO) 1159 c = 0; 1160 if (c < 0 && errno == EWOULDBLOCK) { 1161 c = 0; 1162 } else { 1163 if (c < 0) { 1164 return -1; 1165 } 1166 if (c == 0) { 1167 /* must be an EOF... */ 1168 if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 1169 *ttyiring.supply = termEofChar; 1170 c = 1; 1171 } else { 1172 clienteof = 1; 1173 shutdown(net, 1); 1174 return 0; 1175 } 1176 } 1177 if (termdata) { 1178 Dump('<', ttyiring.supply, c); 1179 } 1180 ring_supplied(&ttyiring, c); 1181 } 1182 returnValue = 1; /* did something useful */ 1183 } 1184 1185 if (set[0].revents & POLLOUT) { 1186 returnValue |= netflush(); 1187 } 1188 if (set[1].revents & POLLOUT) { 1189 returnValue |= (ttyflush(SYNCHing|flushout) > 0); 1190 } 1191 1192 return returnValue; 1193 } 1194