xref: /csrg-svn/usr.bin/telnet/sys_bsd.c (revision 38208)
132147Sminshall /*
233685Sbostic  * Copyright (c) 1988 Regents of the University of California.
333685Sbostic  * All rights reserved.
433685Sbostic  *
533685Sbostic  * Redistribution and use in source and binary forms are permitted
634898Sbostic  * provided that the above copyright notice and this paragraph are
734898Sbostic  * duplicated in all such forms and that any documentation,
834898Sbostic  * advertising materials, and other materials related to such
934898Sbostic  * distribution and use acknowledge that the software was developed
1034898Sbostic  * by the University of California, Berkeley.  The name of the
1134898Sbostic  * University may not be used to endorse or promote products derived
1234898Sbostic  * from this software without specific prior written permission.
1334898Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434898Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534898Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633685Sbostic  */
1733685Sbostic 
1833685Sbostic #ifndef lint
19*38208Sminshall static char sccsid[] = "@(#)sys_bsd.c	1.18 (Berkeley) 05/30/89";
2033685Sbostic #endif /* not lint */
2133685Sbostic 
2233685Sbostic /*
2332147Sminshall  * The following routines try to encapsulate what is system dependent
2432147Sminshall  * (at least between 4.x and dos) which is used in telnet.c.
2532147Sminshall  */
2632147Sminshall 
2732147Sminshall #if	defined(unix)
2832147Sminshall 
2936274Sminshall #include <fcntl.h>
3032147Sminshall #include <sys/ioctl.h>
3132381Sminshall #include <sys/types.h>
3232147Sminshall #include <sys/time.h>
3332531Sminshall #include <sys/socket.h>
3432147Sminshall #include <signal.h>
3532531Sminshall #include <errno.h>
3632147Sminshall 
3732381Sminshall #include "ring.h"
3832381Sminshall 
3932657Sminshall #include "fdset.h"
4032657Sminshall 
4132147Sminshall #include "defines.h"
4232147Sminshall #include "externs.h"
4332147Sminshall #include "types.h"
4432147Sminshall 
4532147Sminshall int
4632531Sminshall 	tout,			/* Output file descriptor */
4732531Sminshall 	tin,			/* Input file descriptor */
4836242Sminshall 	net;
4932147Sminshall 
5032147Sminshall static struct	tchars otc = { 0 }, ntc = { 0 };
5132147Sminshall static struct	ltchars oltc = { 0 }, nltc = { 0 };
5232147Sminshall static struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
5332147Sminshall 
5432531Sminshall static fd_set ibits, obits, xbits;
5532147Sminshall 
5632531Sminshall 
5732531Sminshall init_sys()
5832531Sminshall {
5932531Sminshall     tout = fileno(stdout);
6032531Sminshall     tin = fileno(stdin);
6132531Sminshall     FD_ZERO(&ibits);
6232531Sminshall     FD_ZERO(&obits);
6332531Sminshall     FD_ZERO(&xbits);
6432531Sminshall 
6532531Sminshall     errno = 0;
6632531Sminshall }
6732531Sminshall 
6832531Sminshall 
6933286Sminshall TerminalWrite(buf, n)
7032147Sminshall char	*buf;
7132147Sminshall int	n;
7232147Sminshall {
7333286Sminshall     return write(tout, buf, n);
7432147Sminshall }
7532147Sminshall 
7633286Sminshall TerminalRead(buf, n)
7732147Sminshall char	*buf;
7832147Sminshall int	n;
7932147Sminshall {
8033286Sminshall     return read(tin, buf, n);
8132147Sminshall }
8232147Sminshall 
8332147Sminshall /*
8432147Sminshall  *
8532147Sminshall  */
8632147Sminshall 
8732147Sminshall int
8832553Sminshall TerminalAutoFlush()
8932147Sminshall {
9032147Sminshall #if	defined(LNOFLSH)
9132147Sminshall     int flush;
9232147Sminshall 
9332147Sminshall     ioctl(0, TIOCLGET, (char *)&flush);
9432147Sminshall     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
9532147Sminshall #else	/* LNOFLSH */
9632147Sminshall     return 1;
9732147Sminshall #endif	/* LNOFLSH */
9832147Sminshall }
9932147Sminshall 
10032147Sminshall /*
10132147Sminshall  * TerminalSpecialChars()
10232147Sminshall  *
10332147Sminshall  * Look at an input character to see if it is a special character
10432147Sminshall  * and decide what to do.
10532147Sminshall  *
10632147Sminshall  * Output:
10732147Sminshall  *
10832147Sminshall  *	0	Don't add this character.
10932147Sminshall  *	1	Do add this character
11032147Sminshall  */
11132147Sminshall 
11232147Sminshall int
11332553Sminshall TerminalSpecialChars(c)
11432147Sminshall int	c;
11532147Sminshall {
11632553Sminshall     void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
11732147Sminshall 
11832147Sminshall     if (c == ntc.t_intrc) {
11932147Sminshall 	intp();
12032147Sminshall 	return 0;
12132147Sminshall     } else if (c == ntc.t_quitc) {
12232147Sminshall 	sendbrk();
12332147Sminshall 	return 0;
12432147Sminshall     } else if (c == nltc.t_flushc) {
12532147Sminshall 	xmitAO();		/* Transmit Abort Output */
12632147Sminshall 	return 0;
12732147Sminshall     } else if (!MODE_LOCAL_CHARS(globalmode)) {
12832147Sminshall 	if (c == nttyb.sg_kill) {
12932147Sminshall 	    xmitEL();
13032147Sminshall 	    return 0;
13132147Sminshall 	} else if (c == nttyb.sg_erase) {
13232147Sminshall 	    xmitEC();		/* Transmit Erase Character */
13332147Sminshall 	    return 0;
13432147Sminshall 	}
13532147Sminshall     }
13632147Sminshall     return 1;
13732147Sminshall }
13832147Sminshall 
13932147Sminshall 
14032147Sminshall /*
14132147Sminshall  * Flush output to the terminal
14232147Sminshall  */
14332147Sminshall 
14432147Sminshall void
14532553Sminshall TerminalFlushOutput()
14632147Sminshall {
14732147Sminshall     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
14832147Sminshall }
14932147Sminshall 
15032147Sminshall void
15132553Sminshall TerminalSaveState()
15232147Sminshall {
15332147Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
15432147Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
15532147Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
15632147Sminshall 
15732147Sminshall     ntc = otc;
15832147Sminshall     nltc = oltc;
15932147Sminshall     nttyb = ottyb;
16032254Sminshall 
16132254Sminshall     termEofChar = ntc.t_eofc;
16232254Sminshall     termEraseChar = nttyb.sg_erase;
16332254Sminshall     termFlushChar = nltc.t_flushc;
16432254Sminshall     termIntChar = ntc.t_intrc;
16532254Sminshall     termKillChar = nttyb.sg_kill;
16632254Sminshall     termQuitChar = ntc.t_quitc;
16732147Sminshall }
16832147Sminshall 
16932147Sminshall void
17032553Sminshall TerminalRestoreState()
17132147Sminshall {
17232147Sminshall }
17332147Sminshall 
17432147Sminshall /*
17532147Sminshall  * TerminalNewMode - set up terminal to a specific mode.
17632147Sminshall  */
17732147Sminshall 
17832147Sminshall 
17932147Sminshall void
18033286Sminshall TerminalNewMode(f)
18132147Sminshall register int f;
18232147Sminshall {
18332147Sminshall     static int prevmode = 0;
18432147Sminshall     struct tchars *tc;
18532147Sminshall     struct tchars tc3;
18632147Sminshall     struct ltchars *ltc;
18732147Sminshall     struct sgttyb sb;
18832147Sminshall     int onoff;
18932147Sminshall     int old;
19032147Sminshall     struct	tchars notc2;
19132147Sminshall     struct	ltchars noltc2;
19232147Sminshall     static struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
19332147Sminshall     static struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
19432147Sminshall 
19532147Sminshall     globalmode = f;
19632147Sminshall     if (prevmode == f)
19732147Sminshall 	return;
19832147Sminshall     old = prevmode;
19932147Sminshall     prevmode = f;
20032147Sminshall     sb = nttyb;
20132147Sminshall 
20232147Sminshall     switch (f) {
20332147Sminshall 
20432147Sminshall     case 0:
20532147Sminshall 	onoff = 0;
20632147Sminshall 	tc = &otc;
20732147Sminshall 	ltc = &oltc;
20832147Sminshall 	break;
20932147Sminshall 
21032147Sminshall     case 1:		/* remote character processing, remote echo */
21132147Sminshall     case 2:		/* remote character processing, local echo */
21232147Sminshall     case 6:		/* 3270 mode - like 1, but with xon/xoff local */
21332147Sminshall 		    /* (might be nice to have "6" in telnet also...) */
21432147Sminshall 	    sb.sg_flags |= CBREAK;
21532147Sminshall 	    if ((f == 1) || (f == 6)) {
21632147Sminshall 		sb.sg_flags &= ~(ECHO|CRMOD);
21732147Sminshall 	    } else {
21832147Sminshall 		sb.sg_flags |= ECHO|CRMOD;
21932147Sminshall 	    }
22032147Sminshall 	    sb.sg_erase = sb.sg_kill = -1;
22137219Sminshall 	    if (localflow || (f == 6)) {
22232147Sminshall 		tc = &tc3;
22332147Sminshall 		tc3 = notc;
22432147Sminshall 		    /* get XON, XOFF characters */
22532147Sminshall 		tc3.t_startc = otc.t_startc;
22632147Sminshall 		tc3.t_stopc = otc.t_stopc;
22732147Sminshall 	    } else {
22832147Sminshall 		/*
22932147Sminshall 		 * If user hasn't specified one way or the other,
23032147Sminshall 		 * then default to not trapping signals.
23132147Sminshall 		 */
23232147Sminshall 		if (!donelclchars) {
23332147Sminshall 		    localchars = 0;
23432147Sminshall 		}
23532147Sminshall 		if (localchars) {
23632147Sminshall 		    notc2 = notc;
23732147Sminshall 		    notc2.t_intrc = ntc.t_intrc;
23832147Sminshall 		    notc2.t_quitc = ntc.t_quitc;
23932147Sminshall 		    tc = &notc2;
24032147Sminshall 		} else {
24132147Sminshall 		    tc = &notc;
24232147Sminshall 		}
24332147Sminshall 	    }
24432147Sminshall 	    ltc = &noltc;
24532147Sminshall 	    onoff = 1;
24632147Sminshall 	    break;
24732147Sminshall     case 3:		/* local character processing, remote echo */
24832147Sminshall     case 4:		/* local character processing, local echo */
24932147Sminshall     case 5:		/* local character processing, no echo */
25032147Sminshall 	    sb.sg_flags &= ~CBREAK;
25132147Sminshall 	    sb.sg_flags |= CRMOD;
25232147Sminshall 	    if (f == 4)
25332147Sminshall 		sb.sg_flags |= ECHO;
25432147Sminshall 	    else
25532147Sminshall 		sb.sg_flags &= ~ECHO;
25632147Sminshall 	    notc2 = ntc;
25732147Sminshall 	    tc = &notc2;
25832147Sminshall 	    noltc2 = oltc;
25932147Sminshall 	    ltc = &noltc2;
26032147Sminshall 	    /*
26132147Sminshall 	     * If user hasn't specified one way or the other,
26232147Sminshall 	     * then default to trapping signals.
26332147Sminshall 	     */
26432147Sminshall 	    if (!donelclchars) {
26532147Sminshall 		localchars = 1;
26632147Sminshall 	    }
26732147Sminshall 	    if (localchars) {
26832147Sminshall 		notc2.t_brkc = nltc.t_flushc;
26932147Sminshall 		noltc2.t_flushc = -1;
27032147Sminshall 	    } else {
27132147Sminshall 		notc2.t_intrc = notc2.t_quitc = -1;
27232147Sminshall 	    }
27332147Sminshall 	    noltc2.t_suspc = escape;
27432147Sminshall 	    noltc2.t_dsuspc = -1;
27532147Sminshall 	    onoff = 1;
27632147Sminshall 	    break;
27732147Sminshall 
27832147Sminshall     default:
27932147Sminshall 	    return;
28032147Sminshall     }
28133286Sminshall     ioctl(tin, TIOCSLTC, (char *)ltc);
28233286Sminshall     ioctl(tin, TIOCSETC, (char *)tc);
28333286Sminshall     ioctl(tin, TIOCSETP, (char *)&sb);
28432147Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
28533286Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
28633286Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
28732147Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
28832147Sminshall #if	defined(TN3270)
28936242Sminshall     if (noasynchtty == 0) {
29033286Sminshall 	ioctl(tin, FIOASYNC, (char *)&onoff);
29132147Sminshall     }
29232147Sminshall #endif	/* defined(TN3270) */
29332147Sminshall 
29432147Sminshall     if (MODE_LINE(f)) {
29532147Sminshall 	void doescape();
29632147Sminshall 
29734849Sminshall 	(void) signal(SIGTSTP, (int (*)())doescape);
29832147Sminshall     } else if (MODE_LINE(old)) {
29934849Sminshall 	(void) signal(SIGTSTP, SIG_DFL);
30032147Sminshall 	sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
30132147Sminshall     }
30232147Sminshall }
30332147Sminshall 
30437219Sminshall void
30537219Sminshall TerminalSpeeds(ispeed, ospeed)
30637219Sminshall long *ispeed;
30737219Sminshall long *ospeed;
30837219Sminshall {
30937219Sminshall     /*
31037219Sminshall      * The order here is important.  The index of each speed needs to
31137219Sminshall      * correspond with the sgtty structure value for that speed.
31237219Sminshall      *
31337219Sminshall      * Additionally, the search algorithm assumes the table is in
31437219Sminshall      * ascending sequence.
31537219Sminshall      */
31637219Sminshall     static int ttyspeeds[] = {
31737219Sminshall 	    0, 50, 75, 110, 134, 150, 200, 300,
31837219Sminshall 	    600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 };
31937219Sminshall #define NUMSPEEDS sizeof ttyspeeds/sizeof ttyspeeds[0]
32032147Sminshall 
32137219Sminshall     if ((ottyb.sg_ospeed < 0) || (ottyb.sg_ospeed > NUMSPEEDS) ||
32237219Sminshall 	(ottyb.sg_ispeed < 0) || (ottyb.sg_ispeed > NUMSPEEDS)) {
32337219Sminshall 	ExitString("Invalid terminal speed.");
32437219Sminshall 	/*NOTREACHED*/
32537219Sminshall     } else {
32637219Sminshall 	*ispeed = ttyspeeds[ottyb.sg_ispeed];
32737219Sminshall 	*ospeed = ttyspeeds[ottyb.sg_ospeed];
32837219Sminshall     }
32937219Sminshall }
33037219Sminshall 
33132147Sminshall int
33237219Sminshall TerminalWindowSize(rows, cols)
33337219Sminshall long *rows, *cols;
33437219Sminshall {
33537219Sminshall     struct winsize ws;
33637219Sminshall 
33737219Sminshall     if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) < 0) {
33837219Sminshall 	return 0;
33937219Sminshall     }
34037219Sminshall     *rows = ws.ws_row;
34137219Sminshall     *cols = ws.ws_col;
34237219Sminshall     return 1;
34337219Sminshall }
34437219Sminshall 
34537219Sminshall int
34635417Sminshall NetClose(fd)
34735417Sminshall int	fd;
34832147Sminshall {
34935417Sminshall     return close(fd);
35032147Sminshall }
35132147Sminshall 
35232147Sminshall 
35332147Sminshall void
35432553Sminshall NetNonblockingIO(fd, onoff)
35532147Sminshall int
35632147Sminshall 	fd,
35732147Sminshall 	onoff;
35832147Sminshall {
35932147Sminshall     ioctl(fd, FIONBIO, (char *)&onoff);
36032147Sminshall }
36132147Sminshall 
36234849Sminshall #if	defined(TN3270)
36332147Sminshall void
36432553Sminshall NetSigIO(fd, onoff)
36532147Sminshall int
36632147Sminshall 	fd,
36732147Sminshall 	onoff;
36832147Sminshall {
36932147Sminshall     ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
37032147Sminshall }
37132147Sminshall 
37232147Sminshall void
37332553Sminshall NetSetPgrp(fd)
37432147Sminshall int fd;
37532147Sminshall {
37632147Sminshall     int myPid;
37732147Sminshall 
37832147Sminshall     myPid = getpid();
37936274Sminshall     fcntl(fd, F_SETOWN, myPid);
38032147Sminshall }
38134849Sminshall #endif	/*defined(TN3270)*/
38232553Sminshall 
38332553Sminshall /*
38432553Sminshall  * Various signal handling routines.
38532553Sminshall  */
38632147Sminshall 
38733286Sminshall static void
38832553Sminshall deadpeer()
38932553Sminshall {
39032553Sminshall 	setcommandmode();
39132553Sminshall 	longjmp(peerdied, -1);
39232553Sminshall }
39332147Sminshall 
39433286Sminshall static void
39532553Sminshall intr()
39632553Sminshall {
39732553Sminshall     if (localchars) {
39832553Sminshall 	intp();
39932553Sminshall 	return;
40032553Sminshall     }
40132553Sminshall     setcommandmode();
40232553Sminshall     longjmp(toplevel, -1);
40332553Sminshall }
40432553Sminshall 
40533286Sminshall static void
40632553Sminshall intr2()
40732553Sminshall {
40832553Sminshall     if (localchars) {
40932553Sminshall 	sendbrk();
41032553Sminshall 	return;
41132553Sminshall     }
41232553Sminshall }
41332553Sminshall 
41433286Sminshall static void
41537219Sminshall sendwin()
41637219Sminshall {
41737219Sminshall     if (connected) {
41837219Sminshall 	sendnaws();
41937219Sminshall     }
42037219Sminshall }
42137219Sminshall 
42237219Sminshall static void
42332553Sminshall doescape()
42432553Sminshall {
42532553Sminshall     command(0);
42632553Sminshall }
42732553Sminshall 
42832553Sminshall void
42932531Sminshall sys_telnet_init()
43032531Sminshall {
43134849Sminshall     (void) signal(SIGINT, (int (*)())intr);
43234849Sminshall     (void) signal(SIGQUIT, (int (*)())intr2);
43334849Sminshall     (void) signal(SIGPIPE, (int (*)())deadpeer);
43437219Sminshall     (void) signal(SIGWINCH, (int (*)())sendwin);
43532553Sminshall 
43632531Sminshall     setconnmode();
43732531Sminshall 
43832531Sminshall     NetNonblockingIO(net, 1);
43932531Sminshall 
44032531Sminshall #if	defined(TN3270)
44136242Sminshall     if (noasynchnet == 0) {			/* DBX can't handle! */
44232531Sminshall 	NetSigIO(net, 1);
44332531Sminshall 	NetSetPgrp(net);
44432531Sminshall     }
44532531Sminshall #endif	/* defined(TN3270) */
44632531Sminshall 
44732531Sminshall #if	defined(SO_OOBINLINE)
44834849Sminshall     if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
44934849Sminshall 	perror("SetSockOpt");
45034849Sminshall     }
45132531Sminshall #endif	/* defined(SO_OOBINLINE) */
45232531Sminshall }
45332531Sminshall 
45432531Sminshall /*
45532531Sminshall  * Process rings -
45632531Sminshall  *
45732531Sminshall  *	This routine tries to fill up/empty our various rings.
45832531Sminshall  *
45932531Sminshall  *	The parameter specifies whether this is a poll operation,
46032531Sminshall  *	or a block-until-something-happens operation.
46132531Sminshall  *
46232531Sminshall  *	The return value is 1 if something happened, 0 if not.
46332531Sminshall  */
46432531Sminshall 
46532531Sminshall int
46632531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll)
46732531Sminshall int poll;		/* If 0, then block until something to do */
46832531Sminshall {
46932531Sminshall     register int c;
47032531Sminshall 		/* One wants to be a bit careful about setting returnValue
47132531Sminshall 		 * to one, since a one implies we did some useful work,
47232531Sminshall 		 * and therefore probably won't be called to block next
47332531Sminshall 		 * time (TN3270 mode only).
47432531Sminshall 		 */
47532531Sminshall     int returnValue = 0;
47632531Sminshall     static struct timeval TimeValue = { 0 };
47732531Sminshall 
47832531Sminshall     if (netout) {
47932531Sminshall 	FD_SET(net, &obits);
48032531Sminshall     }
48132531Sminshall     if (ttyout) {
48232531Sminshall 	FD_SET(tout, &obits);
48332531Sminshall     }
48432531Sminshall #if	defined(TN3270)
48532531Sminshall     if (ttyin) {
48632531Sminshall 	FD_SET(tin, &ibits);
48732531Sminshall     }
48832531Sminshall #else	/* defined(TN3270) */
48932531Sminshall     if (ttyin) {
49032531Sminshall 	FD_SET(tin, &ibits);
49132531Sminshall     }
49232531Sminshall #endif	/* defined(TN3270) */
49332531Sminshall #if	defined(TN3270)
49432531Sminshall     if (netin) {
49532531Sminshall 	FD_SET(net, &ibits);
49632531Sminshall     }
49732531Sminshall #   else /* !defined(TN3270) */
49832531Sminshall     if (netin) {
49932531Sminshall 	FD_SET(net, &ibits);
50032531Sminshall     }
50132531Sminshall #   endif /* !defined(TN3270) */
50232531Sminshall     if (netex) {
50332531Sminshall 	FD_SET(net, &xbits);
50432531Sminshall     }
50532531Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
50632531Sminshall 			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
50732531Sminshall 	if (c == -1) {
50832531Sminshall 		    /*
50932531Sminshall 		     * we can get EINTR if we are in line mode,
51032531Sminshall 		     * and the user does an escape (TSTP), or
51132531Sminshall 		     * some other signal generator.
51232531Sminshall 		     */
51332531Sminshall 	    if (errno == EINTR) {
51432531Sminshall 		return 0;
51532531Sminshall 	    }
51632531Sminshall #	    if defined(TN3270)
51732531Sminshall 		    /*
51832531Sminshall 		     * we can get EBADF if we were in transparent
51932531Sminshall 		     * mode, and the transcom process died.
52032531Sminshall 		    */
52132531Sminshall 	    if (errno == EBADF) {
52232531Sminshall 			/*
52332531Sminshall 			 * zero the bits (even though kernel does it)
52432531Sminshall 			 * to make sure we are selecting on the right
52532531Sminshall 			 * ones.
52632531Sminshall 			*/
52732531Sminshall 		FD_ZERO(&ibits);
52832531Sminshall 		FD_ZERO(&obits);
52932531Sminshall 		FD_ZERO(&xbits);
53032531Sminshall 		return 0;
53132531Sminshall 	    }
53232531Sminshall #	    endif /* defined(TN3270) */
53332531Sminshall 		    /* I don't like this, does it ever happen? */
53432531Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
53532531Sminshall 	    sleep(5);
53632531Sminshall 	}
53732531Sminshall 	return 0;
53832531Sminshall     }
53932531Sminshall 
54032531Sminshall     /*
54132531Sminshall      * Any urgent data?
54232531Sminshall      */
54332531Sminshall     if (FD_ISSET(net, &xbits)) {
54432531Sminshall 	FD_CLR(net, &xbits);
54532531Sminshall 	SYNCHing = 1;
54632531Sminshall 	ttyflush(1);	/* flush already enqueued data */
54732531Sminshall     }
54832531Sminshall 
54932531Sminshall     /*
55032531Sminshall      * Something to read from the network...
55132531Sminshall      */
55232531Sminshall     if (FD_ISSET(net, &ibits)) {
55332531Sminshall 	int canread;
55432531Sminshall 
55532531Sminshall 	FD_CLR(net, &ibits);
55632531Sminshall 	canread = ring_empty_consecutive(&netiring);
55732531Sminshall #if	!defined(SO_OOBINLINE)
55832531Sminshall 	    /*
55932531Sminshall 	     * In 4.2 (and some early 4.3) systems, the
56032531Sminshall 	     * OOB indication and data handling in the kernel
56132531Sminshall 	     * is such that if two separate TCP Urgent requests
56232531Sminshall 	     * come in, one byte of TCP data will be overlaid.
56332531Sminshall 	     * This is fatal for Telnet, but we try to live
56432531Sminshall 	     * with it.
56532531Sminshall 	     *
56632531Sminshall 	     * In addition, in 4.2 (and...), a special protocol
56732531Sminshall 	     * is needed to pick up the TCP Urgent data in
56832531Sminshall 	     * the correct sequence.
56932531Sminshall 	     *
57032531Sminshall 	     * What we do is:  if we think we are in urgent
57132531Sminshall 	     * mode, we look to see if we are "at the mark".
57232531Sminshall 	     * If we are, we do an OOB receive.  If we run
57332531Sminshall 	     * this twice, we will do the OOB receive twice,
57432531Sminshall 	     * but the second will fail, since the second
57532531Sminshall 	     * time we were "at the mark", but there wasn't
57632531Sminshall 	     * any data there (the kernel doesn't reset
57732531Sminshall 	     * "at the mark" until we do a normal read).
57832531Sminshall 	     * Once we've read the OOB data, we go ahead
57932531Sminshall 	     * and do normal reads.
58032531Sminshall 	     *
58132531Sminshall 	     * There is also another problem, which is that
58232531Sminshall 	     * since the OOB byte we read doesn't put us
58332531Sminshall 	     * out of OOB state, and since that byte is most
58432531Sminshall 	     * likely the TELNET DM (data mark), we would
58532531Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
58632531Sminshall 	     * So, clocks to the rescue.  If we've "just"
58732531Sminshall 	     * received a DM, then we test for the
58832531Sminshall 	     * presence of OOB data when the receive OOB
58932531Sminshall 	     * fails (and AFTER we did the normal mode read
59032531Sminshall 	     * to clear "at the mark").
59132531Sminshall 	     */
59232531Sminshall 	if (SYNCHing) {
59332531Sminshall 	    int atmark;
59432531Sminshall 
59532531Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
59632531Sminshall 	    if (atmark) {
59732531Sminshall 		c = recv(net, netiring.supply, canread, MSG_OOB);
59832531Sminshall 		if ((c == -1) && (errno == EINVAL)) {
59932531Sminshall 		    c = recv(net, netiring.supply, canread, 0);
60032531Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
60132531Sminshall 			SYNCHing = stilloob(net);
60232531Sminshall 		    }
60332531Sminshall 		}
60432531Sminshall 	    } else {
60532531Sminshall 		c = recv(net, netiring.supply, canread, 0);
60632531Sminshall 	    }
60732531Sminshall 	} else {
60832531Sminshall 	    c = recv(net, netiring.supply, canread, 0);
60932531Sminshall 	}
61032531Sminshall 	settimer(didnetreceive);
61132531Sminshall #else	/* !defined(SO_OOBINLINE) */
61232531Sminshall 	c = recv(net, netiring.supply, canread, 0);
61332531Sminshall #endif	/* !defined(SO_OOBINLINE) */
61432531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
61532531Sminshall 	    c = 0;
61632531Sminshall 	} else if (c <= 0) {
61732531Sminshall 	    return -1;
61832531Sminshall 	}
61932531Sminshall 	if (netdata) {
62032531Sminshall 	    Dump('<', netiring.supply, c);
62132531Sminshall 	}
62232667Sminshall 	if (c)
62332667Sminshall 	    ring_supplied(&netiring, c);
62432531Sminshall 	returnValue = 1;
62532531Sminshall     }
62632531Sminshall 
62732531Sminshall     /*
62832531Sminshall      * Something to read from the tty...
62932531Sminshall      */
63032531Sminshall     if (FD_ISSET(tin, &ibits)) {
63132531Sminshall 	FD_CLR(tin, &ibits);
63233286Sminshall 	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
63332531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
63432531Sminshall 	    c = 0;
63532531Sminshall 	} else {
63632531Sminshall 	    /* EOF detection for line mode!!!! */
63733281Sminshall 	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
63832531Sminshall 			/* must be an EOF... */
63932531Sminshall 		*ttyiring.supply = termEofChar;
64032531Sminshall 		c = 1;
64132531Sminshall 	    }
64232531Sminshall 	    if (c <= 0) {
64332531Sminshall 		return -1;
64432531Sminshall 	    }
645*38208Sminshall 	    if (termdata) {
646*38208Sminshall 		Dump('<', ttyiring.supply, c);
647*38208Sminshall 	    }
64832667Sminshall 	    ring_supplied(&ttyiring, c);
64932531Sminshall 	}
65032531Sminshall 	returnValue = 1;		/* did something useful */
65132531Sminshall     }
65232531Sminshall 
65332531Sminshall     if (FD_ISSET(net, &obits)) {
65432531Sminshall 	FD_CLR(net, &obits);
65532531Sminshall 	returnValue |= netflush();
65632531Sminshall     }
65732531Sminshall     if (FD_ISSET(tout, &obits)) {
65832531Sminshall 	FD_CLR(tout, &obits);
65932531Sminshall 	returnValue |= ttyflush(SYNCHing|flushout);
66032531Sminshall     }
66132531Sminshall 
66232531Sminshall     return returnValue;
66332531Sminshall }
66432531Sminshall #endif	/* defined(unix) */
665