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