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.3 (Berkeley) 02/16/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 memcpy(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 (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 647 #endif /* SIGTSTP */ 648 #ifndef USE_TERMIO 649 ltc = oltc; 650 tc = otc; 651 sb = ottyb; 652 lmode = olmode; 653 #else 654 tmp_tc = old_tc; 655 #endif 656 } 657 #ifndef USE_TERMIO 658 ioctl(tin, TIOCLSET, (char *)&lmode); 659 ioctl(tin, TIOCSLTC, (char *)<c); 660 ioctl(tin, TIOCSETC, (char *)&tc); 661 ioctl(tin, TIOCSETN, (char *)&sb); 662 #else 663 if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) 664 tcsetattr(tin, TCSANOW, &tmp_tc); 665 #endif 666 667 #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 668 # if !defined(sysV88) 669 ioctl(tin, FIONBIO, (char *)&onoff); 670 ioctl(tout, FIONBIO, (char *)&onoff); 671 # endif 672 #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 673 #if defined(TN3270) 674 if (noasynchtty == 0) { 675 ioctl(tin, FIOASYNC, (char *)&onoff); 676 } 677 #endif /* defined(TN3270) */ 678 679 } 680 681 /* 682 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). 683 */ 684 #if B4800 != 4800 685 #define DECODE_BAUD 686 #endif 687 688 #ifdef DECODE_BAUD 689 #ifndef B7200 690 #define B7200 B4800 691 #endif 692 693 #ifndef B14400 694 #define B14400 B9600 695 #endif 696 697 #ifndef B19200 698 # define B19200 B14400 699 #endif 700 701 #ifndef B28800 702 #define B28800 B19200 703 #endif 704 705 #ifndef B38400 706 # define B38400 B28800 707 #endif 708 709 #ifndef B57600 710 #define B57600 B38400 711 #endif 712 713 #ifndef B76800 714 #define B76800 B57600 715 #endif 716 717 #ifndef B115200 718 #define B115200 B76800 719 #endif 720 721 #ifndef B230400 722 #define B230400 B115200 723 #endif 724 725 726 /* 727 * This code assumes that the values B0, B50, B75... 728 * are in ascending order. They do not have to be 729 * contiguous. 730 */ 731 struct termspeeds { 732 long speed; 733 long value; 734 } termspeeds[] = { 735 { 0, B0 }, { 50, B50 }, { 75, B75 }, 736 { 110, B110 }, { 134, B134 }, { 150, B150 }, 737 { 200, B200 }, { 300, B300 }, { 600, B600 }, 738 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 739 { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 }, 740 { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 }, 741 { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 }, 742 { 230400, B230400 }, { -1, B230400 } 743 }; 744 #endif /* DECODE_BAUD */ 745 746 void 747 TerminalSpeeds(ispeed, ospeed) 748 long *ispeed; 749 long *ospeed; 750 { 751 #ifdef DECODE_BAUD 752 register struct termspeeds *tp; 753 #endif /* DECODE_BAUD */ 754 register long in, out; 755 756 out = cfgetospeed(&old_tc); 757 in = cfgetispeed(&old_tc); 758 if (in == 0) 759 in = out; 760 761 #ifdef DECODE_BAUD 762 tp = termspeeds; 763 while ((tp->speed != -1) && (tp->value < in)) 764 tp++; 765 *ispeed = tp->speed; 766 767 tp = termspeeds; 768 while ((tp->speed != -1) && (tp->value < out)) 769 tp++; 770 *ospeed = tp->speed; 771 #else /* DECODE_BAUD */ 772 *ispeed = in; 773 *ospeed = out; 774 #endif /* DECODE_BAUD */ 775 } 776 777 int 778 TerminalWindowSize(rows, cols) 779 long *rows, *cols; 780 { 781 #ifdef TIOCGWINSZ 782 struct winsize ws; 783 784 if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 785 *rows = ws.ws_row; 786 *cols = ws.ws_col; 787 return 1; 788 } 789 #endif /* TIOCGWINSZ */ 790 return 0; 791 } 792 793 int 794 NetClose(fd) 795 int fd; 796 { 797 return close(fd); 798 } 799 800 801 void 802 NetNonblockingIO(fd, onoff) 803 int fd; 804 int onoff; 805 { 806 ioctl(fd, FIONBIO, (char *)&onoff); 807 } 808 809 #if defined(TN3270) 810 void 811 NetSigIO(fd, onoff) 812 int fd; 813 int onoff; 814 { 815 ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ 816 } 817 818 void 819 NetSetPgrp(fd) 820 int fd; 821 { 822 int myPid; 823 824 myPid = getpid(); 825 fcntl(fd, F_SETOWN, myPid); 826 } 827 #endif /*defined(TN3270)*/ 828 829 /* 830 * Various signal handling routines. 831 */ 832 833 /* ARGSUSED */ 834 SIG_FUNC_RET 835 deadpeer(sig) 836 int sig; 837 { 838 setcommandmode(); 839 longjmp(peerdied, -1); 840 } 841 842 /* ARGSUSED */ 843 SIG_FUNC_RET 844 intr(sig) 845 int sig; 846 { 847 if (localchars) { 848 intp(); 849 return; 850 } 851 setcommandmode(); 852 longjmp(toplevel, -1); 853 } 854 855 /* ARGSUSED */ 856 SIG_FUNC_RET 857 intr2(sig) 858 int sig; 859 { 860 if (localchars) { 861 #ifdef KLUDGELINEMODE 862 if (kludgelinemode) 863 sendbrk(); 864 else 865 #endif 866 sendabort(); 867 return; 868 } 869 } 870 871 #ifdef SIGTSTP 872 /* ARGSUSED */ 873 SIG_FUNC_RET 874 susp(sig) 875 int sig; 876 { 877 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) 878 return; 879 if (localchars) 880 sendsusp(); 881 } 882 #endif 883 884 #ifdef SIGWINCH 885 /* ARGSUSED */ 886 SIG_FUNC_RET 887 sendwin(sig) 888 int sig; 889 { 890 if (connected) { 891 sendnaws(); 892 } 893 } 894 #endif 895 896 #ifdef SIGINFO 897 /* ARGSUSED */ 898 SIG_FUNC_RET 899 ayt(sig) 900 int sig; 901 { 902 if (connected) 903 sendayt(); 904 else 905 ayt_status(); 906 } 907 #endif 908 909 910 void 911 sys_telnet_init() 912 { 913 (void) signal(SIGINT, intr); 914 (void) signal(SIGQUIT, intr2); 915 (void) signal(SIGPIPE, deadpeer); 916 #ifdef SIGWINCH 917 (void) signal(SIGWINCH, sendwin); 918 #endif 919 #ifdef SIGTSTP 920 (void) signal(SIGTSTP, susp); 921 #endif 922 #ifdef SIGINFO 923 (void) signal(SIGINFO, ayt); 924 #endif 925 926 setconnmode(0); 927 928 NetNonblockingIO(net, 1); 929 930 #if defined(TN3270) 931 if (noasynchnet == 0) { /* DBX can't handle! */ 932 NetSigIO(net, 1); 933 NetSetPgrp(net); 934 } 935 #endif /* defined(TN3270) */ 936 937 #if defined(SO_OOBINLINE) 938 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 939 perror("SetSockOpt"); 940 } 941 #endif /* defined(SO_OOBINLINE) */ 942 } 943 944 /* 945 * Process rings - 946 * 947 * This routine tries to fill up/empty our various rings. 948 * 949 * The parameter specifies whether this is a poll operation, 950 * or a block-until-something-happens operation. 951 * 952 * The return value is 1 if something happened, 0 if not. 953 */ 954 955 int 956 process_rings(netin, netout, netex, ttyin, ttyout, poll) 957 int poll; /* If 0, then block until something to do */ 958 { 959 register int c; 960 /* One wants to be a bit careful about setting returnValue 961 * to one, since a one implies we did some useful work, 962 * and therefore probably won't be called to block next 963 * time (TN3270 mode only). 964 */ 965 int returnValue = 0; 966 static struct timeval TimeValue = { 0 }; 967 968 if (netout) { 969 FD_SET(net, &obits); 970 } 971 if (ttyout) { 972 FD_SET(tout, &obits); 973 } 974 #if defined(TN3270) 975 if (ttyin) { 976 FD_SET(tin, &ibits); 977 } 978 #else /* defined(TN3270) */ 979 if (ttyin) { 980 FD_SET(tin, &ibits); 981 } 982 #endif /* defined(TN3270) */ 983 #if defined(TN3270) 984 if (netin) { 985 FD_SET(net, &ibits); 986 } 987 # else /* !defined(TN3270) */ 988 if (netin) { 989 FD_SET(net, &ibits); 990 } 991 # endif /* !defined(TN3270) */ 992 if (netex) { 993 FD_SET(net, &xbits); 994 } 995 if ((c = select(16, &ibits, &obits, &xbits, 996 (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { 997 if (c == -1) { 998 /* 999 * we can get EINTR if we are in line mode, 1000 * and the user does an escape (TSTP), or 1001 * some other signal generator. 1002 */ 1003 if (errno == EINTR) { 1004 return 0; 1005 } 1006 # if defined(TN3270) 1007 /* 1008 * we can get EBADF if we were in transparent 1009 * mode, and the transcom process died. 1010 */ 1011 if (errno == EBADF) { 1012 /* 1013 * zero the bits (even though kernel does it) 1014 * to make sure we are selecting on the right 1015 * ones. 1016 */ 1017 FD_ZERO(&ibits); 1018 FD_ZERO(&obits); 1019 FD_ZERO(&xbits); 1020 return 0; 1021 } 1022 # endif /* defined(TN3270) */ 1023 /* I don't like this, does it ever happen? */ 1024 printf("sleep(5) from telnet, after select\r\n"); 1025 sleep(5); 1026 } 1027 return 0; 1028 } 1029 1030 /* 1031 * Any urgent data? 1032 */ 1033 if (FD_ISSET(net, &xbits)) { 1034 FD_CLR(net, &xbits); 1035 SYNCHing = 1; 1036 (void) ttyflush(1); /* flush already enqueued data */ 1037 } 1038 1039 /* 1040 * Something to read from the network... 1041 */ 1042 if (FD_ISSET(net, &ibits)) { 1043 int canread; 1044 1045 FD_CLR(net, &ibits); 1046 canread = ring_empty_consecutive(&netiring); 1047 #if !defined(SO_OOBINLINE) 1048 /* 1049 * In 4.2 (and some early 4.3) systems, the 1050 * OOB indication and data handling in the kernel 1051 * is such that if two separate TCP Urgent requests 1052 * come in, one byte of TCP data will be overlaid. 1053 * This is fatal for Telnet, but we try to live 1054 * with it. 1055 * 1056 * In addition, in 4.2 (and...), a special protocol 1057 * is needed to pick up the TCP Urgent data in 1058 * the correct sequence. 1059 * 1060 * What we do is: if we think we are in urgent 1061 * mode, we look to see if we are "at the mark". 1062 * If we are, we do an OOB receive. If we run 1063 * this twice, we will do the OOB receive twice, 1064 * but the second will fail, since the second 1065 * time we were "at the mark", but there wasn't 1066 * any data there (the kernel doesn't reset 1067 * "at the mark" until we do a normal read). 1068 * Once we've read the OOB data, we go ahead 1069 * and do normal reads. 1070 * 1071 * There is also another problem, which is that 1072 * since the OOB byte we read doesn't put us 1073 * out of OOB state, and since that byte is most 1074 * likely the TELNET DM (data mark), we would 1075 * stay in the TELNET SYNCH (SYNCHing) state. 1076 * So, clocks to the rescue. If we've "just" 1077 * received a DM, then we test for the 1078 * presence of OOB data when the receive OOB 1079 * fails (and AFTER we did the normal mode read 1080 * to clear "at the mark"). 1081 */ 1082 if (SYNCHing) { 1083 int atmark; 1084 static int bogus_oob = 0, first = 1; 1085 1086 ioctl(net, SIOCATMARK, (char *)&atmark); 1087 if (atmark) { 1088 c = recv(net, netiring.supply, canread, MSG_OOB); 1089 if ((c == -1) && (errno == EINVAL)) { 1090 c = recv(net, netiring.supply, canread, 0); 1091 if (clocks.didnetreceive < clocks.gotDM) { 1092 SYNCHing = stilloob(net); 1093 } 1094 } else if (first && c > 0) { 1095 /* 1096 * Bogosity check. Systems based on 4.2BSD 1097 * do not return an error if you do a second 1098 * recv(MSG_OOB). So, we do one. If it 1099 * succeeds and returns exactly the same 1100 * data, then assume that we are running 1101 * on a broken system and set the bogus_oob 1102 * flag. (If the data was different, then 1103 * we probably got some valid new data, so 1104 * increment the count...) 1105 */ 1106 int i; 1107 i = recv(net, netiring.supply + c, canread - c, MSG_OOB); 1108 if (i == c && 1109 bcmp(netiring.supply, netiring.supply + c, i) == 0) { 1110 bogus_oob = 1; 1111 first = 0; 1112 } else if (i < 0) { 1113 bogus_oob = 0; 1114 first = 0; 1115 } else 1116 c += i; 1117 } 1118 if (bogus_oob && c > 0) { 1119 int i; 1120 /* 1121 * Bogosity. We have to do the read 1122 * to clear the atmark to get out of 1123 * an infinate loop. 1124 */ 1125 i = read(net, netiring.supply + c, canread - c); 1126 if (i > 0) 1127 c += i; 1128 } 1129 } else { 1130 c = recv(net, netiring.supply, canread, 0); 1131 } 1132 } else { 1133 c = recv(net, netiring.supply, canread, 0); 1134 } 1135 settimer(didnetreceive); 1136 #else /* !defined(SO_OOBINLINE) */ 1137 c = recv(net, (char *)netiring.supply, canread, 0); 1138 #endif /* !defined(SO_OOBINLINE) */ 1139 if (c < 0 && errno == EWOULDBLOCK) { 1140 c = 0; 1141 } else if (c <= 0) { 1142 return -1; 1143 } 1144 if (netdata) { 1145 Dump('<', netiring.supply, c); 1146 } 1147 if (c) 1148 ring_supplied(&netiring, c); 1149 returnValue = 1; 1150 } 1151 1152 /* 1153 * Something to read from the tty... 1154 */ 1155 if (FD_ISSET(tin, &ibits)) { 1156 FD_CLR(tin, &ibits); 1157 c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 1158 if (c < 0 && errno == EIO) 1159 c = 0; 1160 if (c < 0 && errno == EWOULDBLOCK) { 1161 c = 0; 1162 } else { 1163 /* EOF detection for line mode!!!! */ 1164 if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 1165 /* must be an EOF... */ 1166 *ttyiring.supply = termEofChar; 1167 c = 1; 1168 } 1169 if (c <= 0) { 1170 return -1; 1171 } 1172 if (termdata) { 1173 Dump('<', ttyiring.supply, c); 1174 } 1175 ring_supplied(&ttyiring, c); 1176 } 1177 returnValue = 1; /* did something useful */ 1178 } 1179 1180 if (FD_ISSET(net, &obits)) { 1181 FD_CLR(net, &obits); 1182 returnValue |= netflush(); 1183 } 1184 if (FD_ISSET(tout, &obits)) { 1185 FD_CLR(tout, &obits); 1186 returnValue |= (ttyflush(SYNCHing|flushout) > 0); 1187 } 1188 1189 return returnValue; 1190 } 1191