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