xref: /csrg-svn/usr.bin/telnet/sys_bsd.c (revision 68345)
132147Sminshall /*
262313Sbostic  * Copyright (c) 1988, 1990, 1993
362313Sbostic  *	The Regents of the University of California.  All rights reserved.
433685Sbostic  *
542770Sbostic  * %sccs.include.redist.c%
633685Sbostic  */
733685Sbostic 
833685Sbostic #ifndef lint
9*68345Sdab static char sccsid[] = "@(#)sys_bsd.c	8.3 (Berkeley) 02/16/95";
1033685Sbostic #endif /* not lint */
1133685Sbostic 
1233685Sbostic /*
1332147Sminshall  * The following routines try to encapsulate what is system dependent
1432147Sminshall  * (at least between 4.x and dos) which is used in telnet.c.
1532147Sminshall  */
1632147Sminshall 
1732147Sminshall 
1836274Sminshall #include <fcntl.h>
1932381Sminshall #include <sys/types.h>
2032147Sminshall #include <sys/time.h>
2132531Sminshall #include <sys/socket.h>
2232147Sminshall #include <signal.h>
2332531Sminshall #include <errno.h>
2438689Sborman #include <arpa/telnet.h>
2532147Sminshall 
2632381Sminshall #include "ring.h"
2732381Sminshall 
2832657Sminshall #include "fdset.h"
2932657Sminshall 
3032147Sminshall #include "defines.h"
3132147Sminshall #include "externs.h"
3232147Sminshall #include "types.h"
3332147Sminshall 
3445233Sborman #if	defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO))
3540245Sborman #define	SIG_FUNC_RET	void
3640245Sborman #else
3740245Sborman #define	SIG_FUNC_RET	int
3840245Sborman #endif
3940245Sborman 
4058972Sdab #ifdef	SIGINFO
4158972Sdab extern SIG_FUNC_RET ayt_status();
4265157Sdab #endif
4358972Sdab 
4432147Sminshall int
4532531Sminshall 	tout,			/* Output file descriptor */
4632531Sminshall 	tin,			/* Input file descriptor */
4736242Sminshall 	net;
4832147Sminshall 
4938689Sborman #ifndef	USE_TERMIO
5038689Sborman struct	tchars otc = { 0 }, ntc = { 0 };
5138689Sborman struct	ltchars oltc = { 0 }, nltc = { 0 };
5238689Sborman struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
5338909Sborman int	olmode = 0;
5445233Sborman # define cfgetispeed(ptr)	(ptr)->sg_ispeed
5545233Sborman # define cfgetospeed(ptr)	(ptr)->sg_ospeed
5645233Sborman # define old_tc ottyb
5732147Sminshall 
5838689Sborman #else	/* USE_TERMIO */
5938689Sborman struct	termio old_tc = { 0 };
6038689Sborman extern struct termio new_tc;
6138689Sborman 
6245233Sborman # ifndef	TCSANOW
6345233Sborman #  ifdef TCSETS
6445233Sborman #   define	TCSANOW		TCSETS
6545233Sborman #   define	TCSADRAIN	TCSETSW
6646808Sdab #   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
6745233Sborman #  else
6845233Sborman #   ifdef TCSETA
6945233Sborman #    define	TCSANOW		TCSETA
7045233Sborman #    define	TCSADRAIN	TCSETAW
7146808Sdab #    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
7245233Sborman #   else
7345233Sborman #    define	TCSANOW		TIOCSETA
7445233Sborman #    define	TCSADRAIN	TIOCSETAW
7546808Sdab #    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
7645233Sborman #   endif
7745233Sborman #  endif
7846808Sdab #  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
7945233Sborman #  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
8045233Sborman #  ifdef CIBAUD
8145233Sborman #   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
8245233Sborman #  else
8345233Sborman #   define	cfgetispeed(ptr)	cfgetospeed(ptr)
8445233Sborman #  endif
8545233Sborman # endif /* TCSANOW */
8657213Sdab # ifdef	sysV88
8757213Sdab # define TIOCFLUSH TC_PX_DRAIN
8857213Sdab # endif
8938689Sborman #endif	/* USE_TERMIO */
9038689Sborman 
9132531Sminshall static fd_set ibits, obits, xbits;
9232147Sminshall 
9332531Sminshall 
9446808Sdab     void
9532531Sminshall init_sys()
9632531Sminshall {
9732531Sminshall     tout = fileno(stdout);
9832531Sminshall     tin = fileno(stdin);
9932531Sminshall     FD_ZERO(&ibits);
10032531Sminshall     FD_ZERO(&obits);
10132531Sminshall     FD_ZERO(&xbits);
10232531Sminshall 
10332531Sminshall     errno = 0;
10432531Sminshall }
10532531Sminshall 
10632531Sminshall 
10746808Sdab     int
10833286Sminshall TerminalWrite(buf, n)
10946808Sdab     char *buf;
11046808Sdab     int  n;
11132147Sminshall {
11233286Sminshall     return write(tout, buf, n);
11332147Sminshall }
11432147Sminshall 
11546808Sdab     int
11633286Sminshall TerminalRead(buf, n)
11746808Sdab     char *buf;
11846808Sdab     int  n;
11932147Sminshall {
12033286Sminshall     return read(tin, buf, n);
12132147Sminshall }
12232147Sminshall 
12332147Sminshall /*
12432147Sminshall  *
12532147Sminshall  */
12632147Sminshall 
12746808Sdab     int
12832553Sminshall TerminalAutoFlush()
12932147Sminshall {
13032147Sminshall #if	defined(LNOFLSH)
13132147Sminshall     int flush;
13232147Sminshall 
13332147Sminshall     ioctl(0, TIOCLGET, (char *)&flush);
13432147Sminshall     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
13532147Sminshall #else	/* LNOFLSH */
13632147Sminshall     return 1;
13732147Sminshall #endif	/* LNOFLSH */
13832147Sminshall }
13932147Sminshall 
14038689Sborman #ifdef	KLUDGELINEMODE
14138689Sborman extern int kludgelinemode;
14238689Sborman #endif
14332147Sminshall /*
14432147Sminshall  * TerminalSpecialChars()
14532147Sminshall  *
14632147Sminshall  * Look at an input character to see if it is a special character
14732147Sminshall  * and decide what to do.
14832147Sminshall  *
14932147Sminshall  * Output:
15032147Sminshall  *
15132147Sminshall  *	0	Don't add this character.
15232147Sminshall  *	1	Do add this character
15332147Sminshall  */
15432147Sminshall 
15558972Sdab extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
15658972Sdab 
15746808Sdab     int
15832553Sminshall TerminalSpecialChars(c)
15946808Sdab     int	c;
16032147Sminshall {
16138689Sborman     if (c == termIntChar) {
16232147Sminshall 	intp();
16332147Sminshall 	return 0;
16438689Sborman     } else if (c == termQuitChar) {
16538689Sborman #ifdef	KLUDGELINEMODE
16638689Sborman 	if (kludgelinemode)
16738689Sborman 	    sendbrk();
16838689Sborman 	else
16938689Sborman #endif
17038689Sborman 	    sendabort();
17132147Sminshall 	return 0;
17238689Sborman     } else if (c == termEofChar) {
17338689Sborman 	if (my_want_state_is_will(TELOPT_LINEMODE)) {
17438689Sborman 	    sendeof();
17538689Sborman 	    return 0;
17638689Sborman 	}
17738689Sborman 	return 1;
17838689Sborman     } else if (c == termSuspChar) {
17938689Sborman 	sendsusp();
18038689Sborman 	return(0);
18138689Sborman     } else if (c == termFlushChar) {
18232147Sminshall 	xmitAO();		/* Transmit Abort Output */
18332147Sminshall 	return 0;
18432147Sminshall     } else if (!MODE_LOCAL_CHARS(globalmode)) {
18538689Sborman 	if (c == termKillChar) {
18632147Sminshall 	    xmitEL();
18732147Sminshall 	    return 0;
18838689Sborman 	} else if (c == termEraseChar) {
18932147Sminshall 	    xmitEC();		/* Transmit Erase Character */
19032147Sminshall 	    return 0;
19132147Sminshall 	}
19232147Sminshall     }
19332147Sminshall     return 1;
19432147Sminshall }
19532147Sminshall 
19632147Sminshall 
19732147Sminshall /*
19832147Sminshall  * Flush output to the terminal
19932147Sminshall  */
20032147Sminshall 
20146808Sdab     void
20232553Sminshall TerminalFlushOutput()
20332147Sminshall {
20439529Sborman #ifdef	TIOCFLUSH
20532147Sminshall     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
20638689Sborman #else
20738689Sborman     (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
20838689Sborman #endif
20932147Sminshall }
21032147Sminshall 
21146808Sdab     void
21232553Sminshall TerminalSaveState()
21332147Sminshall {
21438689Sborman #ifndef	USE_TERMIO
21532147Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
21632147Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
21732147Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
21838909Sborman     ioctl(0, TIOCLGET, (char *)&olmode);
21932147Sminshall 
22032147Sminshall     ntc = otc;
22132147Sminshall     nltc = oltc;
22232147Sminshall     nttyb = ottyb;
22332254Sminshall 
22438689Sborman #else	/* USE_TERMIO */
22545233Sborman     tcgetattr(0, &old_tc);
22638689Sborman 
22738689Sborman     new_tc = old_tc;
22838689Sborman 
22945233Sborman #ifndef	VDISCARD
23044361Sborman     termFlushChar = CONTROL('O');
23145233Sborman #endif
23245233Sborman #ifndef	VWERASE
23344361Sborman     termWerasChar = CONTROL('W');
23445233Sborman #endif
23545233Sborman #ifndef	VREPRINT
23644361Sborman     termRprntChar = CONTROL('R');
23745233Sborman #endif
23845233Sborman #ifndef	VLNEXT
23944361Sborman     termLiteralNextChar = CONTROL('V');
24045233Sborman #endif
24145233Sborman #ifndef	VSTART
24244361Sborman     termStartChar = CONTROL('Q');
24345233Sborman #endif
24445233Sborman #ifndef	VSTOP
24544361Sborman     termStopChar = CONTROL('S');
24645233Sborman #endif
24745233Sborman #ifndef	VSTATUS
24845233Sborman     termAytChar = CONTROL('T');
24945233Sborman #endif
25038689Sborman #endif	/* USE_TERMIO */
25132147Sminshall }
25232147Sminshall 
25346808Sdab     cc_t *
25438689Sborman tcval(func)
25546808Sdab     register int func;
25638689Sborman {
25738689Sborman     switch(func) {
25840245Sborman     case SLC_IP:	return(&termIntChar);
25940245Sborman     case SLC_ABORT:	return(&termQuitChar);
26040245Sborman     case SLC_EOF:	return(&termEofChar);
26140245Sborman     case SLC_EC:	return(&termEraseChar);
26240245Sborman     case SLC_EL:	return(&termKillChar);
26340245Sborman     case SLC_XON:	return(&termStartChar);
26440245Sborman     case SLC_XOFF:	return(&termStopChar);
26544361Sborman     case SLC_FORW1:	return(&termForw1Char);
26645233Sborman #ifdef	USE_TERMIO
26745233Sborman     case SLC_FORW2:	return(&termForw2Char);
26845233Sborman # ifdef	VDISCARD
26940245Sborman     case SLC_AO:	return(&termFlushChar);
27045233Sborman # endif
27145233Sborman # ifdef	VSUSP
27240245Sborman     case SLC_SUSP:	return(&termSuspChar);
27345233Sborman # endif
27445233Sborman # ifdef	VWERASE
27540245Sborman     case SLC_EW:	return(&termWerasChar);
27645233Sborman # endif
27745233Sborman # ifdef	VREPRINT
27840245Sborman     case SLC_RP:	return(&termRprntChar);
27945233Sborman # endif
28045233Sborman # ifdef	VLNEXT
28140245Sborman     case SLC_LNEXT:	return(&termLiteralNextChar);
28245233Sborman # endif
28345233Sborman # ifdef	VSTATUS
28445233Sborman     case SLC_AYT:	return(&termAytChar);
28545233Sborman # endif
28644361Sborman #endif
28738689Sborman 
28838689Sborman     case SLC_SYNCH:
28938689Sborman     case SLC_BRK:
29038689Sborman     case SLC_EOR:
29138689Sborman     default:
29240245Sborman 	return((cc_t *)0);
29338689Sborman     }
29438689Sborman }
29538689Sborman 
29646808Sdab     void
29738689Sborman TerminalDefaultChars()
29838689Sborman {
29938689Sborman #ifndef	USE_TERMIO
30038689Sborman     ntc = otc;
30138689Sborman     nltc = oltc;
30238689Sborman     nttyb.sg_kill = ottyb.sg_kill;
30338689Sborman     nttyb.sg_erase = ottyb.sg_erase;
30438689Sborman #else	/* USE_TERMIO */
30538689Sborman     memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
30645233Sborman # ifndef	VDISCARD
30744361Sborman     termFlushChar = CONTROL('O');
30839529Sborman # endif
30939529Sborman # ifndef	VWERASE
31044361Sborman     termWerasChar = CONTROL('W');
31139529Sborman # endif
31239529Sborman # ifndef	VREPRINT
31344361Sborman     termRprntChar = CONTROL('R');
31439529Sborman # endif
31539529Sborman # ifndef	VLNEXT
31644361Sborman     termLiteralNextChar = CONTROL('V');
31739529Sborman # endif
31839529Sborman # ifndef	VSTART
31944361Sborman     termStartChar = CONTROL('Q');
32039529Sborman # endif
32139529Sborman # ifndef	VSTOP
32244361Sborman     termStopChar = CONTROL('S');
32339529Sborman # endif
32445233Sborman # ifndef	VSTATUS
32545233Sborman     termAytChar = CONTROL('T');
32645233Sborman # endif
32738689Sborman #endif	/* USE_TERMIO */
32838689Sborman }
32938689Sborman 
33044361Sborman #ifdef notdef
33138689Sborman void
33232553Sminshall TerminalRestoreState()
33332147Sminshall {
33432147Sminshall }
33544361Sborman #endif
33632147Sminshall 
33732147Sminshall /*
33832147Sminshall  * TerminalNewMode - set up terminal to a specific mode.
33938689Sborman  *	MODE_ECHO: do local terminal echo
34038689Sborman  *	MODE_FLOW: do local flow control
34138689Sborman  *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
34238689Sborman  *	MODE_EDIT: do local line editing
34338689Sborman  *
34438689Sborman  *	Command mode:
34538689Sborman  *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
34638689Sborman  *		local echo
34738689Sborman  *		local editing
34838689Sborman  *		local xon/xoff
34938689Sborman  *		local signal mapping
35038689Sborman  *
35138689Sborman  *	Linemode:
35238689Sborman  *		local/no editing
35338689Sborman  *	Both Linemode and Single Character mode:
35438689Sborman  *		local/remote echo
35538689Sborman  *		local/no xon/xoff
35638689Sborman  *		local/no signal mapping
35732147Sminshall  */
35832147Sminshall 
35932147Sminshall 
36046808Sdab     void
36133286Sminshall TerminalNewMode(f)
36246808Sdab     register int f;
36332147Sminshall {
36432147Sminshall     static int prevmode = 0;
36538689Sborman #ifndef	USE_TERMIO
36638689Sborman     struct tchars tc;
36738689Sborman     struct ltchars ltc;
36832147Sminshall     struct sgttyb sb;
36938909Sborman     int lmode;
37038689Sborman #else	/* USE_TERMIO */
37138689Sborman     struct termio tmp_tc;
37238689Sborman #endif	/* USE_TERMIO */
37332147Sminshall     int onoff;
37432147Sminshall     int old;
37546808Sdab     cc_t esc;
37632147Sminshall 
37738689Sborman     globalmode = f&~MODE_FORCE;
37832147Sminshall     if (prevmode == f)
37932147Sminshall 	return;
38038689Sborman 
38138689Sborman     /*
38238689Sborman      * Write any outstanding data before switching modes
38338689Sborman      * ttyflush() returns 0 only when there is no more data
38438689Sborman      * left to write out, it returns -1 if it couldn't do
38538689Sborman      * anything at all, otherwise it returns 1 + the number
38638689Sborman      * of characters left to write.
38745233Sborman #ifndef	USE_TERMIO
38845233Sborman      * We would really like ask the kernel to wait for the output
38945233Sborman      * to drain, like we can do with the TCSADRAIN, but we don't have
39045233Sborman      * that option.  The only ioctl that waits for the output to
39145233Sborman      * drain, TIOCSETP, also flushes the input queue, which is NOT
39245233Sborman      * what we want (TIOCSETP is like TCSADFLUSH).
39345233Sborman #endif
39438689Sborman      */
39538689Sborman     old = ttyflush(SYNCHing|flushout);
39638689Sborman     if (old < 0 || old > 1) {
39745233Sborman #ifdef	USE_TERMIO
39846808Sdab 	tcgetattr(tin, &tmp_tc);
39938689Sborman #endif	/* USE_TERMIO */
40038689Sborman 	do {
40138689Sborman 	    /*
40238689Sborman 	     * Wait for data to drain, then flush again.
40338689Sborman 	     */
40445233Sborman #ifdef	USE_TERMIO
40546808Sdab 	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
40638689Sborman #endif	/* USE_TERMIO */
40738689Sborman 	    old = ttyflush(SYNCHing|flushout);
40838689Sborman 	} while (old < 0 || old > 1);
40938689Sborman     }
41038689Sborman 
41132147Sminshall     old = prevmode;
41238689Sborman     prevmode = f&~MODE_FORCE;
41338689Sborman #ifndef	USE_TERMIO
41432147Sminshall     sb = nttyb;
41538689Sborman     tc = ntc;
41638689Sborman     ltc = nltc;
41738909Sborman     lmode = olmode;
41838689Sborman #else
41938689Sborman     tmp_tc = new_tc;
42038689Sborman #endif
42132147Sminshall 
42238689Sborman     if (f&MODE_ECHO) {
42338689Sborman #ifndef	USE_TERMIO
42438689Sborman 	sb.sg_flags |= ECHO;
42538689Sborman #else
42638689Sborman 	tmp_tc.c_lflag |= ECHO;
42738689Sborman 	tmp_tc.c_oflag |= ONLCR;
42846808Sdab 	if (crlf)
42946808Sdab 		tmp_tc.c_iflag |= ICRNL;
43038689Sborman #endif
43138689Sborman     } else {
43238689Sborman #ifndef	USE_TERMIO
43338689Sborman 	sb.sg_flags &= ~ECHO;
43438689Sborman #else
43538689Sborman 	tmp_tc.c_lflag &= ~ECHO;
43638689Sborman 	tmp_tc.c_oflag &= ~ONLCR;
43739529Sborman # ifdef notdef
43846808Sdab 	if (crlf)
43946808Sdab 		tmp_tc.c_iflag &= ~ICRNL;
44039529Sborman # endif
44138689Sborman #endif
44238689Sborman     }
44332147Sminshall 
44438689Sborman     if ((f&MODE_FLOW) == 0) {
44538689Sborman #ifndef	USE_TERMIO
44645233Sborman 	tc.t_startc = _POSIX_VDISABLE;
44745233Sborman 	tc.t_stopc = _POSIX_VDISABLE;
44838689Sborman #else
44957213Sdab 	tmp_tc.c_iflag &= ~(IXOFF|IXON);	/* Leave the IXANY bit alone */
45038689Sborman     } else {
45157213Sdab 	if (restartany < 0) {
45257213Sdab 		tmp_tc.c_iflag |= IXOFF|IXON;	/* Leave the IXANY bit alone */
45357213Sdab 	} else if (restartany > 0) {
45457213Sdab 		tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
45557213Sdab 	} else {
45657213Sdab 		tmp_tc.c_iflag |= IXOFF|IXON;
45757213Sdab 		tmp_tc.c_iflag &= ~IXANY;
45857213Sdab 	}
45938689Sborman #endif
46038689Sborman     }
46132147Sminshall 
46238689Sborman     if ((f&MODE_TRAPSIG) == 0) {
46338689Sborman #ifndef	USE_TERMIO
46445233Sborman 	tc.t_intrc = _POSIX_VDISABLE;
46545233Sborman 	tc.t_quitc = _POSIX_VDISABLE;
46645233Sborman 	tc.t_eofc = _POSIX_VDISABLE;
46745233Sborman 	ltc.t_suspc = _POSIX_VDISABLE;
46845233Sborman 	ltc.t_dsuspc = _POSIX_VDISABLE;
46938689Sborman #else
47038689Sborman 	tmp_tc.c_lflag &= ~ISIG;
47138689Sborman #endif
47238689Sborman 	localchars = 0;
47338689Sborman     } else {
47438689Sborman #ifdef	USE_TERMIO
47538689Sborman 	tmp_tc.c_lflag |= ISIG;
47638689Sborman #endif
47738689Sborman 	localchars = 1;
47838689Sborman     }
47938689Sborman 
48038689Sborman     if (f&MODE_EDIT) {
48138689Sborman #ifndef	USE_TERMIO
48238689Sborman 	sb.sg_flags &= ~CBREAK;
48338689Sborman 	sb.sg_flags |= CRMOD;
48438689Sborman #else
48538689Sborman 	tmp_tc.c_lflag |= ICANON;
48638689Sborman #endif
48738689Sborman     } else {
48838689Sborman #ifndef	USE_TERMIO
48938689Sborman 	sb.sg_flags |= CBREAK;
49038689Sborman 	if (f&MODE_ECHO)
49132147Sminshall 	    sb.sg_flags |= CRMOD;
49238689Sborman 	else
49338689Sborman 	    sb.sg_flags &= ~CRMOD;
49438689Sborman #else
49538689Sborman 	tmp_tc.c_lflag &= ~ICANON;
49638689Sborman 	tmp_tc.c_iflag &= ~ICRNL;
49738689Sborman 	tmp_tc.c_cc[VMIN] = 1;
49838689Sborman 	tmp_tc.c_cc[VTIME] = 0;
49938689Sborman #endif
50038689Sborman     }
50132147Sminshall 
50244361Sborman     if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
50344361Sborman #ifndef	USE_TERMIO
50445233Sborman 	ltc.t_lnextc = _POSIX_VDISABLE;
50544361Sborman #else
50644361Sborman # ifdef VLNEXT
50745233Sborman 	tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
50844361Sborman # endif
50944361Sborman #endif
51044361Sborman     }
51144361Sborman 
51244361Sborman     if (f&MODE_SOFT_TAB) {
51344361Sborman #ifndef USE_TERMIO
51444361Sborman 	sb.sg_flags |= XTABS;
51544361Sborman #else
51644361Sborman # ifdef	OXTABS
51744361Sborman 	tmp_tc.c_oflag |= OXTABS;
51844361Sborman # endif
51944361Sborman # ifdef	TABDLY
52044361Sborman 	tmp_tc.c_oflag &= ~TABDLY;
52144361Sborman 	tmp_tc.c_oflag |= TAB3;
52244361Sborman # endif
52344361Sborman #endif
52444361Sborman     } else {
52544361Sborman #ifndef USE_TERMIO
52644361Sborman 	sb.sg_flags &= ~XTABS;
52744361Sborman #else
52844361Sborman # ifdef	OXTABS
52944361Sborman 	tmp_tc.c_oflag &= ~OXTABS;
53044361Sborman # endif
53144361Sborman # ifdef	TABDLY
53244361Sborman 	tmp_tc.c_oflag &= ~TABDLY;
53344361Sborman # endif
53444361Sborman #endif
53544361Sborman     }
53644361Sborman 
53744361Sborman     if (f&MODE_LIT_ECHO) {
53844361Sborman #ifndef USE_TERMIO
53946808Sdab 	lmode &= ~LCTLECH;
54044361Sborman #else
54144361Sborman # ifdef	ECHOCTL
54244361Sborman 	tmp_tc.c_lflag &= ~ECHOCTL;
54344361Sborman # endif
54444361Sborman #endif
54544361Sborman     } else {
54644361Sborman #ifndef USE_TERMIO
54746808Sdab 	lmode |= LCTLECH;
54844361Sborman #else
54944361Sborman # ifdef	ECHOCTL
55044361Sborman 	tmp_tc.c_lflag |= ECHOCTL;
55144361Sborman # endif
55244361Sborman #endif
55344361Sborman     }
55444361Sborman 
55538689Sborman     if (f == -1) {
55638689Sborman 	onoff = 0;
55738689Sborman     } else {
55838909Sborman #ifndef	USE_TERMIO
55939529Sborman 	if (f & MODE_OUTBIN)
56038909Sborman 		lmode |= LLITOUT;
56138909Sborman 	else
56238909Sborman 		lmode &= ~LLITOUT;
56339529Sborman 
56439529Sborman 	if (f & MODE_INBIN)
56538909Sborman 		lmode |= LPASS8;
56638909Sborman 	else
56738909Sborman 		lmode &= ~LPASS8;
56838909Sborman #else
56945233Sborman 	if (f & MODE_INBIN)
57045233Sborman 		tmp_tc.c_iflag &= ~ISTRIP;
57138909Sborman 	else
57245233Sborman 		tmp_tc.c_iflag |= ISTRIP;
57345233Sborman 	if (f & MODE_OUTBIN) {
57439529Sborman 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
57539529Sborman 		tmp_tc.c_cflag |= CS8;
57645233Sborman 		tmp_tc.c_oflag &= ~OPOST;
57739529Sborman 	} else {
57845233Sborman 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
57945233Sborman 		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
58045233Sborman 		tmp_tc.c_oflag |= OPOST;
58139529Sborman 	}
58238909Sborman #endif
58338689Sborman 	onoff = 1;
58432147Sminshall     }
58538689Sborman 
58638689Sborman     if (f != -1) {
58739529Sborman #ifdef	SIGTSTP
58865157Sdab 	SIG_FUNC_RET susp();
58945233Sborman #endif	/* SIGTSTP */
59045233Sborman #ifdef	SIGINFO
59165157Sdab 	SIG_FUNC_RET ayt();
59265157Sdab #endif
59338689Sborman 
59445233Sborman #ifdef	SIGTSTP
59545233Sborman 	(void) signal(SIGTSTP, susp);
59639529Sborman #endif	/* SIGTSTP */
59745233Sborman #ifdef	SIGINFO
59845233Sborman 	(void) signal(SIGINFO, ayt);
59965157Sdab #endif
60045233Sborman #if	defined(USE_TERMIO) && defined(NOKERNINFO)
60145233Sborman 	tmp_tc.c_lflag |= NOKERNINFO;
60245233Sborman #endif
60344361Sborman 	/*
60444361Sborman 	 * We don't want to process ^Y here.  It's just another
60544361Sborman 	 * character that we'll pass on to the back end.  It has
60644361Sborman 	 * to process it because it will be processed when the
60744361Sborman 	 * user attempts to read it, not when we send it.
60844361Sborman 	 */
60944361Sborman #ifndef	USE_TERMIO
61045233Sborman 	ltc.t_dsuspc = _POSIX_VDISABLE;
61144361Sborman #else
61244361Sborman # ifdef	VDSUSP
61345233Sborman 	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
61444361Sborman # endif
61544361Sborman #endif
61640245Sborman #ifdef	USE_TERMIO
61740245Sborman 	/*
61840245Sborman 	 * If the VEOL character is already set, then use VEOL2,
61940245Sborman 	 * otherwise use VEOL.
62040245Sborman 	 */
62146808Sdab 	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
62246808Sdab 	if ((tmp_tc.c_cc[VEOL] != esc)
62344361Sborman # ifdef	VEOL2
62446808Sdab 	    && (tmp_tc.c_cc[VEOL2] != esc)
62544361Sborman # endif
62646808Sdab 	    ) {
62745233Sborman 		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
62846808Sdab 		    tmp_tc.c_cc[VEOL] = esc;
62945233Sborman # ifdef	VEOL2
63045233Sborman 		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
63146808Sdab 		    tmp_tc.c_cc[VEOL2] = esc;
63245233Sborman # endif
63345233Sborman 	}
63440245Sborman #else
63545233Sborman 	if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
63646808Sdab 		tc.t_brkc = esc;
63740245Sborman #endif
63838689Sborman     } else {
63945233Sborman #ifdef	SIGINFO
64060149Sdab 	SIG_FUNC_RET ayt_status();
64160149Sdab 
64245233Sborman 	(void) signal(SIGINFO, ayt_status);
64365157Sdab #endif
64439529Sborman #ifdef	SIGTSTP
64538689Sborman 	(void) signal(SIGTSTP, SIG_DFL);
64644361Sborman 	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
64739529Sborman #endif	/* SIGTSTP */
64839529Sborman #ifndef USE_TERMIO
64939529Sborman 	ltc = oltc;
65039529Sborman 	tc = otc;
65139529Sborman 	sb = ottyb;
65244361Sborman 	lmode = olmode;
65344361Sborman #else
65444361Sborman 	tmp_tc = old_tc;
65539529Sborman #endif
65638689Sborman     }
65739529Sborman #ifndef USE_TERMIO
65839529Sborman     ioctl(tin, TIOCLSET, (char *)&lmode);
65939529Sborman     ioctl(tin, TIOCSLTC, (char *)&ltc);
66039529Sborman     ioctl(tin, TIOCSETC, (char *)&tc);
66145233Sborman     ioctl(tin, TIOCSETN, (char *)&sb);
66239529Sborman #else
66345233Sborman     if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
66445233Sborman 	tcsetattr(tin, TCSANOW, &tmp_tc);
66539529Sborman #endif
66639529Sborman 
66732147Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
66857213Sdab # if	!defined(sysV88)
66933286Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
67033286Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
67157213Sdab # endif
67232147Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
67332147Sminshall #if	defined(TN3270)
67436242Sminshall     if (noasynchtty == 0) {
67533286Sminshall 	ioctl(tin, FIOASYNC, (char *)&onoff);
67632147Sminshall     }
67732147Sminshall #endif	/* defined(TN3270) */
67846808Sdab 
67932147Sminshall }
68032147Sminshall 
681*68345Sdab /*
682*68345Sdab  * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
683*68345Sdab  */
684*68345Sdab #if B4800 != 4800
685*68345Sdab #define	DECODE_BAUD
686*68345Sdab #endif
687*68345Sdab 
688*68345Sdab #ifdef	DECODE_BAUD
689*68345Sdab #ifndef	B7200
690*68345Sdab #define B7200   B4800
691*68345Sdab #endif
692*68345Sdab 
693*68345Sdab #ifndef	B14400
694*68345Sdab #define B14400  B9600
695*68345Sdab #endif
696*68345Sdab 
69739529Sborman #ifndef	B19200
698*68345Sdab # define B19200 B14400
69939529Sborman #endif
70039529Sborman 
701*68345Sdab #ifndef	B28800
702*68345Sdab #define B28800  B19200
703*68345Sdab #endif
704*68345Sdab 
70539529Sborman #ifndef	B38400
706*68345Sdab # define B38400 B28800
70739529Sborman #endif
70839529Sborman 
709*68345Sdab #ifndef B57600
710*68345Sdab #define B57600  B38400
711*68345Sdab #endif
712*68345Sdab 
713*68345Sdab #ifndef B76800
714*68345Sdab #define B76800  B57600
715*68345Sdab #endif
716*68345Sdab 
717*68345Sdab #ifndef B115200
718*68345Sdab #define B115200 B76800
719*68345Sdab #endif
720*68345Sdab 
721*68345Sdab #ifndef B230400
722*68345Sdab #define B230400 B115200
723*68345Sdab #endif
724*68345Sdab 
725*68345Sdab 
72639529Sborman /*
72739529Sborman  * This code assumes that the values B0, B50, B75...
72839529Sborman  * are in ascending order.  They do not have to be
72939529Sborman  * contiguous.
73039529Sborman  */
73139529Sborman struct termspeeds {
73239529Sborman 	long speed;
73339529Sborman 	long value;
73439529Sborman } termspeeds[] = {
735*68345Sdab 	{ 0,      B0 },      { 50,    B50 },    { 75,     B75 },
736*68345Sdab 	{ 110,    B110 },    { 134,   B134 },   { 150,    B150 },
737*68345Sdab 	{ 200,    B200 },    { 300,   B300 },   { 600,    B600 },
738*68345Sdab 	{ 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
739*68345Sdab 	{ 4800,   B4800 },   { 7200,  B7200 },  { 9600,   B9600 },
740*68345Sdab 	{ 14400,  B14400 },  { 19200, B19200 }, { 28800,  B28800 },
741*68345Sdab 	{ 38400,  B38400 },  { 57600, B57600 }, { 115200, B115200 },
742*68345Sdab 	{ 230400, B230400 }, { -1,    B230400 }
74339529Sborman };
744*68345Sdab #endif	/* DECODE_BAUD */
74539529Sborman 
74646808Sdab     void
74737219Sminshall TerminalSpeeds(ispeed, ospeed)
74846808Sdab     long *ispeed;
74946808Sdab     long *ospeed;
75037219Sminshall {
751*68345Sdab #ifdef	DECODE_BAUD
75239529Sborman     register struct termspeeds *tp;
753*68345Sdab #endif	/* DECODE_BAUD */
75445233Sborman     register long in, out;
75532147Sminshall 
75646808Sdab     out = cfgetospeed(&old_tc);
75745233Sborman     in = cfgetispeed(&old_tc);
75846808Sdab     if (in == 0)
75946808Sdab 	in = out;
76045233Sborman 
761*68345Sdab #ifdef	DECODE_BAUD
76239529Sborman     tp = termspeeds;
76345233Sborman     while ((tp->speed != -1) && (tp->value < in))
76439529Sborman 	tp++;
76539529Sborman     *ispeed = tp->speed;
76639529Sborman 
76739529Sborman     tp = termspeeds;
76845233Sborman     while ((tp->speed != -1) && (tp->value < out))
76939529Sborman 	tp++;
77039529Sborman     *ospeed = tp->speed;
771*68345Sdab #else	/* DECODE_BAUD */
772*68345Sdab 	*ispeed = in;
773*68345Sdab 	*ospeed = out;
774*68345Sdab #endif	/* DECODE_BAUD */
77537219Sminshall }
77637219Sminshall 
77746808Sdab     int
77837219Sminshall TerminalWindowSize(rows, cols)
77946808Sdab     long *rows, *cols;
78037219Sminshall {
78138689Sborman #ifdef	TIOCGWINSZ
78237219Sminshall     struct winsize ws;
78337219Sminshall 
78438689Sborman     if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
78538689Sborman 	*rows = ws.ws_row;
78638689Sborman 	*cols = ws.ws_col;
78738689Sborman 	return 1;
78837219Sminshall     }
78938810Sborman #endif	/* TIOCGWINSZ */
79038689Sborman     return 0;
79137219Sminshall }
79237219Sminshall 
79346808Sdab     int
79435417Sminshall NetClose(fd)
79546808Sdab     int	fd;
79632147Sminshall {
79735417Sminshall     return close(fd);
79832147Sminshall }
79932147Sminshall 
80032147Sminshall 
80146808Sdab     void
80232553Sminshall NetNonblockingIO(fd, onoff)
80346808Sdab     int fd;
80446808Sdab     int onoff;
80532147Sminshall {
80632147Sminshall     ioctl(fd, FIONBIO, (char *)&onoff);
80732147Sminshall }
80832147Sminshall 
80934849Sminshall #if	defined(TN3270)
81046808Sdab     void
81132553Sminshall NetSigIO(fd, onoff)
81246808Sdab     int fd;
81346808Sdab     int onoff;
81432147Sminshall {
81532147Sminshall     ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
81632147Sminshall }
81732147Sminshall 
81846808Sdab     void
81932553Sminshall NetSetPgrp(fd)
82046808Sdab     int fd;
82132147Sminshall {
82232147Sminshall     int myPid;
82332147Sminshall 
82432147Sminshall     myPid = getpid();
82536274Sminshall     fcntl(fd, F_SETOWN, myPid);
82632147Sminshall }
82734849Sminshall #endif	/*defined(TN3270)*/
82832553Sminshall 
82932553Sminshall /*
83032553Sminshall  * Various signal handling routines.
83132553Sminshall  */
83232147Sminshall 
83346808Sdab     /* ARGSUSED */
83465157Sdab     SIG_FUNC_RET
83545233Sborman deadpeer(sig)
83646808Sdab     int sig;
83732553Sminshall {
83832553Sminshall 	setcommandmode();
83932553Sminshall 	longjmp(peerdied, -1);
84032553Sminshall }
84132147Sminshall 
84246808Sdab     /* ARGSUSED */
84365157Sdab     SIG_FUNC_RET
84445233Sborman intr(sig)
84546808Sdab     int sig;
84632553Sminshall {
84732553Sminshall     if (localchars) {
84832553Sminshall 	intp();
84932553Sminshall 	return;
85032553Sminshall     }
85132553Sminshall     setcommandmode();
85232553Sminshall     longjmp(toplevel, -1);
85332553Sminshall }
85432553Sminshall 
85546808Sdab     /* ARGSUSED */
85665157Sdab     SIG_FUNC_RET
85745233Sborman intr2(sig)
85846808Sdab     int sig;
85932553Sminshall {
86032553Sminshall     if (localchars) {
86138689Sborman #ifdef	KLUDGELINEMODE
86238689Sborman 	if (kludgelinemode)
86338689Sborman 	    sendbrk();
86438689Sborman 	else
86538689Sborman #endif
86638689Sborman 	    sendabort();
86732553Sminshall 	return;
86832553Sminshall     }
86932553Sminshall }
87032553Sminshall 
87145233Sborman #ifdef	SIGTSTP
87246808Sdab     /* ARGSUSED */
87365157Sdab     SIG_FUNC_RET
87445233Sborman susp(sig)
87546808Sdab     int sig;
87640245Sborman {
87746808Sdab     if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
87846808Sdab 	return;
87940245Sborman     if (localchars)
88040245Sborman 	sendsusp();
88140245Sborman }
88245233Sborman #endif
88340245Sborman 
88445233Sborman #ifdef	SIGWINCH
88546808Sdab     /* ARGSUSED */
88665157Sdab     SIG_FUNC_RET
88745233Sborman sendwin(sig)
88846808Sdab     int sig;
88937219Sminshall {
89037219Sminshall     if (connected) {
89137219Sminshall 	sendnaws();
89237219Sminshall     }
89337219Sminshall }
89445233Sborman #endif
89537219Sminshall 
89645233Sborman #ifdef	SIGINFO
89746808Sdab     /* ARGSUSED */
89865157Sdab     SIG_FUNC_RET
89945233Sborman ayt(sig)
90046808Sdab     int sig;
90145233Sborman {
90245233Sborman     if (connected)
90345233Sborman 	sendayt();
90445233Sborman     else
90545233Sborman 	ayt_status();
90645233Sborman }
90745233Sborman #endif
90845233Sborman 
90932553Sminshall 
91046808Sdab     void
91132531Sminshall sys_telnet_init()
91232531Sminshall {
91345233Sborman     (void) signal(SIGINT, intr);
91445233Sborman     (void) signal(SIGQUIT, intr2);
91545233Sborman     (void) signal(SIGPIPE, deadpeer);
91638689Sborman #ifdef	SIGWINCH
91745233Sborman     (void) signal(SIGWINCH, sendwin);
91838689Sborman #endif
91940245Sborman #ifdef	SIGTSTP
92045233Sborman     (void) signal(SIGTSTP, susp);
92140245Sborman #endif
92245233Sborman #ifdef	SIGINFO
92345233Sborman     (void) signal(SIGINFO, ayt);
92445233Sborman #endif
92532553Sminshall 
92638689Sborman     setconnmode(0);
92732531Sminshall 
92832531Sminshall     NetNonblockingIO(net, 1);
92932531Sminshall 
93032531Sminshall #if	defined(TN3270)
93136242Sminshall     if (noasynchnet == 0) {			/* DBX can't handle! */
93232531Sminshall 	NetSigIO(net, 1);
93332531Sminshall 	NetSetPgrp(net);
93432531Sminshall     }
93532531Sminshall #endif	/* defined(TN3270) */
93632531Sminshall 
93732531Sminshall #if	defined(SO_OOBINLINE)
93834849Sminshall     if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
93934849Sminshall 	perror("SetSockOpt");
94034849Sminshall     }
94132531Sminshall #endif	/* defined(SO_OOBINLINE) */
94232531Sminshall }
94332531Sminshall 
94432531Sminshall /*
94532531Sminshall  * Process rings -
94632531Sminshall  *
94732531Sminshall  *	This routine tries to fill up/empty our various rings.
94832531Sminshall  *
94932531Sminshall  *	The parameter specifies whether this is a poll operation,
95032531Sminshall  *	or a block-until-something-happens operation.
95132531Sminshall  *
95232531Sminshall  *	The return value is 1 if something happened, 0 if not.
95332531Sminshall  */
95432531Sminshall 
95546808Sdab     int
95632531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll)
95746808Sdab     int poll;		/* If 0, then block until something to do */
95832531Sminshall {
95932531Sminshall     register int c;
96032531Sminshall 		/* One wants to be a bit careful about setting returnValue
96132531Sminshall 		 * to one, since a one implies we did some useful work,
96232531Sminshall 		 * and therefore probably won't be called to block next
96332531Sminshall 		 * time (TN3270 mode only).
96432531Sminshall 		 */
96532531Sminshall     int returnValue = 0;
96632531Sminshall     static struct timeval TimeValue = { 0 };
96732531Sminshall 
96832531Sminshall     if (netout) {
96932531Sminshall 	FD_SET(net, &obits);
97032531Sminshall     }
97132531Sminshall     if (ttyout) {
97232531Sminshall 	FD_SET(tout, &obits);
97332531Sminshall     }
97432531Sminshall #if	defined(TN3270)
97532531Sminshall     if (ttyin) {
97632531Sminshall 	FD_SET(tin, &ibits);
97732531Sminshall     }
97832531Sminshall #else	/* defined(TN3270) */
97932531Sminshall     if (ttyin) {
98032531Sminshall 	FD_SET(tin, &ibits);
98132531Sminshall     }
98232531Sminshall #endif	/* defined(TN3270) */
98332531Sminshall #if	defined(TN3270)
98432531Sminshall     if (netin) {
98532531Sminshall 	FD_SET(net, &ibits);
98632531Sminshall     }
98732531Sminshall #   else /* !defined(TN3270) */
98832531Sminshall     if (netin) {
98932531Sminshall 	FD_SET(net, &ibits);
99032531Sminshall     }
99132531Sminshall #   endif /* !defined(TN3270) */
99232531Sminshall     if (netex) {
99332531Sminshall 	FD_SET(net, &xbits);
99432531Sminshall     }
99532531Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
99632531Sminshall 			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
99732531Sminshall 	if (c == -1) {
99832531Sminshall 		    /*
99932531Sminshall 		     * we can get EINTR if we are in line mode,
100032531Sminshall 		     * and the user does an escape (TSTP), or
100132531Sminshall 		     * some other signal generator.
100232531Sminshall 		     */
100332531Sminshall 	    if (errno == EINTR) {
100432531Sminshall 		return 0;
100532531Sminshall 	    }
100632531Sminshall #	    if defined(TN3270)
100732531Sminshall 		    /*
100832531Sminshall 		     * we can get EBADF if we were in transparent
100932531Sminshall 		     * mode, and the transcom process died.
101032531Sminshall 		    */
101132531Sminshall 	    if (errno == EBADF) {
101232531Sminshall 			/*
101332531Sminshall 			 * zero the bits (even though kernel does it)
101432531Sminshall 			 * to make sure we are selecting on the right
101532531Sminshall 			 * ones.
101632531Sminshall 			*/
101732531Sminshall 		FD_ZERO(&ibits);
101832531Sminshall 		FD_ZERO(&obits);
101932531Sminshall 		FD_ZERO(&xbits);
102032531Sminshall 		return 0;
102132531Sminshall 	    }
102232531Sminshall #	    endif /* defined(TN3270) */
102332531Sminshall 		    /* I don't like this, does it ever happen? */
102432531Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
102532531Sminshall 	    sleep(5);
102632531Sminshall 	}
102732531Sminshall 	return 0;
102832531Sminshall     }
102932531Sminshall 
103032531Sminshall     /*
103132531Sminshall      * Any urgent data?
103232531Sminshall      */
103332531Sminshall     if (FD_ISSET(net, &xbits)) {
103432531Sminshall 	FD_CLR(net, &xbits);
103532531Sminshall 	SYNCHing = 1;
103644361Sborman 	(void) ttyflush(1);	/* flush already enqueued data */
103732531Sminshall     }
103832531Sminshall 
103932531Sminshall     /*
104032531Sminshall      * Something to read from the network...
104132531Sminshall      */
104232531Sminshall     if (FD_ISSET(net, &ibits)) {
104332531Sminshall 	int canread;
104432531Sminshall 
104532531Sminshall 	FD_CLR(net, &ibits);
104632531Sminshall 	canread = ring_empty_consecutive(&netiring);
104732531Sminshall #if	!defined(SO_OOBINLINE)
104832531Sminshall 	    /*
104932531Sminshall 	     * In 4.2 (and some early 4.3) systems, the
105032531Sminshall 	     * OOB indication and data handling in the kernel
105132531Sminshall 	     * is such that if two separate TCP Urgent requests
105232531Sminshall 	     * come in, one byte of TCP data will be overlaid.
105332531Sminshall 	     * This is fatal for Telnet, but we try to live
105432531Sminshall 	     * with it.
105532531Sminshall 	     *
105632531Sminshall 	     * In addition, in 4.2 (and...), a special protocol
105732531Sminshall 	     * is needed to pick up the TCP Urgent data in
105832531Sminshall 	     * the correct sequence.
105932531Sminshall 	     *
106032531Sminshall 	     * What we do is:  if we think we are in urgent
106132531Sminshall 	     * mode, we look to see if we are "at the mark".
106232531Sminshall 	     * If we are, we do an OOB receive.  If we run
106332531Sminshall 	     * this twice, we will do the OOB receive twice,
106432531Sminshall 	     * but the second will fail, since the second
106532531Sminshall 	     * time we were "at the mark", but there wasn't
106632531Sminshall 	     * any data there (the kernel doesn't reset
106732531Sminshall 	     * "at the mark" until we do a normal read).
106832531Sminshall 	     * Once we've read the OOB data, we go ahead
106932531Sminshall 	     * and do normal reads.
107032531Sminshall 	     *
107132531Sminshall 	     * There is also another problem, which is that
107232531Sminshall 	     * since the OOB byte we read doesn't put us
107332531Sminshall 	     * out of OOB state, and since that byte is most
107432531Sminshall 	     * likely the TELNET DM (data mark), we would
107532531Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
107632531Sminshall 	     * So, clocks to the rescue.  If we've "just"
107732531Sminshall 	     * received a DM, then we test for the
107832531Sminshall 	     * presence of OOB data when the receive OOB
107932531Sminshall 	     * fails (and AFTER we did the normal mode read
108032531Sminshall 	     * to clear "at the mark").
108132531Sminshall 	     */
108232531Sminshall 	if (SYNCHing) {
108332531Sminshall 	    int atmark;
108439652Sborman 	    static int bogus_oob = 0, first = 1;
108532531Sminshall 
108632531Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
108732531Sminshall 	    if (atmark) {
108832531Sminshall 		c = recv(net, netiring.supply, canread, MSG_OOB);
108932531Sminshall 		if ((c == -1) && (errno == EINVAL)) {
109032531Sminshall 		    c = recv(net, netiring.supply, canread, 0);
109132531Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
109232531Sminshall 			SYNCHing = stilloob(net);
109332531Sminshall 		    }
109439652Sborman 		} else if (first && c > 0) {
109539652Sborman 		    /*
109639652Sborman 		     * Bogosity check.  Systems based on 4.2BSD
109739652Sborman 		     * do not return an error if you do a second
109839652Sborman 		     * recv(MSG_OOB).  So, we do one.  If it
109939652Sborman 		     * succeeds and returns exactly the same
110039652Sborman 		     * data, then assume that we are running
110139652Sborman 		     * on a broken system and set the bogus_oob
110239652Sborman 		     * flag.  (If the data was different, then
110339652Sborman 		     * we probably got some valid new data, so
110439652Sborman 		     * increment the count...)
110539652Sborman 		     */
110639652Sborman 		    int i;
110739652Sborman 		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
110839652Sborman 		    if (i == c &&
110939652Sborman 			  bcmp(netiring.supply, netiring.supply + c, i) == 0) {
111039652Sborman 			bogus_oob = 1;
111139652Sborman 			first = 0;
111239652Sborman 		    } else if (i < 0) {
111339652Sborman 			bogus_oob = 0;
111439652Sborman 			first = 0;
111539652Sborman 		    } else
111639652Sborman 			c += i;
111732531Sminshall 		}
111839652Sborman 		if (bogus_oob && c > 0) {
111939652Sborman 		    int i;
112039652Sborman 		    /*
112139652Sborman 		     * Bogosity.  We have to do the read
112239652Sborman 		     * to clear the atmark to get out of
112339652Sborman 		     * an infinate loop.
112439652Sborman 		     */
112539652Sborman 		    i = read(net, netiring.supply + c, canread - c);
112639652Sborman 		    if (i > 0)
112739652Sborman 			c += i;
112839652Sborman 		}
112932531Sminshall 	    } else {
113032531Sminshall 		c = recv(net, netiring.supply, canread, 0);
113132531Sminshall 	    }
113232531Sminshall 	} else {
113332531Sminshall 	    c = recv(net, netiring.supply, canread, 0);
113432531Sminshall 	}
113532531Sminshall 	settimer(didnetreceive);
113632531Sminshall #else	/* !defined(SO_OOBINLINE) */
113765157Sdab 	c = recv(net, (char *)netiring.supply, canread, 0);
113832531Sminshall #endif	/* !defined(SO_OOBINLINE) */
113932531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
114032531Sminshall 	    c = 0;
114132531Sminshall 	} else if (c <= 0) {
114232531Sminshall 	    return -1;
114332531Sminshall 	}
114432531Sminshall 	if (netdata) {
114532531Sminshall 	    Dump('<', netiring.supply, c);
114632531Sminshall 	}
114732667Sminshall 	if (c)
114832667Sminshall 	    ring_supplied(&netiring, c);
114932531Sminshall 	returnValue = 1;
115032531Sminshall     }
115132531Sminshall 
115232531Sminshall     /*
115332531Sminshall      * Something to read from the tty...
115432531Sminshall      */
115532531Sminshall     if (FD_ISSET(tin, &ibits)) {
115632531Sminshall 	FD_CLR(tin, &ibits);
115733286Sminshall 	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
1158*68345Sdab 	if (c < 0 && errno == EIO)
1159*68345Sdab 	    c = 0;
116032531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
116132531Sminshall 	    c = 0;
116232531Sminshall 	} else {
116332531Sminshall 	    /* EOF detection for line mode!!!! */
116433281Sminshall 	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
116532531Sminshall 			/* must be an EOF... */
116632531Sminshall 		*ttyiring.supply = termEofChar;
116732531Sminshall 		c = 1;
116832531Sminshall 	    }
116932531Sminshall 	    if (c <= 0) {
117032531Sminshall 		return -1;
117132531Sminshall 	    }
117238208Sminshall 	    if (termdata) {
117338208Sminshall 		Dump('<', ttyiring.supply, c);
117438208Sminshall 	    }
117532667Sminshall 	    ring_supplied(&ttyiring, c);
117632531Sminshall 	}
117732531Sminshall 	returnValue = 1;		/* did something useful */
117832531Sminshall     }
117932531Sminshall 
118032531Sminshall     if (FD_ISSET(net, &obits)) {
118132531Sminshall 	FD_CLR(net, &obits);
118232531Sminshall 	returnValue |= netflush();
118332531Sminshall     }
118432531Sminshall     if (FD_ISSET(tout, &obits)) {
118532531Sminshall 	FD_CLR(tout, &obits);
118638689Sborman 	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
118732531Sminshall     }
118832531Sminshall 
118932531Sminshall     return returnValue;
119032531Sminshall }
1191