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