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