/
niceSOFT
/
inetutils
Обзор
Документация
Войти
/
niceSOFT
/
inetutils
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
telnet/sys_bsd.c
1 280 строк
25 KB
Simon Josefsson
Drop non-working TN3270 code
25 янв 2026, 12:58
Не верифицирован
25 янв 2026, 12:58
0fd65f1
Код
Авторство
О чём код?
/* Copyright (C) 1995-2026 Free Software Foundation, Inc. This file is part of GNU Inetutils. GNU Inetutils is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Inetutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see `http://www.gnu.org/licenses/'. */ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * The following routines try to encapsulate what is system dependent * (at least between 4.x and dos) which is used in telnet.c. */ #include <config.h> #include <fcntl.h> #include <sys/types.h> #include <sys/time.h> #include <time.h> #include <sys/socket.h> #include <signal.h> #include <errno.h> #include <arpa/telnet.h> #include <sys/select.h> #include <attribute.h> #include "ring.h" #include "defines.h" #include "externs.h" #include "types.h" #ifdef SIGINFO extern void ayt_status (void); extern void sendayt (void); #endif void susp (int sig); void ayt (int sig); int tout, /* Output file descriptor */ tin, /* Input file descriptor */ net; #ifndef USE_TERMIO struct tchars otc = { 0 }, ntc = { 0 }; struct ltchars oltc = { 0 }, nltc = { 0 }; struct sgttyb ottyb = { 0 }, nttyb = { 0 }; int olmode = 0; # define cfgetispeed(ptr) (ptr)->sg_ispeed # define cfgetospeed(ptr) (ptr)->sg_ospeed # define old_tc ottyb #else /* USE_TERMIO */ struct termio old_tc = { 0 }; extern struct termio new_tc; # ifndef TCSANOW # ifdef TCSETS # define TCSANOW TCSETS # define TCSADRAIN TCSETSW # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) # else # ifdef TCSETA # define TCSANOW TCSETA # define TCSADRAIN TCSETAW # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) # else # define TCSANOW TIOCSETA # define TCSADRAIN TIOCSETAW # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) # endif # endif # define tcsetattr(f, a, t) ioctl(f, a, (char *)t) # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD) # ifdef CIBAUD # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT) # else # define cfgetispeed(ptr) cfgetospeed(ptr) # endif # endif/* TCSANOW */ # ifdef sysV88 # define TIOCFLUSH TC_PX_DRAIN # endif #endif /* USE_TERMIO */ static fd_set ibits, obits, xbits; void init_sys (void) { tout = fileno (stdout); tin = fileno (stdin); FD_ZERO (&ibits); FD_ZERO (&obits); FD_ZERO (&xbits); errno = 0; } int TerminalWrite (char *buf, int n) { return write (tout, buf, n); } int TerminalRead (char *buf, int n) { return read (tin, buf, n); } /* * */ int TerminalAutoFlush (void) { #if defined LNOFLSH int flush; ioctl (0, TIOCLGET, (char *) &flush); return !(flush & LNOFLSH); /* if LNOFLSH, no autoflush */ #else /* LNOFLSH */ return 1; #endif /* LNOFLSH */ } #ifdef KLUDGELINEMODE extern int kludgelinemode; #endif /* * TerminalSpecialChars() * * Look at an input character to see if it is a special character * and decide what to do. * * Output: * * 0 Don't add this character. * 1 Do add this character */ extern void xmitAO (void), xmitEL (void), xmitEC (void), intp (void), sendbrk (void); int TerminalSpecialChars (int c) { if (c == termIntChar) { intp (); return 0; } else if (c == termQuitChar) { #ifdef KLUDGELINEMODE if (kludgelinemode) sendbrk (); else #endif sendabort (); return 0; } else if (c == termEofChar) { if (my_want_state_is_will (TELOPT_LINEMODE)) { sendeof (); return 0; } return 1; } else if (c == termSuspChar) { sendsusp (); return (0); } else if (c == termFlushChar) { xmitAO (); /* Transmit Abort Output */ return 0; } else if (!MODE_LOCAL_CHARS (globalmode)) { if (c == termKillChar) { xmitEL (); return 0; } else if (c == termEraseChar) { xmitEC (); /* Transmit Erase Character */ return 0; } } return 1; } /* * Flush output to the terminal */ void TerminalFlushOutput (void) { int flags = 0; #ifdef TIOCFLUSH ioctl (fileno (stdout), TIOCFLUSH, &flags); #else ioctl (fileno (stdout), TCFLSH, &flags); #endif } void TerminalSaveState (void) { #ifndef USE_TERMIO ioctl (0, TIOCGETP, (char *) &ottyb); ioctl (0, TIOCGETC, (char *) &otc); ioctl (0, TIOCGLTC, (char *) &oltc); ioctl (0, TIOCLGET, (char *) &olmode); ntc = otc; nltc = oltc; nttyb = ottyb; #else /* USE_TERMIO */ tcgetattr (0, &old_tc); new_tc = old_tc; # ifndef VDISCARD termFlushChar = CONTROL ('O'); # endif # ifndef VWERASE termWerasChar = CONTROL ('W'); # endif # ifndef VREPRINT termRprntChar = CONTROL ('R'); # endif # ifndef VLNEXT termLiteralNextChar = CONTROL ('V'); # endif # ifndef VSTART termStartChar = CONTROL ('Q'); # endif # ifndef VSTOP termStopChar = CONTROL ('S'); # endif # ifndef VSTATUS termAytChar = CONTROL ('T'); # endif #endif /* USE_TERMIO */ } cc_t * tcval (int func) { switch (func) { case SLC_IP: return (&termIntChar); case SLC_ABORT: return (&termQuitChar); case SLC_EOF: return (&termEofChar); case SLC_EC: return (&termEraseChar); case SLC_EL: return (&termKillChar); case SLC_XON: return (&termStartChar); case SLC_XOFF: return (&termStopChar); case SLC_FORW1: return (&termForw1Char); #ifdef USE_TERMIO case SLC_FORW2: return (&termForw2Char); # ifdef VDISCARD case SLC_AO: return (&termFlushChar); # endif # ifdef VSUSP case SLC_SUSP: return (&termSuspChar); # endif # ifdef VWERASE case SLC_EW: return (&termWerasChar); # endif # ifdef VREPRINT case SLC_RP: return (&termRprntChar); # endif # ifdef VLNEXT case SLC_LNEXT: return (&termLiteralNextChar); # endif # ifdef VSTATUS case SLC_AYT: return (&termAytChar); # endif #endif case SLC_SYNCH: case SLC_BRK: case SLC_EOR: default: return ((cc_t *) 0); } } void TerminalDefaultChars (void) { #ifndef USE_TERMIO ntc = otc; nltc = oltc; nttyb.sg_kill = ottyb.sg_kill; nttyb.sg_erase = ottyb.sg_erase; #else /* USE_TERMIO */ memmove (new_tc.c_cc, old_tc.c_cc, sizeof (old_tc.c_cc)); # ifndef VDISCARD termFlushChar = CONTROL ('O'); # endif # ifndef VWERASE termWerasChar = CONTROL ('W'); # endif # ifndef VREPRINT termRprntChar = CONTROL ('R'); # endif # ifndef VLNEXT termLiteralNextChar = CONTROL ('V'); # endif # ifndef VSTART termStartChar = CONTROL ('Q'); # endif # ifndef VSTOP termStopChar = CONTROL ('S'); # endif # ifndef VSTATUS termAytChar = CONTROL ('T'); # endif #endif /* USE_TERMIO */ } /* * TerminalNewMode - set up terminal to a specific mode. * MODE_ECHO: do local terminal echo * MODE_FLOW: do local flow control * MODE_TRAPSIG: do local mapping to TELNET IAC sequences * MODE_EDIT: do local line editing * * Command mode: * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG * local echo * local editing * local xon/xoff * local signal mapping * * Linemode: * local/no editing * Both Linemode and Single Character mode: * local/remote echo * local/no xon/xoff * local/no signal mapping */ void TerminalNewMode (int f) { static int prevmode = 0; #ifndef USE_TERMIO struct tchars tc; struct ltchars ltc; struct sgttyb sb; int lmode; #else /* USE_TERMIO */ struct termio tmp_tc; #endif /* USE_TERMIO */ int onoff; int old; cc_t esc; globalmode = f & ~MODE_FORCE; if (prevmode == f) return; /* * Write any outstanding data before switching modes * ttyflush() returns 0 only when there is no more data * left to write out, it returns -1 if it couldn't do * anything at all, otherwise it returns 1 + the number * of characters left to write. #ifndef USE_TERMIO * We would really like ask the kernel to wait for the output * to drain, like we can do with the TCSADRAIN, but we don't have * that option. The only ioctl that waits for the output to * drain, TIOCSETP, also flushes the input queue, which is NOT * what we want (TIOCSETP is like TCSADFLUSH). #endif */ old = ttyflush (SYNCHing | flushout); if (old < 0 || old > 1) { #ifdef USE_TERMIO tcgetattr (tin, &tmp_tc); #endif /* USE_TERMIO */ do { /* * Wait for data to drain, then flush again. */ #ifdef USE_TERMIO tcsetattr (tin, TCSADRAIN, &tmp_tc); #endif /* USE_TERMIO */ old = ttyflush (SYNCHing | flushout); } while (old < 0 || old > 1); } old = prevmode; prevmode = f & ~MODE_FORCE; #ifndef USE_TERMIO sb = nttyb; tc = ntc; ltc = nltc; lmode = olmode; #else tmp_tc = new_tc; #endif if (f & MODE_ECHO) { #ifndef USE_TERMIO sb.sg_flags |= ECHO; #else tmp_tc.c_lflag |= ECHO; tmp_tc.c_oflag |= ONLCR; if (crlf) tmp_tc.c_iflag |= ICRNL; #endif } else { #ifndef USE_TERMIO sb.sg_flags &= ~ECHO; #else tmp_tc.c_lflag &= ~ECHO; tmp_tc.c_oflag &= ~ONLCR; #endif } if ((f & MODE_FLOW) == 0) { #ifndef USE_TERMIO tc.t_startc = _POSIX_VDISABLE; tc.t_stopc = _POSIX_VDISABLE; #else tmp_tc.c_iflag &= ~(IXOFF | IXON); /* Leave the IXANY bit alone */ } else { if (restartany < 0) { tmp_tc.c_iflag |= IXOFF | IXON; /* Leave the IXANY bit alone */ } else if (restartany > 0) { tmp_tc.c_iflag |= IXOFF | IXON | IXANY; } else { tmp_tc.c_iflag |= IXOFF | IXON; tmp_tc.c_iflag &= ~IXANY; } #endif } if ((f & MODE_TRAPSIG) == 0) { #ifndef USE_TERMIO tc.t_intrc = _POSIX_VDISABLE; tc.t_quitc = _POSIX_VDISABLE; tc.t_eofc = _POSIX_VDISABLE; ltc.t_suspc = _POSIX_VDISABLE; ltc.t_dsuspc = _POSIX_VDISABLE; #else tmp_tc.c_lflag &= ~ISIG; #endif localchars = 0; } else { #ifdef USE_TERMIO tmp_tc.c_lflag |= ISIG; #endif localchars = 1; } if (f & MODE_EDIT) { #ifndef USE_TERMIO sb.sg_flags &= ~CBREAK; sb.sg_flags |= CRMOD; #else tmp_tc.c_lflag |= ICANON; #endif } else { #ifndef USE_TERMIO sb.sg_flags |= CBREAK; if (f & MODE_ECHO) sb.sg_flags |= CRMOD; else sb.sg_flags &= ~CRMOD; #else tmp_tc.c_lflag &= ~ICANON; tmp_tc.c_iflag &= ~ICRNL; tmp_tc.c_cc[VMIN] = 1; tmp_tc.c_cc[VTIME] = 0; #endif } if ((f & (MODE_EDIT | MODE_TRAPSIG)) == 0) { #ifndef USE_TERMIO ltc.t_lnextc = _POSIX_VDISABLE; #else # ifdef VLNEXT tmp_tc.c_cc[VLNEXT] = (cc_t) (_POSIX_VDISABLE); # endif #endif } if (f & MODE_SOFT_TAB) { #ifndef USE_TERMIO sb.sg_flags |= XTABS; #else # ifdef OXTABS tmp_tc.c_oflag |= OXTABS; # endif # ifdef TABDLY tmp_tc.c_oflag &= ~TABDLY; tmp_tc.c_oflag |= TAB3; # endif #endif } else { #ifndef USE_TERMIO sb.sg_flags &= ~XTABS; #else # ifdef OXTABS tmp_tc.c_oflag &= ~OXTABS; # endif # ifdef TABDLY tmp_tc.c_oflag &= ~TABDLY; # endif #endif } if (f & MODE_LIT_ECHO) { #ifndef USE_TERMIO lmode &= ~LCTLECH; #else # ifdef ECHOCTL tmp_tc.c_lflag &= ~ECHOCTL; # endif #endif } else { #ifndef USE_TERMIO lmode |= LCTLECH; #else # ifdef ECHOCTL tmp_tc.c_lflag |= ECHOCTL; # endif #endif } if (f == -1) { onoff = 0; } else { #ifndef USE_TERMIO if (f & MODE_OUTBIN) lmode |= LLITOUT; # if 0 /* If not in binary mode, still allow all 8-bits. */ else lmode &= ~LLITOUT; # endif if (f & MODE_INBIN) lmode |= LPASS8; # if 0 /* If not in binary mode, still allow all 8-bits. */ else lmode &= ~LPASS8; # endif #else if (f & MODE_INBIN) tmp_tc.c_iflag &= ~ISTRIP; # if 0 /* If not in binary mode, still allow all 8-bits. */ else tmp_tc.c_iflag |= ISTRIP; # endif if (f & MODE_OUTBIN) { tmp_tc.c_cflag &= ~(CSIZE | PARENB); tmp_tc.c_cflag |= CS8; tmp_tc.c_oflag &= ~OPOST; } else { tmp_tc.c_cflag &= ~(CSIZE | PARENB); tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE | PARENB); tmp_tc.c_oflag |= OPOST; } #endif onoff = 1; } if (f != -1) { #ifdef SIGTSTP signal (SIGTSTP, susp); #endif /* SIGTSTP */ #ifdef SIGINFO signal (SIGINFO, ayt); #endif #if defined USE_TERMIO && defined NOKERNINFO tmp_tc.c_lflag |= NOKERNINFO; #endif /* * We don't want to process ^Y here. It's just another * character that we'll pass on to the back end. It has * to process it because it will be processed when the * user attempts to read it, not when we send it. */ #ifndef USE_TERMIO ltc.t_dsuspc = _POSIX_VDISABLE; #else # ifdef VDSUSP tmp_tc.c_cc[VDSUSP] = (cc_t) (_POSIX_VDISABLE); # endif #endif #ifdef USE_TERMIO /* * If the VEOL character is already set, then use VEOL2, * otherwise use VEOL. */ esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape; if ((tmp_tc.c_cc[VEOL] != esc) # ifdef VEOL2 && (tmp_tc.c_cc[VEOL2] != esc) # endif ) { if (tmp_tc.c_cc[VEOL] == (cc_t) (_POSIX_VDISABLE)) tmp_tc.c_cc[VEOL] = esc; # ifdef VEOL2 else if (tmp_tc.c_cc[VEOL2] == (cc_t) (_POSIX_VDISABLE)) tmp_tc.c_cc[VEOL2] = esc; # endif } #else if (tc.t_brkc == (cc_t) (_POSIX_VDISABLE)) tc.t_brkc = esc; #endif } else { #ifdef SIGINFO signal (SIGINFO, (void (*)(int)) ayt_status); #endif #ifdef SIGTSTP signal (SIGTSTP, SIG_DFL); # ifdef HAVE_SIGACTION { sigset_t sigs; sigemptyset (&sigs); sigaddset (&sigs, SIGTSTP); sigprocmask (SIG_UNBLOCK, &sigs, 0); } # else sigsetmask (sigblock (0) & ~(1 << (SIGTSTP - 1))); # endif/* HAVE_SIGACTION */ #endif /* SIGTSTP */ #ifndef USE_TERMIO ltc = oltc; tc = otc; sb = ottyb; lmode = olmode; #else tmp_tc = old_tc; #endif } #ifndef USE_TERMIO ioctl (tin, TIOCLSET, (char *) &lmode); ioctl (tin, TIOCSLTC, (char *) <c); ioctl (tin, TIOCSETC, (char *) &tc); ioctl (tin, TIOCSETN, (char *) &sb); #else if (tcsetattr (tin, TCSADRAIN, &tmp_tc) < 0) tcsetattr (tin, TCSANOW, &tmp_tc); #endif #if !defined sysV88 ioctl (tin, FIONBIO, (char *) &onoff); ioctl (tout, FIONBIO, (char *) &onoff); #endif } /* * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). */ #if B4800 != 4800 # define DECODE_BAUD #endif #ifdef DECODE_BAUD # ifndef B7200 # define B7200 B4800 # endif # ifndef B14400 # define B14400 B9600 # endif # ifndef B19200 # define B19200 B14400 # endif # ifndef B28800 # define B28800 B19200 # endif # ifndef B38400 # define B38400 B28800 # endif # ifndef B57600 # define B57600 B38400 # endif # ifndef B76800 # define B76800 B57600 # endif # ifndef B115200 # define B115200 B76800 # endif # ifndef B230400 # define B230400 B115200 # endif /* * This code assumes that the values B0, B50, B75... * are in ascending order. They do not have to be * contiguous. */ struct termspeeds { long speed; long value; } termspeeds[] = { {0, B0}, {50, B50}, {75, B75}, {110, B110}, {134, B134}, {150, B150}, {200, B200}, {300, B300}, {600, B600}, {1200, B1200}, {1800, B1800}, {2400, B2400}, {4800, B4800}, {7200, B7200}, {9600, B9600}, {14400, B14400}, {19200, B19200}, {28800, B28800}, {38400, B38400}, {57600, B57600}, {115200, B115200}, {230400, B230400}, {-1, B230400} }; #endif /* DECODE_BAUD */ void TerminalSpeeds (long *ispeed, long *ospeed) { #ifdef DECODE_BAUD struct termspeeds *tp; #endif /* DECODE_BAUD */ long in, out; out = cfgetospeed (&old_tc); in = cfgetispeed (&old_tc); if (in == 0) in = out; #ifdef DECODE_BAUD tp = termspeeds; while ((tp->speed != -1) && (tp->value < in)) tp++; *ispeed = tp->speed; tp = termspeeds; while ((tp->speed != -1) && (tp->value < out)) tp++; *ospeed = tp->speed; #else /* DECODE_BAUD */ *ispeed = in; *ospeed = out; #endif /* DECODE_BAUD */ } int TerminalWindowSize (long *rows, long *cols) { #ifdef TIOCGWINSZ struct winsize ws; if (ioctl (fileno (stdin), TIOCGWINSZ, (char *) &ws) >= 0) { *rows = ws.ws_row; *cols = ws.ws_col; return 1; } #endif /* TIOCGWINSZ */ return 0; } int NetClose (int fd) { return close (fd); } void NetNonblockingIO (int fd, int onoff) { ioctl (fd, FIONBIO, (char *) &onoff); } /* * Various signal handling routines. */ void deadpeer (int sig MAYBE_UNUSED) { setcommandmode (); longjmp (peerdied, -1); } void intr (int sig MAYBE_UNUSED) { if (localchars) { intp (); return; } setcommandmode (); longjmp (toplevel, -1); } void intr2 (int sig MAYBE_UNUSED) { if (localchars) { #ifdef KLUDGELINEMODE if (kludgelinemode) sendbrk (); else #endif sendabort (); return; } } #ifdef SIGTSTP void susp (int sig MAYBE_UNUSED) { if ((rlogin != _POSIX_VDISABLE) && rlogin_susp ()) return; if (localchars) sendsusp (); } #endif #ifdef SIGWINCH void sendwin (int sig MAYBE_UNUSED) { if (connected) { sendnaws (); } } #endif #ifdef SIGINFO void ayt (int sig MAYBE_UNUSED) { if (connected) sendayt (); else ayt_status (); } #endif void sys_telnet_init (void) { struct sigaction sa; sa.sa_flags = SA_RESTART; sigemptyset (&sa.sa_mask); signal (SIGINT, intr); signal (SIGQUIT, intr2); signal (SIGPIPE, deadpeer); #ifdef SIGWINCH sa.sa_handler = sendwin; (void) sigaction (SIGWINCH, &sa, NULL); #endif #ifdef SIGTSTP sa.sa_handler = susp; (void) sigaction (SIGTSTP, &sa, NULL); #endif #ifdef SIGINFO sa.sa_handler = ayt; (void) sigaction (SIGINFO, &sa, NULL); #endif setconnmode (0); NetNonblockingIO (net, 1); #if defined SO_OOBINLINE if (SetSockOpt (net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { perror ("SetSockOpt"); } #endif /* defined(SO_OOBINLINE) */ } /* * Process rings - * * This routine tries to fill up/empty our various rings. * * The parameter specifies whether this is a poll operation, * or a block-until-something-happens operation. * * The return value is 1 if something happened, 0 if not. */ /* poll; If 0, then block until something to do */ int process_rings (int netin, int netout, int netex, int ttyin, int ttyout, int poll) { int c; int returnValue = 0; static struct timeval TimeValue = { 0, 0 }; int nfds = 0; if (netout) { FD_SET (net, &obits); if (net > nfds) nfds = net; } if (ttyout) { FD_SET (tout, &obits); if (tout > nfds) nfds = tout; } if (ttyin) { FD_SET (tin, &ibits); if (tin > nfds) nfds = tin; } if (netin) { FD_SET (net, &ibits); if (net > nfds) nfds = net; } if (netex) { FD_SET (net, &xbits); if (net > nfds) nfds = net; } if ((c = select (nfds + 1, &ibits, &obits, &xbits, (poll == 0) ? (struct timeval *) 0 : &TimeValue)) < 0) { if (c == -1) { /* * we can get EINTR if we are in line mode, * and the user does an escape (TSTP), or * some other signal generator. */ if (errno == EINTR) { return 0; } /* I don't like this, does it ever happen? */ printf ("sleep(5) from telnet, after select\r\n"); sleep (5); } return 0; } /* * Any urgent data? */ if (FD_ISSET (net, &xbits)) { FD_CLR (net, &xbits); SYNCHing = 1; ttyflush (1); /* flush already enqueued data */ } /* * Something to read from the network... */ if (FD_ISSET (net, &ibits)) { int canread; FD_CLR (net, &ibits); canread = ring_empty_consecutive (&netiring); #if !defined SO_OOBINLINE /* * In 4.2 (and some early 4.3) 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; static int bogus_oob = 0, first = 1; ioctl (net, SIOCATMARK, (char *) &atmark); if (atmark) { c = recv (net, netiring.supply, canread, MSG_OOB); if ((c == -1) && (errno == EINVAL)) { c = recv (net, netiring.supply, canread, 0); if (clocks.didnetreceive < clocks.gotDM) { SYNCHing = stilloob (net); } } else if (first && c > 0) { /* * Bogosity check. Systems based on 4.2BSD * do not return an error if you do a second * recv(MSG_OOB). So, we do one. If it * succeeds and returns exactly the same * data, then assume that we are running * on a broken system and set the bogus_oob * flag. (If the data was different, then * we probably got some valid new data, so * increment the count...) */ int i; i = recv (net, netiring.supply + c, canread - c, MSG_OOB); if (i == c && memcmp (netiring.supply, netiring.supply + c, i) == 0) { bogus_oob = 1; first = 0; } else if (i < 0) { bogus_oob = 0; first = 0; } else c += i; } if (bogus_oob && c > 0) { int i; /* * Bogosity. We have to do the read * to clear the atmark to get out of * an infinite loop. */ i = read (net, netiring.supply + c, canread - c); if (i > 0) c += i; } } else { c = recv (net, netiring.supply, canread, 0); } } else { c = recv (net, netiring.supply, canread, 0); } settimer (didnetreceive); #else /* !defined(SO_OOBINLINE) */ c = recv (net, (char *) netiring.supply, canread, 0); #endif /* !defined(SO_OOBINLINE) */ if (c < 0 && errno == EWOULDBLOCK) { c = 0; } else if (c <= 0) { return -1; } if (netdata) { Dump ('<', netiring.supply, c); } if (c) ring_supplied (&netiring, c); returnValue = 1; } /* * Something to read from the tty... */ if (FD_ISSET (tin, &ibits)) { FD_CLR (tin, &ibits); c = TerminalRead ((char *) ttyiring.supply, ring_empty_consecutive (&ttyiring)); if (c < 0 && errno == EIO) c = 0; if (c < 0 && errno == EWOULDBLOCK) { c = 0; } else { /* EOF detection for line mode!!!! */ if ((c == 0) && MODE_LOCAL_CHARS (globalmode) && isatty (tin)) { /* must be an EOF... */ *ttyiring.supply = termEofChar; c = 1; } if (c <= 0) { return -1; } if (termdata) { Dump ('<', ttyiring.supply, c); } ring_supplied (&ttyiring, c); } returnValue = 1; /* did something useful */ } if (FD_ISSET (net, &obits)) { FD_CLR (net, &obits); returnValue |= netflush (); } if (FD_ISSET (tout, &obits)) { FD_CLR (tout, &obits); returnValue |= (ttyflush (SYNCHing | flushout) > 0); } return returnValue; }