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