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