xref: /csrg-svn/usr.bin/telnet/sys_bsd.c (revision 32657)
132147Sminshall /*
232147Sminshall  * The following routines try to encapsulate what is system dependent
332147Sminshall  * (at least between 4.x and dos) which is used in telnet.c.
432147Sminshall  */
532147Sminshall 
632147Sminshall #if	defined(unix)
732147Sminshall 
832147Sminshall #include <sys/ioctl.h>
932381Sminshall #include <sys/types.h>
1032147Sminshall #include <sys/time.h>
1132531Sminshall #include <sys/socket.h>
1232147Sminshall #include <signal.h>
1332531Sminshall #include <errno.h>
1432147Sminshall 
1532381Sminshall #include "ring.h"
1632381Sminshall 
17*32657Sminshall #include "fdset.h"
18*32657Sminshall 
1932147Sminshall #include "defines.h"
2032147Sminshall #include "externs.h"
2132147Sminshall #include "types.h"
2232147Sminshall 
2332147Sminshall int
2432531Sminshall 	tout,			/* Output file descriptor */
2532531Sminshall 	tin,			/* Input file descriptor */
2632531Sminshall 	net,
2732147Sminshall 	HaveInput;		/* There is input available to scan */
2832147Sminshall 
2932147Sminshall #if	defined(TN3270)
3032147Sminshall static char	tline[200];
3132147Sminshall char	*transcom = 0;	/* transparent mode command (default: none) */
3232147Sminshall #endif	/* defined(TN3270) */
3332147Sminshall 
3432147Sminshall static struct	tchars otc = { 0 }, ntc = { 0 };
3532147Sminshall static struct	ltchars oltc = { 0 }, nltc = { 0 };
3632147Sminshall static struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
3732147Sminshall 
3832531Sminshall static fd_set ibits, obits, xbits;
3932147Sminshall 
4032531Sminshall 
4132531Sminshall init_sys()
4232531Sminshall {
4332531Sminshall     tout = fileno(stdout);
4432531Sminshall     tin = fileno(stdin);
4532531Sminshall     FD_ZERO(&ibits);
4632531Sminshall     FD_ZERO(&obits);
4732531Sminshall     FD_ZERO(&xbits);
4832531Sminshall 
4932531Sminshall     errno = 0;
5032531Sminshall }
5132531Sminshall 
5232531Sminshall 
5332147Sminshall TerminalWrite(fd, buf, n)
5432147Sminshall int	fd;
5532147Sminshall char	*buf;
5632147Sminshall int	n;
5732147Sminshall {
5832147Sminshall     return write(fd, buf, n);
5932147Sminshall }
6032147Sminshall 
6132147Sminshall TerminalRead(fd, buf, n)
6232147Sminshall int	fd;
6332147Sminshall char	*buf;
6432147Sminshall int	n;
6532147Sminshall {
6632147Sminshall     return read(fd, buf, n);
6732147Sminshall }
6832147Sminshall 
6932147Sminshall /*
7032147Sminshall  *
7132147Sminshall  */
7232147Sminshall 
7332147Sminshall int
7432553Sminshall TerminalAutoFlush()
7532147Sminshall {
7632147Sminshall #if	defined(LNOFLSH)
7732147Sminshall     int flush;
7832147Sminshall 
7932147Sminshall     ioctl(0, TIOCLGET, (char *)&flush);
8032147Sminshall     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
8132147Sminshall #else	/* LNOFLSH */
8232147Sminshall     return 1;
8332147Sminshall #endif	/* LNOFLSH */
8432147Sminshall }
8532147Sminshall 
8632147Sminshall /*
8732147Sminshall  * TerminalSpecialChars()
8832147Sminshall  *
8932147Sminshall  * Look at an input character to see if it is a special character
9032147Sminshall  * and decide what to do.
9132147Sminshall  *
9232147Sminshall  * Output:
9332147Sminshall  *
9432147Sminshall  *	0	Don't add this character.
9532147Sminshall  *	1	Do add this character
9632147Sminshall  */
9732147Sminshall 
9832147Sminshall int
9932553Sminshall TerminalSpecialChars(c)
10032147Sminshall int	c;
10132147Sminshall {
10232553Sminshall     void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
10332147Sminshall 
10432147Sminshall     if (c == ntc.t_intrc) {
10532147Sminshall 	intp();
10632147Sminshall 	return 0;
10732147Sminshall     } else if (c == ntc.t_quitc) {
10832147Sminshall 	sendbrk();
10932147Sminshall 	return 0;
11032147Sminshall     } else if (c == nltc.t_flushc) {
11132147Sminshall 	xmitAO();		/* Transmit Abort Output */
11232147Sminshall 	return 0;
11332147Sminshall     } else if (!MODE_LOCAL_CHARS(globalmode)) {
11432147Sminshall 	if (c == nttyb.sg_kill) {
11532147Sminshall 	    xmitEL();
11632147Sminshall 	    return 0;
11732147Sminshall 	} else if (c == nttyb.sg_erase) {
11832147Sminshall 	    xmitEC();		/* Transmit Erase Character */
11932147Sminshall 	    return 0;
12032147Sminshall 	}
12132147Sminshall     }
12232147Sminshall     return 1;
12332147Sminshall }
12432147Sminshall 
12532147Sminshall 
12632147Sminshall /*
12732147Sminshall  * Flush output to the terminal
12832147Sminshall  */
12932147Sminshall 
13032147Sminshall void
13132553Sminshall TerminalFlushOutput()
13232147Sminshall {
13332147Sminshall     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
13432147Sminshall }
13532147Sminshall 
13632147Sminshall void
13732553Sminshall TerminalSaveState()
13832147Sminshall {
13932147Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
14032147Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
14132147Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
14232147Sminshall 
14332147Sminshall     ntc = otc;
14432147Sminshall     nltc = oltc;
14532147Sminshall     nttyb = ottyb;
14632254Sminshall 
14732254Sminshall     termEofChar = ntc.t_eofc;
14832254Sminshall     termEraseChar = nttyb.sg_erase;
14932254Sminshall     termFlushChar = nltc.t_flushc;
15032254Sminshall     termIntChar = ntc.t_intrc;
15132254Sminshall     termKillChar = nttyb.sg_kill;
15232254Sminshall     termQuitChar = ntc.t_quitc;
15332147Sminshall }
15432147Sminshall 
15532147Sminshall void
15632553Sminshall TerminalRestoreState()
15732147Sminshall {
15832147Sminshall }
15932147Sminshall 
16032147Sminshall /*
16132147Sminshall  * TerminalNewMode - set up terminal to a specific mode.
16232147Sminshall  */
16332147Sminshall 
16432147Sminshall 
16532147Sminshall void
16632553Sminshall TerminalNewMode(fd_in, fd_out, f)
16732147Sminshall int	fd_in, fd_out;		/* File descriptor */
16832147Sminshall register int f;
16932147Sminshall {
17032147Sminshall     static int prevmode = 0;
17132147Sminshall     struct tchars *tc;
17232147Sminshall     struct tchars tc3;
17332147Sminshall     struct ltchars *ltc;
17432147Sminshall     struct sgttyb sb;
17532147Sminshall     int onoff;
17632147Sminshall     int old;
17732147Sminshall     struct	tchars notc2;
17832147Sminshall     struct	ltchars noltc2;
17932147Sminshall     static struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
18032147Sminshall     static struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
18132147Sminshall 
18232147Sminshall     globalmode = f;
18332147Sminshall     if (prevmode == f)
18432147Sminshall 	return;
18532147Sminshall     old = prevmode;
18632147Sminshall     prevmode = f;
18732147Sminshall     sb = nttyb;
18832147Sminshall 
18932147Sminshall     switch (f) {
19032147Sminshall 
19132147Sminshall     case 0:
19232147Sminshall 	onoff = 0;
19332147Sminshall 	tc = &otc;
19432147Sminshall 	ltc = &oltc;
19532147Sminshall 	break;
19632147Sminshall 
19732147Sminshall     case 1:		/* remote character processing, remote echo */
19832147Sminshall     case 2:		/* remote character processing, local echo */
19932147Sminshall     case 6:		/* 3270 mode - like 1, but with xon/xoff local */
20032147Sminshall 		    /* (might be nice to have "6" in telnet also...) */
20132147Sminshall 	    sb.sg_flags |= CBREAK;
20232147Sminshall 	    if ((f == 1) || (f == 6)) {
20332147Sminshall 		sb.sg_flags &= ~(ECHO|CRMOD);
20432147Sminshall 	    } else {
20532147Sminshall 		sb.sg_flags |= ECHO|CRMOD;
20632147Sminshall 	    }
20732147Sminshall 	    sb.sg_erase = sb.sg_kill = -1;
20832147Sminshall 	    if (f == 6) {
20932147Sminshall 		tc = &tc3;
21032147Sminshall 		tc3 = notc;
21132147Sminshall 		    /* get XON, XOFF characters */
21232147Sminshall 		tc3.t_startc = otc.t_startc;
21332147Sminshall 		tc3.t_stopc = otc.t_stopc;
21432147Sminshall 	    } else {
21532147Sminshall 		/*
21632147Sminshall 		 * If user hasn't specified one way or the other,
21732147Sminshall 		 * then default to not trapping signals.
21832147Sminshall 		 */
21932147Sminshall 		if (!donelclchars) {
22032147Sminshall 		    localchars = 0;
22132147Sminshall 		}
22232147Sminshall 		if (localchars) {
22332147Sminshall 		    notc2 = notc;
22432147Sminshall 		    notc2.t_intrc = ntc.t_intrc;
22532147Sminshall 		    notc2.t_quitc = ntc.t_quitc;
22632147Sminshall 		    tc = &notc2;
22732147Sminshall 		} else {
22832147Sminshall 		    tc = &notc;
22932147Sminshall 		}
23032147Sminshall 	    }
23132147Sminshall 	    ltc = &noltc;
23232147Sminshall 	    onoff = 1;
23332147Sminshall 	    break;
23432147Sminshall     case 3:		/* local character processing, remote echo */
23532147Sminshall     case 4:		/* local character processing, local echo */
23632147Sminshall     case 5:		/* local character processing, no echo */
23732147Sminshall 	    sb.sg_flags &= ~CBREAK;
23832147Sminshall 	    sb.sg_flags |= CRMOD;
23932147Sminshall 	    if (f == 4)
24032147Sminshall 		sb.sg_flags |= ECHO;
24132147Sminshall 	    else
24232147Sminshall 		sb.sg_flags &= ~ECHO;
24332147Sminshall 	    notc2 = ntc;
24432147Sminshall 	    tc = &notc2;
24532147Sminshall 	    noltc2 = oltc;
24632147Sminshall 	    ltc = &noltc2;
24732147Sminshall 	    /*
24832147Sminshall 	     * If user hasn't specified one way or the other,
24932147Sminshall 	     * then default to trapping signals.
25032147Sminshall 	     */
25132147Sminshall 	    if (!donelclchars) {
25232147Sminshall 		localchars = 1;
25332147Sminshall 	    }
25432147Sminshall 	    if (localchars) {
25532147Sminshall 		notc2.t_brkc = nltc.t_flushc;
25632147Sminshall 		noltc2.t_flushc = -1;
25732147Sminshall 	    } else {
25832147Sminshall 		notc2.t_intrc = notc2.t_quitc = -1;
25932147Sminshall 	    }
26032147Sminshall 	    noltc2.t_suspc = escape;
26132147Sminshall 	    noltc2.t_dsuspc = -1;
26232147Sminshall 	    onoff = 1;
26332147Sminshall 	    break;
26432147Sminshall 
26532147Sminshall     default:
26632147Sminshall 	    return;
26732147Sminshall     }
26832147Sminshall     ioctl(fd_in, TIOCSLTC, (char *)ltc);
26932147Sminshall     ioctl(fd_in, TIOCSETC, (char *)tc);
27032147Sminshall     ioctl(fd_in, TIOCSETP, (char *)&sb);
27132147Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
27232147Sminshall     ioctl(fd_in, FIONBIO, (char *)&onoff);
27332147Sminshall     ioctl(fd_out, FIONBIO, (char *)&onoff);
27432147Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
27532147Sminshall #if	defined(TN3270)
27632147Sminshall     if (noasynch == 0) {
27732147Sminshall 	ioctl(fd_in, FIOASYNC, (char *)&onoff);
27832147Sminshall     }
27932147Sminshall #endif	/* defined(TN3270) */
28032147Sminshall 
28132147Sminshall     if (MODE_LINE(f)) {
28232147Sminshall 	void doescape();
28332147Sminshall 
28432147Sminshall 	signal(SIGTSTP, doescape);
28532147Sminshall     } else if (MODE_LINE(old)) {
28632147Sminshall 	signal(SIGTSTP, SIG_DFL);
28732147Sminshall 	sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
28832147Sminshall     }
28932147Sminshall }
29032147Sminshall 
29132147Sminshall 
29232147Sminshall int
29332147Sminshall NetClose(net)
29432147Sminshall int	net;
29532147Sminshall {
29632147Sminshall     return close(net);
29732147Sminshall }
29832147Sminshall 
29932147Sminshall 
30032147Sminshall void
30132553Sminshall NetNonblockingIO(fd, onoff)
30232147Sminshall int
30332147Sminshall 	fd,
30432147Sminshall 	onoff;
30532147Sminshall {
30632147Sminshall     ioctl(fd, FIONBIO, (char *)&onoff);
30732147Sminshall }
30832147Sminshall 
30932147Sminshall void
31032553Sminshall NetSigIO(fd, onoff)
31132147Sminshall int
31232147Sminshall 	fd,
31332147Sminshall 	onoff;
31432147Sminshall {
31532147Sminshall     ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
31632147Sminshall }
31732147Sminshall 
31832147Sminshall void
31932553Sminshall NetSetPgrp(fd)
32032147Sminshall int fd;
32132147Sminshall {
32232147Sminshall     int myPid;
32332147Sminshall 
32432147Sminshall     myPid = getpid();
32532147Sminshall #if	defined(NOT43)
32632147Sminshall     myPid = -myPid;
32732147Sminshall #endif	/* defined(NOT43) */
32832147Sminshall     ioctl(fd, SIOCSPGRP, (char *)&myPid);	/* set my pid */
32932147Sminshall }
33032553Sminshall 
33132553Sminshall /*
33232553Sminshall  * Various signal handling routines.
33332553Sminshall  */
33432147Sminshall 
33532553Sminshall void
33632553Sminshall deadpeer()
33732553Sminshall {
33832553Sminshall 	setcommandmode();
33932553Sminshall 	longjmp(peerdied, -1);
34032553Sminshall }
34132147Sminshall 
34232531Sminshall void
34332553Sminshall intr()
34432553Sminshall {
34532553Sminshall     if (localchars) {
34632553Sminshall 	intp();
34732553Sminshall 	return;
34832553Sminshall     }
34932553Sminshall     setcommandmode();
35032553Sminshall     longjmp(toplevel, -1);
35132553Sminshall }
35232553Sminshall 
35332553Sminshall void
35432553Sminshall intr2()
35532553Sminshall {
35632553Sminshall     if (localchars) {
35732553Sminshall 	sendbrk();
35832553Sminshall 	return;
35932553Sminshall     }
36032553Sminshall }
36132553Sminshall 
36232553Sminshall void
36332553Sminshall doescape()
36432553Sminshall {
36532553Sminshall     command(0);
36632553Sminshall }
36732553Sminshall 
36832553Sminshall void
36932531Sminshall sys_telnet_init()
37032531Sminshall {
37132553Sminshall #if	defined(TN3270)
37232531Sminshall     int myPid;
37332531Sminshall #endif	/* defined(TN3270) */
37432531Sminshall 
37532553Sminshall     signal(SIGINT, intr);
37632553Sminshall     signal(SIGQUIT, intr2);
37732553Sminshall     signal(SIGPIPE, deadpeer);
37832553Sminshall 
37932531Sminshall     setconnmode();
38032531Sminshall 
38132531Sminshall     NetNonblockingIO(net, 1);
38232531Sminshall 
38332531Sminshall #if	defined(TN3270)
38432531Sminshall     if (noasynch == 0) {			/* DBX can't handle! */
38532531Sminshall 	NetSigIO(net, 1);
38632531Sminshall 	NetSetPgrp(net);
38732531Sminshall     }
38832531Sminshall #endif	/* defined(TN3270) */
38932531Sminshall 
39032531Sminshall #if	defined(SO_OOBINLINE)
39132531Sminshall     SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
39232531Sminshall #endif	/* defined(SO_OOBINLINE) */
39332531Sminshall }
39432531Sminshall 
39532531Sminshall /*
39632531Sminshall  * Process rings -
39732531Sminshall  *
39832531Sminshall  *	This routine tries to fill up/empty our various rings.
39932531Sminshall  *
40032531Sminshall  *	The parameter specifies whether this is a poll operation,
40132531Sminshall  *	or a block-until-something-happens operation.
40232531Sminshall  *
40332531Sminshall  *	The return value is 1 if something happened, 0 if not.
40432531Sminshall  */
40532531Sminshall 
40632531Sminshall int
40732531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll)
40832531Sminshall int poll;		/* If 0, then block until something to do */
40932531Sminshall {
41032531Sminshall     register int c;
41132531Sminshall 		/* One wants to be a bit careful about setting returnValue
41232531Sminshall 		 * to one, since a one implies we did some useful work,
41332531Sminshall 		 * and therefore probably won't be called to block next
41432531Sminshall 		 * time (TN3270 mode only).
41532531Sminshall 		 */
41632531Sminshall     int returnValue = 0;
41732531Sminshall     static struct timeval TimeValue = { 0 };
41832531Sminshall 
41932531Sminshall     if (netout) {
42032531Sminshall 	FD_SET(net, &obits);
42132531Sminshall     }
42232531Sminshall     if (ttyout) {
42332531Sminshall 	FD_SET(tout, &obits);
42432531Sminshall     }
42532531Sminshall #if	defined(TN3270)
42632531Sminshall     if (ttyin) {
42732531Sminshall 	FD_SET(tin, &ibits);
42832531Sminshall     }
42932531Sminshall #else	/* defined(TN3270) */
43032531Sminshall     if (ttyin) {
43132531Sminshall 	FD_SET(tin, &ibits);
43232531Sminshall     }
43332531Sminshall #endif	/* defined(TN3270) */
43432531Sminshall #if	defined(TN3270)
43532531Sminshall     if (netin) {
43632531Sminshall 	FD_SET(net, &ibits);
43732531Sminshall     }
43832531Sminshall #   else /* !defined(TN3270) */
43932531Sminshall     if (netin) {
44032531Sminshall 	FD_SET(net, &ibits);
44132531Sminshall     }
44232531Sminshall #   endif /* !defined(TN3270) */
44332531Sminshall     if (netex) {
44432531Sminshall 	FD_SET(net, &xbits);
44532531Sminshall     }
44632531Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
44732531Sminshall 			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
44832531Sminshall 	if (c == -1) {
44932531Sminshall 		    /*
45032531Sminshall 		     * we can get EINTR if we are in line mode,
45132531Sminshall 		     * and the user does an escape (TSTP), or
45232531Sminshall 		     * some other signal generator.
45332531Sminshall 		     */
45432531Sminshall 	    if (errno == EINTR) {
45532531Sminshall 		return 0;
45632531Sminshall 	    }
45732531Sminshall #	    if defined(TN3270)
45832531Sminshall 		    /*
45932531Sminshall 		     * we can get EBADF if we were in transparent
46032531Sminshall 		     * mode, and the transcom process died.
46132531Sminshall 		    */
46232531Sminshall 	    if (errno == EBADF) {
46332531Sminshall 			/*
46432531Sminshall 			 * zero the bits (even though kernel does it)
46532531Sminshall 			 * to make sure we are selecting on the right
46632531Sminshall 			 * ones.
46732531Sminshall 			*/
46832531Sminshall 		FD_ZERO(&ibits);
46932531Sminshall 		FD_ZERO(&obits);
47032531Sminshall 		FD_ZERO(&xbits);
47132531Sminshall 		return 0;
47232531Sminshall 	    }
47332531Sminshall #	    endif /* defined(TN3270) */
47432531Sminshall 		    /* I don't like this, does it ever happen? */
47532531Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
47632531Sminshall 	    sleep(5);
47732531Sminshall 	}
47832531Sminshall 	return 0;
47932531Sminshall     }
48032531Sminshall 
48132531Sminshall     /*
48232531Sminshall      * Any urgent data?
48332531Sminshall      */
48432531Sminshall     if (FD_ISSET(net, &xbits)) {
48532531Sminshall 	FD_CLR(net, &xbits);
48632531Sminshall 	SYNCHing = 1;
48732531Sminshall 	ttyflush(1);	/* flush already enqueued data */
48832531Sminshall     }
48932531Sminshall 
49032531Sminshall     /*
49132531Sminshall      * Something to read from the network...
49232531Sminshall      */
49332531Sminshall     if (FD_ISSET(net, &ibits)) {
49432531Sminshall 	int canread;
49532531Sminshall 
49632531Sminshall 	FD_CLR(net, &ibits);
49732531Sminshall 	canread = ring_empty_consecutive(&netiring);
49832531Sminshall #if	!defined(SO_OOBINLINE)
49932531Sminshall 	    /*
50032531Sminshall 	     * In 4.2 (and some early 4.3) systems, the
50132531Sminshall 	     * OOB indication and data handling in the kernel
50232531Sminshall 	     * is such that if two separate TCP Urgent requests
50332531Sminshall 	     * come in, one byte of TCP data will be overlaid.
50432531Sminshall 	     * This is fatal for Telnet, but we try to live
50532531Sminshall 	     * with it.
50632531Sminshall 	     *
50732531Sminshall 	     * In addition, in 4.2 (and...), a special protocol
50832531Sminshall 	     * is needed to pick up the TCP Urgent data in
50932531Sminshall 	     * the correct sequence.
51032531Sminshall 	     *
51132531Sminshall 	     * What we do is:  if we think we are in urgent
51232531Sminshall 	     * mode, we look to see if we are "at the mark".
51332531Sminshall 	     * If we are, we do an OOB receive.  If we run
51432531Sminshall 	     * this twice, we will do the OOB receive twice,
51532531Sminshall 	     * but the second will fail, since the second
51632531Sminshall 	     * time we were "at the mark", but there wasn't
51732531Sminshall 	     * any data there (the kernel doesn't reset
51832531Sminshall 	     * "at the mark" until we do a normal read).
51932531Sminshall 	     * Once we've read the OOB data, we go ahead
52032531Sminshall 	     * and do normal reads.
52132531Sminshall 	     *
52232531Sminshall 	     * There is also another problem, which is that
52332531Sminshall 	     * since the OOB byte we read doesn't put us
52432531Sminshall 	     * out of OOB state, and since that byte is most
52532531Sminshall 	     * likely the TELNET DM (data mark), we would
52632531Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
52732531Sminshall 	     * So, clocks to the rescue.  If we've "just"
52832531Sminshall 	     * received a DM, then we test for the
52932531Sminshall 	     * presence of OOB data when the receive OOB
53032531Sminshall 	     * fails (and AFTER we did the normal mode read
53132531Sminshall 	     * to clear "at the mark").
53232531Sminshall 	     */
53332531Sminshall 	if (SYNCHing) {
53432531Sminshall 	    int atmark;
53532531Sminshall 
53632531Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
53732531Sminshall 	    if (atmark) {
53832531Sminshall 		c = recv(net, netiring.supply, canread, MSG_OOB);
53932531Sminshall 		if ((c == -1) && (errno == EINVAL)) {
54032531Sminshall 		    c = recv(net, netiring.supply, canread, 0);
54132531Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
54232531Sminshall 			SYNCHing = stilloob(net);
54332531Sminshall 		    }
54432531Sminshall 		}
54532531Sminshall 	    } else {
54632531Sminshall 		c = recv(net, netiring.supply, canread, 0);
54732531Sminshall 	    }
54832531Sminshall 	} else {
54932531Sminshall 	    c = recv(net, netiring.supply, canread, 0);
55032531Sminshall 	}
55132531Sminshall 	settimer(didnetreceive);
55232531Sminshall #else	/* !defined(SO_OOBINLINE) */
55332531Sminshall 	c = recv(net, netiring.supply, canread, 0);
55432531Sminshall #endif	/* !defined(SO_OOBINLINE) */
55532531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
55632531Sminshall 	    c = 0;
55732531Sminshall 	} else if (c <= 0) {
55832531Sminshall 	    return -1;
55932531Sminshall 	}
56032531Sminshall 	if (netdata) {
56132531Sminshall 	    Dump('<', netiring.supply, c);
56232531Sminshall 	}
56332531Sminshall 	ring_supplied(&netiring, c);
56432531Sminshall 	returnValue = 1;
56532531Sminshall     }
56632531Sminshall 
56732531Sminshall     /*
56832531Sminshall      * Something to read from the tty...
56932531Sminshall      */
57032531Sminshall     if (FD_ISSET(tin, &ibits)) {
57132531Sminshall 	FD_CLR(tin, &ibits);
57232531Sminshall 	c = TerminalRead(tin, ttyiring.supply,
57332531Sminshall 			ring_empty_consecutive(&ttyiring));
57432531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
57532531Sminshall 	    c = 0;
57632531Sminshall 	} else {
57732531Sminshall 	    /* EOF detection for line mode!!!! */
57832531Sminshall 	    if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
57932531Sminshall 			/* must be an EOF... */
58032531Sminshall 		*ttyiring.supply = termEofChar;
58132531Sminshall 		c = 1;
58232531Sminshall 	    }
58332531Sminshall 	    if (c <= 0) {
58432531Sminshall 		return -1;
58532531Sminshall 	    }
58632531Sminshall 	}
58732531Sminshall 	ring_supplied(&ttyiring, c);
58832531Sminshall 	returnValue = 1;		/* did something useful */
58932531Sminshall     }
59032531Sminshall 
59132531Sminshall     if (FD_ISSET(net, &obits)) {
59232531Sminshall 	FD_CLR(net, &obits);
59332531Sminshall 	returnValue |= netflush();
59432531Sminshall     }
59532531Sminshall     if (FD_ISSET(tout, &obits)) {
59632531Sminshall 	FD_CLR(tout, &obits);
59732531Sminshall 	returnValue |= ttyflush(SYNCHing|flushout);
59832531Sminshall     }
59932531Sminshall 
60032531Sminshall     return returnValue;
60132531Sminshall }
60232531Sminshall #endif	/* defined(unix) */
603