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