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