132147Sminshall /* 233685Sbostic * Copyright (c) 1988 Regents of the University of California. 333685Sbostic * All rights reserved. 433685Sbostic * 5*42770Sbostic * %sccs.include.redist.c% 633685Sbostic */ 733685Sbostic 833685Sbostic #ifndef lint 9*42770Sbostic static char sccsid[] = "@(#)sys_bsd.c 1.25 (Berkeley) 06/01/90"; 1033685Sbostic #endif /* not lint */ 1133685Sbostic 1233685Sbostic /* 1332147Sminshall * The following routines try to encapsulate what is system dependent 1432147Sminshall * (at least between 4.x and dos) which is used in telnet.c. 1532147Sminshall */ 1632147Sminshall 1732147Sminshall 1836274Sminshall #include <fcntl.h> 1932381Sminshall #include <sys/types.h> 2032147Sminshall #include <sys/time.h> 2132531Sminshall #include <sys/socket.h> 2232147Sminshall #include <signal.h> 2332531Sminshall #include <errno.h> 2438689Sborman #include <arpa/telnet.h> 2532147Sminshall 2632381Sminshall #include "ring.h" 2732381Sminshall 2832657Sminshall #include "fdset.h" 2932657Sminshall 3032147Sminshall #include "defines.h" 3132147Sminshall #include "externs.h" 3232147Sminshall #include "types.h" 3332147Sminshall 3440245Sborman #if defined(CRAY) 3540245Sborman #define SIG_FUNC_RET void 3640245Sborman #else 3740245Sborman #define SIG_FUNC_RET int 3840245Sborman #endif 3940245Sborman 4032147Sminshall int 4132531Sminshall tout, /* Output file descriptor */ 4232531Sminshall tin, /* Input file descriptor */ 4336242Sminshall net; 4432147Sminshall 4538689Sborman #ifndef USE_TERMIO 4638689Sborman struct tchars otc = { 0 }, ntc = { 0 }; 4738689Sborman struct ltchars oltc = { 0 }, nltc = { 0 }; 4838689Sborman struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 4938909Sborman int olmode = 0; 5032147Sminshall 5138689Sborman #else /* USE_TERMIO */ 5238689Sborman struct termio old_tc = { 0 }; 5338689Sborman extern struct termio new_tc; 5438689Sborman 5540245Sborman #ifndef TCGETA 5640245Sborman #define TCGETA TIOCGETA 5740245Sborman #define TCSETA TIOCSETA 5840245Sborman #define TCSETAW TIOCSETAW 5940245Sborman #endif /* TCGETA */ 6038689Sborman #endif /* USE_TERMIO */ 6138689Sborman 6232531Sminshall static fd_set ibits, obits, xbits; 6332147Sminshall 6432531Sminshall 6532531Sminshall init_sys() 6632531Sminshall { 6732531Sminshall tout = fileno(stdout); 6832531Sminshall tin = fileno(stdin); 6932531Sminshall FD_ZERO(&ibits); 7032531Sminshall FD_ZERO(&obits); 7132531Sminshall FD_ZERO(&xbits); 7232531Sminshall 7332531Sminshall errno = 0; 7432531Sminshall } 7532531Sminshall 7632531Sminshall 7733286Sminshall TerminalWrite(buf, n) 7832147Sminshall char *buf; 7932147Sminshall int n; 8032147Sminshall { 8133286Sminshall return write(tout, buf, n); 8232147Sminshall } 8332147Sminshall 8433286Sminshall TerminalRead(buf, n) 8532147Sminshall char *buf; 8632147Sminshall int n; 8732147Sminshall { 8833286Sminshall return read(tin, buf, n); 8932147Sminshall } 9032147Sminshall 9132147Sminshall /* 9232147Sminshall * 9332147Sminshall */ 9432147Sminshall 9532147Sminshall int 9632553Sminshall TerminalAutoFlush() 9732147Sminshall { 9832147Sminshall #if defined(LNOFLSH) 9932147Sminshall int flush; 10032147Sminshall 10132147Sminshall ioctl(0, TIOCLGET, (char *)&flush); 10232147Sminshall return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ 10332147Sminshall #else /* LNOFLSH */ 10432147Sminshall return 1; 10532147Sminshall #endif /* LNOFLSH */ 10632147Sminshall } 10732147Sminshall 10838689Sborman #ifdef KLUDGELINEMODE 10938689Sborman extern int kludgelinemode; 11038689Sborman #endif 11132147Sminshall /* 11232147Sminshall * TerminalSpecialChars() 11332147Sminshall * 11432147Sminshall * Look at an input character to see if it is a special character 11532147Sminshall * and decide what to do. 11632147Sminshall * 11732147Sminshall * Output: 11832147Sminshall * 11932147Sminshall * 0 Don't add this character. 12032147Sminshall * 1 Do add this character 12132147Sminshall */ 12232147Sminshall 12332147Sminshall int 12432553Sminshall TerminalSpecialChars(c) 12532147Sminshall int c; 12632147Sminshall { 12732553Sminshall void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); 12832147Sminshall 12938689Sborman if (c == termIntChar) { 13032147Sminshall intp(); 13132147Sminshall return 0; 13238689Sborman } else if (c == termQuitChar) { 13338689Sborman #ifdef KLUDGELINEMODE 13438689Sborman if (kludgelinemode) 13538689Sborman sendbrk(); 13638689Sborman else 13738689Sborman #endif 13838689Sborman sendabort(); 13932147Sminshall return 0; 14038689Sborman } else if (c == termEofChar) { 14138689Sborman if (my_want_state_is_will(TELOPT_LINEMODE)) { 14238689Sborman sendeof(); 14338689Sborman return 0; 14438689Sborman } 14538689Sborman return 1; 14638689Sborman } else if (c == termSuspChar) { 14738689Sborman sendsusp(); 14838689Sborman return(0); 14938689Sborman } else if (c == termFlushChar) { 15032147Sminshall xmitAO(); /* Transmit Abort Output */ 15132147Sminshall return 0; 15232147Sminshall } else if (!MODE_LOCAL_CHARS(globalmode)) { 15338689Sborman if (c == termKillChar) { 15432147Sminshall xmitEL(); 15532147Sminshall return 0; 15638689Sborman } else if (c == termEraseChar) { 15732147Sminshall xmitEC(); /* Transmit Erase Character */ 15832147Sminshall return 0; 15932147Sminshall } 16032147Sminshall } 16132147Sminshall return 1; 16232147Sminshall } 16332147Sminshall 16432147Sminshall 16532147Sminshall /* 16632147Sminshall * Flush output to the terminal 16732147Sminshall */ 16832147Sminshall 16932147Sminshall void 17032553Sminshall TerminalFlushOutput() 17132147Sminshall { 17239529Sborman #ifdef TIOCFLUSH 17332147Sminshall (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 17438689Sborman #else 17538689Sborman (void) ioctl(fileno(stdout), TCFLSH, (char *) 0); 17638689Sborman #endif 17732147Sminshall } 17832147Sminshall 17932147Sminshall void 18032553Sminshall TerminalSaveState() 18132147Sminshall { 18238689Sborman #ifndef USE_TERMIO 18332147Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 18432147Sminshall ioctl(0, TIOCGETC, (char *)&otc); 18532147Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 18638909Sborman ioctl(0, TIOCLGET, (char *)&olmode); 18732147Sminshall 18832147Sminshall ntc = otc; 18932147Sminshall nltc = oltc; 19032147Sminshall nttyb = ottyb; 19132254Sminshall 19238689Sborman #else /* USE_TERMIO */ 19338689Sborman ioctl(0, TCGETA, &old_tc); 19438689Sborman 19538689Sborman new_tc = old_tc; 19638689Sborman 19738689Sborman termFlushChar = 'O'&0x37; 19838689Sborman termWerasChar = 'W'&0x37; 19938689Sborman termRprntChar = 'R'&0x37; 20038689Sborman termLiteralNextChar = 'V'&0x37; 20138689Sborman termStartChar = 'Q'&0x37; 20238689Sborman termStopChar = 'S'&0x37; 20338689Sborman #endif /* USE_TERMIO */ 20432147Sminshall } 20532147Sminshall 20640245Sborman cc_t * 20738689Sborman tcval(func) 20838689Sborman register int func; 20938689Sborman { 21038689Sborman switch(func) { 21140245Sborman case SLC_IP: return(&termIntChar); 21240245Sborman case SLC_ABORT: return(&termQuitChar); 21340245Sborman case SLC_EOF: return(&termEofChar); 21440245Sborman case SLC_EC: return(&termEraseChar); 21540245Sborman case SLC_EL: return(&termKillChar); 21640245Sborman case SLC_XON: return(&termStartChar); 21740245Sborman case SLC_XOFF: return(&termStopChar); 21839529Sborman #ifndef SYSV_TERMIO 21940245Sborman case SLC_AO: return(&termFlushChar); 22040245Sborman case SLC_SUSP: return(&termSuspChar); 22140245Sborman case SLC_EW: return(&termWerasChar); 22240245Sborman case SLC_RP: return(&termRprntChar); 22340245Sborman case SLC_LNEXT: return(&termLiteralNextChar); 22439529Sborman #endif /* SYSV_TERMIO */ 22538689Sborman 22638689Sborman case SLC_SYNCH: 22738689Sborman case SLC_BRK: 22838689Sborman case SLC_AYT: 22938689Sborman case SLC_EOR: 23038689Sborman case SLC_FORW1: 23138689Sborman case SLC_FORW2: 23238689Sborman default: 23340245Sborman return((cc_t *)0); 23438689Sborman } 23538689Sborman } 23638689Sborman 23732147Sminshall void 23838689Sborman TerminalDefaultChars() 23938689Sborman { 24038689Sborman #ifndef USE_TERMIO 24138689Sborman ntc = otc; 24238689Sborman nltc = oltc; 24338689Sborman nttyb.sg_kill = ottyb.sg_kill; 24438689Sborman nttyb.sg_erase = ottyb.sg_erase; 24538689Sborman #else /* USE_TERMIO */ 24638689Sborman memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); 24739529Sborman # ifndef VFLUSHO 24838689Sborman termFlushChar = 'O'&0x37; 24939529Sborman # endif 25039529Sborman # ifndef VWERASE 25138689Sborman termWerasChar = 'W'&0x37; 25239529Sborman # endif 25339529Sborman # ifndef VREPRINT 25438689Sborman termRprntChar = 'R'&0x37; 25539529Sborman # endif 25639529Sborman # ifndef VLNEXT 25738689Sborman termLiteralNextChar = 'V'&0x37; 25839529Sborman # endif 25939529Sborman # ifndef VSTART 26038689Sborman termStartChar = 'Q'&0x37; 26139529Sborman # endif 26239529Sborman # ifndef VSTOP 26338689Sborman termStopChar = 'S'&0x37; 26439529Sborman # endif 26538689Sborman #endif /* USE_TERMIO */ 26638689Sborman } 26738689Sborman 26838689Sborman void 26932553Sminshall TerminalRestoreState() 27032147Sminshall { 27132147Sminshall } 27232147Sminshall 27332147Sminshall /* 27432147Sminshall * TerminalNewMode - set up terminal to a specific mode. 27538689Sborman * MODE_ECHO: do local terminal echo 27638689Sborman * MODE_FLOW: do local flow control 27738689Sborman * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 27838689Sborman * MODE_EDIT: do local line editing 27938689Sborman * 28038689Sborman * Command mode: 28138689Sborman * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 28238689Sborman * local echo 28338689Sborman * local editing 28438689Sborman * local xon/xoff 28538689Sborman * local signal mapping 28638689Sborman * 28738689Sborman * Linemode: 28838689Sborman * local/no editing 28938689Sborman * Both Linemode and Single Character mode: 29038689Sborman * local/remote echo 29138689Sborman * local/no xon/xoff 29238689Sborman * local/no signal mapping 29332147Sminshall */ 29432147Sminshall 29532147Sminshall 29632147Sminshall void 29733286Sminshall TerminalNewMode(f) 29832147Sminshall register int f; 29932147Sminshall { 30032147Sminshall static int prevmode = 0; 30138689Sborman #ifndef USE_TERMIO 30238689Sborman struct tchars tc; 30338689Sborman struct ltchars ltc; 30432147Sminshall struct sgttyb sb; 30538909Sborman int lmode; 30638689Sborman #else /* USE_TERMIO */ 30738689Sborman struct termio tmp_tc; 30838689Sborman #endif /* USE_TERMIO */ 30932147Sminshall int onoff; 31032147Sminshall int old; 31132147Sminshall 31238689Sborman globalmode = f&~MODE_FORCE; 31332147Sminshall if (prevmode == f) 31432147Sminshall return; 31538689Sborman 31638689Sborman /* 31738689Sborman * Write any outstanding data before switching modes 31838689Sborman * ttyflush() returns 0 only when there is no more data 31938689Sborman * left to write out, it returns -1 if it couldn't do 32038689Sborman * anything at all, otherwise it returns 1 + the number 32138689Sborman * of characters left to write. 32238689Sborman */ 32338689Sborman old = ttyflush(SYNCHing|flushout); 32438689Sborman if (old < 0 || old > 1) { 32538689Sborman #ifndef USE_TERMIO 32638689Sborman ioctl(tin, TIOCGETP, (char *)&sb); 32738689Sborman #else /* USE_TERMIO */ 32838689Sborman ioctl(tin, TCGETA, (char *)&tmp_tc); 32938689Sborman #endif /* USE_TERMIO */ 33038689Sborman do { 33138689Sborman /* 33238689Sborman * Wait for data to drain, then flush again. 33338689Sborman */ 33438689Sborman #ifndef USE_TERMIO 33538689Sborman ioctl(tin, TIOCSETP, (char *)&sb); 33638689Sborman #else /* USE_TERMIO */ 33738689Sborman ioctl(tin, TCSETAW, (char *)&tmp_tc); 33838689Sborman #endif /* USE_TERMIO */ 33938689Sborman old = ttyflush(SYNCHing|flushout); 34038689Sborman } while (old < 0 || old > 1); 34138689Sborman } 34238689Sborman 34332147Sminshall old = prevmode; 34438689Sborman prevmode = f&~MODE_FORCE; 34538689Sborman #ifndef USE_TERMIO 34632147Sminshall sb = nttyb; 34738689Sborman tc = ntc; 34838689Sborman ltc = nltc; 34938909Sborman lmode = olmode; 35038689Sborman #else 35138689Sborman tmp_tc = new_tc; 35238689Sborman #endif 35332147Sminshall 35438689Sborman if (f&MODE_ECHO) { 35538689Sborman #ifndef USE_TERMIO 35638689Sborman sb.sg_flags |= ECHO; 35738689Sborman #else 35838689Sborman tmp_tc.c_lflag |= ECHO; 35938689Sborman tmp_tc.c_oflag |= ONLCR; 36039529Sborman # ifdef notdef 36138689Sborman tmp_tc.c_iflag |= ICRNL; 36239529Sborman # endif 36338689Sborman #endif 36438689Sborman } else { 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 } 37532147Sminshall 37638689Sborman if ((f&MODE_FLOW) == 0) { 37738689Sborman #ifndef USE_TERMIO 37838689Sborman tc.t_startc = -1; 37938689Sborman tc.t_stopc = -1; 38038689Sborman #else 38138689Sborman tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON); 38238689Sborman } else { 38338689Sborman tmp_tc.c_iflag |= IXANY|IXOFF|IXON; 38438689Sborman #endif 38538689Sborman } 38632147Sminshall 38738689Sborman if ((f&MODE_TRAPSIG) == 0) { 38838689Sborman #ifndef USE_TERMIO 38938689Sborman tc.t_intrc = -1; 39038689Sborman tc.t_quitc = -1; 39138689Sborman tc.t_eofc = -1; 39238689Sborman ltc.t_suspc = -1; 39338689Sborman ltc.t_dsuspc = -1; 39438689Sborman #else 39538689Sborman tmp_tc.c_lflag &= ~ISIG; 39638689Sborman #endif 39738689Sborman localchars = 0; 39838689Sborman } else { 39938689Sborman #ifdef USE_TERMIO 40038689Sborman tmp_tc.c_lflag |= ISIG; 40138689Sborman #endif 40238689Sborman localchars = 1; 40338689Sborman } 40438689Sborman 40538689Sborman if (f&MODE_EDIT) { 40638689Sborman #ifndef USE_TERMIO 40738689Sborman sb.sg_flags &= ~CBREAK; 40838689Sborman sb.sg_flags |= CRMOD; 40938689Sborman #else 41038689Sborman tmp_tc.c_lflag |= ICANON; 41138689Sborman #endif 41238689Sborman } else { 41338689Sborman #ifndef USE_TERMIO 41438689Sborman sb.sg_flags |= CBREAK; 41538689Sborman if (f&MODE_ECHO) 41632147Sminshall sb.sg_flags |= CRMOD; 41738689Sborman else 41838689Sborman sb.sg_flags &= ~CRMOD; 41938689Sborman #else 42038689Sborman tmp_tc.c_lflag &= ~ICANON; 42138689Sborman tmp_tc.c_iflag &= ~ICRNL; 42238689Sborman tmp_tc.c_cc[VMIN] = 1; 42338689Sborman tmp_tc.c_cc[VTIME] = 0; 42438689Sborman #endif 42538689Sborman } 42632147Sminshall 42738689Sborman if (f == -1) { 42838689Sborman onoff = 0; 42938689Sborman } else { 43038909Sborman #ifndef USE_TERMIO 43139529Sborman if (f & MODE_OUTBIN) 43238909Sborman lmode |= LLITOUT; 43338909Sborman else 43438909Sborman lmode &= ~LLITOUT; 43539529Sborman 43639529Sborman if (f & MODE_INBIN) 43738909Sborman lmode |= LPASS8; 43838909Sborman else 43938909Sborman lmode &= ~LPASS8; 44038909Sborman #else 44139529Sborman if (f & MODE_OUTBIN) 44239529Sborman tmp_tc.c_lflag &= ~ISTRIP; 44338909Sborman else 44439529Sborman tmp_tc.c_lflag |= ISTRIP; 44539529Sborman if (f & MODE_INBIN) { 44639529Sborman tmp_tc.c_cflag &= ~(CSIZE|PARENB); 44739529Sborman tmp_tc.c_cflag |= CS8; 44839529Sborman tmp_tc.c_cflag &= ~OPOST; 44939529Sborman } else { 45039529Sborman tmp_tc.c_cflag &= ~CSIZE; 45139529Sborman tmp_tc.c_cflag |= CS7|PARENB; 45239529Sborman tmp_tc.c_cflag |= OPOST; 45339529Sborman } 45438909Sborman #endif 45538689Sborman onoff = 1; 45632147Sminshall } 45738689Sborman 45838689Sborman if (f != -1) { 45939529Sborman #ifdef SIGTSTP 46040245Sborman void susp(); 46138689Sborman 46240245Sborman (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp); 46339529Sborman #endif /* SIGTSTP */ 46440245Sborman #ifdef USE_TERMIO 46540245Sborman #ifdef VEOL2 46640245Sborman /* 46740245Sborman * If the VEOL character is already set, then use VEOL2, 46840245Sborman * otherwise use VEOL. 46940245Sborman */ 47040245Sborman if (tmp_tc.c_cc[VEOL] != (cc_t)(-1)) 47140245Sborman tmp_tc.c_cc[VEOL2] = escape; 47240245Sborman else 47340245Sborman #endif 47440245Sborman tmp_tc.c_cc[VEOL] = escape; 47540245Sborman #else 47640245Sborman tc.t_brkc = escape; 47740245Sborman #endif 47838689Sborman } else { 47939529Sborman #ifdef SIGTSTP 48038689Sborman (void) signal(SIGTSTP, SIG_DFL); 48138689Sborman sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 48239529Sborman #endif /* SIGTSTP */ 48339529Sborman #ifndef USE_TERMIO 48439529Sborman ltc = oltc; 48539529Sborman tc = otc; 48639529Sborman sb = ottyb; 48739529Sborman #endif 48838689Sborman } 48939529Sborman #ifndef USE_TERMIO 49039529Sborman ioctl(tin, TIOCLSET, (char *)&lmode); 49139529Sborman ioctl(tin, TIOCSLTC, (char *)<c); 49239529Sborman ioctl(tin, TIOCSETC, (char *)&tc); 49339529Sborman ioctl(tin, TIOCSETP, (char *)&sb); 49439529Sborman #else 49539529Sborman if (ioctl(tin, TCSETAW, &tmp_tc) < 0) 49639529Sborman ioctl(tin, TCSETA, &tmp_tc); 49739529Sborman #endif 49839529Sborman 49932147Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 50033286Sminshall ioctl(tin, FIONBIO, (char *)&onoff); 50133286Sminshall ioctl(tout, FIONBIO, (char *)&onoff); 50232147Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 50332147Sminshall #if defined(TN3270) 50436242Sminshall if (noasynchtty == 0) { 50533286Sminshall ioctl(tin, FIOASYNC, (char *)&onoff); 50632147Sminshall } 50732147Sminshall #endif /* defined(TN3270) */ 50832147Sminshall } 50932147Sminshall 51039529Sborman #ifndef B19200 51139529Sborman # define B19200 B9600 51239529Sborman #endif 51339529Sborman 51439529Sborman #ifndef B38400 51539529Sborman # define B38400 B19200 51639529Sborman #endif 51739529Sborman 51839529Sborman /* 51939529Sborman * This code assumes that the values B0, B50, B75... 52039529Sborman * are in ascending order. They do not have to be 52139529Sborman * contiguous. 52239529Sborman */ 52339529Sborman struct termspeeds { 52439529Sborman long speed; 52539529Sborman long value; 52639529Sborman } termspeeds[] = { 52739529Sborman { 0, B0 }, { 50, B50 }, { 75, B75 }, 52839529Sborman { 110, B110 }, { 134, B134 }, { 150, B150 }, 52939529Sborman { 200, B200 }, { 300, B300 }, { 600, B600 }, 53039529Sborman { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 53139529Sborman { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 }, 53239529Sborman { 38400, B38400 }, { -1, B38400 } 53339529Sborman }; 53439529Sborman 53539529Sborman #ifndef USE_TERMIO 53639529Sborman # define ISPEED ottyb.sg_ispeed 53739529Sborman # define OSPEED ottyb.sg_ospeed 53839529Sborman #else 53939529Sborman # ifdef SYSV_TERMIO 54039529Sborman # define ISPEED (old_tc.c_cflag&CBAUD) 54139529Sborman # define OSPEED ISPEED 54239529Sborman # else 54339529Sborman # define ISPEED old_tc.c_ispeed 54439529Sborman # define OSPEED old_tc.c_ospeed 54539529Sborman # endif 54639529Sborman #endif 54739529Sborman 54837219Sminshall void 54937219Sminshall TerminalSpeeds(ispeed, ospeed) 55037219Sminshall long *ispeed; 55137219Sminshall long *ospeed; 55237219Sminshall { 55339529Sborman register struct termspeeds *tp; 55432147Sminshall 55539529Sborman tp = termspeeds; 55639529Sborman while ((tp->speed != -1) && (tp->value < ISPEED)) 55739529Sborman tp++; 55839529Sborman *ispeed = tp->speed; 55939529Sborman 56039529Sborman tp = termspeeds; 56139529Sborman while ((tp->speed != -1) && (tp->value < OSPEED)) 56239529Sborman tp++; 56339529Sborman *ospeed = tp->speed; 56437219Sminshall } 56537219Sminshall 56632147Sminshall int 56737219Sminshall TerminalWindowSize(rows, cols) 56837219Sminshall long *rows, *cols; 56937219Sminshall { 57038689Sborman #ifdef TIOCGWINSZ 57137219Sminshall struct winsize ws; 57237219Sminshall 57338689Sborman if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 57438689Sborman *rows = ws.ws_row; 57538689Sborman *cols = ws.ws_col; 57638689Sborman return 1; 57737219Sminshall } 57838810Sborman #endif /* TIOCGWINSZ */ 57938689Sborman return 0; 58037219Sminshall } 58137219Sminshall 58237219Sminshall int 58335417Sminshall NetClose(fd) 58435417Sminshall int fd; 58532147Sminshall { 58635417Sminshall return close(fd); 58732147Sminshall } 58832147Sminshall 58932147Sminshall 59032147Sminshall void 59132553Sminshall NetNonblockingIO(fd, onoff) 59232147Sminshall int 59332147Sminshall fd, 59432147Sminshall onoff; 59532147Sminshall { 59632147Sminshall ioctl(fd, FIONBIO, (char *)&onoff); 59732147Sminshall } 59832147Sminshall 59934849Sminshall #if defined(TN3270) 60032147Sminshall void 60132553Sminshall NetSigIO(fd, onoff) 60232147Sminshall int 60332147Sminshall fd, 60432147Sminshall onoff; 60532147Sminshall { 60632147Sminshall ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ 60732147Sminshall } 60832147Sminshall 60932147Sminshall void 61032553Sminshall NetSetPgrp(fd) 61132147Sminshall int fd; 61232147Sminshall { 61332147Sminshall int myPid; 61432147Sminshall 61532147Sminshall myPid = getpid(); 61636274Sminshall fcntl(fd, F_SETOWN, myPid); 61732147Sminshall } 61834849Sminshall #endif /*defined(TN3270)*/ 61932553Sminshall 62032553Sminshall /* 62132553Sminshall * Various signal handling routines. 62232553Sminshall */ 62332147Sminshall 62433286Sminshall static void 62532553Sminshall deadpeer() 62632553Sminshall { 62732553Sminshall setcommandmode(); 62832553Sminshall longjmp(peerdied, -1); 62932553Sminshall } 63032147Sminshall 63133286Sminshall static void 63232553Sminshall intr() 63332553Sminshall { 63432553Sminshall if (localchars) { 63532553Sminshall intp(); 63632553Sminshall return; 63732553Sminshall } 63832553Sminshall setcommandmode(); 63932553Sminshall longjmp(toplevel, -1); 64032553Sminshall } 64132553Sminshall 64233286Sminshall static void 64332553Sminshall intr2() 64432553Sminshall { 64532553Sminshall if (localchars) { 64638689Sborman #ifdef KLUDGELINEMODE 64738689Sborman if (kludgelinemode) 64838689Sborman sendbrk(); 64938689Sborman else 65038689Sborman #endif 65138689Sborman sendabort(); 65232553Sminshall return; 65332553Sminshall } 65432553Sminshall } 65532553Sminshall 65633286Sminshall static void 65740245Sborman susp() 65840245Sborman { 65940245Sborman if (localchars) 66040245Sborman sendsusp(); 66140245Sborman } 66240245Sborman 66340245Sborman static void 66437219Sminshall sendwin() 66537219Sminshall { 66637219Sminshall if (connected) { 66737219Sminshall sendnaws(); 66837219Sminshall } 66937219Sminshall } 67037219Sminshall 67137219Sminshall static void 67232553Sminshall doescape() 67332553Sminshall { 67438689Sborman command(0, 0, 0); 67532553Sminshall } 67632553Sminshall 67732553Sminshall void 67832531Sminshall sys_telnet_init() 67932531Sminshall { 68040245Sborman (void) signal(SIGINT, (SIG_FUNC_RET (*)())intr); 68140245Sborman (void) signal(SIGQUIT, (SIG_FUNC_RET (*)())intr2); 68240245Sborman (void) signal(SIGPIPE, (SIG_FUNC_RET (*)())deadpeer); 68338689Sborman #ifdef SIGWINCH 68440245Sborman (void) signal(SIGWINCH, (SIG_FUNC_RET (*)())sendwin); 68538689Sborman #endif 68640245Sborman #ifdef SIGTSTP 68740245Sborman (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp); 68840245Sborman #endif 68932553Sminshall 69038689Sborman setconnmode(0); 69132531Sminshall 69232531Sminshall NetNonblockingIO(net, 1); 69332531Sminshall 69432531Sminshall #if defined(TN3270) 69536242Sminshall if (noasynchnet == 0) { /* DBX can't handle! */ 69632531Sminshall NetSigIO(net, 1); 69732531Sminshall NetSetPgrp(net); 69832531Sminshall } 69932531Sminshall #endif /* defined(TN3270) */ 70032531Sminshall 70132531Sminshall #if defined(SO_OOBINLINE) 70234849Sminshall if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 70334849Sminshall perror("SetSockOpt"); 70434849Sminshall } 70532531Sminshall #endif /* defined(SO_OOBINLINE) */ 70632531Sminshall } 70732531Sminshall 70832531Sminshall /* 70932531Sminshall * Process rings - 71032531Sminshall * 71132531Sminshall * This routine tries to fill up/empty our various rings. 71232531Sminshall * 71332531Sminshall * The parameter specifies whether this is a poll operation, 71432531Sminshall * or a block-until-something-happens operation. 71532531Sminshall * 71632531Sminshall * The return value is 1 if something happened, 0 if not. 71732531Sminshall */ 71832531Sminshall 71932531Sminshall int 72032531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll) 72132531Sminshall int poll; /* If 0, then block until something to do */ 72232531Sminshall { 72332531Sminshall register int c; 72432531Sminshall /* One wants to be a bit careful about setting returnValue 72532531Sminshall * to one, since a one implies we did some useful work, 72632531Sminshall * and therefore probably won't be called to block next 72732531Sminshall * time (TN3270 mode only). 72832531Sminshall */ 72932531Sminshall int returnValue = 0; 73032531Sminshall static struct timeval TimeValue = { 0 }; 73132531Sminshall 73232531Sminshall if (netout) { 73332531Sminshall FD_SET(net, &obits); 73432531Sminshall } 73532531Sminshall if (ttyout) { 73632531Sminshall FD_SET(tout, &obits); 73732531Sminshall } 73832531Sminshall #if defined(TN3270) 73932531Sminshall if (ttyin) { 74032531Sminshall FD_SET(tin, &ibits); 74132531Sminshall } 74232531Sminshall #else /* defined(TN3270) */ 74332531Sminshall if (ttyin) { 74432531Sminshall FD_SET(tin, &ibits); 74532531Sminshall } 74632531Sminshall #endif /* defined(TN3270) */ 74732531Sminshall #if defined(TN3270) 74832531Sminshall if (netin) { 74932531Sminshall FD_SET(net, &ibits); 75032531Sminshall } 75132531Sminshall # else /* !defined(TN3270) */ 75232531Sminshall if (netin) { 75332531Sminshall FD_SET(net, &ibits); 75432531Sminshall } 75532531Sminshall # endif /* !defined(TN3270) */ 75632531Sminshall if (netex) { 75732531Sminshall FD_SET(net, &xbits); 75832531Sminshall } 75932531Sminshall if ((c = select(16, &ibits, &obits, &xbits, 76032531Sminshall (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { 76132531Sminshall if (c == -1) { 76232531Sminshall /* 76332531Sminshall * we can get EINTR if we are in line mode, 76432531Sminshall * and the user does an escape (TSTP), or 76532531Sminshall * some other signal generator. 76632531Sminshall */ 76732531Sminshall if (errno == EINTR) { 76832531Sminshall return 0; 76932531Sminshall } 77032531Sminshall # if defined(TN3270) 77132531Sminshall /* 77232531Sminshall * we can get EBADF if we were in transparent 77332531Sminshall * mode, and the transcom process died. 77432531Sminshall */ 77532531Sminshall if (errno == EBADF) { 77632531Sminshall /* 77732531Sminshall * zero the bits (even though kernel does it) 77832531Sminshall * to make sure we are selecting on the right 77932531Sminshall * ones. 78032531Sminshall */ 78132531Sminshall FD_ZERO(&ibits); 78232531Sminshall FD_ZERO(&obits); 78332531Sminshall FD_ZERO(&xbits); 78432531Sminshall return 0; 78532531Sminshall } 78632531Sminshall # endif /* defined(TN3270) */ 78732531Sminshall /* I don't like this, does it ever happen? */ 78832531Sminshall printf("sleep(5) from telnet, after select\r\n"); 78932531Sminshall sleep(5); 79032531Sminshall } 79132531Sminshall return 0; 79232531Sminshall } 79332531Sminshall 79432531Sminshall /* 79532531Sminshall * Any urgent data? 79632531Sminshall */ 79732531Sminshall if (FD_ISSET(net, &xbits)) { 79832531Sminshall FD_CLR(net, &xbits); 79932531Sminshall SYNCHing = 1; 80032531Sminshall ttyflush(1); /* flush already enqueued data */ 80132531Sminshall } 80232531Sminshall 80332531Sminshall /* 80432531Sminshall * Something to read from the network... 80532531Sminshall */ 80632531Sminshall if (FD_ISSET(net, &ibits)) { 80732531Sminshall int canread; 80832531Sminshall 80932531Sminshall FD_CLR(net, &ibits); 81032531Sminshall canread = ring_empty_consecutive(&netiring); 81132531Sminshall #if !defined(SO_OOBINLINE) 81232531Sminshall /* 81332531Sminshall * In 4.2 (and some early 4.3) systems, the 81432531Sminshall * OOB indication and data handling in the kernel 81532531Sminshall * is such that if two separate TCP Urgent requests 81632531Sminshall * come in, one byte of TCP data will be overlaid. 81732531Sminshall * This is fatal for Telnet, but we try to live 81832531Sminshall * with it. 81932531Sminshall * 82032531Sminshall * In addition, in 4.2 (and...), a special protocol 82132531Sminshall * is needed to pick up the TCP Urgent data in 82232531Sminshall * the correct sequence. 82332531Sminshall * 82432531Sminshall * What we do is: if we think we are in urgent 82532531Sminshall * mode, we look to see if we are "at the mark". 82632531Sminshall * If we are, we do an OOB receive. If we run 82732531Sminshall * this twice, we will do the OOB receive twice, 82832531Sminshall * but the second will fail, since the second 82932531Sminshall * time we were "at the mark", but there wasn't 83032531Sminshall * any data there (the kernel doesn't reset 83132531Sminshall * "at the mark" until we do a normal read). 83232531Sminshall * Once we've read the OOB data, we go ahead 83332531Sminshall * and do normal reads. 83432531Sminshall * 83532531Sminshall * There is also another problem, which is that 83632531Sminshall * since the OOB byte we read doesn't put us 83732531Sminshall * out of OOB state, and since that byte is most 83832531Sminshall * likely the TELNET DM (data mark), we would 83932531Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 84032531Sminshall * So, clocks to the rescue. If we've "just" 84132531Sminshall * received a DM, then we test for the 84232531Sminshall * presence of OOB data when the receive OOB 84332531Sminshall * fails (and AFTER we did the normal mode read 84432531Sminshall * to clear "at the mark"). 84532531Sminshall */ 84632531Sminshall if (SYNCHing) { 84732531Sminshall int atmark; 84839652Sborman static int bogus_oob = 0, first = 1; 84932531Sminshall 85032531Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 85132531Sminshall if (atmark) { 85232531Sminshall c = recv(net, netiring.supply, canread, MSG_OOB); 85332531Sminshall if ((c == -1) && (errno == EINVAL)) { 85432531Sminshall c = recv(net, netiring.supply, canread, 0); 85532531Sminshall if (clocks.didnetreceive < clocks.gotDM) { 85632531Sminshall SYNCHing = stilloob(net); 85732531Sminshall } 85839652Sborman } else if (first && c > 0) { 85939652Sborman /* 86039652Sborman * Bogosity check. Systems based on 4.2BSD 86139652Sborman * do not return an error if you do a second 86239652Sborman * recv(MSG_OOB). So, we do one. If it 86339652Sborman * succeeds and returns exactly the same 86439652Sborman * data, then assume that we are running 86539652Sborman * on a broken system and set the bogus_oob 86639652Sborman * flag. (If the data was different, then 86739652Sborman * we probably got some valid new data, so 86839652Sborman * increment the count...) 86939652Sborman */ 87039652Sborman int i; 87139652Sborman i = recv(net, netiring.supply + c, canread - c, MSG_OOB); 87239652Sborman if (i == c && 87339652Sborman bcmp(netiring.supply, netiring.supply + c, i) == 0) { 87439652Sborman bogus_oob = 1; 87539652Sborman first = 0; 87639652Sborman } else if (i < 0) { 87739652Sborman bogus_oob = 0; 87839652Sborman first = 0; 87939652Sborman } else 88039652Sborman c += i; 88132531Sminshall } 88239652Sborman if (bogus_oob && c > 0) { 88339652Sborman int i; 88439652Sborman /* 88539652Sborman * Bogosity. We have to do the read 88639652Sborman * to clear the atmark to get out of 88739652Sborman * an infinate loop. 88839652Sborman */ 88939652Sborman i = read(net, netiring.supply + c, canread - c); 89039652Sborman if (i > 0) 89139652Sborman c += i; 89239652Sborman } 89332531Sminshall } else { 89432531Sminshall c = recv(net, netiring.supply, canread, 0); 89532531Sminshall } 89632531Sminshall } else { 89732531Sminshall c = recv(net, netiring.supply, canread, 0); 89832531Sminshall } 89932531Sminshall settimer(didnetreceive); 90032531Sminshall #else /* !defined(SO_OOBINLINE) */ 90132531Sminshall c = recv(net, netiring.supply, canread, 0); 90232531Sminshall #endif /* !defined(SO_OOBINLINE) */ 90332531Sminshall if (c < 0 && errno == EWOULDBLOCK) { 90432531Sminshall c = 0; 90532531Sminshall } else if (c <= 0) { 90632531Sminshall return -1; 90732531Sminshall } 90832531Sminshall if (netdata) { 90932531Sminshall Dump('<', netiring.supply, c); 91032531Sminshall } 91132667Sminshall if (c) 91232667Sminshall ring_supplied(&netiring, c); 91332531Sminshall returnValue = 1; 91432531Sminshall } 91532531Sminshall 91632531Sminshall /* 91732531Sminshall * Something to read from the tty... 91832531Sminshall */ 91932531Sminshall if (FD_ISSET(tin, &ibits)) { 92032531Sminshall FD_CLR(tin, &ibits); 92133286Sminshall c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 92232531Sminshall if (c < 0 && errno == EWOULDBLOCK) { 92332531Sminshall c = 0; 92432531Sminshall } else { 92532531Sminshall /* EOF detection for line mode!!!! */ 92633281Sminshall if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 92732531Sminshall /* must be an EOF... */ 92832531Sminshall *ttyiring.supply = termEofChar; 92932531Sminshall c = 1; 93032531Sminshall } 93132531Sminshall if (c <= 0) { 93232531Sminshall return -1; 93332531Sminshall } 93438208Sminshall if (termdata) { 93538208Sminshall Dump('<', ttyiring.supply, c); 93638208Sminshall } 93732667Sminshall ring_supplied(&ttyiring, c); 93832531Sminshall } 93932531Sminshall returnValue = 1; /* did something useful */ 94032531Sminshall } 94132531Sminshall 94232531Sminshall if (FD_ISSET(net, &obits)) { 94332531Sminshall FD_CLR(net, &obits); 94432531Sminshall returnValue |= netflush(); 94532531Sminshall } 94632531Sminshall if (FD_ISSET(tout, &obits)) { 94732531Sminshall FD_CLR(tout, &obits); 94838689Sborman returnValue |= (ttyflush(SYNCHing|flushout) > 0); 94932531Sminshall } 95032531Sminshall 95132531Sminshall return returnValue; 95232531Sminshall } 953