Home | History | Annotate | Line # | Download | only in telnet
sys_bsd.c revision 1.25
      1 /*	$NetBSD: sys_bsd.c,v 1.25 2003/07/14 15:56:29 itojun Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988, 1990, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 #if 0
     39 from: static char sccsid[] = "@(#)sys_bsd.c	8.4 (Berkeley) 5/30/95";
     40 #else
     41 __RCSID("$NetBSD: sys_bsd.c,v 1.25 2003/07/14 15:56:29 itojun Exp $");
     42 #endif
     43 #endif /* not lint */
     44 
     45 /*
     46  * The following routines try to encapsulate what is system dependent
     47  * (at least between 4.x and dos) which is used in telnet.c.
     48  */
     49 
     50 
     51 #include <fcntl.h>
     52 #include <sys/types.h>
     53 #include <sys/time.h>
     54 #include <sys/socket.h>
     55 #include <signal.h>
     56 #include <stdlib.h>
     57 #include <unistd.h>
     58 #include <errno.h>
     59 #include <poll.h>
     60 #include <arpa/telnet.h>
     61 
     62 #include "ring.h"
     63 
     64 #include "fdset.h"
     65 
     66 #include "defines.h"
     67 #include "externs.h"
     68 #include "types.h"
     69 
     70 #define	SIG_FUNC_RET	void
     71 
     72 SIG_FUNC_RET susp(int);
     73 SIG_FUNC_RET ayt(int);
     74 
     75 SIG_FUNC_RET intr(int);
     76 SIG_FUNC_RET intr2(int);
     77 SIG_FUNC_RET sendwin(int);
     78 SIG_FUNC_RET deadpeer(int);
     79 
     80 
     81 int
     82 	tout,			/* Output file descriptor */
     83 	tin,			/* Input file descriptor */
     84 	net;
     85 
     86 struct	termios old_tc = { 0 };
     87 extern struct termios new_tc;
     88 
     89 # ifndef	TCSANOW
     90 #  ifdef TCSETS
     91 #   define	TCSANOW		TCSETS
     92 #   define	TCSADRAIN	TCSETSW
     93 #   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
     94 #  else
     95 #   ifdef TCSETA
     96 #    define	TCSANOW		TCSETA
     97 #    define	TCSADRAIN	TCSETAW
     98 #    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
     99 #   else
    100 #    define	TCSANOW		TIOCSETA
    101 #    define	TCSADRAIN	TIOCSETAW
    102 #    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
    103 #   endif
    104 #  endif
    105 #  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
    106 #  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
    107 #  ifdef CIBAUD
    108 #   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
    109 #  else
    110 #   define	cfgetispeed(ptr)	cfgetospeed(ptr)
    111 #  endif
    112 # endif /* TCSANOW */
    113 
    114 
    115 void
    116 init_sys(void)
    117 {
    118     tout = fileno(stdout);
    119     tin = fileno(stdin);
    120 
    121     errno = 0;
    122 }
    123 
    124 
    125 int
    126 TerminalWrite(char *buf, int  n)
    127 {
    128     return write(tout, buf, n);
    129 }
    130 
    131 int
    132 TerminalRead(unsigned char *buf, int  n)
    133 {
    134     return read(tin, buf, n);
    135 }
    136 
    137 /*
    138  *
    139  */
    140 
    141 int
    142 TerminalAutoFlush(void)
    143 {
    144 #ifdef LNOFLSH
    145     int flush;
    146 
    147     ioctl(0, TIOCLGET, (char *)&flush);
    148     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
    149 #else	/* LNOFLSH */
    150     return 1;
    151 #endif	/* LNOFLSH */
    152 }
    153 
    154 #ifdef	KLUDGELINEMODE
    155 extern int kludgelinemode;
    156 #endif
    157 /*
    158  * TerminalSpecialChars()
    159  *
    160  * Look at an input character to see if it is a special character
    161  * and decide what to do.
    162  *
    163  * Output:
    164  *
    165  *	0	Don't add this character.
    166  *	1	Do add this character
    167  */
    168 
    169 int
    170 TerminalSpecialChars(int c)
    171 {
    172     if (c == termIntChar) {
    173 	intp();
    174 	return 0;
    175     } else if (c == termQuitChar) {
    176 #ifdef	KLUDGELINEMODE
    177 	if (kludgelinemode)
    178 	    sendbrk();
    179 	else
    180 #endif
    181 	    sendabort();
    182 	return 0;
    183     } else if (c == termEofChar) {
    184 	if (my_want_state_is_will(TELOPT_LINEMODE)) {
    185 	    sendeof();
    186 	    return 0;
    187 	}
    188 	return 1;
    189     } else if (c == termSuspChar) {
    190 	sendsusp();
    191 	return(0);
    192     } else if (c == termFlushChar) {
    193 	xmitAO();		/* Transmit Abort Output */
    194 	return 0;
    195     } else if (!MODE_LOCAL_CHARS(globalmode)) {
    196 	if (c == termKillChar) {
    197 	    xmitEL();
    198 	    return 0;
    199 	} else if (c == termEraseChar) {
    200 	    xmitEC();		/* Transmit Erase Character */
    201 	    return 0;
    202 	}
    203     }
    204     return 1;
    205 }
    206 
    207 
    208 /*
    209  * Flush output to the terminal
    210  */
    211 
    212 void
    213 TerminalFlushOutput(void)
    214 {
    215     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
    216 }
    217 
    218 void
    219 TerminalSaveState(void)
    220 {
    221     tcgetattr(0, &old_tc);
    222 
    223     new_tc = old_tc;
    224 }
    225 
    226 cc_t *
    227 tcval(int func)
    228 {
    229     switch(func) {
    230     case SLC_IP:	return(&termIntChar);
    231     case SLC_ABORT:	return(&termQuitChar);
    232     case SLC_EOF:	return(&termEofChar);
    233     case SLC_EC:	return(&termEraseChar);
    234     case SLC_EL:	return(&termKillChar);
    235     case SLC_XON:	return(&termStartChar);
    236     case SLC_XOFF:	return(&termStopChar);
    237     case SLC_FORW1:	return(&termForw1Char);
    238     case SLC_FORW2:	return(&termForw2Char);
    239 # ifdef	VDISCARD
    240     case SLC_AO:	return(&termFlushChar);
    241 # endif
    242 # ifdef	VSUSP
    243     case SLC_SUSP:	return(&termSuspChar);
    244 # endif
    245 # ifdef	VWERASE
    246     case SLC_EW:	return(&termWerasChar);
    247 # endif
    248 # ifdef	VREPRINT
    249     case SLC_RP:	return(&termRprntChar);
    250 # endif
    251 # ifdef	VLNEXT
    252     case SLC_LNEXT:	return(&termLiteralNextChar);
    253 # endif
    254 # ifdef	VSTATUS
    255     case SLC_AYT:	return(&termAytChar);
    256 # endif
    257 
    258     case SLC_SYNCH:
    259     case SLC_BRK:
    260     case SLC_EOR:
    261     default:
    262 	return((cc_t *)0);
    263     }
    264 }
    265 
    266 void
    267 TerminalDefaultChars(void)
    268 {
    269     memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
    270 # ifndef	VDISCARD
    271     termFlushChar = CONTROL('O');
    272 # endif
    273 # ifndef	VWERASE
    274     termWerasChar = CONTROL('W');
    275 # endif
    276 # ifndef	VREPRINT
    277     termRprntChar = CONTROL('R');
    278 # endif
    279 # ifndef	VLNEXT
    280     termLiteralNextChar = CONTROL('V');
    281 # endif
    282 # ifndef	VSTART
    283     termStartChar = CONTROL('Q');
    284 # endif
    285 # ifndef	VSTOP
    286     termStopChar = CONTROL('S');
    287 # endif
    288 # ifndef	VSTATUS
    289     termAytChar = CONTROL('T');
    290 # endif
    291 }
    292 
    293 #ifdef notdef
    294 void
    295 TerminalRestoreState(void)
    296 {
    297 }
    298 #endif
    299 
    300 /*
    301  * TerminalNewMode - set up terminal to a specific mode.
    302  *	MODE_ECHO: do local terminal echo
    303  *	MODE_FLOW: do local flow control
    304  *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
    305  *	MODE_EDIT: do local line editing
    306  *
    307  *	Command mode:
    308  *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
    309  *		local echo
    310  *		local editing
    311  *		local xon/xoff
    312  *		local signal mapping
    313  *
    314  *	Linemode:
    315  *		local/no editing
    316  *	Both Linemode and Single Character mode:
    317  *		local/remote echo
    318  *		local/no xon/xoff
    319  *		local/no signal mapping
    320  */
    321 
    322 
    323 void
    324 TerminalNewMode(int f)
    325 {
    326     static int prevmode = 0;
    327     struct termios tmp_tc;
    328     int onoff;
    329     int old;
    330     cc_t esc;
    331 
    332     globalmode = f&~MODE_FORCE;
    333     if (prevmode == f)
    334 	return;
    335 
    336     /*
    337      * Write any outstanding data before switching modes
    338      * ttyflush() returns 0 only when there is no more data
    339      * left to write out, it returns -1 if it couldn't do
    340      * anything at all, otherwise it returns 1 + the number
    341      * of characters left to write.
    342 #ifndef	USE_TERMIO
    343      * We would really like to ask the kernel to wait for the output
    344      * to drain, like we can do with the TCSADRAIN, but we don't have
    345      * that option.  The only ioctl that waits for the output to
    346      * drain, TIOCSETP, also flushes the input queue, which is NOT
    347      * what we want (TIOCSETP is like TCSADFLUSH).
    348 #endif
    349      */
    350     old = ttyflush(SYNCHing|flushout);
    351     if (old < 0 || old > 1) {
    352 	tcgetattr(tin, &tmp_tc);
    353 	do {
    354 	    /*
    355 	     * Wait for data to drain, then flush again.
    356 	     */
    357 	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
    358 	    old = ttyflush(SYNCHing|flushout);
    359 	    if (old == -2)
    360 		return;
    361 	} while (old < 0 || old > 1);
    362     }
    363 
    364     old = prevmode;
    365     prevmode = f&~MODE_FORCE;
    366     tmp_tc = new_tc;
    367 
    368     if (f&MODE_ECHO) {
    369 	tmp_tc.c_lflag |= ECHO;
    370 	tmp_tc.c_oflag |= ONLCR;
    371 	if (crlf)
    372 		tmp_tc.c_iflag |= ICRNL;
    373     } else {
    374 	tmp_tc.c_lflag &= ~ECHO;
    375 	tmp_tc.c_oflag &= ~ONLCR;
    376 # ifdef notdef
    377 	if (crlf)
    378 		tmp_tc.c_iflag &= ~ICRNL;
    379 # endif
    380     }
    381 
    382     if ((f&MODE_FLOW) == 0) {
    383 	tmp_tc.c_iflag &= ~(IXOFF|IXON);	/* Leave the IXANY bit alone */
    384     } else {
    385 	if (restartany < 0) {
    386 		tmp_tc.c_iflag |= IXOFF|IXON;	/* Leave the IXANY bit alone */
    387 	} else if (restartany > 0) {
    388 		tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
    389 	} else {
    390 		tmp_tc.c_iflag |= IXOFF|IXON;
    391 		tmp_tc.c_iflag &= ~IXANY;
    392 	}
    393     }
    394 
    395     if ((f&MODE_TRAPSIG) == 0) {
    396 	tmp_tc.c_lflag &= ~ISIG;
    397 	localchars = 0;
    398     } else {
    399 	tmp_tc.c_lflag |= ISIG;
    400 	localchars = 1;
    401     }
    402 
    403     if (f&MODE_EDIT) {
    404 	tmp_tc.c_lflag |= ICANON;
    405     } else {
    406 	tmp_tc.c_lflag &= ~ICANON;
    407 	tmp_tc.c_iflag &= ~ICRNL;
    408 	tmp_tc.c_cc[VMIN] = 1;
    409 	tmp_tc.c_cc[VTIME] = 0;
    410     }
    411 
    412     if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
    413 	tmp_tc.c_lflag &= ~IEXTEN;
    414     }
    415 
    416     if (f&MODE_SOFT_TAB) {
    417 # ifdef	OXTABS
    418 	tmp_tc.c_oflag |= OXTABS;
    419 # endif
    420 # ifdef	TABDLY
    421 	tmp_tc.c_oflag &= ~TABDLY;
    422 	tmp_tc.c_oflag |= TAB3;
    423 # endif
    424     } else {
    425 # ifdef	OXTABS
    426 	tmp_tc.c_oflag &= ~OXTABS;
    427 # endif
    428 # ifdef	TABDLY
    429 	tmp_tc.c_oflag &= ~TABDLY;
    430 # endif
    431     }
    432 
    433     if (f&MODE_LIT_ECHO) {
    434 # ifdef	ECHOCTL
    435 	tmp_tc.c_lflag &= ~ECHOCTL;
    436 # endif
    437     } else {
    438 # ifdef	ECHOCTL
    439 	tmp_tc.c_lflag |= ECHOCTL;
    440 # endif
    441     }
    442 
    443     if (f == -1) {
    444 	onoff = 0;
    445     } else {
    446 	if (f & MODE_INBIN)
    447 		tmp_tc.c_iflag &= ~ISTRIP;
    448 	else
    449 		tmp_tc.c_iflag |= ISTRIP;
    450 	if (f & MODE_OUTBIN) {
    451 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
    452 		tmp_tc.c_cflag |= CS8;
    453 		tmp_tc.c_oflag &= ~OPOST;
    454 	} else {
    455 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
    456 		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
    457 		tmp_tc.c_oflag |= OPOST;
    458 	}
    459 	onoff = 1;
    460     }
    461 
    462     if (f != -1) {
    463 	(void) signal(SIGTSTP, susp);
    464 	(void) signal(SIGINFO, ayt);
    465 #if	defined(USE_TERMIO) && defined(NOKERNINFO)
    466 	tmp_tc.c_lflag |= NOKERNINFO;
    467 #endif
    468 	/*
    469 	 * We don't want to process ^Y here.  It's just another
    470 	 * character that we'll pass on to the back end.  It has
    471 	 * to process it because it will be processed when the
    472 	 * user attempts to read it, not when we send it.
    473 	 */
    474 # ifdef	VDSUSP
    475 	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
    476 # endif
    477 	/*
    478 	 * If the VEOL character is already set, then use VEOL2,
    479 	 * otherwise use VEOL.
    480 	 */
    481 	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
    482 	if ((tmp_tc.c_cc[VEOL] != esc)
    483 # ifdef	VEOL2
    484 	    && (tmp_tc.c_cc[VEOL2] != esc)
    485 # endif
    486 	    ) {
    487 		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
    488 		    tmp_tc.c_cc[VEOL] = esc;
    489 # ifdef	VEOL2
    490 		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
    491 		    tmp_tc.c_cc[VEOL2] = esc;
    492 # endif
    493 	}
    494     } else {
    495 	(void) signal(SIGINFO, (void (*)(int)) ayt_status);
    496 	(void) signal(SIGTSTP, SIG_DFL);
    497 	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
    498 	tmp_tc = old_tc;
    499     }
    500     if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
    501 	tcsetattr(tin, TCSANOW, &tmp_tc);
    502 
    503     ioctl(tin, FIONBIO, (char *)&onoff);
    504     ioctl(tout, FIONBIO, (char *)&onoff);
    505 #if	defined(TN3270)
    506     if (noasynchtty == 0) {
    507 	ioctl(tin, FIOASYNC, (char *)&onoff);
    508     }
    509 #endif	/* defined(TN3270) */
    510 
    511 }
    512 
    513 void
    514 TerminalSpeeds(long *ispeed, long *ospeed)
    515 {
    516     long in, out;
    517 
    518     out = cfgetospeed(&old_tc);
    519     in = cfgetispeed(&old_tc);
    520     if (in == 0)
    521 	in = out;
    522 
    523 	*ispeed = in;
    524 	*ospeed = out;
    525 }
    526 
    527 int
    528 TerminalWindowSize(long *rows, long *cols)
    529 {
    530     struct winsize ws;
    531 
    532     if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
    533 	*rows = ws.ws_row;
    534 	*cols = ws.ws_col;
    535 	return 1;
    536     }
    537     return 0;
    538 }
    539 
    540 int
    541 NetClose(int fd)
    542 {
    543     return close(fd);
    544 }
    545 
    546 
    547 void
    548 NetNonblockingIO(int fd, int onoff)
    549 {
    550     ioctl(fd, FIONBIO, (char *)&onoff);
    551 }
    552 
    553 #ifdef TN3270
    554 void
    555 NetSigIO(int fd, int onoff)
    556 {
    557     ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
    558 }
    559 
    560 void
    561 NetSetPgrp(int fd)
    562 {
    563     int myPid;
    564 
    565     myPid = getpid();
    566     fcntl(fd, F_SETOWN, myPid);
    567 }
    568 #endif	/*defined(TN3270)*/
    569 
    570 /*
    572  * Various signal handling routines.
    573  */
    574 
    575 /* ARGSUSED */
    576 SIG_FUNC_RET
    577 deadpeer(int sig)
    578 {
    579 	setcommandmode();
    580 	longjmp(peerdied, -1);
    581 }
    582 
    583 /* ARGSUSED */
    584 SIG_FUNC_RET
    585 intr(int sig)
    586 {
    587     if (localchars) {
    588 	intp();
    589 	return;
    590     }
    591     setcommandmode();
    592     longjmp(toplevel, -1);
    593 }
    594 
    595 /* ARGSUSED */
    596 SIG_FUNC_RET
    597 intr2(int sig)
    598 {
    599     if (localchars) {
    600 #ifdef	KLUDGELINEMODE
    601 	if (kludgelinemode)
    602 	    sendbrk();
    603 	else
    604 #endif
    605 	    sendabort();
    606 	return;
    607     }
    608 }
    609 
    610 /* ARGSUSED */
    611 SIG_FUNC_RET
    612 susp(int sig)
    613 {
    614     if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
    615 	return;
    616     if (localchars)
    617 	sendsusp();
    618 }
    619 
    620 /* ARGSUSED */
    621 SIG_FUNC_RET
    622 sendwin(int sig)
    623 {
    624     if (connected) {
    625 	sendnaws();
    626     }
    627 }
    628 
    629 /* ARGSUSED */
    630 SIG_FUNC_RET
    631 ayt(int sig)
    632 {
    633     if (connected)
    634 	sendayt();
    635     else
    636 	ayt_status();
    637 }
    638 
    639 
    640 void
    642 sys_telnet_init(void)
    643 {
    644     (void) signal(SIGINT, intr);
    645     (void) signal(SIGQUIT, intr2);
    646     (void) signal(SIGPIPE, deadpeer);
    647     (void) signal(SIGWINCH, sendwin);
    648     (void) signal(SIGTSTP, susp);
    649     (void) signal(SIGINFO, ayt);
    650 
    651     setconnmode(0);
    652 
    653     NetNonblockingIO(net, 1);
    654 
    655 #ifdef TN3270
    656     if (noasynchnet == 0) {			/* DBX can't handle! */
    657 	NetSigIO(net, 1);
    658 	NetSetPgrp(net);
    659     }
    660 #endif	/* defined(TN3270) */
    661 
    662     if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
    663 	perror("SetSockOpt");
    664     }
    665 }
    666 
    667 /*
    668  * Process rings -
    669  *
    670  *	This routine tries to fill up/empty our various rings.
    671  *
    672  *	The parameter specifies whether this is a poll operation,
    673  *	or a block-until-something-happens operation.
    674  *
    675  *	The return value is 1 if something happened, 0 if not, < 0 if an
    676  *	error occured.
    677  */
    678 
    679 int
    680 process_rings(int netin, int netout, int netex, int ttyin, int ttyout,
    681     int dopoll)		/* If 0, then block until something to do */
    682 {
    683     struct pollfd set[3];
    684     int c;
    685 		/* One wants to be a bit careful about setting returnValue
    686 		 * to one, since a one implies we did some useful work,
    687 		 * and therefore probably won't be called to block next
    688 		 * time (TN3270 mode only).
    689 		 */
    690     int returnValue = 0;
    691 
    692     set[0].fd = net;
    693     set[0].events = (netout ? POLLOUT : 0) | (netin ? POLLIN : 0) |
    694 	(netex ? POLLPRI : 0);
    695     set[1].fd = tout;
    696     set[1].events = ttyout ? POLLOUT : 0;
    697     set[2].fd = tin;
    698     set[2].events = ttyin ? POLLIN : 0;
    699 
    700     if ((c = poll(set, 3, dopoll ? 0 : INFTIM)) < 0) {
    701 	if (c == -1) {
    702 		    /*
    703 		     * we can get EINTR if we are in line mode,
    704 		     * and the user does an escape (TSTP), or
    705 		     * some other signal generator.
    706 		     */
    707 	    if (errno == EINTR) {
    708 		return 0;
    709 	    }
    710 #ifdef TN3270
    711 		    /*
    712 		     * we can get EBADF if we were in transparent
    713 		     * mode, and the transcom process died.
    714 		    */
    715 	    if (errno == EBADF)
    716 		return 0;
    717 #endif /* defined(TN3270) */
    718 		    /* I don't like this, does it ever happen? */
    719 	    printf("sleep(5) from telnet, after poll\r\n");
    720 	    sleep(5);
    721 	}
    722 	return 0;
    723     }
    724 
    725     /*
    726      * Any urgent data?
    727      */
    728     if (set[0].revents & POLLPRI) {
    729 	SYNCHing = 1;
    730 	(void) ttyflush(1);	/* flush already enqueued data */
    731     }
    732 
    733     /*
    734      * Something to read from the network...
    735      */
    736     if (set[0].revents & POLLIN) {
    737 	int canread;
    738 
    739 	canread = ring_empty_consecutive(&netiring);
    740 	c = recv(net, (char *)netiring.supply, canread, 0);
    741 	if (c < 0 && errno == EWOULDBLOCK) {
    742 	    c = 0;
    743 	} else if (c <= 0) {
    744 	    return -1;
    745 	}
    746 	if (netdata) {
    747 	    Dump('<', netiring.supply, c);
    748 	}
    749 	if (c)
    750 	    ring_supplied(&netiring, c);
    751 	returnValue = 1;
    752     }
    753 
    754     /*
    755      * Something to read from the tty...
    756      */
    757     if (set[2].revents & POLLIN) {
    758 	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
    759 	if (c < 0 && errno == EIO)
    760 	    c = 0;
    761 	if (c < 0 && errno == EWOULDBLOCK) {
    762 	    c = 0;
    763 	} else {
    764 	    if (c < 0) {
    765 		return -1;
    766 	    }
    767 	    if (c == 0) {
    768 		/* must be an EOF... */
    769 		if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
    770 		    *ttyiring.supply = termEofChar;
    771 		    c = 1;
    772 		} else {
    773 		    clienteof = 1;
    774 		    shutdown(net, 1);
    775 		    return 0;
    776 		}
    777 	    }
    778 	    if (termdata) {
    779 		Dump('<', ttyiring.supply, c);
    780 	    }
    781 	    ring_supplied(&ttyiring, c);
    782 	}
    783 	returnValue = 1;		/* did something useful */
    784     }
    785 
    786     if (set[0].revents & POLLOUT) {
    787 	returnValue |= netflush();
    788     }
    789     if (set[1].revents & POLLOUT) {
    790 	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
    791     }
    792 
    793     return returnValue;
    794 }
    795