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