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