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