132147Sminshall /* 233685Sbostic * Copyright (c) 1988 Regents of the University of California. 333685Sbostic * All rights reserved. 433685Sbostic * 533685Sbostic * Redistribution and use in source and binary forms are permitted 634898Sbostic * provided that the above copyright notice and this paragraph are 734898Sbostic * duplicated in all such forms and that any documentation, 834898Sbostic * advertising materials, and other materials related to such 934898Sbostic * distribution and use acknowledge that the software was developed 1034898Sbostic * by the University of California, Berkeley. The name of the 1134898Sbostic * University may not be used to endorse or promote products derived 1234898Sbostic * from this software without specific prior written permission. 1334898Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434898Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534898Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633685Sbostic */ 1733685Sbostic 1833685Sbostic #ifndef lint 19*40245Sborman static char sccsid[] = "@(#)sys_bsd.c 1.24 (Berkeley) 03/01/90"; 2033685Sbostic #endif /* not lint */ 2133685Sbostic 2233685Sbostic /* 2332147Sminshall * The following routines try to encapsulate what is system dependent 2432147Sminshall * (at least between 4.x and dos) which is used in telnet.c. 2532147Sminshall */ 2632147Sminshall 2732147Sminshall 2836274Sminshall #include <fcntl.h> 2932381Sminshall #include <sys/types.h> 3032147Sminshall #include <sys/time.h> 3132531Sminshall #include <sys/socket.h> 3232147Sminshall #include <signal.h> 3332531Sminshall #include <errno.h> 3438689Sborman #include <arpa/telnet.h> 3532147Sminshall 3632381Sminshall #include "ring.h" 3732381Sminshall 3832657Sminshall #include "fdset.h" 3932657Sminshall 4032147Sminshall #include "defines.h" 4132147Sminshall #include "externs.h" 4232147Sminshall #include "types.h" 4332147Sminshall 44*40245Sborman #if defined(CRAY) 45*40245Sborman #define SIG_FUNC_RET void 46*40245Sborman #else 47*40245Sborman #define SIG_FUNC_RET int 48*40245Sborman #endif 49*40245Sborman 5032147Sminshall int 5132531Sminshall tout, /* Output file descriptor */ 5232531Sminshall tin, /* Input file descriptor */ 5336242Sminshall net; 5432147Sminshall 5538689Sborman #ifndef USE_TERMIO 5638689Sborman struct tchars otc = { 0 }, ntc = { 0 }; 5738689Sborman struct ltchars oltc = { 0 }, nltc = { 0 }; 5838689Sborman struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 5938909Sborman int olmode = 0; 6032147Sminshall 6138689Sborman #else /* USE_TERMIO */ 6238689Sborman struct termio old_tc = { 0 }; 6338689Sborman extern struct termio new_tc; 6438689Sborman 65*40245Sborman #ifndef TCGETA 66*40245Sborman #define TCGETA TIOCGETA 67*40245Sborman #define TCSETA TIOCSETA 68*40245Sborman #define TCSETAW TIOCSETAW 69*40245Sborman #endif /* TCGETA */ 7038689Sborman #endif /* USE_TERMIO */ 7138689Sborman 7232531Sminshall static fd_set ibits, obits, xbits; 7332147Sminshall 7432531Sminshall 7532531Sminshall init_sys() 7632531Sminshall { 7732531Sminshall tout = fileno(stdout); 7832531Sminshall tin = fileno(stdin); 7932531Sminshall FD_ZERO(&ibits); 8032531Sminshall FD_ZERO(&obits); 8132531Sminshall FD_ZERO(&xbits); 8232531Sminshall 8332531Sminshall errno = 0; 8432531Sminshall } 8532531Sminshall 8632531Sminshall 8733286Sminshall TerminalWrite(buf, n) 8832147Sminshall char *buf; 8932147Sminshall int n; 9032147Sminshall { 9133286Sminshall return write(tout, buf, n); 9232147Sminshall } 9332147Sminshall 9433286Sminshall TerminalRead(buf, n) 9532147Sminshall char *buf; 9632147Sminshall int n; 9732147Sminshall { 9833286Sminshall return read(tin, buf, n); 9932147Sminshall } 10032147Sminshall 10132147Sminshall /* 10232147Sminshall * 10332147Sminshall */ 10432147Sminshall 10532147Sminshall int 10632553Sminshall TerminalAutoFlush() 10732147Sminshall { 10832147Sminshall #if defined(LNOFLSH) 10932147Sminshall int flush; 11032147Sminshall 11132147Sminshall ioctl(0, TIOCLGET, (char *)&flush); 11232147Sminshall return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ 11332147Sminshall #else /* LNOFLSH */ 11432147Sminshall return 1; 11532147Sminshall #endif /* LNOFLSH */ 11632147Sminshall } 11732147Sminshall 11838689Sborman #ifdef KLUDGELINEMODE 11938689Sborman extern int kludgelinemode; 12038689Sborman #endif 12132147Sminshall /* 12232147Sminshall * TerminalSpecialChars() 12332147Sminshall * 12432147Sminshall * Look at an input character to see if it is a special character 12532147Sminshall * and decide what to do. 12632147Sminshall * 12732147Sminshall * Output: 12832147Sminshall * 12932147Sminshall * 0 Don't add this character. 13032147Sminshall * 1 Do add this character 13132147Sminshall */ 13232147Sminshall 13332147Sminshall int 13432553Sminshall TerminalSpecialChars(c) 13532147Sminshall int c; 13632147Sminshall { 13732553Sminshall void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); 13832147Sminshall 13938689Sborman if (c == termIntChar) { 14032147Sminshall intp(); 14132147Sminshall return 0; 14238689Sborman } else if (c == termQuitChar) { 14338689Sborman #ifdef KLUDGELINEMODE 14438689Sborman if (kludgelinemode) 14538689Sborman sendbrk(); 14638689Sborman else 14738689Sborman #endif 14838689Sborman sendabort(); 14932147Sminshall return 0; 15038689Sborman } else if (c == termEofChar) { 15138689Sborman if (my_want_state_is_will(TELOPT_LINEMODE)) { 15238689Sborman sendeof(); 15338689Sborman return 0; 15438689Sborman } 15538689Sborman return 1; 15638689Sborman } else if (c == termSuspChar) { 15738689Sborman sendsusp(); 15838689Sborman return(0); 15938689Sborman } else if (c == termFlushChar) { 16032147Sminshall xmitAO(); /* Transmit Abort Output */ 16132147Sminshall return 0; 16232147Sminshall } else if (!MODE_LOCAL_CHARS(globalmode)) { 16338689Sborman if (c == termKillChar) { 16432147Sminshall xmitEL(); 16532147Sminshall return 0; 16638689Sborman } else if (c == termEraseChar) { 16732147Sminshall xmitEC(); /* Transmit Erase Character */ 16832147Sminshall return 0; 16932147Sminshall } 17032147Sminshall } 17132147Sminshall return 1; 17232147Sminshall } 17332147Sminshall 17432147Sminshall 17532147Sminshall /* 17632147Sminshall * Flush output to the terminal 17732147Sminshall */ 17832147Sminshall 17932147Sminshall void 18032553Sminshall TerminalFlushOutput() 18132147Sminshall { 18239529Sborman #ifdef TIOCFLUSH 18332147Sminshall (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 18438689Sborman #else 18538689Sborman (void) ioctl(fileno(stdout), TCFLSH, (char *) 0); 18638689Sborman #endif 18732147Sminshall } 18832147Sminshall 18932147Sminshall void 19032553Sminshall TerminalSaveState() 19132147Sminshall { 19238689Sborman #ifndef USE_TERMIO 19332147Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 19432147Sminshall ioctl(0, TIOCGETC, (char *)&otc); 19532147Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 19638909Sborman ioctl(0, TIOCLGET, (char *)&olmode); 19732147Sminshall 19832147Sminshall ntc = otc; 19932147Sminshall nltc = oltc; 20032147Sminshall nttyb = ottyb; 20132254Sminshall 20238689Sborman #else /* USE_TERMIO */ 20338689Sborman ioctl(0, TCGETA, &old_tc); 20438689Sborman 20538689Sborman new_tc = old_tc; 20638689Sborman 20738689Sborman termFlushChar = 'O'&0x37; 20838689Sborman termWerasChar = 'W'&0x37; 20938689Sborman termRprntChar = 'R'&0x37; 21038689Sborman termLiteralNextChar = 'V'&0x37; 21138689Sborman termStartChar = 'Q'&0x37; 21238689Sborman termStopChar = 'S'&0x37; 21338689Sborman #endif /* USE_TERMIO */ 21432147Sminshall } 21532147Sminshall 216*40245Sborman cc_t * 21738689Sborman tcval(func) 21838689Sborman register int func; 21938689Sborman { 22038689Sborman switch(func) { 221*40245Sborman case SLC_IP: return(&termIntChar); 222*40245Sborman case SLC_ABORT: return(&termQuitChar); 223*40245Sborman case SLC_EOF: return(&termEofChar); 224*40245Sborman case SLC_EC: return(&termEraseChar); 225*40245Sborman case SLC_EL: return(&termKillChar); 226*40245Sborman case SLC_XON: return(&termStartChar); 227*40245Sborman case SLC_XOFF: return(&termStopChar); 22839529Sborman #ifndef SYSV_TERMIO 229*40245Sborman case SLC_AO: return(&termFlushChar); 230*40245Sborman case SLC_SUSP: return(&termSuspChar); 231*40245Sborman case SLC_EW: return(&termWerasChar); 232*40245Sborman case SLC_RP: return(&termRprntChar); 233*40245Sborman case SLC_LNEXT: return(&termLiteralNextChar); 23439529Sborman #endif /* SYSV_TERMIO */ 23538689Sborman 23638689Sborman case SLC_SYNCH: 23738689Sborman case SLC_BRK: 23838689Sborman case SLC_AYT: 23938689Sborman case SLC_EOR: 24038689Sborman case SLC_FORW1: 24138689Sborman case SLC_FORW2: 24238689Sborman default: 243*40245Sborman return((cc_t *)0); 24438689Sborman } 24538689Sborman } 24638689Sborman 24732147Sminshall void 24838689Sborman TerminalDefaultChars() 24938689Sborman { 25038689Sborman #ifndef USE_TERMIO 25138689Sborman ntc = otc; 25238689Sborman nltc = oltc; 25338689Sborman nttyb.sg_kill = ottyb.sg_kill; 25438689Sborman nttyb.sg_erase = ottyb.sg_erase; 25538689Sborman #else /* USE_TERMIO */ 25638689Sborman memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); 25739529Sborman # ifndef VFLUSHO 25838689Sborman termFlushChar = 'O'&0x37; 25939529Sborman # endif 26039529Sborman # ifndef VWERASE 26138689Sborman termWerasChar = 'W'&0x37; 26239529Sborman # endif 26339529Sborman # ifndef VREPRINT 26438689Sborman termRprntChar = 'R'&0x37; 26539529Sborman # endif 26639529Sborman # ifndef VLNEXT 26738689Sborman termLiteralNextChar = 'V'&0x37; 26839529Sborman # endif 26939529Sborman # ifndef VSTART 27038689Sborman termStartChar = 'Q'&0x37; 27139529Sborman # endif 27239529Sborman # ifndef VSTOP 27338689Sborman termStopChar = 'S'&0x37; 27439529Sborman # endif 27538689Sborman #endif /* USE_TERMIO */ 27638689Sborman } 27738689Sborman 27838689Sborman void 27932553Sminshall TerminalRestoreState() 28032147Sminshall { 28132147Sminshall } 28232147Sminshall 28332147Sminshall /* 28432147Sminshall * TerminalNewMode - set up terminal to a specific mode. 28538689Sborman * MODE_ECHO: do local terminal echo 28638689Sborman * MODE_FLOW: do local flow control 28738689Sborman * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 28838689Sborman * MODE_EDIT: do local line editing 28938689Sborman * 29038689Sborman * Command mode: 29138689Sborman * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 29238689Sborman * local echo 29338689Sborman * local editing 29438689Sborman * local xon/xoff 29538689Sborman * local signal mapping 29638689Sborman * 29738689Sborman * Linemode: 29838689Sborman * local/no editing 29938689Sborman * Both Linemode and Single Character mode: 30038689Sborman * local/remote echo 30138689Sborman * local/no xon/xoff 30238689Sborman * local/no signal mapping 30332147Sminshall */ 30432147Sminshall 30532147Sminshall 30632147Sminshall void 30733286Sminshall TerminalNewMode(f) 30832147Sminshall register int f; 30932147Sminshall { 31032147Sminshall static int prevmode = 0; 31138689Sborman #ifndef USE_TERMIO 31238689Sborman struct tchars tc; 31338689Sborman struct ltchars ltc; 31432147Sminshall struct sgttyb sb; 31538909Sborman int lmode; 31638689Sborman #else /* USE_TERMIO */ 31738689Sborman struct termio tmp_tc; 31838689Sborman #endif /* USE_TERMIO */ 31932147Sminshall int onoff; 32032147Sminshall int old; 32132147Sminshall 32238689Sborman globalmode = f&~MODE_FORCE; 32332147Sminshall if (prevmode == f) 32432147Sminshall return; 32538689Sborman 32638689Sborman /* 32738689Sborman * Write any outstanding data before switching modes 32838689Sborman * ttyflush() returns 0 only when there is no more data 32938689Sborman * left to write out, it returns -1 if it couldn't do 33038689Sborman * anything at all, otherwise it returns 1 + the number 33138689Sborman * of characters left to write. 33238689Sborman */ 33338689Sborman old = ttyflush(SYNCHing|flushout); 33438689Sborman if (old < 0 || old > 1) { 33538689Sborman #ifndef USE_TERMIO 33638689Sborman ioctl(tin, TIOCGETP, (char *)&sb); 33738689Sborman #else /* USE_TERMIO */ 33838689Sborman ioctl(tin, TCGETA, (char *)&tmp_tc); 33938689Sborman #endif /* USE_TERMIO */ 34038689Sborman do { 34138689Sborman /* 34238689Sborman * Wait for data to drain, then flush again. 34338689Sborman */ 34438689Sborman #ifndef USE_TERMIO 34538689Sborman ioctl(tin, TIOCSETP, (char *)&sb); 34638689Sborman #else /* USE_TERMIO */ 34738689Sborman ioctl(tin, TCSETAW, (char *)&tmp_tc); 34838689Sborman #endif /* USE_TERMIO */ 34938689Sborman old = ttyflush(SYNCHing|flushout); 35038689Sborman } while (old < 0 || old > 1); 35138689Sborman } 35238689Sborman 35332147Sminshall old = prevmode; 35438689Sborman prevmode = f&~MODE_FORCE; 35538689Sborman #ifndef USE_TERMIO 35632147Sminshall sb = nttyb; 35738689Sborman tc = ntc; 35838689Sborman ltc = nltc; 35938909Sborman lmode = olmode; 36038689Sborman #else 36138689Sborman tmp_tc = new_tc; 36238689Sborman #endif 36332147Sminshall 36438689Sborman if (f&MODE_ECHO) { 36538689Sborman #ifndef USE_TERMIO 36638689Sborman sb.sg_flags |= ECHO; 36738689Sborman #else 36838689Sborman tmp_tc.c_lflag |= ECHO; 36938689Sborman tmp_tc.c_oflag |= ONLCR; 37039529Sborman # ifdef notdef 37138689Sborman tmp_tc.c_iflag |= ICRNL; 37239529Sborman # endif 37338689Sborman #endif 37438689Sborman } else { 37538689Sborman #ifndef USE_TERMIO 37638689Sborman sb.sg_flags &= ~ECHO; 37738689Sborman #else 37838689Sborman tmp_tc.c_lflag &= ~ECHO; 37938689Sborman tmp_tc.c_oflag &= ~ONLCR; 38039529Sborman # ifdef notdef 38138689Sborman tmp_tc.c_iflag &= ~ICRNL; 38239529Sborman # endif 38338689Sborman #endif 38438689Sborman } 38532147Sminshall 38638689Sborman if ((f&MODE_FLOW) == 0) { 38738689Sborman #ifndef USE_TERMIO 38838689Sborman tc.t_startc = -1; 38938689Sborman tc.t_stopc = -1; 39038689Sborman #else 39138689Sborman tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON); 39238689Sborman } else { 39338689Sborman tmp_tc.c_iflag |= IXANY|IXOFF|IXON; 39438689Sborman #endif 39538689Sborman } 39632147Sminshall 39738689Sborman if ((f&MODE_TRAPSIG) == 0) { 39838689Sborman #ifndef USE_TERMIO 39938689Sborman tc.t_intrc = -1; 40038689Sborman tc.t_quitc = -1; 40138689Sborman tc.t_eofc = -1; 40238689Sborman ltc.t_suspc = -1; 40338689Sborman ltc.t_dsuspc = -1; 40438689Sborman #else 40538689Sborman tmp_tc.c_lflag &= ~ISIG; 40638689Sborman #endif 40738689Sborman localchars = 0; 40838689Sborman } else { 40938689Sborman #ifdef USE_TERMIO 41038689Sborman tmp_tc.c_lflag |= ISIG; 41138689Sborman #endif 41238689Sborman localchars = 1; 41338689Sborman } 41438689Sborman 41538689Sborman if (f&MODE_EDIT) { 41638689Sborman #ifndef USE_TERMIO 41738689Sborman sb.sg_flags &= ~CBREAK; 41838689Sborman sb.sg_flags |= CRMOD; 41938689Sborman #else 42038689Sborman tmp_tc.c_lflag |= ICANON; 42138689Sborman #endif 42238689Sborman } else { 42338689Sborman #ifndef USE_TERMIO 42438689Sborman sb.sg_flags |= CBREAK; 42538689Sborman if (f&MODE_ECHO) 42632147Sminshall sb.sg_flags |= CRMOD; 42738689Sborman else 42838689Sborman sb.sg_flags &= ~CRMOD; 42938689Sborman #else 43038689Sborman tmp_tc.c_lflag &= ~ICANON; 43138689Sborman tmp_tc.c_iflag &= ~ICRNL; 43238689Sborman tmp_tc.c_cc[VMIN] = 1; 43338689Sborman tmp_tc.c_cc[VTIME] = 0; 43438689Sborman #endif 43538689Sborman } 43632147Sminshall 43738689Sborman if (f == -1) { 43838689Sborman onoff = 0; 43938689Sborman } else { 44038909Sborman #ifndef USE_TERMIO 44139529Sborman if (f & MODE_OUTBIN) 44238909Sborman lmode |= LLITOUT; 44338909Sborman else 44438909Sborman lmode &= ~LLITOUT; 44539529Sborman 44639529Sborman if (f & MODE_INBIN) 44738909Sborman lmode |= LPASS8; 44838909Sborman else 44938909Sborman lmode &= ~LPASS8; 45038909Sborman #else 45139529Sborman if (f & MODE_OUTBIN) 45239529Sborman tmp_tc.c_lflag &= ~ISTRIP; 45338909Sborman else 45439529Sborman tmp_tc.c_lflag |= ISTRIP; 45539529Sborman if (f & MODE_INBIN) { 45639529Sborman tmp_tc.c_cflag &= ~(CSIZE|PARENB); 45739529Sborman tmp_tc.c_cflag |= CS8; 45839529Sborman tmp_tc.c_cflag &= ~OPOST; 45939529Sborman } else { 46039529Sborman tmp_tc.c_cflag &= ~CSIZE; 46139529Sborman tmp_tc.c_cflag |= CS7|PARENB; 46239529Sborman tmp_tc.c_cflag |= OPOST; 46339529Sborman } 46438909Sborman #endif 46538689Sborman onoff = 1; 46632147Sminshall } 46738689Sborman 46838689Sborman if (f != -1) { 46939529Sborman #ifdef SIGTSTP 470*40245Sborman void susp(); 47138689Sborman 472*40245Sborman (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp); 47339529Sborman #endif /* SIGTSTP */ 474*40245Sborman #ifdef USE_TERMIO 475*40245Sborman #ifdef VEOL2 476*40245Sborman /* 477*40245Sborman * If the VEOL character is already set, then use VEOL2, 478*40245Sborman * otherwise use VEOL. 479*40245Sborman */ 480*40245Sborman if (tmp_tc.c_cc[VEOL] != (cc_t)(-1)) 481*40245Sborman tmp_tc.c_cc[VEOL2] = escape; 482*40245Sborman else 483*40245Sborman #endif 484*40245Sborman tmp_tc.c_cc[VEOL] = escape; 485*40245Sborman #else 486*40245Sborman tc.t_brkc = escape; 487*40245Sborman #endif 48838689Sborman } else { 48939529Sborman #ifdef SIGTSTP 49038689Sborman (void) signal(SIGTSTP, SIG_DFL); 49138689Sborman sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 49239529Sborman #endif /* SIGTSTP */ 49339529Sborman #ifndef USE_TERMIO 49439529Sborman ltc = oltc; 49539529Sborman tc = otc; 49639529Sborman sb = ottyb; 49739529Sborman #endif 49838689Sborman } 49939529Sborman #ifndef USE_TERMIO 50039529Sborman ioctl(tin, TIOCLSET, (char *)&lmode); 50139529Sborman ioctl(tin, TIOCSLTC, (char *)<c); 50239529Sborman ioctl(tin, TIOCSETC, (char *)&tc); 50339529Sborman ioctl(tin, TIOCSETP, (char *)&sb); 50439529Sborman #else 50539529Sborman if (ioctl(tin, TCSETAW, &tmp_tc) < 0) 50639529Sborman ioctl(tin, TCSETA, &tmp_tc); 50739529Sborman #endif 50839529Sborman 50932147Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 51033286Sminshall ioctl(tin, FIONBIO, (char *)&onoff); 51133286Sminshall ioctl(tout, FIONBIO, (char *)&onoff); 51232147Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 51332147Sminshall #if defined(TN3270) 51436242Sminshall if (noasynchtty == 0) { 51533286Sminshall ioctl(tin, FIOASYNC, (char *)&onoff); 51632147Sminshall } 51732147Sminshall #endif /* defined(TN3270) */ 51832147Sminshall } 51932147Sminshall 52039529Sborman #ifndef B19200 52139529Sborman # define B19200 B9600 52239529Sborman #endif 52339529Sborman 52439529Sborman #ifndef B38400 52539529Sborman # define B38400 B19200 52639529Sborman #endif 52739529Sborman 52839529Sborman /* 52939529Sborman * This code assumes that the values B0, B50, B75... 53039529Sborman * are in ascending order. They do not have to be 53139529Sborman * contiguous. 53239529Sborman */ 53339529Sborman struct termspeeds { 53439529Sborman long speed; 53539529Sborman long value; 53639529Sborman } termspeeds[] = { 53739529Sborman { 0, B0 }, { 50, B50 }, { 75, B75 }, 53839529Sborman { 110, B110 }, { 134, B134 }, { 150, B150 }, 53939529Sborman { 200, B200 }, { 300, B300 }, { 600, B600 }, 54039529Sborman { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 54139529Sborman { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 }, 54239529Sborman { 38400, B38400 }, { -1, B38400 } 54339529Sborman }; 54439529Sborman 54539529Sborman #ifndef USE_TERMIO 54639529Sborman # define ISPEED ottyb.sg_ispeed 54739529Sborman # define OSPEED ottyb.sg_ospeed 54839529Sborman #else 54939529Sborman # ifdef SYSV_TERMIO 55039529Sborman # define ISPEED (old_tc.c_cflag&CBAUD) 55139529Sborman # define OSPEED ISPEED 55239529Sborman # else 55339529Sborman # define ISPEED old_tc.c_ispeed 55439529Sborman # define OSPEED old_tc.c_ospeed 55539529Sborman # endif 55639529Sborman #endif 55739529Sborman 55837219Sminshall void 55937219Sminshall TerminalSpeeds(ispeed, ospeed) 56037219Sminshall long *ispeed; 56137219Sminshall long *ospeed; 56237219Sminshall { 56339529Sborman register struct termspeeds *tp; 56432147Sminshall 56539529Sborman tp = termspeeds; 56639529Sborman while ((tp->speed != -1) && (tp->value < ISPEED)) 56739529Sborman tp++; 56839529Sborman *ispeed = tp->speed; 56939529Sborman 57039529Sborman tp = termspeeds; 57139529Sborman while ((tp->speed != -1) && (tp->value < OSPEED)) 57239529Sborman tp++; 57339529Sborman *ospeed = tp->speed; 57437219Sminshall } 57537219Sminshall 57632147Sminshall int 57737219Sminshall TerminalWindowSize(rows, cols) 57837219Sminshall long *rows, *cols; 57937219Sminshall { 58038689Sborman #ifdef TIOCGWINSZ 58137219Sminshall struct winsize ws; 58237219Sminshall 58338689Sborman if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 58438689Sborman *rows = ws.ws_row; 58538689Sborman *cols = ws.ws_col; 58638689Sborman return 1; 58737219Sminshall } 58838810Sborman #endif /* TIOCGWINSZ */ 58938689Sborman return 0; 59037219Sminshall } 59137219Sminshall 59237219Sminshall int 59335417Sminshall NetClose(fd) 59435417Sminshall int fd; 59532147Sminshall { 59635417Sminshall return close(fd); 59732147Sminshall } 59832147Sminshall 59932147Sminshall 60032147Sminshall void 60132553Sminshall NetNonblockingIO(fd, onoff) 60232147Sminshall int 60332147Sminshall fd, 60432147Sminshall onoff; 60532147Sminshall { 60632147Sminshall ioctl(fd, FIONBIO, (char *)&onoff); 60732147Sminshall } 60832147Sminshall 60934849Sminshall #if defined(TN3270) 61032147Sminshall void 61132553Sminshall NetSigIO(fd, onoff) 61232147Sminshall int 61332147Sminshall fd, 61432147Sminshall onoff; 61532147Sminshall { 61632147Sminshall ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ 61732147Sminshall } 61832147Sminshall 61932147Sminshall void 62032553Sminshall NetSetPgrp(fd) 62132147Sminshall int fd; 62232147Sminshall { 62332147Sminshall int myPid; 62432147Sminshall 62532147Sminshall myPid = getpid(); 62636274Sminshall fcntl(fd, F_SETOWN, myPid); 62732147Sminshall } 62834849Sminshall #endif /*defined(TN3270)*/ 62932553Sminshall 63032553Sminshall /* 63132553Sminshall * Various signal handling routines. 63232553Sminshall */ 63332147Sminshall 63433286Sminshall static void 63532553Sminshall deadpeer() 63632553Sminshall { 63732553Sminshall setcommandmode(); 63832553Sminshall longjmp(peerdied, -1); 63932553Sminshall } 64032147Sminshall 64133286Sminshall static void 64232553Sminshall intr() 64332553Sminshall { 64432553Sminshall if (localchars) { 64532553Sminshall intp(); 64632553Sminshall return; 64732553Sminshall } 64832553Sminshall setcommandmode(); 64932553Sminshall longjmp(toplevel, -1); 65032553Sminshall } 65132553Sminshall 65233286Sminshall static void 65332553Sminshall intr2() 65432553Sminshall { 65532553Sminshall if (localchars) { 65638689Sborman #ifdef KLUDGELINEMODE 65738689Sborman if (kludgelinemode) 65838689Sborman sendbrk(); 65938689Sborman else 66038689Sborman #endif 66138689Sborman sendabort(); 66232553Sminshall return; 66332553Sminshall } 66432553Sminshall } 66532553Sminshall 66633286Sminshall static void 667*40245Sborman susp() 668*40245Sborman { 669*40245Sborman if (localchars) 670*40245Sborman sendsusp(); 671*40245Sborman } 672*40245Sborman 673*40245Sborman static void 67437219Sminshall sendwin() 67537219Sminshall { 67637219Sminshall if (connected) { 67737219Sminshall sendnaws(); 67837219Sminshall } 67937219Sminshall } 68037219Sminshall 68137219Sminshall static void 68232553Sminshall doescape() 68332553Sminshall { 68438689Sborman command(0, 0, 0); 68532553Sminshall } 68632553Sminshall 68732553Sminshall void 68832531Sminshall sys_telnet_init() 68932531Sminshall { 690*40245Sborman (void) signal(SIGINT, (SIG_FUNC_RET (*)())intr); 691*40245Sborman (void) signal(SIGQUIT, (SIG_FUNC_RET (*)())intr2); 692*40245Sborman (void) signal(SIGPIPE, (SIG_FUNC_RET (*)())deadpeer); 69338689Sborman #ifdef SIGWINCH 694*40245Sborman (void) signal(SIGWINCH, (SIG_FUNC_RET (*)())sendwin); 69538689Sborman #endif 696*40245Sborman #ifdef SIGTSTP 697*40245Sborman (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp); 698*40245Sborman #endif 69932553Sminshall 70038689Sborman setconnmode(0); 70132531Sminshall 70232531Sminshall NetNonblockingIO(net, 1); 70332531Sminshall 70432531Sminshall #if defined(TN3270) 70536242Sminshall if (noasynchnet == 0) { /* DBX can't handle! */ 70632531Sminshall NetSigIO(net, 1); 70732531Sminshall NetSetPgrp(net); 70832531Sminshall } 70932531Sminshall #endif /* defined(TN3270) */ 71032531Sminshall 71132531Sminshall #if defined(SO_OOBINLINE) 71234849Sminshall if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 71334849Sminshall perror("SetSockOpt"); 71434849Sminshall } 71532531Sminshall #endif /* defined(SO_OOBINLINE) */ 71632531Sminshall } 71732531Sminshall 71832531Sminshall /* 71932531Sminshall * Process rings - 72032531Sminshall * 72132531Sminshall * This routine tries to fill up/empty our various rings. 72232531Sminshall * 72332531Sminshall * The parameter specifies whether this is a poll operation, 72432531Sminshall * or a block-until-something-happens operation. 72532531Sminshall * 72632531Sminshall * The return value is 1 if something happened, 0 if not. 72732531Sminshall */ 72832531Sminshall 72932531Sminshall int 73032531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll) 73132531Sminshall int poll; /* If 0, then block until something to do */ 73232531Sminshall { 73332531Sminshall register int c; 73432531Sminshall /* One wants to be a bit careful about setting returnValue 73532531Sminshall * to one, since a one implies we did some useful work, 73632531Sminshall * and therefore probably won't be called to block next 73732531Sminshall * time (TN3270 mode only). 73832531Sminshall */ 73932531Sminshall int returnValue = 0; 74032531Sminshall static struct timeval TimeValue = { 0 }; 74132531Sminshall 74232531Sminshall if (netout) { 74332531Sminshall FD_SET(net, &obits); 74432531Sminshall } 74532531Sminshall if (ttyout) { 74632531Sminshall FD_SET(tout, &obits); 74732531Sminshall } 74832531Sminshall #if defined(TN3270) 74932531Sminshall if (ttyin) { 75032531Sminshall FD_SET(tin, &ibits); 75132531Sminshall } 75232531Sminshall #else /* defined(TN3270) */ 75332531Sminshall if (ttyin) { 75432531Sminshall FD_SET(tin, &ibits); 75532531Sminshall } 75632531Sminshall #endif /* defined(TN3270) */ 75732531Sminshall #if defined(TN3270) 75832531Sminshall if (netin) { 75932531Sminshall FD_SET(net, &ibits); 76032531Sminshall } 76132531Sminshall # else /* !defined(TN3270) */ 76232531Sminshall if (netin) { 76332531Sminshall FD_SET(net, &ibits); 76432531Sminshall } 76532531Sminshall # endif /* !defined(TN3270) */ 76632531Sminshall if (netex) { 76732531Sminshall FD_SET(net, &xbits); 76832531Sminshall } 76932531Sminshall if ((c = select(16, &ibits, &obits, &xbits, 77032531Sminshall (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { 77132531Sminshall if (c == -1) { 77232531Sminshall /* 77332531Sminshall * we can get EINTR if we are in line mode, 77432531Sminshall * and the user does an escape (TSTP), or 77532531Sminshall * some other signal generator. 77632531Sminshall */ 77732531Sminshall if (errno == EINTR) { 77832531Sminshall return 0; 77932531Sminshall } 78032531Sminshall # if defined(TN3270) 78132531Sminshall /* 78232531Sminshall * we can get EBADF if we were in transparent 78332531Sminshall * mode, and the transcom process died. 78432531Sminshall */ 78532531Sminshall if (errno == EBADF) { 78632531Sminshall /* 78732531Sminshall * zero the bits (even though kernel does it) 78832531Sminshall * to make sure we are selecting on the right 78932531Sminshall * ones. 79032531Sminshall */ 79132531Sminshall FD_ZERO(&ibits); 79232531Sminshall FD_ZERO(&obits); 79332531Sminshall FD_ZERO(&xbits); 79432531Sminshall return 0; 79532531Sminshall } 79632531Sminshall # endif /* defined(TN3270) */ 79732531Sminshall /* I don't like this, does it ever happen? */ 79832531Sminshall printf("sleep(5) from telnet, after select\r\n"); 79932531Sminshall sleep(5); 80032531Sminshall } 80132531Sminshall return 0; 80232531Sminshall } 80332531Sminshall 80432531Sminshall /* 80532531Sminshall * Any urgent data? 80632531Sminshall */ 80732531Sminshall if (FD_ISSET(net, &xbits)) { 80832531Sminshall FD_CLR(net, &xbits); 80932531Sminshall SYNCHing = 1; 81032531Sminshall ttyflush(1); /* flush already enqueued data */ 81132531Sminshall } 81232531Sminshall 81332531Sminshall /* 81432531Sminshall * Something to read from the network... 81532531Sminshall */ 81632531Sminshall if (FD_ISSET(net, &ibits)) { 81732531Sminshall int canread; 81832531Sminshall 81932531Sminshall FD_CLR(net, &ibits); 82032531Sminshall canread = ring_empty_consecutive(&netiring); 82132531Sminshall #if !defined(SO_OOBINLINE) 82232531Sminshall /* 82332531Sminshall * In 4.2 (and some early 4.3) systems, the 82432531Sminshall * OOB indication and data handling in the kernel 82532531Sminshall * is such that if two separate TCP Urgent requests 82632531Sminshall * come in, one byte of TCP data will be overlaid. 82732531Sminshall * This is fatal for Telnet, but we try to live 82832531Sminshall * with it. 82932531Sminshall * 83032531Sminshall * In addition, in 4.2 (and...), a special protocol 83132531Sminshall * is needed to pick up the TCP Urgent data in 83232531Sminshall * the correct sequence. 83332531Sminshall * 83432531Sminshall * What we do is: if we think we are in urgent 83532531Sminshall * mode, we look to see if we are "at the mark". 83632531Sminshall * If we are, we do an OOB receive. If we run 83732531Sminshall * this twice, we will do the OOB receive twice, 83832531Sminshall * but the second will fail, since the second 83932531Sminshall * time we were "at the mark", but there wasn't 84032531Sminshall * any data there (the kernel doesn't reset 84132531Sminshall * "at the mark" until we do a normal read). 84232531Sminshall * Once we've read the OOB data, we go ahead 84332531Sminshall * and do normal reads. 84432531Sminshall * 84532531Sminshall * There is also another problem, which is that 84632531Sminshall * since the OOB byte we read doesn't put us 84732531Sminshall * out of OOB state, and since that byte is most 84832531Sminshall * likely the TELNET DM (data mark), we would 84932531Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 85032531Sminshall * So, clocks to the rescue. If we've "just" 85132531Sminshall * received a DM, then we test for the 85232531Sminshall * presence of OOB data when the receive OOB 85332531Sminshall * fails (and AFTER we did the normal mode read 85432531Sminshall * to clear "at the mark"). 85532531Sminshall */ 85632531Sminshall if (SYNCHing) { 85732531Sminshall int atmark; 85839652Sborman static int bogus_oob = 0, first = 1; 85932531Sminshall 86032531Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 86132531Sminshall if (atmark) { 86232531Sminshall c = recv(net, netiring.supply, canread, MSG_OOB); 86332531Sminshall if ((c == -1) && (errno == EINVAL)) { 86432531Sminshall c = recv(net, netiring.supply, canread, 0); 86532531Sminshall if (clocks.didnetreceive < clocks.gotDM) { 86632531Sminshall SYNCHing = stilloob(net); 86732531Sminshall } 86839652Sborman } else if (first && c > 0) { 86939652Sborman /* 87039652Sborman * Bogosity check. Systems based on 4.2BSD 87139652Sborman * do not return an error if you do a second 87239652Sborman * recv(MSG_OOB). So, we do one. If it 87339652Sborman * succeeds and returns exactly the same 87439652Sborman * data, then assume that we are running 87539652Sborman * on a broken system and set the bogus_oob 87639652Sborman * flag. (If the data was different, then 87739652Sborman * we probably got some valid new data, so 87839652Sborman * increment the count...) 87939652Sborman */ 88039652Sborman int i; 88139652Sborman i = recv(net, netiring.supply + c, canread - c, MSG_OOB); 88239652Sborman if (i == c && 88339652Sborman bcmp(netiring.supply, netiring.supply + c, i) == 0) { 88439652Sborman bogus_oob = 1; 88539652Sborman first = 0; 88639652Sborman } else if (i < 0) { 88739652Sborman bogus_oob = 0; 88839652Sborman first = 0; 88939652Sborman } else 89039652Sborman c += i; 89132531Sminshall } 89239652Sborman if (bogus_oob && c > 0) { 89339652Sborman int i; 89439652Sborman /* 89539652Sborman * Bogosity. We have to do the read 89639652Sborman * to clear the atmark to get out of 89739652Sborman * an infinate loop. 89839652Sborman */ 89939652Sborman i = read(net, netiring.supply + c, canread - c); 90039652Sborman if (i > 0) 90139652Sborman c += i; 90239652Sborman } 90332531Sminshall } else { 90432531Sminshall c = recv(net, netiring.supply, canread, 0); 90532531Sminshall } 90632531Sminshall } else { 90732531Sminshall c = recv(net, netiring.supply, canread, 0); 90832531Sminshall } 90932531Sminshall settimer(didnetreceive); 91032531Sminshall #else /* !defined(SO_OOBINLINE) */ 91132531Sminshall c = recv(net, netiring.supply, canread, 0); 91232531Sminshall #endif /* !defined(SO_OOBINLINE) */ 91332531Sminshall if (c < 0 && errno == EWOULDBLOCK) { 91432531Sminshall c = 0; 91532531Sminshall } else if (c <= 0) { 91632531Sminshall return -1; 91732531Sminshall } 91832531Sminshall if (netdata) { 91932531Sminshall Dump('<', netiring.supply, c); 92032531Sminshall } 92132667Sminshall if (c) 92232667Sminshall ring_supplied(&netiring, c); 92332531Sminshall returnValue = 1; 92432531Sminshall } 92532531Sminshall 92632531Sminshall /* 92732531Sminshall * Something to read from the tty... 92832531Sminshall */ 92932531Sminshall if (FD_ISSET(tin, &ibits)) { 93032531Sminshall FD_CLR(tin, &ibits); 93133286Sminshall c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 93232531Sminshall if (c < 0 && errno == EWOULDBLOCK) { 93332531Sminshall c = 0; 93432531Sminshall } else { 93532531Sminshall /* EOF detection for line mode!!!! */ 93633281Sminshall if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 93732531Sminshall /* must be an EOF... */ 93832531Sminshall *ttyiring.supply = termEofChar; 93932531Sminshall c = 1; 94032531Sminshall } 94132531Sminshall if (c <= 0) { 94232531Sminshall return -1; 94332531Sminshall } 94438208Sminshall if (termdata) { 94538208Sminshall Dump('<', ttyiring.supply, c); 94638208Sminshall } 94732667Sminshall ring_supplied(&ttyiring, c); 94832531Sminshall } 94932531Sminshall returnValue = 1; /* did something useful */ 95032531Sminshall } 95132531Sminshall 95232531Sminshall if (FD_ISSET(net, &obits)) { 95332531Sminshall FD_CLR(net, &obits); 95432531Sminshall returnValue |= netflush(); 95532531Sminshall } 95632531Sminshall if (FD_ISSET(tout, &obits)) { 95732531Sminshall FD_CLR(tout, &obits); 95838689Sborman returnValue |= (ttyflush(SYNCHing|flushout) > 0); 95932531Sminshall } 96032531Sminshall 96132531Sminshall return returnValue; 96232531Sminshall } 963