xref: /csrg-svn/usr.bin/telnet/sys_bsd.c (revision 38689)
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 *)&ltc);
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