|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that this notice is preserved and that due credit is given ! 7: * to the University of California at Berkeley. The name of the University ! 8: * may not be used to endorse or promote products derived from this ! 9: * software without specific prior written permission. This software ! 10: * is provided ``as is'' without express or implied warranty. ! 11: */ ! 12: ! 13: #ifndef lint ! 14: static char sccsid[] = "@(#)sys_bsd.c 1.11 (Berkeley) 3/27/88"; ! 15: #endif /* not lint */ ! 16: ! 17: /* ! 18: * The following routines try to encapsulate what is system dependent ! 19: * (at least between 4.x and dos) which is used in telnet.c. ! 20: */ ! 21: ! 22: #if defined(unix) ! 23: ! 24: #include <sys/ioctl.h> ! 25: #include <sys/types.h> ! 26: #include <sys/time.h> ! 27: #include <sys/socket.h> ! 28: #include <signal.h> ! 29: #include <errno.h> ! 30: ! 31: #include "ring.h" ! 32: ! 33: #include "fdset.h" ! 34: ! 35: #include "defines.h" ! 36: #include "externs.h" ! 37: #include "types.h" ! 38: ! 39: int ! 40: tout, /* Output file descriptor */ ! 41: tin, /* Input file descriptor */ ! 42: net, ! 43: HaveInput; /* There is input available to scan */ ! 44: ! 45: static struct tchars otc = { 0 }, ntc = { 0 }; ! 46: static struct ltchars oltc = { 0 }, nltc = { 0 }; ! 47: static struct sgttyb ottyb = { 0 }, nttyb = { 0 }; ! 48: ! 49: static fd_set ibits, obits, xbits; ! 50: ! 51: ! 52: init_sys() ! 53: { ! 54: tout = fileno(stdout); ! 55: tin = fileno(stdin); ! 56: FD_ZERO(&ibits); ! 57: FD_ZERO(&obits); ! 58: FD_ZERO(&xbits); ! 59: ! 60: errno = 0; ! 61: } ! 62: ! 63: ! 64: TerminalWrite(buf, n) ! 65: char *buf; ! 66: int n; ! 67: { ! 68: return write(tout, buf, n); ! 69: } ! 70: ! 71: TerminalRead(buf, n) ! 72: char *buf; ! 73: int n; ! 74: { ! 75: return read(tin, buf, n); ! 76: } ! 77: ! 78: /* ! 79: * ! 80: */ ! 81: ! 82: int ! 83: TerminalAutoFlush() ! 84: { ! 85: #if defined(LNOFLSH) ! 86: int flush; ! 87: ! 88: ioctl(0, TIOCLGET, (char *)&flush); ! 89: return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ ! 90: #else /* LNOFLSH */ ! 91: return 1; ! 92: #endif /* LNOFLSH */ ! 93: } ! 94: ! 95: /* ! 96: * TerminalSpecialChars() ! 97: * ! 98: * Look at an input character to see if it is a special character ! 99: * and decide what to do. ! 100: * ! 101: * Output: ! 102: * ! 103: * 0 Don't add this character. ! 104: * 1 Do add this character ! 105: */ ! 106: ! 107: int ! 108: TerminalSpecialChars(c) ! 109: int c; ! 110: { ! 111: void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); ! 112: ! 113: if (c == ntc.t_intrc) { ! 114: intp(); ! 115: return 0; ! 116: } else if (c == ntc.t_quitc) { ! 117: sendbrk(); ! 118: return 0; ! 119: } else if (c == nltc.t_flushc) { ! 120: xmitAO(); /* Transmit Abort Output */ ! 121: return 0; ! 122: } else if (!MODE_LOCAL_CHARS(globalmode)) { ! 123: if (c == nttyb.sg_kill) { ! 124: xmitEL(); ! 125: return 0; ! 126: } else if (c == nttyb.sg_erase) { ! 127: xmitEC(); /* Transmit Erase Character */ ! 128: return 0; ! 129: } ! 130: } ! 131: return 1; ! 132: } ! 133: ! 134: ! 135: /* ! 136: * Flush output to the terminal ! 137: */ ! 138: ! 139: void ! 140: TerminalFlushOutput() ! 141: { ! 142: (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); ! 143: } ! 144: ! 145: void ! 146: TerminalSaveState() ! 147: { ! 148: ioctl(0, TIOCGETP, (char *)&ottyb); ! 149: ioctl(0, TIOCGETC, (char *)&otc); ! 150: ioctl(0, TIOCGLTC, (char *)&oltc); ! 151: ! 152: ntc = otc; ! 153: nltc = oltc; ! 154: nttyb = ottyb; ! 155: ! 156: termEofChar = ntc.t_eofc; ! 157: termEraseChar = nttyb.sg_erase; ! 158: termFlushChar = nltc.t_flushc; ! 159: termIntChar = ntc.t_intrc; ! 160: termKillChar = nttyb.sg_kill; ! 161: termQuitChar = ntc.t_quitc; ! 162: } ! 163: ! 164: void ! 165: TerminalRestoreState() ! 166: { ! 167: } ! 168: ! 169: /* ! 170: * TerminalNewMode - set up terminal to a specific mode. ! 171: */ ! 172: ! 173: ! 174: void ! 175: TerminalNewMode(f) ! 176: register int f; ! 177: { ! 178: static int prevmode = 0; ! 179: struct tchars *tc; ! 180: struct tchars tc3; ! 181: struct ltchars *ltc; ! 182: struct sgttyb sb; ! 183: int onoff; ! 184: int old; ! 185: struct tchars notc2; ! 186: struct ltchars noltc2; ! 187: static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; ! 188: static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; ! 189: ! 190: globalmode = f; ! 191: if (prevmode == f) ! 192: return; ! 193: old = prevmode; ! 194: prevmode = f; ! 195: sb = nttyb; ! 196: ! 197: switch (f) { ! 198: ! 199: case 0: ! 200: onoff = 0; ! 201: tc = &otc; ! 202: ltc = &oltc; ! 203: break; ! 204: ! 205: case 1: /* remote character processing, remote echo */ ! 206: case 2: /* remote character processing, local echo */ ! 207: case 6: /* 3270 mode - like 1, but with xon/xoff local */ ! 208: /* (might be nice to have "6" in telnet also...) */ ! 209: sb.sg_flags |= CBREAK; ! 210: if ((f == 1) || (f == 6)) { ! 211: sb.sg_flags &= ~(ECHO|CRMOD); ! 212: } else { ! 213: sb.sg_flags |= ECHO|CRMOD; ! 214: } ! 215: sb.sg_erase = sb.sg_kill = -1; ! 216: if (f == 6) { ! 217: tc = &tc3; ! 218: tc3 = notc; ! 219: /* get XON, XOFF characters */ ! 220: tc3.t_startc = otc.t_startc; ! 221: tc3.t_stopc = otc.t_stopc; ! 222: } else { ! 223: /* ! 224: * If user hasn't specified one way or the other, ! 225: * then default to not trapping signals. ! 226: */ ! 227: if (!donelclchars) { ! 228: localchars = 0; ! 229: } ! 230: if (localchars) { ! 231: notc2 = notc; ! 232: notc2.t_intrc = ntc.t_intrc; ! 233: notc2.t_quitc = ntc.t_quitc; ! 234: tc = ¬c2; ! 235: } else { ! 236: tc = ¬c; ! 237: } ! 238: } ! 239: ltc = &noltc; ! 240: onoff = 1; ! 241: break; ! 242: case 3: /* local character processing, remote echo */ ! 243: case 4: /* local character processing, local echo */ ! 244: case 5: /* local character processing, no echo */ ! 245: sb.sg_flags &= ~CBREAK; ! 246: sb.sg_flags |= CRMOD; ! 247: if (f == 4) ! 248: sb.sg_flags |= ECHO; ! 249: else ! 250: sb.sg_flags &= ~ECHO; ! 251: notc2 = ntc; ! 252: tc = ¬c2; ! 253: noltc2 = oltc; ! 254: ltc = &noltc2; ! 255: /* ! 256: * If user hasn't specified one way or the other, ! 257: * then default to trapping signals. ! 258: */ ! 259: if (!donelclchars) { ! 260: localchars = 1; ! 261: } ! 262: if (localchars) { ! 263: notc2.t_brkc = nltc.t_flushc; ! 264: noltc2.t_flushc = -1; ! 265: } else { ! 266: notc2.t_intrc = notc2.t_quitc = -1; ! 267: } ! 268: noltc2.t_suspc = escape; ! 269: noltc2.t_dsuspc = -1; ! 270: onoff = 1; ! 271: break; ! 272: ! 273: default: ! 274: return; ! 275: } ! 276: ioctl(tin, TIOCSLTC, (char *)ltc); ! 277: ioctl(tin, TIOCSETC, (char *)tc); ! 278: ioctl(tin, TIOCSETP, (char *)&sb); ! 279: #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) ! 280: ioctl(tin, FIONBIO, (char *)&onoff); ! 281: ioctl(tout, FIONBIO, (char *)&onoff); ! 282: #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ ! 283: #if defined(TN3270) ! 284: if (noasynch == 0) { ! 285: ioctl(tin, FIOASYNC, (char *)&onoff); ! 286: } ! 287: #endif /* defined(TN3270) */ ! 288: ! 289: if (MODE_LINE(f)) { ! 290: void doescape(); ! 291: ! 292: signal(SIGTSTP, doescape); ! 293: } else if (MODE_LINE(old)) { ! 294: signal(SIGTSTP, SIG_DFL); ! 295: sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); ! 296: } ! 297: } ! 298: ! 299: ! 300: int ! 301: NetClose(net) ! 302: int net; ! 303: { ! 304: return close(net); ! 305: } ! 306: ! 307: ! 308: void ! 309: NetNonblockingIO(fd, onoff) ! 310: int ! 311: fd, ! 312: onoff; ! 313: { ! 314: ioctl(fd, FIONBIO, (char *)&onoff); ! 315: } ! 316: ! 317: void ! 318: NetSigIO(fd, onoff) ! 319: int ! 320: fd, ! 321: onoff; ! 322: { ! 323: ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ ! 324: } ! 325: ! 326: void ! 327: NetSetPgrp(fd) ! 328: int fd; ! 329: { ! 330: int myPid; ! 331: ! 332: myPid = getpid(); ! 333: #if defined(NOT43) ! 334: myPid = -myPid; ! 335: #endif /* defined(NOT43) */ ! 336: ioctl(fd, SIOCSPGRP, (char *)&myPid); /* set my pid */ ! 337: } ! 338: ! 339: /* ! 340: * Various signal handling routines. ! 341: */ ! 342: ! 343: static void ! 344: deadpeer() ! 345: { ! 346: setcommandmode(); ! 347: longjmp(peerdied, -1); ! 348: } ! 349: ! 350: static void ! 351: intr() ! 352: { ! 353: if (localchars) { ! 354: intp(); ! 355: return; ! 356: } ! 357: setcommandmode(); ! 358: longjmp(toplevel, -1); ! 359: } ! 360: ! 361: static void ! 362: intr2() ! 363: { ! 364: if (localchars) { ! 365: sendbrk(); ! 366: return; ! 367: } ! 368: } ! 369: ! 370: static void ! 371: doescape() ! 372: { ! 373: command(0); ! 374: } ! 375: ! 376: void ! 377: sys_telnet_init() ! 378: { ! 379: #if defined(TN3270) ! 380: int myPid; ! 381: #endif /* defined(TN3270) */ ! 382: ! 383: signal(SIGINT, intr); ! 384: signal(SIGQUIT, intr2); ! 385: signal(SIGPIPE, deadpeer); ! 386: ! 387: setconnmode(); ! 388: ! 389: NetNonblockingIO(net, 1); ! 390: ! 391: #if defined(TN3270) ! 392: if (noasynch == 0) { /* DBX can't handle! */ ! 393: NetSigIO(net, 1); ! 394: NetSetPgrp(net); ! 395: } ! 396: #endif /* defined(TN3270) */ ! 397: ! 398: #if defined(SO_OOBINLINE) ! 399: SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); ! 400: #endif /* defined(SO_OOBINLINE) */ ! 401: } ! 402: ! 403: /* ! 404: * Process rings - ! 405: * ! 406: * This routine tries to fill up/empty our various rings. ! 407: * ! 408: * The parameter specifies whether this is a poll operation, ! 409: * or a block-until-something-happens operation. ! 410: * ! 411: * The return value is 1 if something happened, 0 if not. ! 412: */ ! 413: ! 414: int ! 415: process_rings(netin, netout, netex, ttyin, ttyout, poll) ! 416: int poll; /* If 0, then block until something to do */ ! 417: { ! 418: register int c; ! 419: /* One wants to be a bit careful about setting returnValue ! 420: * to one, since a one implies we did some useful work, ! 421: * and therefore probably won't be called to block next ! 422: * time (TN3270 mode only). ! 423: */ ! 424: int returnValue = 0; ! 425: static struct timeval TimeValue = { 0 }; ! 426: ! 427: if (netout) { ! 428: FD_SET(net, &obits); ! 429: } ! 430: if (ttyout) { ! 431: FD_SET(tout, &obits); ! 432: } ! 433: #if defined(TN3270) ! 434: if (ttyin) { ! 435: FD_SET(tin, &ibits); ! 436: } ! 437: #else /* defined(TN3270) */ ! 438: if (ttyin) { ! 439: FD_SET(tin, &ibits); ! 440: } ! 441: #endif /* defined(TN3270) */ ! 442: #if defined(TN3270) ! 443: if (netin) { ! 444: FD_SET(net, &ibits); ! 445: } ! 446: # else /* !defined(TN3270) */ ! 447: if (netin) { ! 448: FD_SET(net, &ibits); ! 449: } ! 450: # endif /* !defined(TN3270) */ ! 451: if (netex) { ! 452: FD_SET(net, &xbits); ! 453: } ! 454: if ((c = select(16, &ibits, &obits, &xbits, ! 455: (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { ! 456: if (c == -1) { ! 457: /* ! 458: * we can get EINTR if we are in line mode, ! 459: * and the user does an escape (TSTP), or ! 460: * some other signal generator. ! 461: */ ! 462: if (errno == EINTR) { ! 463: return 0; ! 464: } ! 465: # if defined(TN3270) ! 466: /* ! 467: * we can get EBADF if we were in transparent ! 468: * mode, and the transcom process died. ! 469: */ ! 470: if (errno == EBADF) { ! 471: /* ! 472: * zero the bits (even though kernel does it) ! 473: * to make sure we are selecting on the right ! 474: * ones. ! 475: */ ! 476: FD_ZERO(&ibits); ! 477: FD_ZERO(&obits); ! 478: FD_ZERO(&xbits); ! 479: return 0; ! 480: } ! 481: # endif /* defined(TN3270) */ ! 482: /* I don't like this, does it ever happen? */ ! 483: printf("sleep(5) from telnet, after select\r\n"); ! 484: sleep(5); ! 485: } ! 486: return 0; ! 487: } ! 488: ! 489: /* ! 490: * Any urgent data? ! 491: */ ! 492: if (FD_ISSET(net, &xbits)) { ! 493: FD_CLR(net, &xbits); ! 494: SYNCHing = 1; ! 495: ttyflush(1); /* flush already enqueued data */ ! 496: } ! 497: ! 498: /* ! 499: * Something to read from the network... ! 500: */ ! 501: if (FD_ISSET(net, &ibits)) { ! 502: int canread; ! 503: ! 504: FD_CLR(net, &ibits); ! 505: canread = ring_empty_consecutive(&netiring); ! 506: #if !defined(SO_OOBINLINE) ! 507: /* ! 508: * In 4.2 (and some early 4.3) systems, the ! 509: * OOB indication and data handling in the kernel ! 510: * is such that if two separate TCP Urgent requests ! 511: * come in, one byte of TCP data will be overlaid. ! 512: * This is fatal for Telnet, but we try to live ! 513: * with it. ! 514: * ! 515: * In addition, in 4.2 (and...), a special protocol ! 516: * is needed to pick up the TCP Urgent data in ! 517: * the correct sequence. ! 518: * ! 519: * What we do is: if we think we are in urgent ! 520: * mode, we look to see if we are "at the mark". ! 521: * If we are, we do an OOB receive. If we run ! 522: * this twice, we will do the OOB receive twice, ! 523: * but the second will fail, since the second ! 524: * time we were "at the mark", but there wasn't ! 525: * any data there (the kernel doesn't reset ! 526: * "at the mark" until we do a normal read). ! 527: * Once we've read the OOB data, we go ahead ! 528: * and do normal reads. ! 529: * ! 530: * There is also another problem, which is that ! 531: * since the OOB byte we read doesn't put us ! 532: * out of OOB state, and since that byte is most ! 533: * likely the TELNET DM (data mark), we would ! 534: * stay in the TELNET SYNCH (SYNCHing) state. ! 535: * So, clocks to the rescue. If we've "just" ! 536: * received a DM, then we test for the ! 537: * presence of OOB data when the receive OOB ! 538: * fails (and AFTER we did the normal mode read ! 539: * to clear "at the mark"). ! 540: */ ! 541: if (SYNCHing) { ! 542: int atmark; ! 543: ! 544: ioctl(net, SIOCATMARK, (char *)&atmark); ! 545: if (atmark) { ! 546: c = recv(net, netiring.supply, canread, MSG_OOB); ! 547: if ((c == -1) && (errno == EINVAL)) { ! 548: c = recv(net, netiring.supply, canread, 0); ! 549: if (clocks.didnetreceive < clocks.gotDM) { ! 550: SYNCHing = stilloob(net); ! 551: } ! 552: } ! 553: } else { ! 554: c = recv(net, netiring.supply, canread, 0); ! 555: } ! 556: } else { ! 557: c = recv(net, netiring.supply, canread, 0); ! 558: } ! 559: settimer(didnetreceive); ! 560: #else /* !defined(SO_OOBINLINE) */ ! 561: c = recv(net, netiring.supply, canread, 0); ! 562: #endif /* !defined(SO_OOBINLINE) */ ! 563: if (c < 0 && errno == EWOULDBLOCK) { ! 564: c = 0; ! 565: } else if (c <= 0) { ! 566: return -1; ! 567: } ! 568: if (netdata) { ! 569: Dump('<', netiring.supply, c); ! 570: } ! 571: if (c) ! 572: ring_supplied(&netiring, c); ! 573: returnValue = 1; ! 574: } ! 575: ! 576: /* ! 577: * Something to read from the tty... ! 578: */ ! 579: if (FD_ISSET(tin, &ibits)) { ! 580: FD_CLR(tin, &ibits); ! 581: c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); ! 582: if (c < 0 && errno == EWOULDBLOCK) { ! 583: c = 0; ! 584: } else { ! 585: /* EOF detection for line mode!!!! */ ! 586: if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { ! 587: /* must be an EOF... */ ! 588: *ttyiring.supply = termEofChar; ! 589: c = 1; ! 590: } ! 591: if (c <= 0) { ! 592: return -1; ! 593: } ! 594: ring_supplied(&ttyiring, c); ! 595: } ! 596: returnValue = 1; /* did something useful */ ! 597: } ! 598: ! 599: if (FD_ISSET(net, &obits)) { ! 600: FD_CLR(net, &obits); ! 601: returnValue |= netflush(); ! 602: } ! 603: if (FD_ISSET(tout, &obits)) { ! 604: FD_CLR(tout, &obits); ! 605: returnValue |= ttyflush(SYNCHing|flushout); ! 606: } ! 607: ! 608: return returnValue; ! 609: } ! 610: #endif /* defined(unix) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.