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*38689Sborman static char sccsid[] = "@(#)sys_bsd.c 1.19 (Berkeley) 08/21/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> 35*38689Sborman #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 50*38689Sborman #ifndef USE_TERMIO 51*38689Sborman struct tchars otc = { 0 }, ntc = { 0 }; 52*38689Sborman struct ltchars oltc = { 0 }, nltc = { 0 }; 53*38689Sborman struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 5432147Sminshall 55*38689Sborman #define ISPEED ottyb.sg_ispeed 56*38689Sborman #define OSPEED ottyb.sg_ospeed 57*38689Sborman #else /* USE_TERMIO */ 58*38689Sborman struct termio old_tc = { 0 }; 59*38689Sborman extern struct termio new_tc; 60*38689Sborman 61*38689Sborman #define ISPEED (old_tc.c_cflag&CBAUD) 62*38689Sborman #define OSPEED ISPEED 63*38689Sborman #endif /* USE_TERMIO */ 64*38689Sborman 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 111*38689Sborman #ifdef KLUDGELINEMODE 112*38689Sborman extern int kludgelinemode; 113*38689Sborman #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 132*38689Sborman if (c == termIntChar) { 13332147Sminshall intp(); 13432147Sminshall return 0; 135*38689Sborman } else if (c == termQuitChar) { 136*38689Sborman #ifdef KLUDGELINEMODE 137*38689Sborman if (kludgelinemode) 138*38689Sborman sendbrk(); 139*38689Sborman else 140*38689Sborman #endif 141*38689Sborman sendabort(); 14232147Sminshall return 0; 143*38689Sborman } else if (c == termEofChar) { 144*38689Sborman if (my_want_state_is_will(TELOPT_LINEMODE)) { 145*38689Sborman sendeof(); 146*38689Sborman return 0; 147*38689Sborman } 148*38689Sborman return 1; 149*38689Sborman } else if (c == termSuspChar) { 150*38689Sborman sendsusp(); 151*38689Sborman return(0); 152*38689Sborman } else if (c == termFlushChar) { 15332147Sminshall xmitAO(); /* Transmit Abort Output */ 15432147Sminshall return 0; 15532147Sminshall } else if (!MODE_LOCAL_CHARS(globalmode)) { 156*38689Sborman if (c == termKillChar) { 15732147Sminshall xmitEL(); 15832147Sminshall return 0; 159*38689Sborman } 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 { 175*38689Sborman #ifndef USE_TERMIO 17632147Sminshall (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 177*38689Sborman #else 178*38689Sborman (void) ioctl(fileno(stdout), TCFLSH, (char *) 0); 179*38689Sborman #endif 18032147Sminshall } 18132147Sminshall 18232147Sminshall void 18332553Sminshall TerminalSaveState() 18432147Sminshall { 185*38689Sborman #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 194*38689Sborman #else /* USE_TERMIO */ 195*38689Sborman ioctl(0, TCGETA, &old_tc); 196*38689Sborman 197*38689Sborman new_tc = old_tc; 198*38689Sborman 199*38689Sborman termFlushChar = 'O'&0x37; 200*38689Sborman termWerasChar = 'W'&0x37; 201*38689Sborman termRprntChar = 'R'&0x37; 202*38689Sborman termLiteralNextChar = 'V'&0x37; 203*38689Sborman termStartChar = 'Q'&0x37; 204*38689Sborman termStopChar = 'S'&0x37; 205*38689Sborman #endif /* USE_TERMIO */ 20632147Sminshall } 20732147Sminshall 208*38689Sborman char * 209*38689Sborman tcval(func) 210*38689Sborman register int func; 211*38689Sborman { 212*38689Sborman switch(func) { 213*38689Sborman case SLC_IP: return(&termIntChar); 214*38689Sborman case SLC_ABORT: return(&termQuitChar); 215*38689Sborman case SLC_EOF: return(&termEofChar); 216*38689Sborman case SLC_EC: return(&termEraseChar); 217*38689Sborman case SLC_EL: return(&termKillChar); 218*38689Sborman case SLC_XON: return(&termStartChar); 219*38689Sborman case SLC_XOFF: return(&termStopChar); 220*38689Sborman #ifndef CRAY 221*38689Sborman case SLC_AO: return(&termFlushChar); 222*38689Sborman case SLC_SUSP: return(&termSuspChar); 223*38689Sborman case SLC_EW: return(&termWerasChar); 224*38689Sborman case SLC_RP: return(&termRprntChar); 225*38689Sborman case SLC_LNEXT: return(&termLiteralNextChar); 226*38689Sborman #endif CRAY 227*38689Sborman 228*38689Sborman case SLC_SYNCH: 229*38689Sborman case SLC_BRK: 230*38689Sborman case SLC_AYT: 231*38689Sborman case SLC_EOR: 232*38689Sborman case SLC_FORW1: 233*38689Sborman case SLC_FORW2: 234*38689Sborman default: 235*38689Sborman return((char *)0); 236*38689Sborman } 237*38689Sborman } 238*38689Sborman 23932147Sminshall void 240*38689Sborman TerminalDefaultChars() 241*38689Sborman { 242*38689Sborman #ifndef USE_TERMIO 243*38689Sborman ntc = otc; 244*38689Sborman nltc = oltc; 245*38689Sborman nttyb.sg_kill = ottyb.sg_kill; 246*38689Sborman nttyb.sg_erase = ottyb.sg_erase; 247*38689Sborman #else /* USE_TERMIO */ 248*38689Sborman memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); 249*38689Sborman termFlushChar = 'O'&0x37; 250*38689Sborman termWerasChar = 'W'&0x37; 251*38689Sborman termRprntChar = 'R'&0x37; 252*38689Sborman termLiteralNextChar = 'V'&0x37; 253*38689Sborman termStartChar = 'Q'&0x37; 254*38689Sborman termStopChar = 'S'&0x37; 255*38689Sborman #endif /* USE_TERMIO */ 256*38689Sborman } 257*38689Sborman 258*38689Sborman void 25932553Sminshall TerminalRestoreState() 26032147Sminshall { 26132147Sminshall } 26232147Sminshall 26332147Sminshall /* 26432147Sminshall * TerminalNewMode - set up terminal to a specific mode. 265*38689Sborman * MODE_ECHO: do local terminal echo 266*38689Sborman * MODE_FLOW: do local flow control 267*38689Sborman * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 268*38689Sborman * MODE_EDIT: do local line editing 269*38689Sborman * 270*38689Sborman * Command mode: 271*38689Sborman * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 272*38689Sborman * local echo 273*38689Sborman * local editing 274*38689Sborman * local xon/xoff 275*38689Sborman * local signal mapping 276*38689Sborman * 277*38689Sborman * Linemode: 278*38689Sborman * local/no editing 279*38689Sborman * Both Linemode and Single Character mode: 280*38689Sborman * local/remote echo 281*38689Sborman * local/no xon/xoff 282*38689Sborman * local/no signal mapping 28332147Sminshall */ 28432147Sminshall 28532147Sminshall 28632147Sminshall void 28733286Sminshall TerminalNewMode(f) 28832147Sminshall register int f; 28932147Sminshall { 29032147Sminshall static int prevmode = 0; 291*38689Sborman #ifndef USE_TERMIO 292*38689Sborman struct tchars tc; 293*38689Sborman struct ltchars ltc; 29432147Sminshall struct sgttyb sb; 295*38689Sborman #else /* USE_TERMIO */ 296*38689Sborman struct termio tmp_tc; 297*38689Sborman #endif /* USE_TERMIO */ 29832147Sminshall int onoff; 29932147Sminshall int old; 30032147Sminshall 301*38689Sborman globalmode = f&~MODE_FORCE; 30232147Sminshall if (prevmode == f) 30332147Sminshall return; 304*38689Sborman 305*38689Sborman /* 306*38689Sborman * Write any outstanding data before switching modes 307*38689Sborman * ttyflush() returns 0 only when there is no more data 308*38689Sborman * left to write out, it returns -1 if it couldn't do 309*38689Sborman * anything at all, otherwise it returns 1 + the number 310*38689Sborman * of characters left to write. 311*38689Sborman */ 312*38689Sborman old = ttyflush(SYNCHing|flushout); 313*38689Sborman if (old < 0 || old > 1) { 314*38689Sborman #ifndef USE_TERMIO 315*38689Sborman ioctl(tin, TIOCGETP, (char *)&sb); 316*38689Sborman #else /* USE_TERMIO */ 317*38689Sborman ioctl(tin, TCGETA, (char *)&tmp_tc); 318*38689Sborman #endif /* USE_TERMIO */ 319*38689Sborman do { 320*38689Sborman /* 321*38689Sborman * Wait for data to drain, then flush again. 322*38689Sborman */ 323*38689Sborman #ifndef USE_TERMIO 324*38689Sborman ioctl(tin, TIOCSETP, (char *)&sb); 325*38689Sborman #else /* USE_TERMIO */ 326*38689Sborman ioctl(tin, TCSETAW, (char *)&tmp_tc); 327*38689Sborman #endif /* USE_TERMIO */ 328*38689Sborman old = ttyflush(SYNCHing|flushout); 329*38689Sborman } while (old < 0 || old > 1); 330*38689Sborman } 331*38689Sborman 33232147Sminshall old = prevmode; 333*38689Sborman prevmode = f&~MODE_FORCE; 334*38689Sborman #ifndef USE_TERMIO 33532147Sminshall sb = nttyb; 336*38689Sborman tc = ntc; 337*38689Sborman ltc = nltc; 338*38689Sborman #else 339*38689Sborman tmp_tc = new_tc; 340*38689Sborman #endif 34132147Sminshall 342*38689Sborman if (f&MODE_ECHO) { 343*38689Sborman #ifndef USE_TERMIO 344*38689Sborman sb.sg_flags |= ECHO; 345*38689Sborman #else 346*38689Sborman tmp_tc.c_lflag |= ECHO; 347*38689Sborman tmp_tc.c_oflag |= ONLCR; 348*38689Sborman tmp_tc.c_iflag |= ICRNL; 349*38689Sborman #endif 350*38689Sborman } else { 351*38689Sborman #ifndef USE_TERMIO 352*38689Sborman sb.sg_flags &= ~ECHO; 353*38689Sborman #else 354*38689Sborman tmp_tc.c_lflag &= ~ECHO; 355*38689Sborman tmp_tc.c_oflag &= ~ONLCR; 356*38689Sborman tmp_tc.c_iflag &= ~ICRNL; 357*38689Sborman #endif 358*38689Sborman } 35932147Sminshall 360*38689Sborman if ((f&MODE_FLOW) == 0) { 361*38689Sborman #ifndef USE_TERMIO 362*38689Sborman tc.t_startc = -1; 363*38689Sborman tc.t_stopc = -1; 364*38689Sborman #else 365*38689Sborman tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON); 366*38689Sborman } else { 367*38689Sborman tmp_tc.c_iflag |= IXANY|IXOFF|IXON; 368*38689Sborman #endif 369*38689Sborman } 37032147Sminshall 371*38689Sborman if ((f&MODE_TRAPSIG) == 0) { 372*38689Sborman #ifndef USE_TERMIO 373*38689Sborman tc.t_intrc = -1; 374*38689Sborman tc.t_quitc = -1; 375*38689Sborman tc.t_eofc = -1; 376*38689Sborman ltc.t_suspc = -1; 377*38689Sborman ltc.t_dsuspc = -1; 378*38689Sborman #else 379*38689Sborman tmp_tc.c_lflag &= ~ISIG; 380*38689Sborman #endif 381*38689Sborman localchars = 0; 382*38689Sborman } else { 383*38689Sborman #ifdef USE_TERMIO 384*38689Sborman tmp_tc.c_lflag |= ISIG; 385*38689Sborman #endif 386*38689Sborman localchars = 1; 387*38689Sborman } 388*38689Sborman 389*38689Sborman if (f&MODE_EDIT) { 390*38689Sborman #ifndef USE_TERMIO 391*38689Sborman sb.sg_flags &= ~CBREAK; 392*38689Sborman sb.sg_flags |= CRMOD; 393*38689Sborman #else 394*38689Sborman tmp_tc.c_lflag |= ICANON; 395*38689Sborman #endif 396*38689Sborman } else { 397*38689Sborman #ifndef USE_TERMIO 398*38689Sborman sb.sg_flags |= CBREAK; 399*38689Sborman if (f&MODE_ECHO) 40032147Sminshall sb.sg_flags |= CRMOD; 401*38689Sborman else 402*38689Sborman sb.sg_flags &= ~CRMOD; 403*38689Sborman #else 404*38689Sborman tmp_tc.c_lflag &= ~ICANON; 405*38689Sborman tmp_tc.c_iflag &= ~ICRNL; 406*38689Sborman tmp_tc.c_cc[VMIN] = 1; 407*38689Sborman tmp_tc.c_cc[VTIME] = 0; 408*38689Sborman #endif 409*38689Sborman } 41032147Sminshall 411*38689Sborman if (f == -1) { 412*38689Sborman onoff = 0; 413*38689Sborman } else { 414*38689Sborman onoff = 1; 41532147Sminshall } 416*38689Sborman 417*38689Sborman #ifndef USE_TERMIO 418*38689Sborman if (f != -1) { 419*38689Sborman if (f&MODE_EDIT) { 420*38689Sborman void doescape(); 421*38689Sborman 422*38689Sborman ltc.t_suspc = escape; 423*38689Sborman (void) signal(SIGTSTP, (int (*)())doescape); 424*38689Sborman } else if (old&MODE_EDIT) { 425*38689Sborman (void) signal(SIGTSTP, SIG_DFL); 426*38689Sborman sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 427*38689Sborman } 428*38689Sborman ioctl(tin, TIOCSLTC, (char *)<c); 429*38689Sborman ioctl(tin, TIOCSETC, (char *)&tc); 430*38689Sborman ioctl(tin, TIOCSETP, (char *)&sb); 431*38689Sborman } else { 432*38689Sborman (void) signal(SIGTSTP, SIG_DFL); 433*38689Sborman sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 434*38689Sborman ioctl(tin, TIOCSLTC, (char *)&oltc); 435*38689Sborman ioctl(tin, TIOCSETC, (char *)&otc); 436*38689Sborman ioctl(tin, TIOCSETP, (char *)&ottyb); 437*38689Sborman } 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) */ 447*38689Sborman #else /* USE_TERMIO */ 448*38689Sborman if (ioctl(tin, TCSETAW, &tmp_tc) < 0) 449*38689Sborman ioctl(tin, TCSETA, &tmp_tc); 450*38689Sborman #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 470*38689Sborman if ((OSPEED < 0) || (OSPEED > NUMSPEEDS) || 471*38689Sborman (ISPEED < 0) || (ISPEED > NUMSPEEDS)) { 47237219Sminshall ExitString("Invalid terminal speed."); 47337219Sminshall /*NOTREACHED*/ 47437219Sminshall } else { 475*38689Sborman *ispeed = ttyspeeds[ISPEED]; 476*38689Sborman *ospeed = ttyspeeds[OSPEED]; 47737219Sminshall } 47837219Sminshall } 47937219Sminshall 48032147Sminshall int 48137219Sminshall TerminalWindowSize(rows, cols) 48237219Sminshall long *rows, *cols; 48337219Sminshall { 484*38689Sborman #ifdef TIOCGWINSZ 48537219Sminshall struct winsize ws; 48637219Sminshall 487*38689Sborman if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 488*38689Sborman *rows = ws.ws_row; 489*38689Sborman *cols = ws.ws_col; 490*38689Sborman return 1; 49137219Sminshall } 492*38689Sborman #endif TIOCGWINSZ 493*38689Sborman 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) { 560*38689Sborman #ifdef KLUDGELINEMODE 561*38689Sborman if (kludgelinemode) 562*38689Sborman sendbrk(); 563*38689Sborman else 564*38689Sborman #endif 565*38689Sborman 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 { 581*38689Sborman command(0, 0, 0); 58232553Sminshall } 58332553Sminshall 58432553Sminshall void 58532531Sminshall sys_telnet_init() 58632531Sminshall { 587*38689Sborman #ifndef CRAY 58834849Sminshall (void) signal(SIGINT, (int (*)())intr); 58934849Sminshall (void) signal(SIGQUIT, (int (*)())intr2); 59034849Sminshall (void) signal(SIGPIPE, (int (*)())deadpeer); 591*38689Sborman #else 592*38689Sborman (void) signal(SIGINT, (void (*)())intr); 593*38689Sborman (void) signal(SIGQUIT, (void (*)())intr2); 594*38689Sborman (void) signal(SIGPIPE, (void (*)())deadpeer); 595*38689Sborman #endif 596*38689Sborman #ifdef SIGWINCH 59737219Sminshall (void) signal(SIGWINCH, (int (*)())sendwin); 598*38689Sborman #endif 59932553Sminshall 600*38689Sborman 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); 823*38689Sborman returnValue |= (ttyflush(SYNCHing|flushout) > 0); 82432531Sminshall } 82532531Sminshall 82632531Sminshall return returnValue; 82732531Sminshall } 82832531Sminshall #endif /* defined(unix) */ 829