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