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