157416Smarkm/* 257416Smarkm * Copyright (c) 1988, 1990, 1993 357416Smarkm * The Regents of the University of California. All rights reserved. 457416Smarkm * 557416Smarkm * Redistribution and use in source and binary forms, with or without 657416Smarkm * modification, are permitted provided that the following conditions 757416Smarkm * are met: 857416Smarkm * 1. Redistributions of source code must retain the above copyright 957416Smarkm * notice, this list of conditions and the following disclaimer. 1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157416Smarkm * notice, this list of conditions and the following disclaimer in the 1257416Smarkm * documentation and/or other materials provided with the distribution. 1357416Smarkm * 3. All advertising materials mentioning features or use of this software 1457416Smarkm * must display the following acknowledgement: 1557416Smarkm * This product includes software developed by the University of 1657416Smarkm * California, Berkeley and its contributors. 1757416Smarkm * 4. Neither the name of the University nor the names of its contributors 1857416Smarkm * may be used to endorse or promote products derived from this software 1957416Smarkm * without specific prior written permission. 2057416Smarkm * 2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2457416Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3157416Smarkm * SUCH DAMAGE. 3257416Smarkm */ 3357416Smarkm 3457416Smarkm#include "telnet_locl.h" 3557416Smarkm 36178825SdfrRCSID("$Id: sys_bsd.c 10941 2002-04-18 16:18:43Z joda $"); 3757416Smarkm 3857416Smarkm/* 3957416Smarkm * The following routines try to encapsulate what is system dependent 4057416Smarkm * (at least between 4.x and dos) which is used in telnet.c. 4157416Smarkm */ 4257416Smarkm 4357416Smarkmint 4457416Smarkm tout, /* Output file descriptor */ 4557416Smarkm tin, /* Input file descriptor */ 4657416Smarkm net; 4757416Smarkm 4857416Smarkmstruct termios old_tc = { 0 }; 4957416Smarkmextern struct termios new_tc; 5057416Smarkm 5157416Smarkm# ifndef TCSANOW 5257416Smarkm# ifdef TCSETS 5357416Smarkm# define TCSANOW TCSETS 5457416Smarkm# define TCSADRAIN TCSETSW 5557416Smarkm# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) 5657416Smarkm# else 5757416Smarkm# ifdef TCSETA 5857416Smarkm# define TCSANOW TCSETA 5957416Smarkm# define TCSADRAIN TCSETAW 6057416Smarkm# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) 6157416Smarkm# else 6257416Smarkm# define TCSANOW TIOCSETA 6357416Smarkm# define TCSADRAIN TIOCSETAW 6457416Smarkm# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) 6557416Smarkm# endif 6657416Smarkm# endif 6757416Smarkm# define tcsetattr(f, a, t) ioctl(f, a, (char *)t) 6857416Smarkm# define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD) 6957416Smarkm# ifdef CIBAUD 7057416Smarkm# define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT) 7157416Smarkm# else 7257416Smarkm# define cfgetispeed(ptr) cfgetospeed(ptr) 7357416Smarkm# endif 7457416Smarkm# endif /* TCSANOW */ 7557416Smarkm 7657416Smarkmstatic fd_set ibits, obits, xbits; 7757416Smarkm 7857416Smarkm 7957416Smarkmvoid 8057416Smarkminit_sys(void) 8157416Smarkm{ 8257416Smarkm tout = fileno(stdout); 8357416Smarkm tin = fileno(stdin); 8457416Smarkm FD_ZERO(&ibits); 8557416Smarkm FD_ZERO(&obits); 8657416Smarkm FD_ZERO(&xbits); 8757416Smarkm 8857416Smarkm errno = 0; 8957416Smarkm} 9057416Smarkm 9157416Smarkm 9257416Smarkmint 9357416SmarkmTerminalWrite(char *buf, int n) 9457416Smarkm{ 9557416Smarkm return write(tout, buf, n); 9657416Smarkm} 9757416Smarkm 9857416Smarkmint 9957416SmarkmTerminalRead(unsigned char *buf, int n) 10057416Smarkm{ 10157416Smarkm return read(tin, buf, n); 10257416Smarkm} 10357416Smarkm 10457416Smarkm/* 10557416Smarkm * 10657416Smarkm */ 10757416Smarkm 10857416Smarkmint 10957416SmarkmTerminalAutoFlush(void) 11057416Smarkm{ 11157416Smarkm#if defined(LNOFLSH) 11257416Smarkm int flush; 11357416Smarkm 11457416Smarkm ioctl(0, TIOCLGET, (char *)&flush); 11557416Smarkm return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ 11657416Smarkm#else /* LNOFLSH */ 11757416Smarkm return 1; 11857416Smarkm#endif /* LNOFLSH */ 11957416Smarkm} 12057416Smarkm 12157416Smarkm/* 12257416Smarkm * TerminalSpecialChars() 12357416Smarkm * 12457416Smarkm * Look at an input character to see if it is a special character 12557416Smarkm * and decide what to do. 12657416Smarkm * 12757416Smarkm * Output: 12857416Smarkm * 12957416Smarkm * 0 Don't add this character. 13057416Smarkm * 1 Do add this character 13157416Smarkm */ 13257416Smarkm 13357416Smarkmint 13457416SmarkmTerminalSpecialChars(int c) 13557416Smarkm{ 13657416Smarkm if (c == termIntChar) { 13757416Smarkm intp(); 13857416Smarkm return 0; 13957416Smarkm } else if (c == termQuitChar) { 14057416Smarkm#ifdef KLUDGELINEMODE 14157416Smarkm if (kludgelinemode) 14257416Smarkm sendbrk(); 14357416Smarkm else 14457416Smarkm#endif 14557416Smarkm sendabort(); 14657416Smarkm return 0; 14757416Smarkm } else if (c == termEofChar) { 14857416Smarkm if (my_want_state_is_will(TELOPT_LINEMODE)) { 14957416Smarkm sendeof(); 15057416Smarkm return 0; 15157416Smarkm } 15257416Smarkm return 1; 15357416Smarkm } else if (c == termSuspChar) { 15457416Smarkm sendsusp(); 15557416Smarkm return(0); 15657416Smarkm } else if (c == termFlushChar) { 15757416Smarkm xmitAO(); /* Transmit Abort Output */ 15857416Smarkm return 0; 15957416Smarkm } else if (!MODE_LOCAL_CHARS(globalmode)) { 16057416Smarkm if (c == termKillChar) { 16157416Smarkm xmitEL(); 16257416Smarkm return 0; 16357416Smarkm } else if (c == termEraseChar) { 16457416Smarkm xmitEC(); /* Transmit Erase Character */ 16557416Smarkm return 0; 16657416Smarkm } 16757416Smarkm } 16857416Smarkm return 1; 16957416Smarkm} 17057416Smarkm 17157416Smarkm 17257416Smarkm/* 17357416Smarkm * Flush output to the terminal 17457416Smarkm */ 17557416Smarkm 17657416Smarkmvoid 17757416SmarkmTerminalFlushOutput(void) 17857416Smarkm{ 17957416Smarkm#ifdef TIOCFLUSH 18057416Smarkm ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 18157416Smarkm#else 18257416Smarkm ioctl(fileno(stdout), TCFLSH, (char *) 0); 18357416Smarkm#endif 18457416Smarkm} 18557416Smarkm 18657416Smarkmvoid 18757416SmarkmTerminalSaveState(void) 18857416Smarkm{ 18957416Smarkm tcgetattr(0, &old_tc); 19057416Smarkm 19157416Smarkm new_tc = old_tc; 19257416Smarkm 19357416Smarkm#ifndef VDISCARD 19457416Smarkm termFlushChar = CONTROL('O'); 19557416Smarkm#endif 19657416Smarkm#ifndef VWERASE 19757416Smarkm termWerasChar = CONTROL('W'); 19857416Smarkm#endif 19957416Smarkm#ifndef VREPRINT 20057416Smarkm termRprntChar = CONTROL('R'); 20157416Smarkm#endif 20257416Smarkm#ifndef VLNEXT 20357416Smarkm termLiteralNextChar = CONTROL('V'); 20457416Smarkm#endif 20557416Smarkm#ifndef VSTART 20657416Smarkm termStartChar = CONTROL('Q'); 20757416Smarkm#endif 20857416Smarkm#ifndef VSTOP 20957416Smarkm termStopChar = CONTROL('S'); 21057416Smarkm#endif 21157416Smarkm#ifndef VSTATUS 21257416Smarkm termAytChar = CONTROL('T'); 21357416Smarkm#endif 21457416Smarkm} 21557416Smarkm 21657416Smarkmcc_t* 21757416Smarkmtcval(int func) 21857416Smarkm{ 21957416Smarkm switch(func) { 22057416Smarkm case SLC_IP: return(&termIntChar); 22157416Smarkm case SLC_ABORT: return(&termQuitChar); 22257416Smarkm case SLC_EOF: return(&termEofChar); 22357416Smarkm case SLC_EC: return(&termEraseChar); 22457416Smarkm case SLC_EL: return(&termKillChar); 22557416Smarkm case SLC_XON: return(&termStartChar); 22657416Smarkm case SLC_XOFF: return(&termStopChar); 22757416Smarkm case SLC_FORW1: return(&termForw1Char); 22857416Smarkm case SLC_FORW2: return(&termForw2Char); 22957416Smarkm# ifdef VDISCARD 23057416Smarkm case SLC_AO: return(&termFlushChar); 23157416Smarkm# endif 23257416Smarkm# ifdef VSUSP 23357416Smarkm case SLC_SUSP: return(&termSuspChar); 23457416Smarkm# endif 23557416Smarkm# ifdef VWERASE 23657416Smarkm case SLC_EW: return(&termWerasChar); 23757416Smarkm# endif 23857416Smarkm# ifdef VREPRINT 23957416Smarkm case SLC_RP: return(&termRprntChar); 24057416Smarkm# endif 24157416Smarkm# ifdef VLNEXT 24257416Smarkm case SLC_LNEXT: return(&termLiteralNextChar); 24357416Smarkm# endif 24457416Smarkm# ifdef VSTATUS 24557416Smarkm case SLC_AYT: return(&termAytChar); 24657416Smarkm# endif 24757416Smarkm 24857416Smarkm case SLC_SYNCH: 24957416Smarkm case SLC_BRK: 25057416Smarkm case SLC_EOR: 25157416Smarkm default: 25257416Smarkm return((cc_t *)0); 25357416Smarkm } 25457416Smarkm} 25557416Smarkm 25657416Smarkmvoid 25757416SmarkmTerminalDefaultChars(void) 25857416Smarkm{ 25957416Smarkm memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); 26057416Smarkm# ifndef VDISCARD 26157416Smarkm termFlushChar = CONTROL('O'); 26257416Smarkm# endif 26357416Smarkm# ifndef VWERASE 26457416Smarkm termWerasChar = CONTROL('W'); 26557416Smarkm# endif 26657416Smarkm# ifndef VREPRINT 26757416Smarkm termRprntChar = CONTROL('R'); 26857416Smarkm# endif 26957416Smarkm# ifndef VLNEXT 27057416Smarkm termLiteralNextChar = CONTROL('V'); 27157416Smarkm# endif 27257416Smarkm# ifndef VSTART 27357416Smarkm termStartChar = CONTROL('Q'); 27457416Smarkm# endif 27557416Smarkm# ifndef VSTOP 27657416Smarkm termStopChar = CONTROL('S'); 27757416Smarkm# endif 27857416Smarkm# ifndef VSTATUS 27957416Smarkm termAytChar = CONTROL('T'); 28057416Smarkm# endif 28157416Smarkm} 28257416Smarkm 28357416Smarkm#ifdef notdef 28457416Smarkmvoid 28557416SmarkmTerminalRestoreState() 28657416Smarkm{ 28757416Smarkm} 28857416Smarkm#endif 28957416Smarkm 29057416Smarkm/* 29157416Smarkm * TerminalNewMode - set up terminal to a specific mode. 29257416Smarkm * MODE_ECHO: do local terminal echo 29357416Smarkm * MODE_FLOW: do local flow control 29457416Smarkm * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 29557416Smarkm * MODE_EDIT: do local line editing 29657416Smarkm * 29757416Smarkm * Command mode: 29857416Smarkm * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 29957416Smarkm * local echo 30057416Smarkm * local editing 30157416Smarkm * local xon/xoff 30257416Smarkm * local signal mapping 30357416Smarkm * 30457416Smarkm * Linemode: 30557416Smarkm * local/no editing 30657416Smarkm * Both Linemode and Single Character mode: 30757416Smarkm * local/remote echo 30857416Smarkm * local/no xon/xoff 30957416Smarkm * local/no signal mapping 31057416Smarkm */ 31157416Smarkm 31257416Smarkm 31357416Smarkm#ifdef SIGTSTP 31472445Sassarstatic RETSIGTYPE susp(int); 31557416Smarkm#endif /* SIGTSTP */ 31657416Smarkm#ifdef SIGINFO 31772445Sassarstatic RETSIGTYPE ayt(int); 31857416Smarkm#endif 31957416Smarkm 32057416Smarkmvoid 32157416SmarkmTerminalNewMode(int f) 32257416Smarkm{ 32357416Smarkm static int prevmode = 0; 32457416Smarkm struct termios tmp_tc; 32557416Smarkm int onoff; 32657416Smarkm int old; 32757416Smarkm cc_t esc; 32857416Smarkm 32957416Smarkm globalmode = f&~MODE_FORCE; 33057416Smarkm if (prevmode == f) 33157416Smarkm return; 33257416Smarkm 33357416Smarkm /* 33457416Smarkm * Write any outstanding data before switching modes 33557416Smarkm * ttyflush() returns 0 only when there is no more data 33657416Smarkm * left to write out, it returns -1 if it couldn't do 33757416Smarkm * anything at all, otherwise it returns 1 + the number 33857416Smarkm * of characters left to write. 33957416Smarkm */ 34057416Smarkm old = ttyflush(SYNCHing|flushout); 34157416Smarkm if (old < 0 || old > 1) { 34257416Smarkm tcgetattr(tin, &tmp_tc); 34357416Smarkm do { 34457416Smarkm /* 34557416Smarkm * Wait for data to drain, then flush again. 34657416Smarkm */ 34757416Smarkm tcsetattr(tin, TCSADRAIN, &tmp_tc); 34857416Smarkm old = ttyflush(SYNCHing|flushout); 34957416Smarkm } while (old < 0 || old > 1); 35057416Smarkm } 35157416Smarkm 35257416Smarkm old = prevmode; 35357416Smarkm prevmode = f&~MODE_FORCE; 35457416Smarkm tmp_tc = new_tc; 35557416Smarkm 35657416Smarkm if (f&MODE_ECHO) { 35757416Smarkm tmp_tc.c_lflag |= ECHO; 35857416Smarkm tmp_tc.c_oflag |= ONLCR; 35957416Smarkm if (crlf) 36057416Smarkm tmp_tc.c_iflag |= ICRNL; 36157416Smarkm } else { 36257416Smarkm tmp_tc.c_lflag &= ~ECHO; 36357416Smarkm tmp_tc.c_oflag &= ~ONLCR; 36457416Smarkm# ifdef notdef 36557416Smarkm if (crlf) 36657416Smarkm tmp_tc.c_iflag &= ~ICRNL; 36757416Smarkm# endif 36857416Smarkm } 36957416Smarkm 37057416Smarkm if ((f&MODE_FLOW) == 0) { 37157416Smarkm tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */ 37257416Smarkm } else { 37357416Smarkm if (restartany < 0) { 37457416Smarkm tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */ 37557416Smarkm } else if (restartany > 0) { 37657416Smarkm tmp_tc.c_iflag |= IXOFF|IXON|IXANY; 37757416Smarkm } else { 37857416Smarkm tmp_tc.c_iflag |= IXOFF|IXON; 37957416Smarkm tmp_tc.c_iflag &= ~IXANY; 38057416Smarkm } 38157416Smarkm } 38257416Smarkm 38357416Smarkm if ((f&MODE_TRAPSIG) == 0) { 38457416Smarkm tmp_tc.c_lflag &= ~ISIG; 38557416Smarkm localchars = 0; 38657416Smarkm } else { 38757416Smarkm tmp_tc.c_lflag |= ISIG; 38857416Smarkm localchars = 1; 38957416Smarkm } 39057416Smarkm 39157416Smarkm if (f&MODE_EDIT) { 39257416Smarkm tmp_tc.c_lflag |= ICANON; 39357416Smarkm } else { 39457416Smarkm tmp_tc.c_lflag &= ~ICANON; 39557416Smarkm tmp_tc.c_iflag &= ~ICRNL; 39657416Smarkm tmp_tc.c_cc[VMIN] = 1; 39757416Smarkm tmp_tc.c_cc[VTIME] = 0; 39857416Smarkm } 39957416Smarkm 40057416Smarkm if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { 40157416Smarkm# ifdef VLNEXT 40257416Smarkm tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE); 40357416Smarkm# endif 40457416Smarkm } 40557416Smarkm 40657416Smarkm if (f&MODE_SOFT_TAB) { 40757416Smarkm# ifdef OXTABS 40857416Smarkm tmp_tc.c_oflag |= OXTABS; 40957416Smarkm# endif 41057416Smarkm# ifdef TABDLY 41157416Smarkm tmp_tc.c_oflag &= ~TABDLY; 41257416Smarkm tmp_tc.c_oflag |= TAB3; 41357416Smarkm# endif 41457416Smarkm } else { 41557416Smarkm# ifdef OXTABS 41657416Smarkm tmp_tc.c_oflag &= ~OXTABS; 41757416Smarkm# endif 41857416Smarkm# ifdef TABDLY 41957416Smarkm tmp_tc.c_oflag &= ~TABDLY; 42057416Smarkm# endif 42157416Smarkm } 42257416Smarkm 42357416Smarkm if (f&MODE_LIT_ECHO) { 42457416Smarkm# ifdef ECHOCTL 42557416Smarkm tmp_tc.c_lflag &= ~ECHOCTL; 42657416Smarkm# endif 42757416Smarkm } else { 42857416Smarkm# ifdef ECHOCTL 42957416Smarkm tmp_tc.c_lflag |= ECHOCTL; 43057416Smarkm# endif 43157416Smarkm } 43257416Smarkm 43357416Smarkm if (f == -1) { 43457416Smarkm onoff = 0; 43557416Smarkm } else { 43657416Smarkm if (f & MODE_INBIN) 43757416Smarkm tmp_tc.c_iflag &= ~ISTRIP; 43857416Smarkm else 43957416Smarkm tmp_tc.c_iflag |= ISTRIP; 44057416Smarkm if ((f & MODE_OUTBIN) || (f & MODE_OUT8)) { 44157416Smarkm tmp_tc.c_cflag &= ~(CSIZE|PARENB); 44257416Smarkm tmp_tc.c_cflag |= CS8; 44357416Smarkm if(f & MODE_OUTBIN) 44457416Smarkm tmp_tc.c_oflag &= ~OPOST; 44557416Smarkm else 44657416Smarkm tmp_tc.c_oflag |= OPOST; 44757416Smarkm } else { 44857416Smarkm tmp_tc.c_cflag &= ~(CSIZE|PARENB); 44957416Smarkm tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB); 45057416Smarkm tmp_tc.c_oflag |= OPOST; 45157416Smarkm } 45257416Smarkm onoff = 1; 45357416Smarkm } 45457416Smarkm 45557416Smarkm if (f != -1) { 45657416Smarkm 45757416Smarkm#ifdef SIGTSTP 45857416Smarkm signal(SIGTSTP, susp); 45957416Smarkm#endif /* SIGTSTP */ 46057416Smarkm#ifdef SIGINFO 46157416Smarkm signal(SIGINFO, ayt); 46257416Smarkm#endif 46357416Smarkm#ifdef NOKERNINFO 46457416Smarkm tmp_tc.c_lflag |= NOKERNINFO; 46557416Smarkm#endif 46657416Smarkm /* 46757416Smarkm * We don't want to process ^Y here. It's just another 46857416Smarkm * character that we'll pass on to the back end. It has 46957416Smarkm * to process it because it will be processed when the 47057416Smarkm * user attempts to read it, not when we send it. 47157416Smarkm */ 47257416Smarkm# ifdef VDSUSP 47357416Smarkm tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE); 47457416Smarkm# endif 47557416Smarkm /* 47657416Smarkm * If the VEOL character is already set, then use VEOL2, 47757416Smarkm * otherwise use VEOL. 47857416Smarkm */ 47957416Smarkm esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape; 48057416Smarkm if ((tmp_tc.c_cc[VEOL] != esc) 48157416Smarkm# ifdef VEOL2 48257416Smarkm && (tmp_tc.c_cc[VEOL2] != esc) 48357416Smarkm# endif 48457416Smarkm ) { 48557416Smarkm if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE)) 48657416Smarkm tmp_tc.c_cc[VEOL] = esc; 48757416Smarkm# ifdef VEOL2 48857416Smarkm else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE)) 48957416Smarkm tmp_tc.c_cc[VEOL2] = esc; 49057416Smarkm# endif 49157416Smarkm } 49257416Smarkm } else { 49357416Smarkm sigset_t sm; 49490926Snectar 49557416Smarkm#ifdef SIGINFO 49657416Smarkm signal(SIGINFO, ayt_status); 49757416Smarkm#endif 49857416Smarkm#ifdef SIGTSTP 49957416Smarkm signal(SIGTSTP, SIG_DFL); 50057416Smarkm sigemptyset(&sm); 50157416Smarkm sigaddset(&sm, SIGTSTP); 50257416Smarkm sigprocmask(SIG_UNBLOCK, &sm, NULL); 50357416Smarkm#endif /* SIGTSTP */ 50457416Smarkm tmp_tc = old_tc; 50557416Smarkm } 50657416Smarkm if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) 50757416Smarkm tcsetattr(tin, TCSANOW, &tmp_tc); 50857416Smarkm 50957416Smarkm ioctl(tin, FIONBIO, (char *)&onoff); 51057416Smarkm ioctl(tout, FIONBIO, (char *)&onoff); 51157416Smarkm 51257416Smarkm} 51357416Smarkm 51457416Smarkm/* 51557416Smarkm * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). 51657416Smarkm */ 51757416Smarkm#if B4800 != 4800 51857416Smarkm#define DECODE_BAUD 51957416Smarkm#endif 52057416Smarkm 52157416Smarkm#ifdef DECODE_BAUD 52257416Smarkm#ifndef B7200 52357416Smarkm#define B7200 B4800 52457416Smarkm#endif 52557416Smarkm 52657416Smarkm#ifndef B14400 52757416Smarkm#define B14400 B9600 52857416Smarkm#endif 52957416Smarkm 53057416Smarkm#ifndef B19200 53157416Smarkm# define B19200 B14400 53257416Smarkm#endif 53357416Smarkm 53457416Smarkm#ifndef B28800 53557416Smarkm#define B28800 B19200 53657416Smarkm#endif 53757416Smarkm 53857416Smarkm#ifndef B38400 53957416Smarkm# define B38400 B28800 54057416Smarkm#endif 54157416Smarkm 54257416Smarkm#ifndef B57600 54357416Smarkm#define B57600 B38400 54457416Smarkm#endif 54557416Smarkm 54657416Smarkm#ifndef B76800 54757416Smarkm#define B76800 B57600 54857416Smarkm#endif 54957416Smarkm 55057416Smarkm#ifndef B115200 55157416Smarkm#define B115200 B76800 55257416Smarkm#endif 55357416Smarkm 55457416Smarkm#ifndef B230400 55557416Smarkm#define B230400 B115200 55657416Smarkm#endif 55757416Smarkm 55857416Smarkm 55957416Smarkm/* 56057416Smarkm * This code assumes that the values B0, B50, B75... 56157416Smarkm * are in ascending order. They do not have to be 56257416Smarkm * contiguous. 56357416Smarkm */ 56457416Smarkmstruct termspeeds { 56557416Smarkm long speed; 56657416Smarkm long value; 56757416Smarkm} termspeeds[] = { 56857416Smarkm { 0, B0 }, { 50, B50 }, { 75, B75 }, 56957416Smarkm { 110, B110 }, { 134, B134 }, { 150, B150 }, 57057416Smarkm { 200, B200 }, { 300, B300 }, { 600, B600 }, 57157416Smarkm { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 57257416Smarkm { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 }, 57357416Smarkm { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 }, 57457416Smarkm { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 }, 57557416Smarkm { 230400, B230400 }, { -1, B230400 } 57657416Smarkm}; 57757416Smarkm#endif /* DECODE_BAUD */ 57857416Smarkm 57957416Smarkmvoid 58057416SmarkmTerminalSpeeds(long *input_speed, long *output_speed) 58157416Smarkm{ 58257416Smarkm#ifdef DECODE_BAUD 58357416Smarkm struct termspeeds *tp; 58457416Smarkm#endif /* DECODE_BAUD */ 58557416Smarkm long in, out; 58657416Smarkm 58757416Smarkm out = cfgetospeed(&old_tc); 58857416Smarkm in = cfgetispeed(&old_tc); 58957416Smarkm if (in == 0) 59057416Smarkm in = out; 59157416Smarkm 59257416Smarkm#ifdef DECODE_BAUD 59357416Smarkm tp = termspeeds; 59457416Smarkm while ((tp->speed != -1) && (tp->value < in)) 59557416Smarkm tp++; 59657416Smarkm *input_speed = tp->speed; 59757416Smarkm 59857416Smarkm tp = termspeeds; 59957416Smarkm while ((tp->speed != -1) && (tp->value < out)) 60057416Smarkm tp++; 60157416Smarkm *output_speed = tp->speed; 60257416Smarkm#else /* DECODE_BAUD */ 60357416Smarkm *input_speed = in; 60457416Smarkm *output_speed = out; 60557416Smarkm#endif /* DECODE_BAUD */ 60657416Smarkm} 60757416Smarkm 60857416Smarkmint 60957416SmarkmTerminalWindowSize(long *rows, long *cols) 61057416Smarkm{ 61157416Smarkm struct winsize ws; 61257416Smarkm 61357416Smarkm if (get_window_size (STDIN_FILENO, &ws) == 0) { 61457416Smarkm *rows = ws.ws_row; 61557416Smarkm *cols = ws.ws_col; 61657416Smarkm return 1; 61757416Smarkm } else 61857416Smarkm return 0; 61957416Smarkm} 62057416Smarkm 62157416Smarkmint 62257416SmarkmNetClose(int fd) 62357416Smarkm{ 62457416Smarkm return close(fd); 62557416Smarkm} 62657416Smarkm 62757416Smarkm 62857416Smarkmvoid 62957416SmarkmNetNonblockingIO(int fd, int onoff) 63057416Smarkm{ 63157416Smarkm ioctl(fd, FIONBIO, (char *)&onoff); 63257416Smarkm} 63357416Smarkm 63457416Smarkm 63557416Smarkm/* 63657416Smarkm * Various signal handling routines. 63757416Smarkm */ 63857416Smarkm 63957416Smarkmstatic RETSIGTYPE deadpeer(int), 64057416Smarkm intr(int), intr2(int), susp(int), sendwin(int); 64157416Smarkm#ifdef SIGINFO 64257416Smarkmstatic RETSIGTYPE ayt(int); 64357416Smarkm#endif 64457416Smarkm 64557416Smarkm 64657416Smarkm /* ARGSUSED */ 64757416Smarkmstatic RETSIGTYPE 64857416Smarkmdeadpeer(int sig) 64957416Smarkm{ 65057416Smarkm setcommandmode(); 65157416Smarkm longjmp(peerdied, -1); 65257416Smarkm} 65357416Smarkm 65490926Snectarint intr_happened = 0; 65590926Snectarint intr_waiting = 0; 65690926Snectar 65757416Smarkm /* ARGSUSED */ 65857416Smarkmstatic RETSIGTYPE 65957416Smarkmintr(int sig) 66057416Smarkm{ 66190926Snectar if (intr_waiting) { 66290926Snectar intr_happened = 1; 66390926Snectar return; 66490926Snectar } 66557416Smarkm if (localchars) { 66657416Smarkm intp(); 66757416Smarkm return; 66857416Smarkm } 66957416Smarkm setcommandmode(); 67057416Smarkm longjmp(toplevel, -1); 67157416Smarkm} 67257416Smarkm 67357416Smarkm /* ARGSUSED */ 67457416Smarkmstatic RETSIGTYPE 67557416Smarkmintr2(int sig) 67657416Smarkm{ 67757416Smarkm if (localchars) { 67857416Smarkm#ifdef KLUDGELINEMODE 67957416Smarkm if (kludgelinemode) 68057416Smarkm sendbrk(); 68157416Smarkm else 68257416Smarkm#endif 68357416Smarkm sendabort(); 68457416Smarkm return; 68557416Smarkm } 68657416Smarkm} 68757416Smarkm 68857416Smarkm#ifdef SIGTSTP 68957416Smarkm /* ARGSUSED */ 69057416Smarkmstatic RETSIGTYPE 69157416Smarkmsusp(int sig) 69257416Smarkm{ 69357416Smarkm if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) 69457416Smarkm return; 69557416Smarkm if (localchars) 69657416Smarkm sendsusp(); 69757416Smarkm} 69857416Smarkm#endif 69957416Smarkm 70057416Smarkm#ifdef SIGWINCH 70157416Smarkm /* ARGSUSED */ 70257416Smarkmstatic RETSIGTYPE 70357416Smarkmsendwin(int sig) 70457416Smarkm{ 70557416Smarkm if (connected) { 70657416Smarkm sendnaws(); 70757416Smarkm } 70857416Smarkm} 70957416Smarkm#endif 71057416Smarkm 71157416Smarkm#ifdef SIGINFO 71257416Smarkm /* ARGSUSED */ 71357416Smarkmstatic RETSIGTYPE 71457416Smarkmayt(int sig) 71557416Smarkm{ 71657416Smarkm if (connected) 71757416Smarkm sendayt(); 71857416Smarkm else 71957416Smarkm ayt_status(sig); 72057416Smarkm} 72157416Smarkm#endif 72257416Smarkm 72357416Smarkm 72457416Smarkmvoid 72557416Smarkmsys_telnet_init(void) 72657416Smarkm{ 72757416Smarkm signal(SIGINT, intr); 72857416Smarkm signal(SIGQUIT, intr2); 72957416Smarkm signal(SIGPIPE, deadpeer); 73057416Smarkm#ifdef SIGWINCH 73157416Smarkm signal(SIGWINCH, sendwin); 73257416Smarkm#endif 73357416Smarkm#ifdef SIGTSTP 73457416Smarkm signal(SIGTSTP, susp); 73557416Smarkm#endif 73657416Smarkm#ifdef SIGINFO 73757416Smarkm signal(SIGINFO, ayt); 73857416Smarkm#endif 73957416Smarkm 74057416Smarkm setconnmode(0); 74157416Smarkm 74257416Smarkm NetNonblockingIO(net, 1); 74357416Smarkm 74457416Smarkm 74557416Smarkm#if defined(SO_OOBINLINE) 746102644Snectar if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) 747102644Snectar perror("setsockopt (SO_OOBINLINE) (ignored)"); 74857416Smarkm#endif /* defined(SO_OOBINLINE) */ 74957416Smarkm} 75057416Smarkm 75157416Smarkm/* 75257416Smarkm * Process rings - 75357416Smarkm * 75457416Smarkm * This routine tries to fill up/empty our various rings. 75557416Smarkm * 75657416Smarkm * The parameter specifies whether this is a poll operation, 75757416Smarkm * or a block-until-something-happens operation. 75857416Smarkm * 75957416Smarkm * The return value is 1 if something happened, 0 if not. 76057416Smarkm */ 76157416Smarkm 76257416Smarkmint 76357416Smarkmprocess_rings(int netin, 76457416Smarkm int netout, 76557416Smarkm int netex, 76657416Smarkm int ttyin, 76757416Smarkm int ttyout, 76857416Smarkm int poll) /* If 0, then block until something to do */ 76957416Smarkm{ 77057416Smarkm int c; 77157416Smarkm /* One wants to be a bit careful about setting returnValue 77257416Smarkm * to one, since a one implies we did some useful work, 77357416Smarkm * and therefore probably won't be called to block next 77457416Smarkm * time (TN3270 mode only). 77557416Smarkm */ 77657416Smarkm int returnValue = 0; 77757416Smarkm static struct timeval TimeValue = { 0 }; 77857416Smarkm 77972445Sassar if (net >= FD_SETSIZE 78072445Sassar || tout >= FD_SETSIZE 78172445Sassar || tin >= FD_SETSIZE) 78272445Sassar errx (1, "fd too large"); 78372445Sassar 78457416Smarkm if (netout) { 78557416Smarkm FD_SET(net, &obits); 78657416Smarkm } 78757416Smarkm if (ttyout) { 78857416Smarkm FD_SET(tout, &obits); 78957416Smarkm } 79057416Smarkm if (ttyin) { 79157416Smarkm FD_SET(tin, &ibits); 79257416Smarkm } 79357416Smarkm if (netin) { 79457416Smarkm FD_SET(net, &ibits); 79557416Smarkm } 79657416Smarkm#if !defined(SO_OOBINLINE) 79757416Smarkm if (netex) { 79857416Smarkm FD_SET(net, &xbits); 79957416Smarkm } 80057416Smarkm#endif 80172445Sassar if ((c = select(FD_SETSIZE, &ibits, &obits, &xbits, 80257416Smarkm (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { 80357416Smarkm if (c == -1) { 80457416Smarkm /* 80557416Smarkm * we can get EINTR if we are in line mode, 80657416Smarkm * and the user does an escape (TSTP), or 80757416Smarkm * some other signal generator. 80857416Smarkm */ 80957416Smarkm if (errno == EINTR) { 81057416Smarkm return 0; 81157416Smarkm } 81257416Smarkm /* I don't like this, does it ever happen? */ 81357416Smarkm printf("sleep(5) from telnet, after select\r\n"); 81457416Smarkm sleep(5); 81557416Smarkm } 81657416Smarkm return 0; 81757416Smarkm } 81857416Smarkm 81957416Smarkm /* 82057416Smarkm * Any urgent data? 82157416Smarkm */ 82257416Smarkm if (FD_ISSET(net, &xbits)) { 82357416Smarkm FD_CLR(net, &xbits); 82457416Smarkm SYNCHing = 1; 82557416Smarkm ttyflush(1); /* flush already enqueued data */ 82657416Smarkm } 82757416Smarkm 82857416Smarkm /* 82957416Smarkm * Something to read from the network... 83057416Smarkm */ 83157416Smarkm if (FD_ISSET(net, &ibits)) { 83257416Smarkm int canread; 83357416Smarkm 83457416Smarkm FD_CLR(net, &ibits); 83557416Smarkm canread = ring_empty_consecutive(&netiring); 83657416Smarkm#if !defined(SO_OOBINLINE) 83757416Smarkm /* 83857416Smarkm * In 4.2 (and some early 4.3) systems, the 83957416Smarkm * OOB indication and data handling in the kernel 84057416Smarkm * is such that if two separate TCP Urgent requests 84157416Smarkm * come in, one byte of TCP data will be overlaid. 84257416Smarkm * This is fatal for Telnet, but we try to live 84357416Smarkm * with it. 84457416Smarkm * 84557416Smarkm * In addition, in 4.2 (and...), a special protocol 84657416Smarkm * is needed to pick up the TCP Urgent data in 84757416Smarkm * the correct sequence. 84857416Smarkm * 84957416Smarkm * What we do is: if we think we are in urgent 85057416Smarkm * mode, we look to see if we are "at the mark". 85157416Smarkm * If we are, we do an OOB receive. If we run 85257416Smarkm * this twice, we will do the OOB receive twice, 85357416Smarkm * but the second will fail, since the second 85457416Smarkm * time we were "at the mark", but there wasn't 85557416Smarkm * any data there (the kernel doesn't reset 85657416Smarkm * "at the mark" until we do a normal read). 85757416Smarkm * Once we've read the OOB data, we go ahead 85857416Smarkm * and do normal reads. 85957416Smarkm * 86057416Smarkm * There is also another problem, which is that 86157416Smarkm * since the OOB byte we read doesn't put us 86257416Smarkm * out of OOB state, and since that byte is most 86357416Smarkm * likely the TELNET DM (data mark), we would 86457416Smarkm * stay in the TELNET SYNCH (SYNCHing) state. 86557416Smarkm * So, clocks to the rescue. If we've "just" 86657416Smarkm * received a DM, then we test for the 86757416Smarkm * presence of OOB data when the receive OOB 86857416Smarkm * fails (and AFTER we did the normal mode read 86957416Smarkm * to clear "at the mark"). 87057416Smarkm */ 87157416Smarkm if (SYNCHing) { 87257416Smarkm int atmark; 87357416Smarkm static int bogus_oob = 0, first = 1; 87457416Smarkm 87557416Smarkm ioctl(net, SIOCATMARK, (char *)&atmark); 87657416Smarkm if (atmark) { 87757416Smarkm c = recv(net, netiring.supply, canread, MSG_OOB); 87857416Smarkm if ((c == -1) && (errno == EINVAL)) { 87957416Smarkm c = recv(net, netiring.supply, canread, 0); 88057416Smarkm if (clocks.didnetreceive < clocks.gotDM) { 88157416Smarkm SYNCHing = stilloob(); 88257416Smarkm } 88357416Smarkm } else if (first && c > 0) { 88457416Smarkm /* 88557416Smarkm * Bogosity check. Systems based on 4.2BSD 88657416Smarkm * do not return an error if you do a second 88757416Smarkm * recv(MSG_OOB). So, we do one. If it 88857416Smarkm * succeeds and returns exactly the same 88957416Smarkm * data, then assume that we are running 89057416Smarkm * on a broken system and set the bogus_oob 89157416Smarkm * flag. (If the data was different, then 89257416Smarkm * we probably got some valid new data, so 89357416Smarkm * increment the count...) 89457416Smarkm */ 89557416Smarkm int i; 89657416Smarkm i = recv(net, netiring.supply + c, canread - c, MSG_OOB); 89757416Smarkm if (i == c && 89857416Smarkm memcmp(netiring.supply, netiring.supply + c, i) == 0) { 89957416Smarkm bogus_oob = 1; 90057416Smarkm first = 0; 90157416Smarkm } else if (i < 0) { 90257416Smarkm bogus_oob = 0; 90357416Smarkm first = 0; 90457416Smarkm } else 90557416Smarkm c += i; 90657416Smarkm } 90757416Smarkm if (bogus_oob && c > 0) { 90857416Smarkm int i; 90957416Smarkm /* 91057416Smarkm * Bogosity. We have to do the read 91157416Smarkm * to clear the atmark to get out of 91257416Smarkm * an infinate loop. 91357416Smarkm */ 91457416Smarkm i = read(net, netiring.supply + c, canread - c); 91557416Smarkm if (i > 0) 91657416Smarkm c += i; 91757416Smarkm } 91857416Smarkm } else { 91957416Smarkm c = recv(net, netiring.supply, canread, 0); 92057416Smarkm } 92157416Smarkm } else { 92257416Smarkm c = recv(net, netiring.supply, canread, 0); 92357416Smarkm } 92457416Smarkm settimer(didnetreceive); 92557416Smarkm#else /* !defined(SO_OOBINLINE) */ 92657416Smarkm c = recv(net, (char *)netiring.supply, canread, 0); 92757416Smarkm#endif /* !defined(SO_OOBINLINE) */ 92857416Smarkm if (c < 0 && errno == EWOULDBLOCK) { 92957416Smarkm c = 0; 93057416Smarkm } else if (c <= 0) { 93157416Smarkm return -1; 93257416Smarkm } 93357416Smarkm if (netdata) { 93457416Smarkm Dump('<', netiring.supply, c); 93557416Smarkm } 93657416Smarkm if (c) 93757416Smarkm ring_supplied(&netiring, c); 93857416Smarkm returnValue = 1; 93957416Smarkm } 94057416Smarkm 94157416Smarkm /* 94257416Smarkm * Something to read from the tty... 94357416Smarkm */ 94457416Smarkm if (FD_ISSET(tin, &ibits)) { 94557416Smarkm FD_CLR(tin, &ibits); 94657416Smarkm c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 94757416Smarkm if (c < 0 && errno == EIO) 94857416Smarkm c = 0; 94957416Smarkm if (c < 0 && errno == EWOULDBLOCK) { 95057416Smarkm c = 0; 95157416Smarkm } else { 95257416Smarkm /* EOF detection for line mode!!!! */ 95357416Smarkm if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 95457416Smarkm /* must be an EOF... */ 95557416Smarkm *ttyiring.supply = termEofChar; 95657416Smarkm c = 1; 95757416Smarkm } 95857416Smarkm if (c <= 0) { 95957416Smarkm return -1; 96057416Smarkm } 96157416Smarkm if (termdata) { 96257416Smarkm Dump('<', ttyiring.supply, c); 96357416Smarkm } 96457416Smarkm ring_supplied(&ttyiring, c); 96557416Smarkm } 96657416Smarkm returnValue = 1; /* did something useful */ 96757416Smarkm } 96857416Smarkm 96957416Smarkm if (FD_ISSET(net, &obits)) { 97057416Smarkm FD_CLR(net, &obits); 97157416Smarkm returnValue |= netflush(); 97257416Smarkm } 97357416Smarkm if (FD_ISSET(tout, &obits)) { 97457416Smarkm FD_CLR(tout, &obits); 97557416Smarkm returnValue |= (ttyflush(SYNCHing|flushout) > 0); 97657416Smarkm } 97757416Smarkm 97857416Smarkm return returnValue; 97957416Smarkm} 980