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