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*38810Sborman static char sccsid[] = "@(#)sys_bsd.c 1.20 (Berkeley) 08/28/89"; 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 #if defined(unix) 2832147Sminshall 2936274Sminshall #include <fcntl.h> 3032381Sminshall #include <sys/types.h> 3132147Sminshall #include <sys/time.h> 3232531Sminshall #include <sys/socket.h> 3332147Sminshall #include <signal.h> 3432531Sminshall #include <errno.h> 3538689Sborman #include <arpa/telnet.h> 3632147Sminshall 3732381Sminshall #include "ring.h" 3832381Sminshall 3932657Sminshall #include "fdset.h" 4032657Sminshall 4132147Sminshall #include "defines.h" 4232147Sminshall #include "externs.h" 4332147Sminshall #include "types.h" 4432147Sminshall 4532147Sminshall int 4632531Sminshall tout, /* Output file descriptor */ 4732531Sminshall tin, /* Input file descriptor */ 4836242Sminshall net; 4932147Sminshall 5038689Sborman #ifndef USE_TERMIO 5138689Sborman struct tchars otc = { 0 }, ntc = { 0 }; 5238689Sborman struct ltchars oltc = { 0 }, nltc = { 0 }; 5338689Sborman struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 5432147Sminshall 5538689Sborman #define ISPEED ottyb.sg_ispeed 5638689Sborman #define OSPEED ottyb.sg_ospeed 5738689Sborman #else /* USE_TERMIO */ 5838689Sborman struct termio old_tc = { 0 }; 5938689Sborman extern struct termio new_tc; 6038689Sborman 6138689Sborman #define ISPEED (old_tc.c_cflag&CBAUD) 6238689Sborman #define OSPEED ISPEED 6338689Sborman #endif /* USE_TERMIO */ 6438689Sborman 6532531Sminshall static fd_set ibits, obits, xbits; 6632147Sminshall 6732531Sminshall 6832531Sminshall init_sys() 6932531Sminshall { 7032531Sminshall tout = fileno(stdout); 7132531Sminshall tin = fileno(stdin); 7232531Sminshall FD_ZERO(&ibits); 7332531Sminshall FD_ZERO(&obits); 7432531Sminshall FD_ZERO(&xbits); 7532531Sminshall 7632531Sminshall errno = 0; 7732531Sminshall } 7832531Sminshall 7932531Sminshall 8033286Sminshall TerminalWrite(buf, n) 8132147Sminshall char *buf; 8232147Sminshall int n; 8332147Sminshall { 8433286Sminshall return write(tout, buf, n); 8532147Sminshall } 8632147Sminshall 8733286Sminshall TerminalRead(buf, n) 8832147Sminshall char *buf; 8932147Sminshall int n; 9032147Sminshall { 9133286Sminshall return read(tin, buf, n); 9232147Sminshall } 9332147Sminshall 9432147Sminshall /* 9532147Sminshall * 9632147Sminshall */ 9732147Sminshall 9832147Sminshall int 9932553Sminshall TerminalAutoFlush() 10032147Sminshall { 10132147Sminshall #if defined(LNOFLSH) 10232147Sminshall int flush; 10332147Sminshall 10432147Sminshall ioctl(0, TIOCLGET, (char *)&flush); 10532147Sminshall return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ 10632147Sminshall #else /* LNOFLSH */ 10732147Sminshall return 1; 10832147Sminshall #endif /* LNOFLSH */ 10932147Sminshall } 11032147Sminshall 11138689Sborman #ifdef KLUDGELINEMODE 11238689Sborman extern int kludgelinemode; 11338689Sborman #endif 11432147Sminshall /* 11532147Sminshall * TerminalSpecialChars() 11632147Sminshall * 11732147Sminshall * Look at an input character to see if it is a special character 11832147Sminshall * and decide what to do. 11932147Sminshall * 12032147Sminshall * Output: 12132147Sminshall * 12232147Sminshall * 0 Don't add this character. 12332147Sminshall * 1 Do add this character 12432147Sminshall */ 12532147Sminshall 12632147Sminshall int 12732553Sminshall TerminalSpecialChars(c) 12832147Sminshall int c; 12932147Sminshall { 13032553Sminshall void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); 13132147Sminshall 13238689Sborman if (c == termIntChar) { 13332147Sminshall intp(); 13432147Sminshall return 0; 13538689Sborman } else if (c == termQuitChar) { 13638689Sborman #ifdef KLUDGELINEMODE 13738689Sborman if (kludgelinemode) 13838689Sborman sendbrk(); 13938689Sborman else 14038689Sborman #endif 14138689Sborman sendabort(); 14232147Sminshall return 0; 14338689Sborman } else if (c == termEofChar) { 14438689Sborman if (my_want_state_is_will(TELOPT_LINEMODE)) { 14538689Sborman sendeof(); 14638689Sborman return 0; 14738689Sborman } 14838689Sborman return 1; 14938689Sborman } else if (c == termSuspChar) { 15038689Sborman sendsusp(); 15138689Sborman return(0); 15238689Sborman } else if (c == termFlushChar) { 15332147Sminshall xmitAO(); /* Transmit Abort Output */ 15432147Sminshall return 0; 15532147Sminshall } else if (!MODE_LOCAL_CHARS(globalmode)) { 15638689Sborman if (c == termKillChar) { 15732147Sminshall xmitEL(); 15832147Sminshall return 0; 15938689Sborman } else if (c == termEraseChar) { 16032147Sminshall xmitEC(); /* Transmit Erase Character */ 16132147Sminshall return 0; 16232147Sminshall } 16332147Sminshall } 16432147Sminshall return 1; 16532147Sminshall } 16632147Sminshall 16732147Sminshall 16832147Sminshall /* 16932147Sminshall * Flush output to the terminal 17032147Sminshall */ 17132147Sminshall 17232147Sminshall void 17332553Sminshall TerminalFlushOutput() 17432147Sminshall { 17538689Sborman #ifndef USE_TERMIO 17632147Sminshall (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 17738689Sborman #else 17838689Sborman (void) ioctl(fileno(stdout), TCFLSH, (char *) 0); 17938689Sborman #endif 18032147Sminshall } 18132147Sminshall 18232147Sminshall void 18332553Sminshall TerminalSaveState() 18432147Sminshall { 18538689Sborman #ifndef USE_TERMIO 18632147Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 18732147Sminshall ioctl(0, TIOCGETC, (char *)&otc); 18832147Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 18932147Sminshall 19032147Sminshall ntc = otc; 19132147Sminshall nltc = oltc; 19232147Sminshall nttyb = ottyb; 19332254Sminshall 19438689Sborman #else /* USE_TERMIO */ 19538689Sborman ioctl(0, TCGETA, &old_tc); 19638689Sborman 19738689Sborman new_tc = old_tc; 19838689Sborman 19938689Sborman termFlushChar = 'O'&0x37; 20038689Sborman termWerasChar = 'W'&0x37; 20138689Sborman termRprntChar = 'R'&0x37; 20238689Sborman termLiteralNextChar = 'V'&0x37; 20338689Sborman termStartChar = 'Q'&0x37; 20438689Sborman termStopChar = 'S'&0x37; 20538689Sborman #endif /* USE_TERMIO */ 20632147Sminshall } 20732147Sminshall 20838689Sborman char * 20938689Sborman tcval(func) 21038689Sborman register int func; 21138689Sborman { 21238689Sborman switch(func) { 21338689Sborman case SLC_IP: return(&termIntChar); 21438689Sborman case SLC_ABORT: return(&termQuitChar); 21538689Sborman case SLC_EOF: return(&termEofChar); 21638689Sborman case SLC_EC: return(&termEraseChar); 21738689Sborman case SLC_EL: return(&termKillChar); 21838689Sborman case SLC_XON: return(&termStartChar); 21938689Sborman case SLC_XOFF: return(&termStopChar); 22038689Sborman #ifndef CRAY 22138689Sborman case SLC_AO: return(&termFlushChar); 22238689Sborman case SLC_SUSP: return(&termSuspChar); 22338689Sborman case SLC_EW: return(&termWerasChar); 22438689Sborman case SLC_RP: return(&termRprntChar); 22538689Sborman case SLC_LNEXT: return(&termLiteralNextChar); 226*38810Sborman #endif /* CRAY */ 22738689Sborman 22838689Sborman case SLC_SYNCH: 22938689Sborman case SLC_BRK: 23038689Sborman case SLC_AYT: 23138689Sborman case SLC_EOR: 23238689Sborman case SLC_FORW1: 23338689Sborman case SLC_FORW2: 23438689Sborman default: 23538689Sborman return((char *)0); 23638689Sborman } 23738689Sborman } 23838689Sborman 23932147Sminshall void 24038689Sborman TerminalDefaultChars() 24138689Sborman { 24238689Sborman #ifndef USE_TERMIO 24338689Sborman ntc = otc; 24438689Sborman nltc = oltc; 24538689Sborman nttyb.sg_kill = ottyb.sg_kill; 24638689Sborman nttyb.sg_erase = ottyb.sg_erase; 24738689Sborman #else /* USE_TERMIO */ 24838689Sborman memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); 24938689Sborman termFlushChar = 'O'&0x37; 25038689Sborman termWerasChar = 'W'&0x37; 25138689Sborman termRprntChar = 'R'&0x37; 25238689Sborman termLiteralNextChar = 'V'&0x37; 25338689Sborman termStartChar = 'Q'&0x37; 25438689Sborman termStopChar = 'S'&0x37; 25538689Sborman #endif /* USE_TERMIO */ 25638689Sborman } 25738689Sborman 25838689Sborman void 25932553Sminshall TerminalRestoreState() 26032147Sminshall { 26132147Sminshall } 26232147Sminshall 26332147Sminshall /* 26432147Sminshall * TerminalNewMode - set up terminal to a specific mode. 26538689Sborman * MODE_ECHO: do local terminal echo 26638689Sborman * MODE_FLOW: do local flow control 26738689Sborman * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 26838689Sborman * MODE_EDIT: do local line editing 26938689Sborman * 27038689Sborman * Command mode: 27138689Sborman * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 27238689Sborman * local echo 27338689Sborman * local editing 27438689Sborman * local xon/xoff 27538689Sborman * local signal mapping 27638689Sborman * 27738689Sborman * Linemode: 27838689Sborman * local/no editing 27938689Sborman * Both Linemode and Single Character mode: 28038689Sborman * local/remote echo 28138689Sborman * local/no xon/xoff 28238689Sborman * local/no signal mapping 28332147Sminshall */ 28432147Sminshall 28532147Sminshall 28632147Sminshall void 28733286Sminshall TerminalNewMode(f) 28832147Sminshall register int f; 28932147Sminshall { 29032147Sminshall static int prevmode = 0; 29138689Sborman #ifndef USE_TERMIO 29238689Sborman struct tchars tc; 29338689Sborman struct ltchars ltc; 29432147Sminshall struct sgttyb sb; 29538689Sborman #else /* USE_TERMIO */ 29638689Sborman struct termio tmp_tc; 29738689Sborman #endif /* USE_TERMIO */ 29832147Sminshall int onoff; 29932147Sminshall int old; 30032147Sminshall 30138689Sborman globalmode = f&~MODE_FORCE; 30232147Sminshall if (prevmode == f) 30332147Sminshall return; 30438689Sborman 30538689Sborman /* 30638689Sborman * Write any outstanding data before switching modes 30738689Sborman * ttyflush() returns 0 only when there is no more data 30838689Sborman * left to write out, it returns -1 if it couldn't do 30938689Sborman * anything at all, otherwise it returns 1 + the number 31038689Sborman * of characters left to write. 31138689Sborman */ 31238689Sborman old = ttyflush(SYNCHing|flushout); 31338689Sborman if (old < 0 || old > 1) { 31438689Sborman #ifndef USE_TERMIO 31538689Sborman ioctl(tin, TIOCGETP, (char *)&sb); 31638689Sborman #else /* USE_TERMIO */ 31738689Sborman ioctl(tin, TCGETA, (char *)&tmp_tc); 31838689Sborman #endif /* USE_TERMIO */ 31938689Sborman do { 32038689Sborman /* 32138689Sborman * Wait for data to drain, then flush again. 32238689Sborman */ 32338689Sborman #ifndef USE_TERMIO 32438689Sborman ioctl(tin, TIOCSETP, (char *)&sb); 32538689Sborman #else /* USE_TERMIO */ 32638689Sborman ioctl(tin, TCSETAW, (char *)&tmp_tc); 32738689Sborman #endif /* USE_TERMIO */ 32838689Sborman old = ttyflush(SYNCHing|flushout); 32938689Sborman } while (old < 0 || old > 1); 33038689Sborman } 33138689Sborman 33232147Sminshall old = prevmode; 33338689Sborman prevmode = f&~MODE_FORCE; 33438689Sborman #ifndef USE_TERMIO 33532147Sminshall sb = nttyb; 33638689Sborman tc = ntc; 33738689Sborman ltc = nltc; 33838689Sborman #else 33938689Sborman tmp_tc = new_tc; 34038689Sborman #endif 34132147Sminshall 34238689Sborman if (f&MODE_ECHO) { 34338689Sborman #ifndef USE_TERMIO 34438689Sborman sb.sg_flags |= ECHO; 34538689Sborman #else 34638689Sborman tmp_tc.c_lflag |= ECHO; 34738689Sborman tmp_tc.c_oflag |= ONLCR; 34838689Sborman tmp_tc.c_iflag |= ICRNL; 34938689Sborman #endif 35038689Sborman } else { 35138689Sborman #ifndef USE_TERMIO 35238689Sborman sb.sg_flags &= ~ECHO; 35338689Sborman #else 35438689Sborman tmp_tc.c_lflag &= ~ECHO; 35538689Sborman tmp_tc.c_oflag &= ~ONLCR; 35638689Sborman tmp_tc.c_iflag &= ~ICRNL; 35738689Sborman #endif 35838689Sborman } 35932147Sminshall 36038689Sborman if ((f&MODE_FLOW) == 0) { 36138689Sborman #ifndef USE_TERMIO 36238689Sborman tc.t_startc = -1; 36338689Sborman tc.t_stopc = -1; 36438689Sborman #else 36538689Sborman tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON); 36638689Sborman } else { 36738689Sborman tmp_tc.c_iflag |= IXANY|IXOFF|IXON; 36838689Sborman #endif 36938689Sborman } 37032147Sminshall 37138689Sborman if ((f&MODE_TRAPSIG) == 0) { 37238689Sborman #ifndef USE_TERMIO 37338689Sborman tc.t_intrc = -1; 37438689Sborman tc.t_quitc = -1; 37538689Sborman tc.t_eofc = -1; 37638689Sborman ltc.t_suspc = -1; 37738689Sborman ltc.t_dsuspc = -1; 37838689Sborman #else 37938689Sborman tmp_tc.c_lflag &= ~ISIG; 38038689Sborman #endif 38138689Sborman localchars = 0; 38238689Sborman } else { 38338689Sborman #ifdef USE_TERMIO 38438689Sborman tmp_tc.c_lflag |= ISIG; 38538689Sborman #endif 38638689Sborman localchars = 1; 38738689Sborman } 38838689Sborman 38938689Sborman if (f&MODE_EDIT) { 39038689Sborman #ifndef USE_TERMIO 39138689Sborman sb.sg_flags &= ~CBREAK; 39238689Sborman sb.sg_flags |= CRMOD; 39338689Sborman #else 39438689Sborman tmp_tc.c_lflag |= ICANON; 39538689Sborman #endif 39638689Sborman } else { 39738689Sborman #ifndef USE_TERMIO 39838689Sborman sb.sg_flags |= CBREAK; 39938689Sborman if (f&MODE_ECHO) 40032147Sminshall sb.sg_flags |= CRMOD; 40138689Sborman else 40238689Sborman sb.sg_flags &= ~CRMOD; 40338689Sborman #else 40438689Sborman tmp_tc.c_lflag &= ~ICANON; 40538689Sborman tmp_tc.c_iflag &= ~ICRNL; 40638689Sborman tmp_tc.c_cc[VMIN] = 1; 40738689Sborman tmp_tc.c_cc[VTIME] = 0; 40838689Sborman #endif 40938689Sborman } 41032147Sminshall 41138689Sborman if (f == -1) { 41238689Sborman onoff = 0; 41338689Sborman } else { 41438689Sborman onoff = 1; 41532147Sminshall } 41638689Sborman 41738689Sborman #ifndef USE_TERMIO 41838689Sborman if (f != -1) { 41938689Sborman if (f&MODE_EDIT) { 42038689Sborman void doescape(); 42138689Sborman 42238689Sborman ltc.t_suspc = escape; 42338689Sborman (void) signal(SIGTSTP, (int (*)())doescape); 42438689Sborman } else if (old&MODE_EDIT) { 42538689Sborman (void) signal(SIGTSTP, SIG_DFL); 42638689Sborman sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 42738689Sborman } 42838689Sborman ioctl(tin, TIOCSLTC, (char *)<c); 42938689Sborman ioctl(tin, TIOCSETC, (char *)&tc); 43038689Sborman ioctl(tin, TIOCSETP, (char *)&sb); 43138689Sborman } else { 43238689Sborman (void) signal(SIGTSTP, SIG_DFL); 43338689Sborman sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 43438689Sborman ioctl(tin, TIOCSLTC, (char *)&oltc); 43538689Sborman ioctl(tin, TIOCSETC, (char *)&otc); 43638689Sborman ioctl(tin, TIOCSETP, (char *)&ottyb); 43738689Sborman } 43832147Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 43933286Sminshall ioctl(tin, FIONBIO, (char *)&onoff); 44033286Sminshall ioctl(tout, FIONBIO, (char *)&onoff); 44132147Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 44232147Sminshall #if defined(TN3270) 44336242Sminshall if (noasynchtty == 0) { 44433286Sminshall ioctl(tin, FIOASYNC, (char *)&onoff); 44532147Sminshall } 44632147Sminshall #endif /* defined(TN3270) */ 44738689Sborman #else /* USE_TERMIO */ 44838689Sborman if (ioctl(tin, TCSETAW, &tmp_tc) < 0) 44938689Sborman ioctl(tin, TCSETA, &tmp_tc); 45038689Sborman #endif /* USE_TERMIO */ 45132147Sminshall } 45232147Sminshall 45337219Sminshall void 45437219Sminshall TerminalSpeeds(ispeed, ospeed) 45537219Sminshall long *ispeed; 45637219Sminshall long *ospeed; 45737219Sminshall { 45837219Sminshall /* 45937219Sminshall * The order here is important. The index of each speed needs to 46037219Sminshall * correspond with the sgtty structure value for that speed. 46137219Sminshall * 46237219Sminshall * Additionally, the search algorithm assumes the table is in 46337219Sminshall * ascending sequence. 46437219Sminshall */ 46537219Sminshall static int ttyspeeds[] = { 46637219Sminshall 0, 50, 75, 110, 134, 150, 200, 300, 46737219Sminshall 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 }; 46837219Sminshall #define NUMSPEEDS sizeof ttyspeeds/sizeof ttyspeeds[0] 46932147Sminshall 47038689Sborman if ((OSPEED < 0) || (OSPEED > NUMSPEEDS) || 47138689Sborman (ISPEED < 0) || (ISPEED > NUMSPEEDS)) { 47237219Sminshall ExitString("Invalid terminal speed."); 47337219Sminshall /*NOTREACHED*/ 47437219Sminshall } else { 47538689Sborman *ispeed = ttyspeeds[ISPEED]; 47638689Sborman *ospeed = ttyspeeds[OSPEED]; 47737219Sminshall } 47837219Sminshall } 47937219Sminshall 48032147Sminshall int 48137219Sminshall TerminalWindowSize(rows, cols) 48237219Sminshall long *rows, *cols; 48337219Sminshall { 48438689Sborman #ifdef TIOCGWINSZ 48537219Sminshall struct winsize ws; 48637219Sminshall 48738689Sborman if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 48838689Sborman *rows = ws.ws_row; 48938689Sborman *cols = ws.ws_col; 49038689Sborman return 1; 49137219Sminshall } 492*38810Sborman #endif /* TIOCGWINSZ */ 49338689Sborman return 0; 49437219Sminshall } 49537219Sminshall 49637219Sminshall int 49735417Sminshall NetClose(fd) 49835417Sminshall int fd; 49932147Sminshall { 50035417Sminshall return close(fd); 50132147Sminshall } 50232147Sminshall 50332147Sminshall 50432147Sminshall void 50532553Sminshall NetNonblockingIO(fd, onoff) 50632147Sminshall int 50732147Sminshall fd, 50832147Sminshall onoff; 50932147Sminshall { 51032147Sminshall ioctl(fd, FIONBIO, (char *)&onoff); 51132147Sminshall } 51232147Sminshall 51334849Sminshall #if defined(TN3270) 51432147Sminshall void 51532553Sminshall NetSigIO(fd, onoff) 51632147Sminshall int 51732147Sminshall fd, 51832147Sminshall onoff; 51932147Sminshall { 52032147Sminshall ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ 52132147Sminshall } 52232147Sminshall 52332147Sminshall void 52432553Sminshall NetSetPgrp(fd) 52532147Sminshall int fd; 52632147Sminshall { 52732147Sminshall int myPid; 52832147Sminshall 52932147Sminshall myPid = getpid(); 53036274Sminshall fcntl(fd, F_SETOWN, myPid); 53132147Sminshall } 53234849Sminshall #endif /*defined(TN3270)*/ 53332553Sminshall 53432553Sminshall /* 53532553Sminshall * Various signal handling routines. 53632553Sminshall */ 53732147Sminshall 53833286Sminshall static void 53932553Sminshall deadpeer() 54032553Sminshall { 54132553Sminshall setcommandmode(); 54232553Sminshall longjmp(peerdied, -1); 54332553Sminshall } 54432147Sminshall 54533286Sminshall static void 54632553Sminshall intr() 54732553Sminshall { 54832553Sminshall if (localchars) { 54932553Sminshall intp(); 55032553Sminshall return; 55132553Sminshall } 55232553Sminshall setcommandmode(); 55332553Sminshall longjmp(toplevel, -1); 55432553Sminshall } 55532553Sminshall 55633286Sminshall static void 55732553Sminshall intr2() 55832553Sminshall { 55932553Sminshall if (localchars) { 56038689Sborman #ifdef KLUDGELINEMODE 56138689Sborman if (kludgelinemode) 56238689Sborman sendbrk(); 56338689Sborman else 56438689Sborman #endif 56538689Sborman sendabort(); 56632553Sminshall return; 56732553Sminshall } 56832553Sminshall } 56932553Sminshall 57033286Sminshall static void 57137219Sminshall sendwin() 57237219Sminshall { 57337219Sminshall if (connected) { 57437219Sminshall sendnaws(); 57537219Sminshall } 57637219Sminshall } 57737219Sminshall 57837219Sminshall static void 57932553Sminshall doescape() 58032553Sminshall { 58138689Sborman command(0, 0, 0); 58232553Sminshall } 58332553Sminshall 58432553Sminshall void 58532531Sminshall sys_telnet_init() 58632531Sminshall { 58738689Sborman #ifndef CRAY 58834849Sminshall (void) signal(SIGINT, (int (*)())intr); 58934849Sminshall (void) signal(SIGQUIT, (int (*)())intr2); 59034849Sminshall (void) signal(SIGPIPE, (int (*)())deadpeer); 59138689Sborman #else 59238689Sborman (void) signal(SIGINT, (void (*)())intr); 59338689Sborman (void) signal(SIGQUIT, (void (*)())intr2); 59438689Sborman (void) signal(SIGPIPE, (void (*)())deadpeer); 59538689Sborman #endif 59638689Sborman #ifdef SIGWINCH 59737219Sminshall (void) signal(SIGWINCH, (int (*)())sendwin); 59838689Sborman #endif 59932553Sminshall 60038689Sborman setconnmode(0); 60132531Sminshall 60232531Sminshall NetNonblockingIO(net, 1); 60332531Sminshall 60432531Sminshall #if defined(TN3270) 60536242Sminshall if (noasynchnet == 0) { /* DBX can't handle! */ 60632531Sminshall NetSigIO(net, 1); 60732531Sminshall NetSetPgrp(net); 60832531Sminshall } 60932531Sminshall #endif /* defined(TN3270) */ 61032531Sminshall 61132531Sminshall #if defined(SO_OOBINLINE) 61234849Sminshall if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 61334849Sminshall perror("SetSockOpt"); 61434849Sminshall } 61532531Sminshall #endif /* defined(SO_OOBINLINE) */ 61632531Sminshall } 61732531Sminshall 61832531Sminshall /* 61932531Sminshall * Process rings - 62032531Sminshall * 62132531Sminshall * This routine tries to fill up/empty our various rings. 62232531Sminshall * 62332531Sminshall * The parameter specifies whether this is a poll operation, 62432531Sminshall * or a block-until-something-happens operation. 62532531Sminshall * 62632531Sminshall * The return value is 1 if something happened, 0 if not. 62732531Sminshall */ 62832531Sminshall 62932531Sminshall int 63032531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll) 63132531Sminshall int poll; /* If 0, then block until something to do */ 63232531Sminshall { 63332531Sminshall register int c; 63432531Sminshall /* One wants to be a bit careful about setting returnValue 63532531Sminshall * to one, since a one implies we did some useful work, 63632531Sminshall * and therefore probably won't be called to block next 63732531Sminshall * time (TN3270 mode only). 63832531Sminshall */ 63932531Sminshall int returnValue = 0; 64032531Sminshall static struct timeval TimeValue = { 0 }; 64132531Sminshall 64232531Sminshall if (netout) { 64332531Sminshall FD_SET(net, &obits); 64432531Sminshall } 64532531Sminshall if (ttyout) { 64632531Sminshall FD_SET(tout, &obits); 64732531Sminshall } 64832531Sminshall #if defined(TN3270) 64932531Sminshall if (ttyin) { 65032531Sminshall FD_SET(tin, &ibits); 65132531Sminshall } 65232531Sminshall #else /* defined(TN3270) */ 65332531Sminshall if (ttyin) { 65432531Sminshall FD_SET(tin, &ibits); 65532531Sminshall } 65632531Sminshall #endif /* defined(TN3270) */ 65732531Sminshall #if defined(TN3270) 65832531Sminshall if (netin) { 65932531Sminshall FD_SET(net, &ibits); 66032531Sminshall } 66132531Sminshall # else /* !defined(TN3270) */ 66232531Sminshall if (netin) { 66332531Sminshall FD_SET(net, &ibits); 66432531Sminshall } 66532531Sminshall # endif /* !defined(TN3270) */ 66632531Sminshall if (netex) { 66732531Sminshall FD_SET(net, &xbits); 66832531Sminshall } 66932531Sminshall if ((c = select(16, &ibits, &obits, &xbits, 67032531Sminshall (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { 67132531Sminshall if (c == -1) { 67232531Sminshall /* 67332531Sminshall * we can get EINTR if we are in line mode, 67432531Sminshall * and the user does an escape (TSTP), or 67532531Sminshall * some other signal generator. 67632531Sminshall */ 67732531Sminshall if (errno == EINTR) { 67832531Sminshall return 0; 67932531Sminshall } 68032531Sminshall # if defined(TN3270) 68132531Sminshall /* 68232531Sminshall * we can get EBADF if we were in transparent 68332531Sminshall * mode, and the transcom process died. 68432531Sminshall */ 68532531Sminshall if (errno == EBADF) { 68632531Sminshall /* 68732531Sminshall * zero the bits (even though kernel does it) 68832531Sminshall * to make sure we are selecting on the right 68932531Sminshall * ones. 69032531Sminshall */ 69132531Sminshall FD_ZERO(&ibits); 69232531Sminshall FD_ZERO(&obits); 69332531Sminshall FD_ZERO(&xbits); 69432531Sminshall return 0; 69532531Sminshall } 69632531Sminshall # endif /* defined(TN3270) */ 69732531Sminshall /* I don't like this, does it ever happen? */ 69832531Sminshall printf("sleep(5) from telnet, after select\r\n"); 69932531Sminshall sleep(5); 70032531Sminshall } 70132531Sminshall return 0; 70232531Sminshall } 70332531Sminshall 70432531Sminshall /* 70532531Sminshall * Any urgent data? 70632531Sminshall */ 70732531Sminshall if (FD_ISSET(net, &xbits)) { 70832531Sminshall FD_CLR(net, &xbits); 70932531Sminshall SYNCHing = 1; 71032531Sminshall ttyflush(1); /* flush already enqueued data */ 71132531Sminshall } 71232531Sminshall 71332531Sminshall /* 71432531Sminshall * Something to read from the network... 71532531Sminshall */ 71632531Sminshall if (FD_ISSET(net, &ibits)) { 71732531Sminshall int canread; 71832531Sminshall 71932531Sminshall FD_CLR(net, &ibits); 72032531Sminshall canread = ring_empty_consecutive(&netiring); 72132531Sminshall #if !defined(SO_OOBINLINE) 72232531Sminshall /* 72332531Sminshall * In 4.2 (and some early 4.3) systems, the 72432531Sminshall * OOB indication and data handling in the kernel 72532531Sminshall * is such that if two separate TCP Urgent requests 72632531Sminshall * come in, one byte of TCP data will be overlaid. 72732531Sminshall * This is fatal for Telnet, but we try to live 72832531Sminshall * with it. 72932531Sminshall * 73032531Sminshall * In addition, in 4.2 (and...), a special protocol 73132531Sminshall * is needed to pick up the TCP Urgent data in 73232531Sminshall * the correct sequence. 73332531Sminshall * 73432531Sminshall * What we do is: if we think we are in urgent 73532531Sminshall * mode, we look to see if we are "at the mark". 73632531Sminshall * If we are, we do an OOB receive. If we run 73732531Sminshall * this twice, we will do the OOB receive twice, 73832531Sminshall * but the second will fail, since the second 73932531Sminshall * time we were "at the mark", but there wasn't 74032531Sminshall * any data there (the kernel doesn't reset 74132531Sminshall * "at the mark" until we do a normal read). 74232531Sminshall * Once we've read the OOB data, we go ahead 74332531Sminshall * and do normal reads. 74432531Sminshall * 74532531Sminshall * There is also another problem, which is that 74632531Sminshall * since the OOB byte we read doesn't put us 74732531Sminshall * out of OOB state, and since that byte is most 74832531Sminshall * likely the TELNET DM (data mark), we would 74932531Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 75032531Sminshall * So, clocks to the rescue. If we've "just" 75132531Sminshall * received a DM, then we test for the 75232531Sminshall * presence of OOB data when the receive OOB 75332531Sminshall * fails (and AFTER we did the normal mode read 75432531Sminshall * to clear "at the mark"). 75532531Sminshall */ 75632531Sminshall if (SYNCHing) { 75732531Sminshall int atmark; 75832531Sminshall 75932531Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 76032531Sminshall if (atmark) { 76132531Sminshall c = recv(net, netiring.supply, canread, MSG_OOB); 76232531Sminshall if ((c == -1) && (errno == EINVAL)) { 76332531Sminshall c = recv(net, netiring.supply, canread, 0); 76432531Sminshall if (clocks.didnetreceive < clocks.gotDM) { 76532531Sminshall SYNCHing = stilloob(net); 76632531Sminshall } 76732531Sminshall } 76832531Sminshall } else { 76932531Sminshall c = recv(net, netiring.supply, canread, 0); 77032531Sminshall } 77132531Sminshall } else { 77232531Sminshall c = recv(net, netiring.supply, canread, 0); 77332531Sminshall } 77432531Sminshall settimer(didnetreceive); 77532531Sminshall #else /* !defined(SO_OOBINLINE) */ 77632531Sminshall c = recv(net, netiring.supply, canread, 0); 77732531Sminshall #endif /* !defined(SO_OOBINLINE) */ 77832531Sminshall if (c < 0 && errno == EWOULDBLOCK) { 77932531Sminshall c = 0; 78032531Sminshall } else if (c <= 0) { 78132531Sminshall return -1; 78232531Sminshall } 78332531Sminshall if (netdata) { 78432531Sminshall Dump('<', netiring.supply, c); 78532531Sminshall } 78632667Sminshall if (c) 78732667Sminshall ring_supplied(&netiring, c); 78832531Sminshall returnValue = 1; 78932531Sminshall } 79032531Sminshall 79132531Sminshall /* 79232531Sminshall * Something to read from the tty... 79332531Sminshall */ 79432531Sminshall if (FD_ISSET(tin, &ibits)) { 79532531Sminshall FD_CLR(tin, &ibits); 79633286Sminshall c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 79732531Sminshall if (c < 0 && errno == EWOULDBLOCK) { 79832531Sminshall c = 0; 79932531Sminshall } else { 80032531Sminshall /* EOF detection for line mode!!!! */ 80133281Sminshall if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 80232531Sminshall /* must be an EOF... */ 80332531Sminshall *ttyiring.supply = termEofChar; 80432531Sminshall c = 1; 80532531Sminshall } 80632531Sminshall if (c <= 0) { 80732531Sminshall return -1; 80832531Sminshall } 80938208Sminshall if (termdata) { 81038208Sminshall Dump('<', ttyiring.supply, c); 81138208Sminshall } 81232667Sminshall ring_supplied(&ttyiring, c); 81332531Sminshall } 81432531Sminshall returnValue = 1; /* did something useful */ 81532531Sminshall } 81632531Sminshall 81732531Sminshall if (FD_ISSET(net, &obits)) { 81832531Sminshall FD_CLR(net, &obits); 81932531Sminshall returnValue |= netflush(); 82032531Sminshall } 82132531Sminshall if (FD_ISSET(tout, &obits)) { 82232531Sminshall FD_CLR(tout, &obits); 82338689Sborman returnValue |= (ttyflush(SYNCHing|flushout) > 0); 82432531Sminshall } 82532531Sminshall 82632531Sminshall return returnValue; 82732531Sminshall } 82832531Sminshall #endif /* defined(unix) */ 829