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