telnetd.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,646 行 · 第 1/3 页
C
1,646 行
SYNCHing = 1; } /* * Something to read from the network... */ if (FD_ISSET(net, &ibits)) {#if !defined(SO_OOBINLINE) /* * In 4.2 (and 4.3 beta) systems, the * OOB indication and data handling in the kernel * is such that if two separate TCP Urgent requests * come in, one byte of TCP data will be overlaid. * This is fatal for Telnet, but we try to live * with it. * * In addition, in 4.2 (and...), a special protocol * is needed to pick up the TCP Urgent data in * the correct sequence. * * What we do is: if we think we are in urgent * mode, we look to see if we are "at the mark". * If we are, we do an OOB receive. If we run * this twice, we will do the OOB receive twice, * but the second will fail, since the second * time we were "at the mark", but there wasn't * any data there (the kernel doesn't reset * "at the mark" until we do a normal read). * Once we've read the OOB data, we go ahead * and do normal reads. * * There is also another problem, which is that * since the OOB byte we read doesn't put us * out of OOB state, and since that byte is most * likely the TELNET DM (data mark), we would * stay in the TELNET SYNCH (SYNCHing) state. * So, clocks to the rescue. If we've "just" * received a DM, then we test for the * presence of OOB data when the receive OOB * fails (and AFTER we did the normal mode read * to clear "at the mark"). */ if (SYNCHing) { int atmark; ioctl(net, SIOCATMARK, (char *)&atmark); if (atmark) { ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); if ((ncc == -1) && (errno == EINVAL)) { ncc = read(net, netibuf, sizeof (netibuf)); if (sequenceIs(didnetreceive, gotDM)) { SYNCHing = stilloob(net); } } } else { ncc = read(net, netibuf, sizeof (netibuf)); } } else { ncc = read(net, netibuf, sizeof (netibuf)); } settimer(didnetreceive);#else /* !defined(SO_OOBINLINE)) */ ncc = read(net, netibuf, sizeof (netibuf));#endif /* !defined(SO_OOBINLINE)) */ if (ncc < 0 && errno == EWOULDBLOCK) ncc = 0; else { if (ncc <= 0) { break; } netip = netibuf; } } /* * Something to read from the pty... */ if (FD_ISSET(p, &ibits)) { pcc = read(p, ptyibuf, BUFSIZ); if (pcc < 0 && errno == EWOULDBLOCK) pcc = 0; else { if (pcc <= 0) break; ptyip = ptyibuf; } } while (pcc > 0) { if ((&netobuf[BUFSIZ] - nfrontp) < 2) break; c = *ptyip++ & 0377, pcc--; if (c == IAC) *nfrontp++ = c; *nfrontp++ = c; if (c == '\r') { if (pcc > 0 && ((*ptyip & 0377) == '\n')) { *nfrontp++ = *ptyip++ & 0377; pcc--; } else *nfrontp++ = '\0'; } } if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) netflush(); if (ncc > 0) telrcv(); if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) ptyflush(); } cleanup();} /* * State for recv fsm */#define TS_DATA 0 /* base state */#define TS_IAC 1 /* look for double IAC's */#define TS_CR 2 /* CR-LF ->'s CR */#define TS_SB 3 /* throw away begin's... */#define TS_SE 4 /* ...end's (suboption negotiation) */#define TS_WILL 5 /* will option negotiation */#define TS_WONT 6 /* wont " */#define TS_DO 7 /* do " */#define TS_DONT 8 /* dont " */telrcv(){ register int c; static int state = TS_DATA; while (ncc > 0) { if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) return; c = *netip++ & 0377, ncc--; switch (state) { case TS_CR: state = TS_DATA; if ((c == 0) || (c == '\n')) { break; } /* FALL THROUGH */ case TS_DATA: if (c == IAC) { state = TS_IAC; break; } if (inter > 0) break; /* * We now map \r\n ==> \r for pragmatic reasons. * Many client implementations send \r\n when * the user hits the CarriageReturn key. * * We USED to map \r\n ==> \n, since \r\n says * that we want to be in column 1 of the next * printable line, and \n is the standard * unix way of saying that (\r is only good * if CRMOD is set, which it normally is). */ if ((c == '\r') && (hisopts[TELOPT_BINARY] == OPT_NO)) { state = TS_CR; } *pfrontp++ = c; break; case TS_IAC: switch (c) { /* * Send the process on the pty side an * interrupt. Do this with a NULL or * interrupt char; depending on the tty mode. */ case IP: interrupt(); break; case BREAK: sendbrk(); break; /* * Are You There? */ case AYT: strcpy(nfrontp, "\r\n[Yes]\r\n"); nfrontp += 9; break; /* * Abort Output */ case AO: { struct ltchars tmpltc; ptyflush(); /* half-hearted */ ioctl(pty, TIOCGLTC, &tmpltc); if (tmpltc.t_flushc != '\377') { *pfrontp++ = tmpltc.t_flushc; } netclear(); /* clear buffer back */ *nfrontp++ = IAC; *nfrontp++ = DM; neturg = nfrontp-1; /* off by one XXX */ break; } /* * Erase Character and * Erase Line */ case EC: case EL: { struct sgttyb b; char ch; ptyflush(); /* half-hearted */ ioctl(pty, TIOCGETP, &b); ch = (c == EC) ? b.sg_erase : b.sg_kill; if (ch != '\377') { *pfrontp++ = ch; } break; } /* * Check for urgent data... */ case DM: SYNCHing = stilloob(net); settimer(gotDM); break; /* * Begin option subnegotiation... */ case SB: state = TS_SB; continue; case WILL: state = TS_WILL; continue; case WONT: state = TS_WONT; continue; case DO: state = TS_DO; continue; case DONT: state = TS_DONT; continue; case IAC: *pfrontp++ = c; break; } state = TS_DATA; break; case TS_SB: if (c == IAC) { state = TS_SE; } else { SB_ACCUM(c); } break; case TS_SE: if (c != SE) { if (c != IAC) { SB_ACCUM(IAC); } SB_ACCUM(c); state = TS_SB; } else { SB_TERM(); suboption(); /* handle sub-option */ state = TS_DATA; } break; case TS_WILL: if (hisopts[c] != OPT_YES) willoption(c); state = TS_DATA; continue; case TS_WONT: if (hisopts[c] != OPT_NO) wontoption(c); state = TS_DATA; continue; case TS_DO: if (myopts[c] != OPT_YES) dooption(c); state = TS_DATA; continue; case TS_DONT: if (myopts[c] != OPT_NO) { dontoption(c); } state = TS_DATA; continue; default: syslog(LOG_ERR, "telnetd: panic state=%d\n", state); printf("telnetd: panic state=%d\n", state); exit(1); } }}willoption(option) int option;{ char *fmt; switch (option) { case TELOPT_BINARY: mode(RAW, 0); fmt = doopt; break; case TELOPT_ECHO: not42 = 0; /* looks like a 4.2 system */ /* * Now, in a 4.2 system, to break them out of ECHOing * (to the terminal) mode, we need to send a "WILL ECHO". * Kludge upon kludge! */ if (myopts[TELOPT_ECHO] == OPT_YES) { dooption(TELOPT_ECHO); } fmt = dont; break; case TELOPT_TTYPE: settimer(ttypeopt); if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) { hisopts[TELOPT_TTYPE] = OPT_YES; return; } fmt = doopt; break; case TELOPT_SGA: fmt = doopt; break; case TELOPT_TM: fmt = dont; break; default: fmt = dont; break; } if (fmt == doopt) { hisopts[option] = OPT_YES; } else { hisopts[option] = OPT_NO; } (void) sprintf(nfrontp, fmt, option); nfrontp += sizeof (dont) - 2;}wontoption(option) int option;{ char *fmt; switch (option) { case TELOPT_ECHO: not42 = 1; /* doesn't seem to be a 4.2 system */ break; case TELOPT_BINARY: mode(0, RAW); break; case TELOPT_TTYPE: settimer(ttypeopt); break; } fmt = dont; hisopts[option] = OPT_NO; sprintf(nfrontp, fmt, option); nfrontp += sizeof (doopt) - 2;}dooption(option) int option;{ char *fmt; switch (option) { case TELOPT_TM: fmt = wont; break; case TELOPT_ECHO: mode(ECHO|CRMOD, 0); fmt = will; break; case TELOPT_BINARY: mode(RAW, 0); fmt = will; break; case TELOPT_SGA: fmt = will; break; default: fmt = wont; break; } if (fmt == will) { myopts[option] = OPT_YES; } else { myopts[option] = OPT_NO; } sprintf(nfrontp, fmt, option); nfrontp += sizeof (doopt) - 2;}dontoption(option)int option;{ char *fmt; switch (option) { case TELOPT_ECHO: /* we should stop echoing */ mode(0, ECHO|CRMOD); fmt = wont; break; default: fmt = wont; break; } if (fmt = wont) { myopts[option] = OPT_NO; } else { myopts[option] = OPT_YES; } (void) sprintf(nfrontp, fmt, option); nfrontp += sizeof (wont) - 2;}/* * suboption() * * Look at the sub-option buffer, and try to be helpful to the other * side. * * Currently we recognize: * * Terminal type is */suboption(){ switch (SB_GET()) { case TELOPT_TTYPE: { /* Yaaaay! */ static char terminalname[5+41] = "TERM="; settimer(ttypesubopt); if (SB_GET() != TELQUAL_IS) { return; /* ??? XXX but, this is the most robust */ } terminaltype = terminalname+strlen(terminalname); while ((terminaltype < (terminalname + sizeof terminalname-1)) && !SB_EOF()) { register int c; c = SB_GET(); if (isupper(c)) { c = tolower(c); } *terminaltype++ = c; /* accumulate name */ } *terminaltype = 0; terminaltype = terminalname; break; } default: ; }}mode(on, off) int on, off;{ struct sgttyb b; ptyflush(); ioctl(pty, TIOCGETP, &b); b.sg_flags |= on; b.sg_flags &= ~off; ioctl(pty, TIOCSETP, &b);}/* * Send interrupt to process on other side of pty. * If it is in raw mode, just write NULL; * otherwise, write intr char. */interrupt(){ struct sgttyb b; struct tchars tchars; ptyflush(); /* half-hearted */ ioctl(pty, TIOCGETP, &b); if (b.sg_flags & RAW) { *pfrontp++ = '\0'; return; } *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ? '\177' : tchars.t_intrc;}/* * Send quit to process on other side of pty. * If it is in raw mode, just write NULL; * otherwise, write quit char.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?