129088Smarkm/*
229088Smarkm * Copyright (c) 1988, 1990, 1993
329088Smarkm *	The Regents of the University of California.  All rights reserved.
429088Smarkm *
529088Smarkm * Redistribution and use in source and binary forms, with or without
629088Smarkm * modification, are permitted provided that the following conditions
729088Smarkm * are met:
829088Smarkm * 1. Redistributions of source code must retain the above copyright
929088Smarkm *    notice, this list of conditions and the following disclaimer.
1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1129088Smarkm *    notice, this list of conditions and the following disclaimer in the
1229088Smarkm *    documentation and/or other materials provided with the distribution.
1329088Smarkm * 3. All advertising materials mentioning features or use of this software
1429088Smarkm *    must display the following acknowledgement:
1529088Smarkm *	This product includes software developed by the University of
1629088Smarkm *	California, Berkeley and its contributors.
1729088Smarkm * 4. Neither the name of the University nor the names of its contributors
1829088Smarkm *    may be used to endorse or promote products derived from this software
1929088Smarkm *    without specific prior written permission.
2029088Smarkm *
2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2429088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3129088Smarkm * SUCH DAMAGE.
3229088Smarkm */
3329088Smarkm
34114630Sobrien#if 0
3529088Smarkm#ifndef lint
3629181Smarkmstatic const char sccsid[] = "@(#)sys_bsd.c	8.4 (Berkeley) 5/30/95";
3763248Speter#endif
38114630Sobrien#endif
39114630Sobrien#include <sys/cdefs.h>
40114630Sobrien__FBSDID("$FreeBSD$");
4129088Smarkm
4229088Smarkm/*
4329088Smarkm * The following routines try to encapsulate what is system dependent
4429088Smarkm * (at least between 4.x and dos) which is used in telnet.c.
4529088Smarkm */
4629088Smarkm
47103954Smarkm#include <sys/param.h>
4887139Smarkm#include <sys/socket.h>
4929088Smarkm#include <sys/time.h>
50114630Sobrien#include <err.h>
5187139Smarkm#include <errno.h>
5287139Smarkm#include <fcntl.h>
5329088Smarkm#include <signal.h>
54114630Sobrien#include <stdlib.h>
5587139Smarkm#include <unistd.h>
5629088Smarkm#include <arpa/telnet.h>
5729088Smarkm
5829088Smarkm#include "ring.h"
5929088Smarkm#include "fdset.h"
6029088Smarkm#include "defines.h"
6129088Smarkm#include "externs.h"
6229088Smarkm#include "types.h"
6329088Smarkm
6429088Smarkmint
6529088Smarkm	tout,			/* Output file descriptor */
6629088Smarkm	tin,			/* Input file descriptor */
6729088Smarkm	net;
6829088Smarkm
6929088Smarkm#ifndef	USE_TERMIO
7029088Smarkmstruct	tchars otc = { 0 }, ntc = { 0 };
7129088Smarkmstruct	ltchars oltc = { 0 }, nltc = { 0 };
7229088Smarkmstruct	sgttyb ottyb = { 0 }, nttyb = { 0 };
7329088Smarkmint	olmode = 0;
7429088Smarkm# define cfgetispeed(ptr)	(ptr)->sg_ispeed
7529088Smarkm# define cfgetospeed(ptr)	(ptr)->sg_ospeed
7629088Smarkm# define old_tc ottyb
7729088Smarkm
7829088Smarkm#else	/* USE_TERMIO */
7987139Smarkmstruct	termio old_tc = { 0, 0, 0, 0, {}, 0, 0 };
8029088Smarkm
8129088Smarkm# ifndef	TCSANOW
8229088Smarkm#  ifdef TCSETS
8329088Smarkm#   define	TCSANOW		TCSETS
8429088Smarkm#   define	TCSADRAIN	TCSETSW
8529088Smarkm#   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
8629088Smarkm#  else
8729088Smarkm#   ifdef TCSETA
8829088Smarkm#    define	TCSANOW		TCSETA
8929088Smarkm#    define	TCSADRAIN	TCSETAW
9029088Smarkm#    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
9129088Smarkm#   else
9229088Smarkm#    define	TCSANOW		TIOCSETA
9329088Smarkm#    define	TCSADRAIN	TIOCSETAW
9429088Smarkm#    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
9529088Smarkm#   endif
9629088Smarkm#  endif
9729088Smarkm#  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
9829088Smarkm#  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
9929088Smarkm#  ifdef CIBAUD
10029088Smarkm#   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
10129088Smarkm#  else
10229088Smarkm#   define	cfgetispeed(ptr)	cfgetospeed(ptr)
10329088Smarkm#  endif
10429088Smarkm# endif /* TCSANOW */
10529088Smarkm# ifdef	sysV88
10629088Smarkm# define TIOCFLUSH TC_PX_DRAIN
10729088Smarkm# endif
10829088Smarkm#endif	/* USE_TERMIO */
10929088Smarkm
11087558Sjkhstatic fd_set *ibitsp, *obitsp, *xbitsp;
11187558Sjkhint fdsn;
11229088Smarkm
11387139Smarkm#ifdef	SIGINT
11487139Smarkmstatic SIG_FUNC_RET intr(int);
11587139Smarkm#endif	/* SIGINT */
11687139Smarkm#ifdef	SIGQUIT
11787139Smarkmstatic SIG_FUNC_RET intr2(int);
11887139Smarkm#endif	/* SIGQUIT */
11987139Smarkm#ifdef	SIGTSTP
12087139Smarkmstatic SIG_FUNC_RET susp(int);
12187139Smarkm#endif	/* SIGTSTP */
12287139Smarkm#ifdef	SIGINFO
12387139Smarkmstatic SIG_FUNC_RET ayt(int);
12487139Smarkm#endif
12529088Smarkm
12687139Smarkmvoid
12787139Smarkminit_sys(void)
12829088Smarkm{
12929088Smarkm    tout = fileno(stdout);
13029088Smarkm    tin = fileno(stdin);
13129088Smarkm    errno = 0;
13229088Smarkm}
13329088Smarkm
13487139Smarkmint
13587139SmarkmTerminalWrite(char *buf, int n)
13629088Smarkm{
13729088Smarkm    return write(tout, buf, n);
13829088Smarkm}
13929088Smarkm
14087139Smarkmint
14187139SmarkmTerminalRead(char *buf, int n)
14229088Smarkm{
14329088Smarkm    return read(tin, buf, n);
14429088Smarkm}
14529088Smarkm
14629088Smarkm/*
14729088Smarkm *
14829088Smarkm */
14929088Smarkm
15087139Smarkmint
15187139SmarkmTerminalAutoFlush(void)
15229088Smarkm{
15329088Smarkm#if	defined(LNOFLSH)
15429088Smarkm    int flush;
15529088Smarkm
15629088Smarkm    ioctl(0, TIOCLGET, (char *)&flush);
15729088Smarkm    return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
15829088Smarkm#else	/* LNOFLSH */
15929088Smarkm    return 1;
16029088Smarkm#endif	/* LNOFLSH */
16129088Smarkm}
16229088Smarkm
16329088Smarkm#ifdef	KLUDGELINEMODE
16429088Smarkmextern int kludgelinemode;
16529088Smarkm#endif
16629088Smarkm/*
16729088Smarkm * TerminalSpecialChars()
16829088Smarkm *
16929088Smarkm * Look at an input character to see if it is a special character
17029088Smarkm * and decide what to do.
17129088Smarkm *
17229088Smarkm * Output:
17329088Smarkm *
17429088Smarkm *	0	Don't add this character.
17529088Smarkm *	1	Do add this character
17629088Smarkm */
17729088Smarkm
17887139Smarkmint
17987139SmarkmTerminalSpecialChars(int c)
18029088Smarkm{
18129088Smarkm    if (c == termIntChar) {
18229088Smarkm	intp();
18329088Smarkm	return 0;
18429088Smarkm    } else if (c == termQuitChar) {
18529088Smarkm#ifdef	KLUDGELINEMODE
18629088Smarkm	if (kludgelinemode)
18729088Smarkm	    sendbrk();
18829088Smarkm	else
18929088Smarkm#endif
19029088Smarkm	    sendabort();
19129088Smarkm	return 0;
19229088Smarkm    } else if (c == termEofChar) {
19329088Smarkm	if (my_want_state_is_will(TELOPT_LINEMODE)) {
19429088Smarkm	    sendeof();
19529088Smarkm	    return 0;
19629088Smarkm	}
19729088Smarkm	return 1;
19829088Smarkm    } else if (c == termSuspChar) {
19929088Smarkm	sendsusp();
20029088Smarkm	return(0);
20129088Smarkm    } else if (c == termFlushChar) {
20229088Smarkm	xmitAO();		/* Transmit Abort Output */
20329088Smarkm	return 0;
20429088Smarkm    } else if (!MODE_LOCAL_CHARS(globalmode)) {
20529088Smarkm	if (c == termKillChar) {
20629088Smarkm	    xmitEL();
20729088Smarkm	    return 0;
20829088Smarkm	} else if (c == termEraseChar) {
20929088Smarkm	    xmitEC();		/* Transmit Erase Character */
21029088Smarkm	    return 0;
21129088Smarkm	}
21229088Smarkm    }
21329088Smarkm    return 1;
21429088Smarkm}
21529088Smarkm
21629088Smarkm
21729088Smarkm/*
21829088Smarkm * Flush output to the terminal
21929088Smarkm */
22029088Smarkm
22187139Smarkmvoid
22287139SmarkmTerminalFlushOutput(void)
22329088Smarkm{
22429088Smarkm#ifdef	TIOCFLUSH
22529088Smarkm    (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
22629088Smarkm#else
22729088Smarkm    (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
22829088Smarkm#endif
22929088Smarkm}
23029088Smarkm
23187139Smarkmvoid
23287139SmarkmTerminalSaveState(void)
23329088Smarkm{
23429088Smarkm#ifndef	USE_TERMIO
23529088Smarkm    ioctl(0, TIOCGETP, (char *)&ottyb);
23629088Smarkm    ioctl(0, TIOCGETC, (char *)&otc);
23729088Smarkm    ioctl(0, TIOCGLTC, (char *)&oltc);
23829088Smarkm    ioctl(0, TIOCLGET, (char *)&olmode);
23929088Smarkm
24029088Smarkm    ntc = otc;
24129088Smarkm    nltc = oltc;
24229088Smarkm    nttyb = ottyb;
24329088Smarkm
24429088Smarkm#else	/* USE_TERMIO */
24529088Smarkm    tcgetattr(0, &old_tc);
24629088Smarkm
24729088Smarkm    new_tc = old_tc;
24829088Smarkm
24929088Smarkm#ifndef	VDISCARD
25029088Smarkm    termFlushChar = CONTROL('O');
25129088Smarkm#endif
25229088Smarkm#ifndef	VWERASE
25329088Smarkm    termWerasChar = CONTROL('W');
25429088Smarkm#endif
25529088Smarkm#ifndef	VREPRINT
25629088Smarkm    termRprntChar = CONTROL('R');
25729088Smarkm#endif
25829088Smarkm#ifndef	VLNEXT
25929088Smarkm    termLiteralNextChar = CONTROL('V');
26029088Smarkm#endif
26129088Smarkm#ifndef	VSTART
26229088Smarkm    termStartChar = CONTROL('Q');
26329088Smarkm#endif
26429088Smarkm#ifndef	VSTOP
26529088Smarkm    termStopChar = CONTROL('S');
26629088Smarkm#endif
26729088Smarkm#ifndef	VSTATUS
26829088Smarkm    termAytChar = CONTROL('T');
26929088Smarkm#endif
27029088Smarkm#endif	/* USE_TERMIO */
27129088Smarkm}
27229088Smarkm
27387139Smarkmcc_t *
27487139Smarkmtcval(int func)
27529088Smarkm{
27629088Smarkm    switch(func) {
27729088Smarkm    case SLC_IP:	return(&termIntChar);
27829088Smarkm    case SLC_ABORT:	return(&termQuitChar);
27929088Smarkm    case SLC_EOF:	return(&termEofChar);
28029088Smarkm    case SLC_EC:	return(&termEraseChar);
28129088Smarkm    case SLC_EL:	return(&termKillChar);
28229088Smarkm    case SLC_XON:	return(&termStartChar);
28329088Smarkm    case SLC_XOFF:	return(&termStopChar);
28429088Smarkm    case SLC_FORW1:	return(&termForw1Char);
28529088Smarkm#ifdef	USE_TERMIO
28629088Smarkm    case SLC_FORW2:	return(&termForw2Char);
28729088Smarkm# ifdef	VDISCARD
28829088Smarkm    case SLC_AO:	return(&termFlushChar);
28929088Smarkm# endif
29029088Smarkm# ifdef	VSUSP
29129088Smarkm    case SLC_SUSP:	return(&termSuspChar);
29229088Smarkm# endif
29329088Smarkm# ifdef	VWERASE
29429088Smarkm    case SLC_EW:	return(&termWerasChar);
29529088Smarkm# endif
29629088Smarkm# ifdef	VREPRINT
29729088Smarkm    case SLC_RP:	return(&termRprntChar);
29829088Smarkm# endif
29929088Smarkm# ifdef	VLNEXT
30029088Smarkm    case SLC_LNEXT:	return(&termLiteralNextChar);
30129088Smarkm# endif
30229088Smarkm# ifdef	VSTATUS
30329088Smarkm    case SLC_AYT:	return(&termAytChar);
30429088Smarkm# endif
30529088Smarkm#endif
30629088Smarkm
30729088Smarkm    case SLC_SYNCH:
30829088Smarkm    case SLC_BRK:
30929088Smarkm    case SLC_EOR:
31029088Smarkm    default:
31129088Smarkm	return((cc_t *)0);
31229088Smarkm    }
31329088Smarkm}
31429088Smarkm
31587139Smarkmvoid
31687139SmarkmTerminalDefaultChars(void)
31729088Smarkm{
31829088Smarkm#ifndef	USE_TERMIO
31929088Smarkm    ntc = otc;
32029088Smarkm    nltc = oltc;
32129088Smarkm    nttyb.sg_kill = ottyb.sg_kill;
32229088Smarkm    nttyb.sg_erase = ottyb.sg_erase;
32329088Smarkm#else	/* USE_TERMIO */
32481965Smarkm    memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
32529088Smarkm# ifndef	VDISCARD
32629088Smarkm    termFlushChar = CONTROL('O');
32729088Smarkm# endif
32829088Smarkm# ifndef	VWERASE
32929088Smarkm    termWerasChar = CONTROL('W');
33029088Smarkm# endif
33129088Smarkm# ifndef	VREPRINT
33229088Smarkm    termRprntChar = CONTROL('R');
33329088Smarkm# endif
33429088Smarkm# ifndef	VLNEXT
33529088Smarkm    termLiteralNextChar = CONTROL('V');
33629088Smarkm# endif
33729088Smarkm# ifndef	VSTART
33829088Smarkm    termStartChar = CONTROL('Q');
33929088Smarkm# endif
34029088Smarkm# ifndef	VSTOP
34129088Smarkm    termStopChar = CONTROL('S');
34229088Smarkm# endif
34329088Smarkm# ifndef	VSTATUS
34429088Smarkm    termAytChar = CONTROL('T');
34529088Smarkm# endif
34629088Smarkm#endif	/* USE_TERMIO */
34729088Smarkm}
34829088Smarkm
34929088Smarkm/*
35029088Smarkm * TerminalNewMode - set up terminal to a specific mode.
35129088Smarkm *	MODE_ECHO: do local terminal echo
35229088Smarkm *	MODE_FLOW: do local flow control
35329088Smarkm *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
35429088Smarkm *	MODE_EDIT: do local line editing
35529088Smarkm *
35629088Smarkm *	Command mode:
35729088Smarkm *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
35829088Smarkm *		local echo
35929088Smarkm *		local editing
36029088Smarkm *		local xon/xoff
36129088Smarkm *		local signal mapping
36229088Smarkm *
36329088Smarkm *	Linemode:
36429088Smarkm *		local/no editing
36529088Smarkm *	Both Linemode and Single Character mode:
36629088Smarkm *		local/remote echo
36729088Smarkm *		local/no xon/xoff
36829088Smarkm *		local/no signal mapping
36929088Smarkm */
37029088Smarkm
37187139Smarkmvoid
37287139SmarkmTerminalNewMode(int f)
37329088Smarkm{
37429088Smarkm    static int prevmode = 0;
37529088Smarkm#ifndef	USE_TERMIO
37629088Smarkm    struct tchars tc;
37729088Smarkm    struct ltchars ltc;
37829088Smarkm    struct sgttyb sb;
37929088Smarkm    int lmode;
38029088Smarkm#else	/* USE_TERMIO */
38129088Smarkm    struct termio tmp_tc;
38229088Smarkm#endif	/* USE_TERMIO */
38329088Smarkm    int onoff;
38429088Smarkm    int old;
38529088Smarkm    cc_t esc;
38629088Smarkm
38729088Smarkm    globalmode = f&~MODE_FORCE;
38829088Smarkm    if (prevmode == f)
38929088Smarkm	return;
39029088Smarkm
39129088Smarkm    /*
39229088Smarkm     * Write any outstanding data before switching modes
39329088Smarkm     * ttyflush() returns 0 only when there is no more data
39429088Smarkm     * left to write out, it returns -1 if it couldn't do
39529088Smarkm     * anything at all, otherwise it returns 1 + the number
39629088Smarkm     * of characters left to write.
39729088Smarkm#ifndef	USE_TERMIO
39829088Smarkm     * We would really like ask the kernel to wait for the output
39929088Smarkm     * to drain, like we can do with the TCSADRAIN, but we don't have
40029088Smarkm     * that option.  The only ioctl that waits for the output to
40129088Smarkm     * drain, TIOCSETP, also flushes the input queue, which is NOT
40229088Smarkm     * what we want (TIOCSETP is like TCSADFLUSH).
40329088Smarkm#endif
40429088Smarkm     */
40529088Smarkm    old = ttyflush(SYNCHing|flushout);
40629088Smarkm    if (old < 0 || old > 1) {
40729088Smarkm#ifdef	USE_TERMIO
40829088Smarkm	tcgetattr(tin, &tmp_tc);
40929088Smarkm#endif	/* USE_TERMIO */
41029088Smarkm	do {
41129088Smarkm	    /*
41229088Smarkm	     * Wait for data to drain, then flush again.
41329088Smarkm	     */
41429088Smarkm#ifdef	USE_TERMIO
41529088Smarkm	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
41629088Smarkm#endif	/* USE_TERMIO */
41729088Smarkm	    old = ttyflush(SYNCHing|flushout);
41829088Smarkm	} while (old < 0 || old > 1);
41929088Smarkm    }
42029088Smarkm
42129088Smarkm    old = prevmode;
42229088Smarkm    prevmode = f&~MODE_FORCE;
42329088Smarkm#ifndef	USE_TERMIO
42429088Smarkm    sb = nttyb;
42529088Smarkm    tc = ntc;
42629088Smarkm    ltc = nltc;
42729088Smarkm    lmode = olmode;
42829088Smarkm#else
42929088Smarkm    tmp_tc = new_tc;
43029088Smarkm#endif
43129088Smarkm
43229088Smarkm    if (f&MODE_ECHO) {
43329088Smarkm#ifndef	USE_TERMIO
43429088Smarkm	sb.sg_flags |= ECHO;
43529088Smarkm#else
43629088Smarkm	tmp_tc.c_lflag |= ECHO;
43729088Smarkm	tmp_tc.c_oflag |= ONLCR;
43829088Smarkm	if (crlf)
43929088Smarkm		tmp_tc.c_iflag |= ICRNL;
44029088Smarkm#endif
44129088Smarkm    } else {
44229088Smarkm#ifndef	USE_TERMIO
44329088Smarkm	sb.sg_flags &= ~ECHO;
44429088Smarkm#else
44529088Smarkm	tmp_tc.c_lflag &= ~ECHO;
44629088Smarkm	tmp_tc.c_oflag &= ~ONLCR;
44729088Smarkm#endif
44829088Smarkm    }
44929088Smarkm
45029088Smarkm    if ((f&MODE_FLOW) == 0) {
45129088Smarkm#ifndef	USE_TERMIO
45229088Smarkm	tc.t_startc = _POSIX_VDISABLE;
45329088Smarkm	tc.t_stopc = _POSIX_VDISABLE;
45429088Smarkm#else
45529088Smarkm	tmp_tc.c_iflag &= ~(IXOFF|IXON);	/* Leave the IXANY bit alone */
45629088Smarkm    } else {
45729088Smarkm	if (restartany < 0) {
45829088Smarkm		tmp_tc.c_iflag |= IXOFF|IXON;	/* Leave the IXANY bit alone */
45929088Smarkm	} else if (restartany > 0) {
46029088Smarkm		tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
46129088Smarkm	} else {
46229088Smarkm		tmp_tc.c_iflag |= IXOFF|IXON;
46329088Smarkm		tmp_tc.c_iflag &= ~IXANY;
46429088Smarkm	}
46529088Smarkm#endif
46629088Smarkm    }
46729088Smarkm
46829088Smarkm    if ((f&MODE_TRAPSIG) == 0) {
46929088Smarkm#ifndef	USE_TERMIO
47029088Smarkm	tc.t_intrc = _POSIX_VDISABLE;
47129088Smarkm	tc.t_quitc = _POSIX_VDISABLE;
47229088Smarkm	tc.t_eofc = _POSIX_VDISABLE;
47329088Smarkm	ltc.t_suspc = _POSIX_VDISABLE;
47429088Smarkm	ltc.t_dsuspc = _POSIX_VDISABLE;
47529088Smarkm#else
47629088Smarkm	tmp_tc.c_lflag &= ~ISIG;
47729088Smarkm#endif
47829088Smarkm	localchars = 0;
47929088Smarkm    } else {
48029088Smarkm#ifdef	USE_TERMIO
48129088Smarkm	tmp_tc.c_lflag |= ISIG;
48229088Smarkm#endif
48329088Smarkm	localchars = 1;
48429088Smarkm    }
48529088Smarkm
48629088Smarkm    if (f&MODE_EDIT) {
48729088Smarkm#ifndef	USE_TERMIO
48829088Smarkm	sb.sg_flags &= ~CBREAK;
48929088Smarkm	sb.sg_flags |= CRMOD;
49029088Smarkm#else
49129088Smarkm	tmp_tc.c_lflag |= ICANON;
49229088Smarkm#endif
49329088Smarkm    } else {
49429088Smarkm#ifndef	USE_TERMIO
49529088Smarkm	sb.sg_flags |= CBREAK;
49629088Smarkm	if (f&MODE_ECHO)
49729088Smarkm	    sb.sg_flags |= CRMOD;
49829088Smarkm	else
49929088Smarkm	    sb.sg_flags &= ~CRMOD;
50029088Smarkm#else
50129088Smarkm	tmp_tc.c_lflag &= ~ICANON;
50229088Smarkm	tmp_tc.c_iflag &= ~ICRNL;
50329088Smarkm	tmp_tc.c_cc[VMIN] = 1;
50429088Smarkm	tmp_tc.c_cc[VTIME] = 0;
50529088Smarkm#endif
50629088Smarkm    }
50729088Smarkm
50829088Smarkm    if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
50929088Smarkm#ifndef	USE_TERMIO
51029088Smarkm	ltc.t_lnextc = _POSIX_VDISABLE;
51129088Smarkm#else
51229088Smarkm# ifdef VLNEXT
51329088Smarkm	tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
51429088Smarkm# endif
51529088Smarkm#endif
51629088Smarkm    }
51729088Smarkm
51829088Smarkm    if (f&MODE_SOFT_TAB) {
51929088Smarkm#ifndef USE_TERMIO
52029088Smarkm	sb.sg_flags |= XTABS;
52129088Smarkm#else
52229088Smarkm# ifdef	OXTABS
52329088Smarkm	tmp_tc.c_oflag |= OXTABS;
52429088Smarkm# endif
52529088Smarkm# ifdef	TABDLY
52629088Smarkm	tmp_tc.c_oflag &= ~TABDLY;
52729088Smarkm	tmp_tc.c_oflag |= TAB3;
52829088Smarkm# endif
52929088Smarkm#endif
53029088Smarkm    } else {
53129088Smarkm#ifndef USE_TERMIO
53229088Smarkm	sb.sg_flags &= ~XTABS;
53329088Smarkm#else
53429088Smarkm# ifdef	OXTABS
53529088Smarkm	tmp_tc.c_oflag &= ~OXTABS;
53629088Smarkm# endif
53729088Smarkm# ifdef	TABDLY
53829088Smarkm	tmp_tc.c_oflag &= ~TABDLY;
53929088Smarkm# endif
54029088Smarkm#endif
54129088Smarkm    }
54229088Smarkm
54329088Smarkm    if (f&MODE_LIT_ECHO) {
54429088Smarkm#ifndef USE_TERMIO
54529088Smarkm	lmode &= ~LCTLECH;
54629088Smarkm#else
54729088Smarkm# ifdef	ECHOCTL
54829088Smarkm	tmp_tc.c_lflag &= ~ECHOCTL;
54929088Smarkm# endif
55029088Smarkm#endif
55129088Smarkm    } else {
55229088Smarkm#ifndef USE_TERMIO
55329088Smarkm	lmode |= LCTLECH;
55429088Smarkm#else
55529088Smarkm# ifdef	ECHOCTL
55629088Smarkm	tmp_tc.c_lflag |= ECHOCTL;
55729088Smarkm# endif
55829088Smarkm#endif
55929088Smarkm    }
56029088Smarkm
56129088Smarkm    if (f == -1) {
56229088Smarkm	onoff = 0;
56329088Smarkm    } else {
56429088Smarkm#ifndef	USE_TERMIO
56529088Smarkm	if (f & MODE_OUTBIN)
56629088Smarkm		lmode |= LLITOUT;
56729088Smarkm	else
56829088Smarkm		lmode &= ~LLITOUT;
56929088Smarkm
57029088Smarkm	if (f & MODE_INBIN)
57129088Smarkm		lmode |= LPASS8;
57229088Smarkm	else
57329088Smarkm		lmode &= ~LPASS8;
57429088Smarkm#else
57529088Smarkm	if (f & MODE_INBIN)
57629088Smarkm		tmp_tc.c_iflag &= ~ISTRIP;
57729088Smarkm	else
57829088Smarkm		tmp_tc.c_iflag |= ISTRIP;
57929088Smarkm	if (f & MODE_OUTBIN) {
58029088Smarkm		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
58129088Smarkm		tmp_tc.c_cflag |= CS8;
58229088Smarkm		tmp_tc.c_oflag &= ~OPOST;
58329088Smarkm	} else {
58429088Smarkm		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
58529088Smarkm		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
58629088Smarkm		tmp_tc.c_oflag |= OPOST;
58729088Smarkm	}
58829088Smarkm#endif
58929088Smarkm	onoff = 1;
59029088Smarkm    }
59129088Smarkm
59229088Smarkm    if (f != -1) {
59375236Snsayer#ifdef  SIGINT
59475236Snsayer	(void) signal(SIGINT, intr);
59575236Snsayer#endif
59675236Snsayer#ifdef  SIGQUIT
59781965Smarkm	(void) signal(SIGQUIT, intr2);
59875236Snsayer#endif
59929088Smarkm#ifdef	SIGTSTP
60029088Smarkm	(void) signal(SIGTSTP, susp);
60129088Smarkm#endif	/* SIGTSTP */
60229088Smarkm#ifdef	SIGINFO
60329088Smarkm	(void) signal(SIGINFO, ayt);
60429088Smarkm#endif
60529088Smarkm#if	defined(USE_TERMIO) && defined(NOKERNINFO)
60629088Smarkm	tmp_tc.c_lflag |= NOKERNINFO;
60729088Smarkm#endif
60829088Smarkm	/*
60929088Smarkm	 * We don't want to process ^Y here.  It's just another
61029088Smarkm	 * character that we'll pass on to the back end.  It has
61129088Smarkm	 * to process it because it will be processed when the
61229088Smarkm	 * user attempts to read it, not when we send it.
61329088Smarkm	 */
61429088Smarkm#ifndef	USE_TERMIO
61529088Smarkm	ltc.t_dsuspc = _POSIX_VDISABLE;
61629088Smarkm#else
61729088Smarkm# ifdef	VDSUSP
61829088Smarkm	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
61929088Smarkm# endif
62029088Smarkm#endif
62129088Smarkm#ifdef	USE_TERMIO
62229088Smarkm	/*
62329088Smarkm	 * If the VEOL character is already set, then use VEOL2,
62429088Smarkm	 * otherwise use VEOL.
62529088Smarkm	 */
62629088Smarkm	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
62729088Smarkm	if ((tmp_tc.c_cc[VEOL] != esc)
62829088Smarkm# ifdef	VEOL2
62929088Smarkm	    && (tmp_tc.c_cc[VEOL2] != esc)
63029088Smarkm# endif
63129088Smarkm	    ) {
63229088Smarkm		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
63329088Smarkm		    tmp_tc.c_cc[VEOL] = esc;
63429088Smarkm# ifdef	VEOL2
63529088Smarkm		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
63629088Smarkm		    tmp_tc.c_cc[VEOL2] = esc;
63729088Smarkm# endif
63829088Smarkm	}
63929088Smarkm#else
64029088Smarkm	if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
64129088Smarkm		tc.t_brkc = esc;
64229088Smarkm#endif
64329088Smarkm    } else {
64429088Smarkm#ifdef	SIGINFO
64587139Smarkm	(void) signal(SIGINFO, (void (*)(int))ayt_status);
64629088Smarkm#endif
64775236Snsayer#ifdef  SIGINT
64875236Snsayer	(void) signal(SIGINT, SIG_DFL);
64975236Snsayer#endif
65075236Snsayer#ifdef  SIGQUIT
65175236Snsayer	(void) signal(SIGQUIT, SIG_DFL);
65275236Snsayer#endif
65329088Smarkm#ifdef	SIGTSTP
65429088Smarkm	(void) signal(SIGTSTP, SIG_DFL);
65529088Smarkm# ifndef SOLARIS
65629088Smarkm	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
65796385Salfred# else	/* SOLARIS */
65829088Smarkm	(void) sigrelse(SIGTSTP);
65996385Salfred# endif	/* SOLARIS */
66029088Smarkm#endif	/* SIGTSTP */
66129088Smarkm#ifndef USE_TERMIO
66229088Smarkm	ltc = oltc;
66329088Smarkm	tc = otc;
66429088Smarkm	sb = ottyb;
66529088Smarkm	lmode = olmode;
66629088Smarkm#else
66729088Smarkm	tmp_tc = old_tc;
66829088Smarkm#endif
66929088Smarkm    }
67029088Smarkm#ifndef USE_TERMIO
67129088Smarkm    ioctl(tin, TIOCLSET, (char *)&lmode);
67229088Smarkm    ioctl(tin, TIOCSLTC, (char *)&ltc);
67329088Smarkm    ioctl(tin, TIOCSETC, (char *)&tc);
67429088Smarkm    ioctl(tin, TIOCSETN, (char *)&sb);
67529088Smarkm#else
67629088Smarkm    if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
67729088Smarkm	tcsetattr(tin, TCSANOW, &tmp_tc);
67829088Smarkm#endif
67929088Smarkm
68029088Smarkm    ioctl(tin, FIONBIO, (char *)&onoff);
68129088Smarkm    ioctl(tout, FIONBIO, (char *)&onoff);
68229088Smarkm
68329088Smarkm}
68429088Smarkm
68529088Smarkm/*
68629088Smarkm * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
68729088Smarkm */
68829088Smarkm#if B4800 != 4800
68929088Smarkm#define	DECODE_BAUD
69029088Smarkm#endif
69129088Smarkm
69229088Smarkm#ifdef	DECODE_BAUD
69329088Smarkm#ifndef	B7200
69429088Smarkm#define B7200   B4800
69529088Smarkm#endif
69629088Smarkm
69729088Smarkm#ifndef	B14400
69829088Smarkm#define B14400  B9600
69929088Smarkm#endif
70029088Smarkm
70129088Smarkm#ifndef	B19200
70229088Smarkm# define B19200 B14400
70329088Smarkm#endif
70429088Smarkm
70529088Smarkm#ifndef	B28800
70629088Smarkm#define B28800  B19200
70729088Smarkm#endif
70829088Smarkm
70929088Smarkm#ifndef	B38400
71029088Smarkm# define B38400 B28800
71129088Smarkm#endif
71229088Smarkm
71329088Smarkm#ifndef B57600
71429088Smarkm#define B57600  B38400
71529088Smarkm#endif
71629088Smarkm
71729088Smarkm#ifndef B76800
71829088Smarkm#define B76800  B57600
71929088Smarkm#endif
72029088Smarkm
72129088Smarkm#ifndef B115200
72229088Smarkm#define B115200 B76800
72329088Smarkm#endif
72429088Smarkm
72529088Smarkm#ifndef B230400
72629088Smarkm#define B230400 B115200
72729088Smarkm#endif
72829088Smarkm
72929088Smarkm
73029088Smarkm/*
73129088Smarkm * This code assumes that the values B0, B50, B75...
73229088Smarkm * are in ascending order.  They do not have to be
73329088Smarkm * contiguous.
73429088Smarkm */
73529088Smarkmstruct termspeeds {
73629088Smarkm	long speed;
73729088Smarkm	long value;
73829088Smarkm} termspeeds[] = {
73929088Smarkm	{ 0,      B0 },      { 50,    B50 },    { 75,     B75 },
74029088Smarkm	{ 110,    B110 },    { 134,   B134 },   { 150,    B150 },
74129088Smarkm	{ 200,    B200 },    { 300,   B300 },   { 600,    B600 },
74229088Smarkm	{ 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
74329088Smarkm	{ 4800,   B4800 },   { 7200,  B7200 },  { 9600,   B9600 },
74429088Smarkm	{ 14400,  B14400 },  { 19200, B19200 }, { 28800,  B28800 },
74529088Smarkm	{ 38400,  B38400 },  { 57600, B57600 }, { 115200, B115200 },
74629088Smarkm	{ 230400, B230400 }, { -1,    B230400 }
74729088Smarkm};
74829088Smarkm#endif	/* DECODE_BAUD */
74929088Smarkm
75087139Smarkmvoid
75187139SmarkmTerminalSpeeds(long *ispeed, long *ospeed)
75229088Smarkm{
75329088Smarkm#ifdef	DECODE_BAUD
75487139Smarkm    struct termspeeds *tp;
75529088Smarkm#endif	/* DECODE_BAUD */
75687139Smarkm    long in, out;
75729088Smarkm
75829088Smarkm    out = cfgetospeed(&old_tc);
75929088Smarkm    in = cfgetispeed(&old_tc);
76029088Smarkm    if (in == 0)
76129088Smarkm	in = out;
76229088Smarkm
76329088Smarkm#ifdef	DECODE_BAUD
76429088Smarkm    tp = termspeeds;
76529088Smarkm    while ((tp->speed != -1) && (tp->value < in))
76629088Smarkm	tp++;
76729088Smarkm    *ispeed = tp->speed;
76829088Smarkm
76929088Smarkm    tp = termspeeds;
77029088Smarkm    while ((tp->speed != -1) && (tp->value < out))
77129088Smarkm	tp++;
77229088Smarkm    *ospeed = tp->speed;
77329088Smarkm#else	/* DECODE_BAUD */
77429088Smarkm	*ispeed = in;
77529088Smarkm	*ospeed = out;
77629088Smarkm#endif	/* DECODE_BAUD */
77729088Smarkm}
77829088Smarkm
77987139Smarkmint
78087139SmarkmTerminalWindowSize(long *rows, long *cols)
78129088Smarkm{
78229088Smarkm#ifdef	TIOCGWINSZ
78329088Smarkm    struct winsize ws;
78429088Smarkm
78529088Smarkm    if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
78629088Smarkm	*rows = ws.ws_row;
78729088Smarkm	*cols = ws.ws_col;
78829088Smarkm	return 1;
78929088Smarkm    }
79029088Smarkm#endif	/* TIOCGWINSZ */
79129088Smarkm    return 0;
79229088Smarkm}
79329088Smarkm
79487139Smarkmint
79587139SmarkmNetClose(int fd)
79629088Smarkm{
79729088Smarkm    return close(fd);
79829088Smarkm}
79929088Smarkm
80087139Smarkmstatic void
80187139SmarkmNetNonblockingIO(int fd, int onoff)
80229088Smarkm{
80329088Smarkm    ioctl(fd, FIONBIO, (char *)&onoff);
80429088Smarkm}
80529088Smarkm
80629088Smarkm
80729088Smarkm/*
80829088Smarkm * Various signal handling routines.
80929088Smarkm */
81029088Smarkm
81187139Smarkm/* ARGSUSED */
81287139SmarkmSIG_FUNC_RET
81387139Smarkmintr(int sig __unused)
81429088Smarkm{
81529088Smarkm    if (localchars) {
81629088Smarkm	intp();
81729088Smarkm	return;
81829088Smarkm    }
81929088Smarkm    setcommandmode();
82029088Smarkm    longjmp(toplevel, -1);
82129088Smarkm}
82229088Smarkm
82387139Smarkm/* ARGSUSED */
82487139SmarkmSIG_FUNC_RET
82587139Smarkmintr2(int sig __unused)
82629088Smarkm{
82729088Smarkm    if (localchars) {
82829088Smarkm#ifdef	KLUDGELINEMODE
82929088Smarkm	if (kludgelinemode)
83029088Smarkm	    sendbrk();
83129088Smarkm	else
83229088Smarkm#endif
83329088Smarkm	    sendabort();
83429088Smarkm	return;
83529088Smarkm    }
83629088Smarkm}
83729088Smarkm
83829088Smarkm#ifdef	SIGTSTP
83987139Smarkm/* ARGSUSED */
84087139SmarkmSIG_FUNC_RET
84187139Smarkmsusp(int sig __unused)
84229088Smarkm{
84329088Smarkm    if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
84429088Smarkm	return;
84529088Smarkm    if (localchars)
84629088Smarkm	sendsusp();
84729088Smarkm}
84829088Smarkm#endif
84929088Smarkm
85029088Smarkm#ifdef	SIGWINCH
85187139Smarkm/* ARGSUSED */
85287139Smarkmstatic SIG_FUNC_RET
85387139Smarkmsendwin(int sig __unused)
85429088Smarkm{
85529088Smarkm    if (connected) {
85629088Smarkm	sendnaws();
85729088Smarkm    }
85829088Smarkm}
85929088Smarkm#endif
86029088Smarkm
86129088Smarkm#ifdef	SIGINFO
86287139Smarkm/* ARGSUSED */
86387139SmarkmSIG_FUNC_RET
86487139Smarkmayt(int sig __unused)
86529088Smarkm{
86629088Smarkm    if (connected)
86729088Smarkm	sendayt();
86829088Smarkm    else
86929088Smarkm	ayt_status();
87029088Smarkm}
87129088Smarkm#endif
87229088Smarkm
87329088Smarkm
87487139Smarkmvoid
87587139Smarkmsys_telnet_init(void)
87629088Smarkm{
87729088Smarkm    (void) signal(SIGINT, intr);
87829088Smarkm    (void) signal(SIGQUIT, intr2);
879207449Sjilles    (void) signal(SIGPIPE, SIG_IGN);
88029088Smarkm#ifdef	SIGWINCH
88129088Smarkm    (void) signal(SIGWINCH, sendwin);
88229088Smarkm#endif
88329088Smarkm#ifdef	SIGTSTP
88429088Smarkm    (void) signal(SIGTSTP, susp);
88529088Smarkm#endif
88629088Smarkm#ifdef	SIGINFO
88729088Smarkm    (void) signal(SIGINFO, ayt);
88829088Smarkm#endif
88929088Smarkm
89029088Smarkm    setconnmode(0);
89129088Smarkm
89229088Smarkm    NetNonblockingIO(net, 1);
89329088Smarkm
89429088Smarkm#if	defined(SO_OOBINLINE)
89529088Smarkm    if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
89629088Smarkm	perror("SetSockOpt");
89729088Smarkm    }
89829088Smarkm#endif	/* defined(SO_OOBINLINE) */
89929088Smarkm}
90029088Smarkm
90129088Smarkm/*
90229088Smarkm * Process rings -
90329088Smarkm *
90429088Smarkm *	This routine tries to fill up/empty our various rings.
90529088Smarkm *
90629088Smarkm *	The parameter specifies whether this is a poll operation,
90729088Smarkm *	or a block-until-something-happens operation.
90829088Smarkm *
90929088Smarkm *	The return value is 1 if something happened, 0 if not.
91029088Smarkm */
91129088Smarkm
91287139Smarkmint
91387139Smarkmprocess_rings(int netin, int netout, int netex, int ttyin, int ttyout, int poll)
91429088Smarkm{
91587139Smarkm    int c;
91629088Smarkm    int returnValue = 0;
91787139Smarkm    static struct timeval TimeValue = { 0, 0 };
91887558Sjkh    int maxfd = -1;
91987558Sjkh    int tmp;
92029088Smarkm
92187558Sjkh    if ((netout || netin || netex) && net > maxfd)
92287558Sjkh	maxfd = net;
92387558Sjkh
92487558Sjkh    if (ttyout && tout > maxfd)
92587558Sjkh	maxfd = tout;
92687558Sjkh    if (ttyin && tin > maxfd)
92787558Sjkh	maxfd = tin;
92887558Sjkh    tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
92987558Sjkh    if (tmp > fdsn) {
93087558Sjkh	if (ibitsp)
93187558Sjkh	    free(ibitsp);
93287558Sjkh	if (obitsp)
93387558Sjkh	    free(obitsp);
93487558Sjkh	if (xbitsp)
93587558Sjkh	    free(xbitsp);
93687558Sjkh
93787558Sjkh	fdsn = tmp;
93887558Sjkh	if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL)
93987558Sjkh	    err(1, "malloc");
94087558Sjkh	if ((obitsp = (fd_set *)malloc(fdsn)) == NULL)
94187558Sjkh	    err(1, "malloc");
94287558Sjkh	if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL)
94387558Sjkh	    err(1, "malloc");
94487558Sjkh	memset(ibitsp, 0, fdsn);
94587558Sjkh	memset(obitsp, 0, fdsn);
94687558Sjkh	memset(xbitsp, 0, fdsn);
94729088Smarkm    }
94887558Sjkh
94987558Sjkh    if (netout)
95087558Sjkh	FD_SET(net, obitsp);
95187558Sjkh    if (ttyout)
95287558Sjkh	FD_SET(tout, obitsp);
95387558Sjkh    if (ttyin)
95487558Sjkh	FD_SET(tin, ibitsp);
95587558Sjkh    if (netin)
95687558Sjkh	FD_SET(net, ibitsp);
95787558Sjkh    if (netex)
95887558Sjkh	FD_SET(net, xbitsp);
95987558Sjkh    if ((c = select(maxfd + 1, ibitsp, obitsp, xbitsp,
96087558Sjkh	     (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
96129088Smarkm	if (c == -1) {
96229088Smarkm		    /*
96329088Smarkm		     * we can get EINTR if we are in line mode,
96429088Smarkm		     * and the user does an escape (TSTP), or
96529088Smarkm		     * some other signal generator.
96629088Smarkm		     */
96729088Smarkm	    if (errno == EINTR) {
96829088Smarkm		return 0;
96929088Smarkm	    }
97029088Smarkm		    /* I don't like this, does it ever happen? */
97129181Smarkm	    printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno));
97229088Smarkm	    sleep(5);
97329088Smarkm	}
97429088Smarkm	return 0;
97529088Smarkm    }
97629088Smarkm
97729088Smarkm    /*
97829088Smarkm     * Any urgent data?
97929088Smarkm     */
98087558Sjkh    if (FD_ISSET(net, xbitsp)) {
98187558Sjkh	FD_CLR(net, xbitsp);
98229088Smarkm	SYNCHing = 1;
98329088Smarkm	(void) ttyflush(1);	/* flush already enqueued data */
98429088Smarkm    }
98529088Smarkm
98629088Smarkm    /*
98729088Smarkm     * Something to read from the network...
98829088Smarkm     */
98987558Sjkh    if (FD_ISSET(net, ibitsp)) {
99029088Smarkm	int canread;
99129088Smarkm
99287558Sjkh	FD_CLR(net, ibitsp);
99329088Smarkm	canread = ring_empty_consecutive(&netiring);
99429088Smarkm#if	!defined(SO_OOBINLINE)
99529088Smarkm	    /*
99629088Smarkm	     * In 4.2 (and some early 4.3) systems, the
99729088Smarkm	     * OOB indication and data handling in the kernel
99829088Smarkm	     * is such that if two separate TCP Urgent requests
99929088Smarkm	     * come in, one byte of TCP data will be overlaid.
100029088Smarkm	     * This is fatal for Telnet, but we try to live
100129088Smarkm	     * with it.
100229088Smarkm	     *
100329088Smarkm	     * In addition, in 4.2 (and...), a special protocol
100429088Smarkm	     * is needed to pick up the TCP Urgent data in
100529088Smarkm	     * the correct sequence.
100629088Smarkm	     *
100729088Smarkm	     * What we do is:  if we think we are in urgent
100829088Smarkm	     * mode, we look to see if we are "at the mark".
100929088Smarkm	     * If we are, we do an OOB receive.  If we run
101029088Smarkm	     * this twice, we will do the OOB receive twice,
101129088Smarkm	     * but the second will fail, since the second
101229088Smarkm	     * time we were "at the mark", but there wasn't
101329088Smarkm	     * any data there (the kernel doesn't reset
101429088Smarkm	     * "at the mark" until we do a normal read).
101529088Smarkm	     * Once we've read the OOB data, we go ahead
101629088Smarkm	     * and do normal reads.
101729088Smarkm	     *
101829088Smarkm	     * There is also another problem, which is that
101929088Smarkm	     * since the OOB byte we read doesn't put us
102029088Smarkm	     * out of OOB state, and since that byte is most
102129088Smarkm	     * likely the TELNET DM (data mark), we would
102229088Smarkm	     * stay in the TELNET SYNCH (SYNCHing) state.
102329088Smarkm	     * So, clocks to the rescue.  If we've "just"
102429088Smarkm	     * received a DM, then we test for the
102529088Smarkm	     * presence of OOB data when the receive OOB
102629088Smarkm	     * fails (and AFTER we did the normal mode read
102729088Smarkm	     * to clear "at the mark").
102829088Smarkm	     */
102929088Smarkm	if (SYNCHing) {
103029088Smarkm	    int atmark;
103129088Smarkm	    static int bogus_oob = 0, first = 1;
103229088Smarkm
103329088Smarkm	    ioctl(net, SIOCATMARK, (char *)&atmark);
103429088Smarkm	    if (atmark) {
103529088Smarkm		c = recv(net, netiring.supply, canread, MSG_OOB);
103629088Smarkm		if ((c == -1) && (errno == EINVAL)) {
103729088Smarkm		    c = recv(net, netiring.supply, canread, 0);
103829088Smarkm		    if (clocks.didnetreceive < clocks.gotDM) {
103929088Smarkm			SYNCHing = stilloob(net);
104029088Smarkm		    }
104129088Smarkm		} else if (first && c > 0) {
104229088Smarkm		    /*
104329088Smarkm		     * Bogosity check.  Systems based on 4.2BSD
104429088Smarkm		     * do not return an error if you do a second
104529088Smarkm		     * recv(MSG_OOB).  So, we do one.  If it
104629088Smarkm		     * succeeds and returns exactly the same
104729088Smarkm		     * data, then assume that we are running
104829088Smarkm		     * on a broken system and set the bogus_oob
104929088Smarkm		     * flag.  (If the data was different, then
105029088Smarkm		     * we probably got some valid new data, so
105129088Smarkm		     * increment the count...)
105229088Smarkm		     */
105329088Smarkm		    int i;
105429088Smarkm		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
105529088Smarkm		    if (i == c &&
105681965Smarkm			memcmp(netiring.supply, netiring.supply + c, i) == 0) {
105729088Smarkm			bogus_oob = 1;
105829088Smarkm			first = 0;
105929088Smarkm		    } else if (i < 0) {
106029088Smarkm			bogus_oob = 0;
106129088Smarkm			first = 0;
106229088Smarkm		    } else
106329088Smarkm			c += i;
106429088Smarkm		}
106529088Smarkm		if (bogus_oob && c > 0) {
106629088Smarkm		    int i;
106729088Smarkm		    /*
106829088Smarkm		     * Bogosity.  We have to do the read
106929088Smarkm		     * to clear the atmark to get out of
107029088Smarkm		     * an infinate loop.
107129088Smarkm		     */
107229088Smarkm		    i = read(net, netiring.supply + c, canread - c);
107329088Smarkm		    if (i > 0)
107429088Smarkm			c += i;
107529088Smarkm		}
107629088Smarkm	    } else {
107729088Smarkm		c = recv(net, netiring.supply, canread, 0);
107829088Smarkm	    }
107929088Smarkm	} else {
108029088Smarkm	    c = recv(net, netiring.supply, canread, 0);
108129088Smarkm	}
108229088Smarkm	settimer(didnetreceive);
108329088Smarkm#else	/* !defined(SO_OOBINLINE) */
108429088Smarkm	c = recv(net, (char *)netiring.supply, canread, 0);
108529088Smarkm#endif	/* !defined(SO_OOBINLINE) */
108629088Smarkm	if (c < 0 && errno == EWOULDBLOCK) {
108729088Smarkm	    c = 0;
108829088Smarkm	} else if (c <= 0) {
108929088Smarkm	    return -1;
109029088Smarkm	}
109129088Smarkm	if (netdata) {
109229088Smarkm	    Dump('<', netiring.supply, c);
109329088Smarkm	}
109429088Smarkm	if (c)
109529088Smarkm	    ring_supplied(&netiring, c);
109629088Smarkm	returnValue = 1;
109729088Smarkm    }
109829088Smarkm
109929088Smarkm    /*
110029088Smarkm     * Something to read from the tty...
110129088Smarkm     */
110287558Sjkh    if (FD_ISSET(tin, ibitsp)) {
110387558Sjkh	FD_CLR(tin, ibitsp);
110429088Smarkm	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
110529088Smarkm	if (c < 0 && errno == EIO)
110629088Smarkm	    c = 0;
110729088Smarkm	if (c < 0 && errno == EWOULDBLOCK) {
110829088Smarkm	    c = 0;
110929088Smarkm	} else {
111029088Smarkm	    /* EOF detection for line mode!!!! */
111129088Smarkm	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
111229088Smarkm			/* must be an EOF... */
111329088Smarkm		*ttyiring.supply = termEofChar;
111429088Smarkm		c = 1;
111529088Smarkm	    }
111629088Smarkm	    if (c <= 0) {
111729088Smarkm		return -1;
111829088Smarkm	    }
111929088Smarkm	    if (termdata) {
112029088Smarkm		Dump('<', ttyiring.supply, c);
112129088Smarkm	    }
112229088Smarkm	    ring_supplied(&ttyiring, c);
112329088Smarkm	}
112429088Smarkm	returnValue = 1;		/* did something useful */
112529088Smarkm    }
112629088Smarkm
112787558Sjkh    if (FD_ISSET(net, obitsp)) {
112887558Sjkh	FD_CLR(net, obitsp);
112929088Smarkm	returnValue |= netflush();
113029088Smarkm    }
113187558Sjkh    if (FD_ISSET(tout, obitsp)) {
113287558Sjkh	FD_CLR(tout, obitsp);
113329088Smarkm	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
113429088Smarkm    }
113529088Smarkm
113629088Smarkm    return returnValue;
113729088Smarkm}
1138