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