Home | History | Annotate | Line # | Download | only in telnet
sys_bsd.c revision 1.13
      1 /*	$NetBSD: sys_bsd.c,v 1.13 1998/07/09 18:34:02 msaitoh 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.13 1998/07/09 18:34:02 msaitoh 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 <arpa/telnet.h>
     60 
     61 #include "ring.h"
     62 
     63 #include "fdset.h"
     64 
     65 #include "defines.h"
     66 #include "externs.h"
     67 #include "types.h"
     68 
     69 #if	defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO))
     70 #define	SIG_FUNC_RET	void
     71 #else
     72 #define	SIG_FUNC_RET	int
     73 #endif
     74 
     75 #ifdef	SIGTSTP
     76 SIG_FUNC_RET susp P((int));
     77 #endif	/* SIGTSTP */
     78 #ifdef	SIGINFO
     79 SIG_FUNC_RET ayt P((int));
     80 #endif
     81 
     82 SIG_FUNC_RET intr P((int));
     83 SIG_FUNC_RET intr2 P((int));
     84 SIG_FUNC_RET sendwin P((int));
     85 SIG_FUNC_RET deadpeer P((int));
     86 
     87 
     88 int
     89 	tout,			/* Output file descriptor */
     90 	tin,			/* Input file descriptor */
     91 	net;
     92 
     93 #ifndef	USE_TERMIO
     94 struct	tchars otc = { 0 }, ntc = { 0 };
     95 struct	ltchars oltc = { 0 }, nltc = { 0 };
     96 struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
     97 int	olmode = 0;
     98 # define cfgetispeed(ptr)	(ptr)->sg_ispeed
     99 # define cfgetospeed(ptr)	(ptr)->sg_ospeed
    100 # define old_tc ottyb
    101 
    102 #else	/* USE_TERMIO */
    103 struct	termio old_tc = { 0 };
    104 extern struct termio new_tc;
    105 
    106 # ifndef	TCSANOW
    107 #  ifdef TCSETS
    108 #   define	TCSANOW		TCSETS
    109 #   define	TCSADRAIN	TCSETSW
    110 #   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
    111 #  else
    112 #   ifdef TCSETA
    113 #    define	TCSANOW		TCSETA
    114 #    define	TCSADRAIN	TCSETAW
    115 #    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
    116 #   else
    117 #    define	TCSANOW		TIOCSETA
    118 #    define	TCSADRAIN	TIOCSETAW
    119 #    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
    120 #   endif
    121 #  endif
    122 #  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
    123 #  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
    124 #  ifdef CIBAUD
    125 #   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
    126 #  else
    127 #   define	cfgetispeed(ptr)	cfgetospeed(ptr)
    128 #  endif
    129 # endif /* TCSANOW */
    130 # ifdef	sysV88
    131 # define TIOCFLUSH TC_PX_DRAIN
    132 # endif
    133 #endif	/* USE_TERMIO */
    134 
    135 static fd_set ibits, obits, xbits;
    136 
    137 
    138     void
    139 init_sys()
    140 {
    141     tout = fileno(stdout);
    142     tin = fileno(stdin);
    143     FD_ZERO(&ibits);
    144     FD_ZERO(&obits);
    145     FD_ZERO(&xbits);
    146 
    147     errno = 0;
    148 }
    149 
    150 
    151     int
    152 TerminalWrite(buf, n)
    153     char *buf;
    154     int  n;
    155 {
    156     return write(tout, buf, n);
    157 }
    158 
    159     int
    160 TerminalRead(buf, n)
    161     unsigned char *buf;
    162     int  n;
    163 {
    164     return read(tin, buf, n);
    165 }
    166 
    167 /*
    168  *
    169  */
    170 
    171     int
    172 TerminalAutoFlush()
    173 {
    174 #if	defined(LNOFLSH)
    175     int flush;
    176 
    177     ioctl(0, TIOCLGET, (char *)&flush);
    178     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
    179 #else	/* LNOFLSH */
    180     return 1;
    181 #endif	/* LNOFLSH */
    182 }
    183 
    184 #ifdef	KLUDGELINEMODE
    185 extern int kludgelinemode;
    186 #endif
    187 /*
    188  * TerminalSpecialChars()
    189  *
    190  * Look at an input character to see if it is a special character
    191  * and decide what to do.
    192  *
    193  * Output:
    194  *
    195  *	0	Don't add this character.
    196  *	1	Do add this character
    197  */
    198 
    199     int
    200 TerminalSpecialChars(c)
    201     int	c;
    202 {
    203     if (c == termIntChar) {
    204 	intp();
    205 	return 0;
    206     } else if (c == termQuitChar) {
    207 #ifdef	KLUDGELINEMODE
    208 	if (kludgelinemode)
    209 	    sendbrk();
    210 	else
    211 #endif
    212 	    sendabort();
    213 	return 0;
    214     } else if (c == termEofChar) {
    215 	if (my_want_state_is_will(TELOPT_LINEMODE)) {
    216 	    sendeof();
    217 	    return 0;
    218 	}
    219 	return 1;
    220     } else if (c == termSuspChar) {
    221 	sendsusp();
    222 	return(0);
    223     } else if (c == termFlushChar) {
    224 	xmitAO();		/* Transmit Abort Output */
    225 	return 0;
    226     } else if (!MODE_LOCAL_CHARS(globalmode)) {
    227 	if (c == termKillChar) {
    228 	    xmitEL();
    229 	    return 0;
    230 	} else if (c == termEraseChar) {
    231 	    xmitEC();		/* Transmit Erase Character */
    232 	    return 0;
    233 	}
    234     }
    235     return 1;
    236 }
    237 
    238 
    239 /*
    240  * Flush output to the terminal
    241  */
    242 
    243     void
    244 TerminalFlushOutput()
    245 {
    246 #ifdef	TIOCFLUSH
    247     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
    248 #else
    249     (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
    250 #endif
    251 }
    252 
    253     void
    254 TerminalSaveState()
    255 {
    256 #ifndef	USE_TERMIO
    257     ioctl(0, TIOCGETP, (char *)&ottyb);
    258     ioctl(0, TIOCGETC, (char *)&otc);
    259     ioctl(0, TIOCGLTC, (char *)&oltc);
    260     ioctl(0, TIOCLGET, (char *)&olmode);
    261 
    262     ntc = otc;
    263     nltc = oltc;
    264     nttyb = ottyb;
    265 
    266 #else	/* USE_TERMIO */
    267     tcgetattr(0, &old_tc);
    268 
    269     new_tc = old_tc;
    270 
    271 #ifndef	VDISCARD
    272     termFlushChar = CONTROL('O');
    273 #endif
    274 #ifndef	VWERASE
    275     termWerasChar = CONTROL('W');
    276 #endif
    277 #ifndef	VREPRINT
    278     termRprntChar = CONTROL('R');
    279 #endif
    280 #ifndef	VLNEXT
    281     termLiteralNextChar = CONTROL('V');
    282 #endif
    283 #ifndef	VSTART
    284     termStartChar = CONTROL('Q');
    285 #endif
    286 #ifndef	VSTOP
    287     termStopChar = CONTROL('S');
    288 #endif
    289 #ifndef	VSTATUS
    290     termAytChar = CONTROL('T');
    291 #endif
    292 #endif	/* USE_TERMIO */
    293 }
    294 
    295     cc_t *
    296 tcval(func)
    297     register int func;
    298 {
    299     switch(func) {
    300     case SLC_IP:	return(&termIntChar);
    301     case SLC_ABORT:	return(&termQuitChar);
    302     case SLC_EOF:	return(&termEofChar);
    303     case SLC_EC:	return(&termEraseChar);
    304     case SLC_EL:	return(&termKillChar);
    305     case SLC_XON:	return(&termStartChar);
    306     case SLC_XOFF:	return(&termStopChar);
    307     case SLC_FORW1:	return(&termForw1Char);
    308 #ifdef	USE_TERMIO
    309     case SLC_FORW2:	return(&termForw2Char);
    310 # ifdef	VDISCARD
    311     case SLC_AO:	return(&termFlushChar);
    312 # endif
    313 # ifdef	VSUSP
    314     case SLC_SUSP:	return(&termSuspChar);
    315 # endif
    316 # ifdef	VWERASE
    317     case SLC_EW:	return(&termWerasChar);
    318 # endif
    319 # ifdef	VREPRINT
    320     case SLC_RP:	return(&termRprntChar);
    321 # endif
    322 # ifdef	VLNEXT
    323     case SLC_LNEXT:	return(&termLiteralNextChar);
    324 # endif
    325 # ifdef	VSTATUS
    326     case SLC_AYT:	return(&termAytChar);
    327 # endif
    328 #endif
    329 
    330     case SLC_SYNCH:
    331     case SLC_BRK:
    332     case SLC_EOR:
    333     default:
    334 	return((cc_t *)0);
    335     }
    336 }
    337 
    338     void
    339 TerminalDefaultChars()
    340 {
    341 #ifndef	USE_TERMIO
    342     ntc = otc;
    343     nltc = oltc;
    344     nttyb.sg_kill = ottyb.sg_kill;
    345     nttyb.sg_erase = ottyb.sg_erase;
    346 #else	/* USE_TERMIO */
    347     memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
    348 # ifndef	VDISCARD
    349     termFlushChar = CONTROL('O');
    350 # endif
    351 # ifndef	VWERASE
    352     termWerasChar = CONTROL('W');
    353 # endif
    354 # ifndef	VREPRINT
    355     termRprntChar = CONTROL('R');
    356 # endif
    357 # ifndef	VLNEXT
    358     termLiteralNextChar = CONTROL('V');
    359 # endif
    360 # ifndef	VSTART
    361     termStartChar = CONTROL('Q');
    362 # endif
    363 # ifndef	VSTOP
    364     termStopChar = CONTROL('S');
    365 # endif
    366 # ifndef	VSTATUS
    367     termAytChar = CONTROL('T');
    368 # endif
    369 #endif	/* USE_TERMIO */
    370 }
    371 
    372 #ifdef notdef
    373 void
    374 TerminalRestoreState()
    375 {
    376 }
    377 #endif
    378 
    379 /*
    380  * TerminalNewMode - set up terminal to a specific mode.
    381  *	MODE_ECHO: do local terminal echo
    382  *	MODE_FLOW: do local flow control
    383  *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
    384  *	MODE_EDIT: do local line editing
    385  *
    386  *	Command mode:
    387  *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
    388  *		local echo
    389  *		local editing
    390  *		local xon/xoff
    391  *		local signal mapping
    392  *
    393  *	Linemode:
    394  *		local/no editing
    395  *	Both Linemode and Single Character mode:
    396  *		local/remote echo
    397  *		local/no xon/xoff
    398  *		local/no signal mapping
    399  */
    400 
    401 
    402     void
    403 TerminalNewMode(f)
    404     register int f;
    405 {
    406     static int prevmode = 0;
    407 #ifndef	USE_TERMIO
    408     struct tchars tc;
    409     struct ltchars ltc;
    410     struct sgttyb sb;
    411     int lmode;
    412 #else	/* USE_TERMIO */
    413     struct termio tmp_tc;
    414 #endif	/* USE_TERMIO */
    415     int onoff;
    416     int old;
    417     cc_t esc;
    418 
    419     globalmode = f&~MODE_FORCE;
    420     if (prevmode == f)
    421 	return;
    422 
    423     /*
    424      * Write any outstanding data before switching modes
    425      * ttyflush() returns 0 only when there is no more data
    426      * left to write out, it returns -1 if it couldn't do
    427      * anything at all, otherwise it returns 1 + the number
    428      * of characters left to write.
    429 #ifndef	USE_TERMIO
    430      * We would really like ask the kernel to wait for the output
    431      * to drain, like we can do with the TCSADRAIN, but we don't have
    432      * that option.  The only ioctl that waits for the output to
    433      * drain, TIOCSETP, also flushes the input queue, which is NOT
    434      * what we want (TIOCSETP is like TCSADFLUSH).
    435 #endif
    436      */
    437     old = ttyflush(SYNCHing|flushout);
    438     if (old < 0 || old > 1) {
    439 #ifdef	USE_TERMIO
    440 	tcgetattr(tin, &tmp_tc);
    441 #endif	/* USE_TERMIO */
    442 	do {
    443 	    /*
    444 	     * Wait for data to drain, then flush again.
    445 	     */
    446 #ifdef	USE_TERMIO
    447 	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
    448 #endif	/* USE_TERMIO */
    449 	    old = ttyflush(SYNCHing|flushout);
    450 	} while (old < 0 || old > 1);
    451     }
    452 
    453     old = prevmode;
    454     prevmode = f&~MODE_FORCE;
    455 #ifndef	USE_TERMIO
    456     sb = nttyb;
    457     tc = ntc;
    458     ltc = nltc;
    459     lmode = olmode;
    460 #else
    461     tmp_tc = new_tc;
    462 #endif
    463 
    464     if (f&MODE_ECHO) {
    465 #ifndef	USE_TERMIO
    466 	sb.sg_flags |= ECHO;
    467 #else
    468 	tmp_tc.c_lflag |= ECHO;
    469 	tmp_tc.c_oflag |= ONLCR;
    470 	if (crlf)
    471 		tmp_tc.c_iflag |= ICRNL;
    472 #endif
    473     } else {
    474 #ifndef	USE_TERMIO
    475 	sb.sg_flags &= ~ECHO;
    476 #else
    477 	tmp_tc.c_lflag &= ~ECHO;
    478 	tmp_tc.c_oflag &= ~ONLCR;
    479 # ifdef notdef
    480 	if (crlf)
    481 		tmp_tc.c_iflag &= ~ICRNL;
    482 # endif
    483 #endif
    484     }
    485 
    486     if ((f&MODE_FLOW) == 0) {
    487 #ifndef	USE_TERMIO
    488 	tc.t_startc = _POSIX_VDISABLE;
    489 	tc.t_stopc = _POSIX_VDISABLE;
    490 #else
    491 	tmp_tc.c_iflag &= ~(IXOFF|IXON);	/* Leave the IXANY bit alone */
    492     } else {
    493 	if (restartany < 0) {
    494 		tmp_tc.c_iflag |= IXOFF|IXON;	/* Leave the IXANY bit alone */
    495 	} else if (restartany > 0) {
    496 		tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
    497 	} else {
    498 		tmp_tc.c_iflag |= IXOFF|IXON;
    499 		tmp_tc.c_iflag &= ~IXANY;
    500 	}
    501 #endif
    502     }
    503 
    504     if ((f&MODE_TRAPSIG) == 0) {
    505 #ifndef	USE_TERMIO
    506 	tc.t_intrc = _POSIX_VDISABLE;
    507 	tc.t_quitc = _POSIX_VDISABLE;
    508 	tc.t_eofc = _POSIX_VDISABLE;
    509 	ltc.t_suspc = _POSIX_VDISABLE;
    510 	ltc.t_dsuspc = _POSIX_VDISABLE;
    511 #else
    512 	tmp_tc.c_lflag &= ~ISIG;
    513 #endif
    514 	localchars = 0;
    515     } else {
    516 #ifdef	USE_TERMIO
    517 	tmp_tc.c_lflag |= ISIG;
    518 #endif
    519 	localchars = 1;
    520     }
    521 
    522     if (f&MODE_EDIT) {
    523 #ifndef	USE_TERMIO
    524 	sb.sg_flags &= ~CBREAK;
    525 	sb.sg_flags |= CRMOD;
    526 #else
    527 	tmp_tc.c_lflag |= ICANON;
    528 #endif
    529     } else {
    530 #ifndef	USE_TERMIO
    531 	sb.sg_flags |= CBREAK;
    532 	if (f&MODE_ECHO)
    533 	    sb.sg_flags |= CRMOD;
    534 	else
    535 	    sb.sg_flags &= ~CRMOD;
    536 #else
    537 	tmp_tc.c_lflag &= ~ICANON;
    538 	tmp_tc.c_iflag &= ~ICRNL;
    539 	tmp_tc.c_cc[VMIN] = 1;
    540 	tmp_tc.c_cc[VTIME] = 0;
    541 #endif
    542     }
    543 
    544     if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
    545 #ifndef	USE_TERMIO
    546 	ltc.t_lnextc = _POSIX_VDISABLE;
    547 #else
    548 	tmp_tc.c_lflag &= ~IEXTEN;
    549 #endif
    550     }
    551 
    552     if (f&MODE_SOFT_TAB) {
    553 #ifndef USE_TERMIO
    554 	sb.sg_flags |= XTABS;
    555 #else
    556 # ifdef	OXTABS
    557 	tmp_tc.c_oflag |= OXTABS;
    558 # endif
    559 # ifdef	TABDLY
    560 	tmp_tc.c_oflag &= ~TABDLY;
    561 	tmp_tc.c_oflag |= TAB3;
    562 # endif
    563 #endif
    564     } else {
    565 #ifndef USE_TERMIO
    566 	sb.sg_flags &= ~XTABS;
    567 #else
    568 # ifdef	OXTABS
    569 	tmp_tc.c_oflag &= ~OXTABS;
    570 # endif
    571 # ifdef	TABDLY
    572 	tmp_tc.c_oflag &= ~TABDLY;
    573 # endif
    574 #endif
    575     }
    576 
    577     if (f&MODE_LIT_ECHO) {
    578 #ifndef USE_TERMIO
    579 	lmode &= ~LCTLECH;
    580 #else
    581 # ifdef	ECHOCTL
    582 	tmp_tc.c_lflag &= ~ECHOCTL;
    583 # endif
    584 #endif
    585     } else {
    586 #ifndef USE_TERMIO
    587 	lmode |= LCTLECH;
    588 #else
    589 # ifdef	ECHOCTL
    590 	tmp_tc.c_lflag |= ECHOCTL;
    591 # endif
    592 #endif
    593     }
    594 
    595     if (f == -1) {
    596 	onoff = 0;
    597     } else {
    598 #ifndef	USE_TERMIO
    599 	if (f & MODE_OUTBIN)
    600 		lmode |= LLITOUT;
    601 	else
    602 		lmode &= ~LLITOUT;
    603 
    604 	if (f & MODE_INBIN)
    605 		lmode |= LPASS8;
    606 	else
    607 		lmode &= ~LPASS8;
    608 #else
    609 	if (f & MODE_INBIN)
    610 		tmp_tc.c_iflag &= ~ISTRIP;
    611 	else
    612 		tmp_tc.c_iflag |= ISTRIP;
    613 	if (f & MODE_OUTBIN) {
    614 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
    615 		tmp_tc.c_cflag |= CS8;
    616 		tmp_tc.c_oflag &= ~OPOST;
    617 	} else {
    618 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
    619 		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
    620 		tmp_tc.c_oflag |= OPOST;
    621 	}
    622 #endif
    623 	onoff = 1;
    624     }
    625 
    626     if (f != -1) {
    627 #ifdef	SIGTSTP
    628 	(void) signal(SIGTSTP, susp);
    629 #endif	/* SIGTSTP */
    630 #ifdef	SIGINFO
    631 	(void) signal(SIGINFO, ayt);
    632 #endif
    633 #if	defined(USE_TERMIO) && defined(NOKERNINFO)
    634 	tmp_tc.c_lflag |= NOKERNINFO;
    635 #endif
    636 	/*
    637 	 * We don't want to process ^Y here.  It's just another
    638 	 * character that we'll pass on to the back end.  It has
    639 	 * to process it because it will be processed when the
    640 	 * user attempts to read it, not when we send it.
    641 	 */
    642 #ifndef	USE_TERMIO
    643 	ltc.t_dsuspc = _POSIX_VDISABLE;
    644 #else
    645 # ifdef	VDSUSP
    646 	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
    647 # endif
    648 #endif
    649 #ifdef	USE_TERMIO
    650 	/*
    651 	 * If the VEOL character is already set, then use VEOL2,
    652 	 * otherwise use VEOL.
    653 	 */
    654 	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
    655 	if ((tmp_tc.c_cc[VEOL] != esc)
    656 # ifdef	VEOL2
    657 	    && (tmp_tc.c_cc[VEOL2] != esc)
    658 # endif
    659 	    ) {
    660 		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
    661 		    tmp_tc.c_cc[VEOL] = esc;
    662 # ifdef	VEOL2
    663 		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
    664 		    tmp_tc.c_cc[VEOL2] = esc;
    665 # endif
    666 	}
    667 #else
    668 	if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
    669 		tc.t_brkc = esc;
    670 #endif
    671     } else {
    672 #ifdef	SIGINFO
    673 	(void) signal(SIGINFO, (void (*) P((int))) ayt_status);
    674 #endif
    675 #ifdef	SIGTSTP
    676 	(void) signal(SIGTSTP, SIG_DFL);
    677 # ifndef SOLARIS
    678 	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
    679 # else	SOLARIS
    680 	(void) sigrelse(SIGTSTP);
    681 # endif	SOLARIS
    682 #endif	/* SIGTSTP */
    683 #ifndef USE_TERMIO
    684 	ltc = oltc;
    685 	tc = otc;
    686 	sb = ottyb;
    687 	lmode = olmode;
    688 #else
    689 	tmp_tc = old_tc;
    690 #endif
    691     }
    692 #ifndef USE_TERMIO
    693     ioctl(tin, TIOCLSET, (char *)&lmode);
    694     ioctl(tin, TIOCSLTC, (char *)&ltc);
    695     ioctl(tin, TIOCSETC, (char *)&tc);
    696     ioctl(tin, TIOCSETN, (char *)&sb);
    697 #else
    698     if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
    699 	tcsetattr(tin, TCSANOW, &tmp_tc);
    700 #endif
    701 
    702 #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
    703 # if	!defined(sysV88)
    704     ioctl(tin, FIONBIO, (char *)&onoff);
    705     ioctl(tout, FIONBIO, (char *)&onoff);
    706 # endif
    707 #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
    708 #if	defined(TN3270)
    709     if (noasynchtty == 0) {
    710 	ioctl(tin, FIOASYNC, (char *)&onoff);
    711     }
    712 #endif	/* defined(TN3270) */
    713 
    714 }
    715 
    716 /*
    717  * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
    718  */
    719 #if B4800 != 4800
    720 #define	DECODE_BAUD
    721 #endif
    722 
    723 #ifdef	DECODE_BAUD
    724 #ifndef	B7200
    725 #define B7200   B4800
    726 #endif
    727 
    728 #ifndef	B14400
    729 #define B14400  B9600
    730 #endif
    731 
    732 #ifndef	B19200
    733 # define B19200 B14400
    734 #endif
    735 
    736 #ifndef	B28800
    737 #define B28800  B19200
    738 #endif
    739 
    740 #ifndef	B38400
    741 # define B38400 B28800
    742 #endif
    743 
    744 #ifndef B57600
    745 #define B57600  B38400
    746 #endif
    747 
    748 #ifndef B76800
    749 #define B76800  B57600
    750 #endif
    751 
    752 #ifndef B115200
    753 #define B115200 B76800
    754 #endif
    755 
    756 #ifndef B230400
    757 #define B230400 B115200
    758 #endif
    759 
    760 
    761 /*
    762  * This code assumes that the values B0, B50, B75...
    763  * are in ascending order.  They do not have to be
    764  * contiguous.
    765  */
    766 struct termspeeds {
    767 	long speed;
    768 	long value;
    769 } termspeeds[] = {
    770 	{ 0,      B0 },      { 50,    B50 },    { 75,     B75 },
    771 	{ 110,    B110 },    { 134,   B134 },   { 150,    B150 },
    772 	{ 200,    B200 },    { 300,   B300 },   { 600,    B600 },
    773 	{ 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
    774 	{ 4800,   B4800 },   { 7200,  B7200 },  { 9600,   B9600 },
    775 	{ 14400,  B14400 },  { 19200, B19200 }, { 28800,  B28800 },
    776 	{ 38400,  B38400 },  { 57600, B57600 }, { 115200, B115200 },
    777 	{ 230400, B230400 }, { -1,    B230400 }
    778 };
    779 #endif	/* DECODE_BAUD */
    780 
    781     void
    782 TerminalSpeeds(ispeed, ospeed)
    783     long *ispeed;
    784     long *ospeed;
    785 {
    786 #ifdef	DECODE_BAUD
    787     register struct termspeeds *tp;
    788 #endif	/* DECODE_BAUD */
    789     register long in, out;
    790 
    791     out = cfgetospeed(&old_tc);
    792     in = cfgetispeed(&old_tc);
    793     if (in == 0)
    794 	in = out;
    795 
    796 #ifdef	DECODE_BAUD
    797     tp = termspeeds;
    798     while ((tp->speed != -1) && (tp->value < in))
    799 	tp++;
    800     *ispeed = tp->speed;
    801 
    802     tp = termspeeds;
    803     while ((tp->speed != -1) && (tp->value < out))
    804 	tp++;
    805     *ospeed = tp->speed;
    806 #else	/* DECODE_BAUD */
    807 	*ispeed = in;
    808 	*ospeed = out;
    809 #endif	/* DECODE_BAUD */
    810 }
    811 
    812     int
    813 TerminalWindowSize(rows, cols)
    814     long *rows, *cols;
    815 {
    816 #ifdef	TIOCGWINSZ
    817     struct winsize ws;
    818 
    819     if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
    820 	*rows = ws.ws_row;
    821 	*cols = ws.ws_col;
    822 	return 1;
    823     }
    824 #endif	/* TIOCGWINSZ */
    825     return 0;
    826 }
    827 
    828     int
    829 NetClose(fd)
    830     int	fd;
    831 {
    832     return close(fd);
    833 }
    834 
    835 
    836     void
    837 NetNonblockingIO(fd, onoff)
    838     int fd;
    839     int onoff;
    840 {
    841     ioctl(fd, FIONBIO, (char *)&onoff);
    842 }
    843 
    844 #if	defined(TN3270)
    845     void
    846 NetSigIO(fd, onoff)
    847     int fd;
    848     int onoff;
    849 {
    850     ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
    851 }
    852 
    853     void
    854 NetSetPgrp(fd)
    855     int fd;
    856 {
    857     int myPid;
    858 
    859     myPid = getpid();
    860     fcntl(fd, F_SETOWN, myPid);
    861 }
    862 #endif	/*defined(TN3270)*/
    863 
    864 /*
    866  * Various signal handling routines.
    867  */
    868 
    869     /* ARGSUSED */
    870     SIG_FUNC_RET
    871 deadpeer(sig)
    872     int sig;
    873 {
    874 	setcommandmode();
    875 	longjmp(peerdied, -1);
    876 }
    877 
    878     /* ARGSUSED */
    879     SIG_FUNC_RET
    880 intr(sig)
    881     int sig;
    882 {
    883     if (localchars) {
    884 	intp();
    885 	return;
    886     }
    887     setcommandmode();
    888     longjmp(toplevel, -1);
    889 }
    890 
    891     /* ARGSUSED */
    892     SIG_FUNC_RET
    893 intr2(sig)
    894     int sig;
    895 {
    896     if (localchars) {
    897 #ifdef	KLUDGELINEMODE
    898 	if (kludgelinemode)
    899 	    sendbrk();
    900 	else
    901 #endif
    902 	    sendabort();
    903 	return;
    904     }
    905 }
    906 
    907 #ifdef	SIGTSTP
    908     /* ARGSUSED */
    909     SIG_FUNC_RET
    910 susp(sig)
    911     int sig;
    912 {
    913     if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
    914 	return;
    915     if (localchars)
    916 	sendsusp();
    917 }
    918 #endif
    919 
    920 #ifdef	SIGWINCH
    921     /* ARGSUSED */
    922     SIG_FUNC_RET
    923 sendwin(sig)
    924     int sig;
    925 {
    926     if (connected) {
    927 	sendnaws();
    928     }
    929 }
    930 #endif
    931 
    932 #ifdef	SIGINFO
    933     /* ARGSUSED */
    934     SIG_FUNC_RET
    935 ayt(sig)
    936     int sig;
    937 {
    938     if (connected)
    939 	sendayt();
    940     else
    941 	ayt_status();
    942 }
    943 #endif
    944 
    945 
    946     void
    948 sys_telnet_init()
    949 {
    950     (void) signal(SIGINT, intr);
    951     (void) signal(SIGQUIT, intr2);
    952     (void) signal(SIGPIPE, deadpeer);
    953 #ifdef	SIGWINCH
    954     (void) signal(SIGWINCH, sendwin);
    955 #endif
    956 #ifdef	SIGTSTP
    957     (void) signal(SIGTSTP, susp);
    958 #endif
    959 #ifdef	SIGINFO
    960     (void) signal(SIGINFO, ayt);
    961 #endif
    962 
    963     setconnmode(0);
    964 
    965     NetNonblockingIO(net, 1);
    966 
    967 #if	defined(TN3270)
    968     if (noasynchnet == 0) {			/* DBX can't handle! */
    969 	NetSigIO(net, 1);
    970 	NetSetPgrp(net);
    971     }
    972 #endif	/* defined(TN3270) */
    973 
    974 #if	defined(SO_OOBINLINE)
    975     if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
    976 	perror("SetSockOpt");
    977     }
    978 #endif	/* defined(SO_OOBINLINE) */
    979 }
    980 
    981 /*
    982  * Process rings -
    983  *
    984  *	This routine tries to fill up/empty our various rings.
    985  *
    986  *	The parameter specifies whether this is a poll operation,
    987  *	or a block-until-something-happens operation.
    988  *
    989  *	The return value is 1 if something happened, 0 if not.
    990  */
    991 
    992     int
    993 process_rings(netin, netout, netex, ttyin, ttyout, poll)
    994 	int netin, netout, netex, ttyin, ttyout;
    995     int poll;		/* If 0, then block until something to do */
    996 {
    997     register int c;
    998 		/* One wants to be a bit careful about setting returnValue
    999 		 * to one, since a one implies we did some useful work,
   1000 		 * and therefore probably won't be called to block next
   1001 		 * time (TN3270 mode only).
   1002 		 */
   1003     int returnValue = 0;
   1004     static struct timeval TimeValue = { 0 };
   1005 
   1006     if (netout) {
   1007 	FD_SET(net, &obits);
   1008     }
   1009     if (ttyout) {
   1010 	FD_SET(tout, &obits);
   1011     }
   1012 #if	defined(TN3270)
   1013     if (ttyin) {
   1014 	FD_SET(tin, &ibits);
   1015     }
   1016 #else	/* defined(TN3270) */
   1017     if (ttyin) {
   1018 	FD_SET(tin, &ibits);
   1019     }
   1020 #endif	/* defined(TN3270) */
   1021 #if	defined(TN3270)
   1022     if (netin) {
   1023 	FD_SET(net, &ibits);
   1024     }
   1025 #   else /* !defined(TN3270) */
   1026     if (netin) {
   1027 	FD_SET(net, &ibits);
   1028     }
   1029 #   endif /* !defined(TN3270) */
   1030     if (netex) {
   1031 	FD_SET(net, &xbits);
   1032     }
   1033     if ((c = select(16, &ibits, &obits, &xbits,
   1034 			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
   1035 	if (c == -1) {
   1036 		    /*
   1037 		     * we can get EINTR if we are in line mode,
   1038 		     * and the user does an escape (TSTP), or
   1039 		     * some other signal generator.
   1040 		     */
   1041 	    if (errno == EINTR) {
   1042 		return 0;
   1043 	    }
   1044 #	    if defined(TN3270)
   1045 		    /*
   1046 		     * we can get EBADF if we were in transparent
   1047 		     * mode, and the transcom process died.
   1048 		    */
   1049 	    if (errno == EBADF) {
   1050 			/*
   1051 			 * zero the bits (even though kernel does it)
   1052 			 * to make sure we are selecting on the right
   1053 			 * ones.
   1054 			*/
   1055 		FD_ZERO(&ibits);
   1056 		FD_ZERO(&obits);
   1057 		FD_ZERO(&xbits);
   1058 		return 0;
   1059 	    }
   1060 #	    endif /* defined(TN3270) */
   1061 		    /* I don't like this, does it ever happen? */
   1062 	    printf("sleep(5) from telnet, after select\r\n");
   1063 	    sleep(5);
   1064 	}
   1065 	return 0;
   1066     }
   1067 
   1068     /*
   1069      * Any urgent data?
   1070      */
   1071     if (FD_ISSET(net, &xbits)) {
   1072 	FD_CLR(net, &xbits);
   1073 	SYNCHing = 1;
   1074 	(void) ttyflush(1);	/* flush already enqueued data */
   1075     }
   1076 
   1077     /*
   1078      * Something to read from the network...
   1079      */
   1080     if (FD_ISSET(net, &ibits)) {
   1081 	int canread;
   1082 
   1083 	FD_CLR(net, &ibits);
   1084 	canread = ring_empty_consecutive(&netiring);
   1085 #if	!defined(SO_OOBINLINE)
   1086 	    /*
   1087 	     * In 4.2 (and some early 4.3) systems, the
   1088 	     * OOB indication and data handling in the kernel
   1089 	     * is such that if two separate TCP Urgent requests
   1090 	     * come in, one byte of TCP data will be overlaid.
   1091 	     * This is fatal for Telnet, but we try to live
   1092 	     * with it.
   1093 	     *
   1094 	     * In addition, in 4.2 (and...), a special protocol
   1095 	     * is needed to pick up the TCP Urgent data in
   1096 	     * the correct sequence.
   1097 	     *
   1098 	     * What we do is:  if we think we are in urgent
   1099 	     * mode, we look to see if we are "at the mark".
   1100 	     * If we are, we do an OOB receive.  If we run
   1101 	     * this twice, we will do the OOB receive twice,
   1102 	     * but the second will fail, since the second
   1103 	     * time we were "at the mark", but there wasn't
   1104 	     * any data there (the kernel doesn't reset
   1105 	     * "at the mark" until we do a normal read).
   1106 	     * Once we've read the OOB data, we go ahead
   1107 	     * and do normal reads.
   1108 	     *
   1109 	     * There is also another problem, which is that
   1110 	     * since the OOB byte we read doesn't put us
   1111 	     * out of OOB state, and since that byte is most
   1112 	     * likely the TELNET DM (data mark), we would
   1113 	     * stay in the TELNET SYNCH (SYNCHing) state.
   1114 	     * So, clocks to the rescue.  If we've "just"
   1115 	     * received a DM, then we test for the
   1116 	     * presence of OOB data when the receive OOB
   1117 	     * fails (and AFTER we did the normal mode read
   1118 	     * to clear "at the mark").
   1119 	     */
   1120 	if (SYNCHing) {
   1121 	    int atmark;
   1122 	    static int bogus_oob = 0, first = 1;
   1123 
   1124 	    ioctl(net, SIOCATMARK, (char *)&atmark);
   1125 	    if (atmark) {
   1126 		c = recv(net, netiring.supply, canread, MSG_OOB);
   1127 		if ((c == -1) && (errno == EINVAL)) {
   1128 		    c = recv(net, netiring.supply, canread, 0);
   1129 		    if (clocks.didnetreceive < clocks.gotDM) {
   1130 			SYNCHing = stilloob(net);
   1131 		    }
   1132 		} else if (first && c > 0) {
   1133 		    /*
   1134 		     * Bogosity check.  Systems based on 4.2BSD
   1135 		     * do not return an error if you do a second
   1136 		     * recv(MSG_OOB).  So, we do one.  If it
   1137 		     * succeeds and returns exactly the same
   1138 		     * data, then assume that we are running
   1139 		     * on a broken system and set the bogus_oob
   1140 		     * flag.  (If the data was different, then
   1141 		     * we probably got some valid new data, so
   1142 		     * increment the count...)
   1143 		     */
   1144 		    int i;
   1145 		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
   1146 		    if (i == c &&
   1147 			 memcmp(netiring.supply, netiring.supply + c, i) == 0) {
   1148 			bogus_oob = 1;
   1149 			first = 0;
   1150 		    } else if (i < 0) {
   1151 			bogus_oob = 0;
   1152 			first = 0;
   1153 		    } else
   1154 			c += i;
   1155 		}
   1156 		if (bogus_oob && c > 0) {
   1157 		    int i;
   1158 		    /*
   1159 		     * Bogosity.  We have to do the read
   1160 		     * to clear the atmark to get out of
   1161 		     * an infinate loop.
   1162 		     */
   1163 		    i = read(net, netiring.supply + c, canread - c);
   1164 		    if (i > 0)
   1165 			c += i;
   1166 		}
   1167 	    } else {
   1168 		c = recv(net, netiring.supply, canread, 0);
   1169 	    }
   1170 	} else {
   1171 	    c = recv(net, netiring.supply, canread, 0);
   1172 	}
   1173 	settimer(didnetreceive);
   1174 #else	/* !defined(SO_OOBINLINE) */
   1175 	c = recv(net, (char *)netiring.supply, canread, 0);
   1176 #endif	/* !defined(SO_OOBINLINE) */
   1177 	if (c < 0 && errno == EWOULDBLOCK) {
   1178 	    c = 0;
   1179 	} else if (c <= 0) {
   1180 	    return -1;
   1181 	}
   1182 	if (netdata) {
   1183 	    Dump('<', netiring.supply, c);
   1184 	}
   1185 	if (c)
   1186 	    ring_supplied(&netiring, c);
   1187 	returnValue = 1;
   1188     }
   1189 
   1190     /*
   1191      * Something to read from the tty...
   1192      */
   1193     if (FD_ISSET(tin, &ibits)) {
   1194 	FD_CLR(tin, &ibits);
   1195 	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
   1196 	if (c < 0 && errno == EIO)
   1197 	    c = 0;
   1198 	if (c < 0 && errno == EWOULDBLOCK) {
   1199 	    c = 0;
   1200 	} else {
   1201 	    if (c < 0) {
   1202 		return -1;
   1203 	    }
   1204 	    if (c == 0) {
   1205 		/* must be an EOF... */
   1206 		if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
   1207 		    *ttyiring.supply = termEofChar;
   1208 		    c = 1;
   1209 		} else {
   1210 		    clienteof = 1;
   1211 		    shutdown(net, 1);
   1212 		    return 0;
   1213 		}
   1214 	    }
   1215 	    if (termdata) {
   1216 		Dump('<', ttyiring.supply, c);
   1217 	    }
   1218 	    ring_supplied(&ttyiring, c);
   1219 	}
   1220 	returnValue = 1;		/* did something useful */
   1221     }
   1222 
   1223     if (FD_ISSET(net, &obits)) {
   1224 	FD_CLR(net, &obits);
   1225 	returnValue |= netflush();
   1226     }
   1227     if (FD_ISSET(tout, &obits)) {
   1228 	FD_CLR(tout, &obits);
   1229 	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
   1230     }
   1231 
   1232     return returnValue;
   1233 }
   1234