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