sys_bsd.c revision 82497
1/*
2 * Copyright (c) 1988, 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35#if 0
36static const char sccsid[] = "@(#)sys_bsd.c	8.4 (Berkeley) 5/30/95";
37#else
38static const char rcsid[] =
39 "$FreeBSD: head/contrib/telnet/telnet/sys_bsd.c 82497 2001-08-29 14:16:17Z markm $";
40#endif
41#endif /* not lint */
42
43/*
44 * The following routines try to encapsulate what is system dependent
45 * (at least between 4.x and dos) which is used in telnet.c.
46 */
47
48
49#include <fcntl.h>
50#include <sys/types.h>
51#include <sys/time.h>
52#include <sys/socket.h>
53#include <signal.h>
54#include <errno.h>
55#include <arpa/telnet.h>
56#include <unistd.h>
57
58#include "ring.h"
59
60#include "fdset.h"
61
62#include "defines.h"
63#include "externs.h"
64#include "types.h"
65
66#if	defined(USE_TERMIO) && !defined(SYSV_TERMIO)
67#define	SIG_FUNC_RET	void
68#else
69#define	SIG_FUNC_RET	int
70#endif
71
72#ifdef	SIGINFO
73extern SIG_FUNC_RET ayt_status();
74#endif
75
76int
77	tout,			/* Output file descriptor */
78	tin,			/* Input file descriptor */
79	net;
80
81#ifndef	USE_TERMIO
82struct	tchars otc = { 0 }, ntc = { 0 };
83struct	ltchars oltc = { 0 }, nltc = { 0 };
84struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
85int	olmode = 0;
86# define cfgetispeed(ptr)	(ptr)->sg_ispeed
87# define cfgetospeed(ptr)	(ptr)->sg_ospeed
88# define old_tc ottyb
89
90#else	/* USE_TERMIO */
91struct	termio old_tc = { 0 };
92extern struct termio new_tc;
93
94# ifndef	TCSANOW
95#  ifdef TCSETS
96#   define	TCSANOW		TCSETS
97#   define	TCSADRAIN	TCSETSW
98#   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
99#  else
100#   ifdef TCSETA
101#    define	TCSANOW		TCSETA
102#    define	TCSADRAIN	TCSETAW
103#    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
104#   else
105#    define	TCSANOW		TIOCSETA
106#    define	TCSADRAIN	TIOCSETAW
107#    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
108#   endif
109#  endif
110#  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
111#  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
112#  ifdef CIBAUD
113#   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
114#  else
115#   define	cfgetispeed(ptr)	cfgetospeed(ptr)
116#  endif
117# endif /* TCSANOW */
118# ifdef	sysV88
119# define TIOCFLUSH TC_PX_DRAIN
120# endif
121#endif	/* USE_TERMIO */
122
123static fd_set ibits, obits, xbits;
124
125
126    void
127init_sys()
128{
129    tout = fileno(stdout);
130    tin = fileno(stdin);
131    FD_ZERO(&ibits);
132    FD_ZERO(&obits);
133    FD_ZERO(&xbits);
134
135    errno = 0;
136}
137
138
139    int
140TerminalWrite(buf, n)
141    char *buf;
142    int  n;
143{
144    return write(tout, buf, n);
145}
146
147    int
148TerminalRead(buf, n)
149    char *buf;
150    int  n;
151{
152    return read(tin, buf, n);
153}
154
155/*
156 *
157 */
158
159    int
160TerminalAutoFlush()
161{
162#if	defined(LNOFLSH)
163    int flush;
164
165    ioctl(0, TIOCLGET, (char *)&flush);
166    return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
167#else	/* LNOFLSH */
168    return 1;
169#endif	/* LNOFLSH */
170}
171
172#ifdef	KLUDGELINEMODE
173extern int kludgelinemode;
174#endif
175/*
176 * TerminalSpecialChars()
177 *
178 * Look at an input character to see if it is a special character
179 * and decide what to do.
180 *
181 * Output:
182 *
183 *	0	Don't add this character.
184 *	1	Do add this character
185 */
186
187extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
188
189    int
190TerminalSpecialChars(c)
191    int	c;
192{
193    if (c == termIntChar) {
194	intp();
195	return 0;
196    } else if (c == termQuitChar) {
197#ifdef	KLUDGELINEMODE
198	if (kludgelinemode)
199	    sendbrk();
200	else
201#endif
202	    sendabort();
203	return 0;
204    } else if (c == termEofChar) {
205	if (my_want_state_is_will(TELOPT_LINEMODE)) {
206	    sendeof();
207	    return 0;
208	}
209	return 1;
210    } else if (c == termSuspChar) {
211	sendsusp();
212	return(0);
213    } else if (c == termFlushChar) {
214	xmitAO();		/* Transmit Abort Output */
215	return 0;
216    } else if (!MODE_LOCAL_CHARS(globalmode)) {
217	if (c == termKillChar) {
218	    xmitEL();
219	    return 0;
220	} else if (c == termEraseChar) {
221	    xmitEC();		/* Transmit Erase Character */
222	    return 0;
223	}
224    }
225    return 1;
226}
227
228
229/*
230 * Flush output to the terminal
231 */
232
233    void
234TerminalFlushOutput()
235{
236#ifdef	TIOCFLUSH
237    (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
238#else
239    (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
240#endif
241}
242
243    void
244TerminalSaveState()
245{
246#ifndef	USE_TERMIO
247    ioctl(0, TIOCGETP, (char *)&ottyb);
248    ioctl(0, TIOCGETC, (char *)&otc);
249    ioctl(0, TIOCGLTC, (char *)&oltc);
250    ioctl(0, TIOCLGET, (char *)&olmode);
251
252    ntc = otc;
253    nltc = oltc;
254    nttyb = ottyb;
255
256#else	/* USE_TERMIO */
257    tcgetattr(0, &old_tc);
258
259    new_tc = old_tc;
260
261#ifndef	VDISCARD
262    termFlushChar = CONTROL('O');
263#endif
264#ifndef	VWERASE
265    termWerasChar = CONTROL('W');
266#endif
267#ifndef	VREPRINT
268    termRprntChar = CONTROL('R');
269#endif
270#ifndef	VLNEXT
271    termLiteralNextChar = CONTROL('V');
272#endif
273#ifndef	VSTART
274    termStartChar = CONTROL('Q');
275#endif
276#ifndef	VSTOP
277    termStopChar = CONTROL('S');
278#endif
279#ifndef	VSTATUS
280    termAytChar = CONTROL('T');
281#endif
282#endif	/* USE_TERMIO */
283}
284
285    cc_t *
286tcval(func)
287    register int func;
288{
289    switch(func) {
290    case SLC_IP:	return(&termIntChar);
291    case SLC_ABORT:	return(&termQuitChar);
292    case SLC_EOF:	return(&termEofChar);
293    case SLC_EC:	return(&termEraseChar);
294    case SLC_EL:	return(&termKillChar);
295    case SLC_XON:	return(&termStartChar);
296    case SLC_XOFF:	return(&termStopChar);
297    case SLC_FORW1:	return(&termForw1Char);
298#ifdef	USE_TERMIO
299    case SLC_FORW2:	return(&termForw2Char);
300# ifdef	VDISCARD
301    case SLC_AO:	return(&termFlushChar);
302# endif
303# ifdef	VSUSP
304    case SLC_SUSP:	return(&termSuspChar);
305# endif
306# ifdef	VWERASE
307    case SLC_EW:	return(&termWerasChar);
308# endif
309# ifdef	VREPRINT
310    case SLC_RP:	return(&termRprntChar);
311# endif
312# ifdef	VLNEXT
313    case SLC_LNEXT:	return(&termLiteralNextChar);
314# endif
315# ifdef	VSTATUS
316    case SLC_AYT:	return(&termAytChar);
317# endif
318#endif
319
320    case SLC_SYNCH:
321    case SLC_BRK:
322    case SLC_EOR:
323    default:
324	return((cc_t *)0);
325    }
326}
327
328    void
329TerminalDefaultChars()
330{
331#ifndef	USE_TERMIO
332    ntc = otc;
333    nltc = oltc;
334    nttyb.sg_kill = ottyb.sg_kill;
335    nttyb.sg_erase = ottyb.sg_erase;
336#else	/* USE_TERMIO */
337    memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
338# ifndef	VDISCARD
339    termFlushChar = CONTROL('O');
340# endif
341# ifndef	VWERASE
342    termWerasChar = CONTROL('W');
343# endif
344# ifndef	VREPRINT
345    termRprntChar = CONTROL('R');
346# endif
347# ifndef	VLNEXT
348    termLiteralNextChar = CONTROL('V');
349# endif
350# ifndef	VSTART
351    termStartChar = CONTROL('Q');
352# endif
353# ifndef	VSTOP
354    termStopChar = CONTROL('S');
355# endif
356# ifndef	VSTATUS
357    termAytChar = CONTROL('T');
358# endif
359#endif	/* USE_TERMIO */
360}
361
362#ifdef notdef
363void
364TerminalRestoreState()
365{
366}
367#endif
368
369/*
370 * TerminalNewMode - set up terminal to a specific mode.
371 *	MODE_ECHO: do local terminal echo
372 *	MODE_FLOW: do local flow control
373 *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
374 *	MODE_EDIT: do local line editing
375 *
376 *	Command mode:
377 *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
378 *		local echo
379 *		local editing
380 *		local xon/xoff
381 *		local signal mapping
382 *
383 *	Linemode:
384 *		local/no editing
385 *	Both Linemode and Single Character mode:
386 *		local/remote echo
387 *		local/no xon/xoff
388 *		local/no signal mapping
389 */
390
391
392    void
393TerminalNewMode(f)
394    register int f;
395{
396    static int prevmode = 0;
397#ifndef	USE_TERMIO
398    struct tchars tc;
399    struct ltchars ltc;
400    struct sgttyb sb;
401    int lmode;
402#else	/* USE_TERMIO */
403    struct termio tmp_tc;
404#endif	/* USE_TERMIO */
405    int onoff;
406    int old;
407    cc_t esc;
408
409    globalmode = f&~MODE_FORCE;
410    if (prevmode == f)
411	return;
412
413    /*
414     * Write any outstanding data before switching modes
415     * ttyflush() returns 0 only when there is no more data
416     * left to write out, it returns -1 if it couldn't do
417     * anything at all, otherwise it returns 1 + the number
418     * of characters left to write.
419#ifndef	USE_TERMIO
420     * We would really like ask the kernel to wait for the output
421     * to drain, like we can do with the TCSADRAIN, but we don't have
422     * that option.  The only ioctl that waits for the output to
423     * drain, TIOCSETP, also flushes the input queue, which is NOT
424     * what we want (TIOCSETP is like TCSADFLUSH).
425#endif
426     */
427    old = ttyflush(SYNCHing|flushout);
428    if (old < 0 || old > 1) {
429#ifdef	USE_TERMIO
430	tcgetattr(tin, &tmp_tc);
431#endif	/* USE_TERMIO */
432	do {
433	    /*
434	     * Wait for data to drain, then flush again.
435	     */
436#ifdef	USE_TERMIO
437	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
438#endif	/* USE_TERMIO */
439	    old = ttyflush(SYNCHing|flushout);
440	} while (old < 0 || old > 1);
441    }
442
443    old = prevmode;
444    prevmode = f&~MODE_FORCE;
445#ifndef	USE_TERMIO
446    sb = nttyb;
447    tc = ntc;
448    ltc = nltc;
449    lmode = olmode;
450#else
451    tmp_tc = new_tc;
452#endif
453
454    if (f&MODE_ECHO) {
455#ifndef	USE_TERMIO
456	sb.sg_flags |= ECHO;
457#else
458	tmp_tc.c_lflag |= ECHO;
459	tmp_tc.c_oflag |= ONLCR;
460	if (crlf)
461		tmp_tc.c_iflag |= ICRNL;
462#endif
463    } else {
464#ifndef	USE_TERMIO
465	sb.sg_flags &= ~ECHO;
466#else
467	tmp_tc.c_lflag &= ~ECHO;
468	tmp_tc.c_oflag &= ~ONLCR;
469# ifdef notdef
470	if (crlf)
471		tmp_tc.c_iflag &= ~ICRNL;
472# endif
473#endif
474    }
475
476    if ((f&MODE_FLOW) == 0) {
477#ifndef	USE_TERMIO
478	tc.t_startc = _POSIX_VDISABLE;
479	tc.t_stopc = _POSIX_VDISABLE;
480#else
481	tmp_tc.c_iflag &= ~(IXOFF|IXON);	/* Leave the IXANY bit alone */
482    } else {
483	if (restartany < 0) {
484		tmp_tc.c_iflag |= IXOFF|IXON;	/* Leave the IXANY bit alone */
485	} else if (restartany > 0) {
486		tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
487	} else {
488		tmp_tc.c_iflag |= IXOFF|IXON;
489		tmp_tc.c_iflag &= ~IXANY;
490	}
491#endif
492    }
493
494    if ((f&MODE_TRAPSIG) == 0) {
495#ifndef	USE_TERMIO
496	tc.t_intrc = _POSIX_VDISABLE;
497	tc.t_quitc = _POSIX_VDISABLE;
498	tc.t_eofc = _POSIX_VDISABLE;
499	ltc.t_suspc = _POSIX_VDISABLE;
500	ltc.t_dsuspc = _POSIX_VDISABLE;
501#else
502	tmp_tc.c_lflag &= ~ISIG;
503#endif
504	localchars = 0;
505    } else {
506#ifdef	USE_TERMIO
507	tmp_tc.c_lflag |= ISIG;
508#endif
509	localchars = 1;
510    }
511
512    if (f&MODE_EDIT) {
513#ifndef	USE_TERMIO
514	sb.sg_flags &= ~CBREAK;
515	sb.sg_flags |= CRMOD;
516#else
517	tmp_tc.c_lflag |= ICANON;
518#endif
519    } else {
520#ifndef	USE_TERMIO
521	sb.sg_flags |= CBREAK;
522	if (f&MODE_ECHO)
523	    sb.sg_flags |= CRMOD;
524	else
525	    sb.sg_flags &= ~CRMOD;
526#else
527	tmp_tc.c_lflag &= ~ICANON;
528	tmp_tc.c_iflag &= ~ICRNL;
529	tmp_tc.c_cc[VMIN] = 1;
530	tmp_tc.c_cc[VTIME] = 0;
531#endif
532    }
533
534    if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
535#ifndef	USE_TERMIO
536	ltc.t_lnextc = _POSIX_VDISABLE;
537#else
538# ifdef VLNEXT
539	tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
540# endif
541#endif
542    }
543
544    if (f&MODE_SOFT_TAB) {
545#ifndef USE_TERMIO
546	sb.sg_flags |= XTABS;
547#else
548# ifdef	OXTABS
549	tmp_tc.c_oflag |= OXTABS;
550# endif
551# ifdef	TABDLY
552	tmp_tc.c_oflag &= ~TABDLY;
553	tmp_tc.c_oflag |= TAB3;
554# endif
555#endif
556    } else {
557#ifndef USE_TERMIO
558	sb.sg_flags &= ~XTABS;
559#else
560# ifdef	OXTABS
561	tmp_tc.c_oflag &= ~OXTABS;
562# endif
563# ifdef	TABDLY
564	tmp_tc.c_oflag &= ~TABDLY;
565# endif
566#endif
567    }
568
569    if (f&MODE_LIT_ECHO) {
570#ifndef USE_TERMIO
571	lmode &= ~LCTLECH;
572#else
573# ifdef	ECHOCTL
574	tmp_tc.c_lflag &= ~ECHOCTL;
575# endif
576#endif
577    } else {
578#ifndef USE_TERMIO
579	lmode |= LCTLECH;
580#else
581# ifdef	ECHOCTL
582	tmp_tc.c_lflag |= ECHOCTL;
583# endif
584#endif
585    }
586
587    if (f == -1) {
588	onoff = 0;
589    } else {
590#ifndef	USE_TERMIO
591	if (f & MODE_OUTBIN)
592		lmode |= LLITOUT;
593	else
594		lmode &= ~LLITOUT;
595
596	if (f & MODE_INBIN)
597		lmode |= LPASS8;
598	else
599		lmode &= ~LPASS8;
600#else
601	if (f & MODE_INBIN)
602		tmp_tc.c_iflag &= ~ISTRIP;
603	else
604		tmp_tc.c_iflag |= ISTRIP;
605	if (f & MODE_OUTBIN) {
606		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
607		tmp_tc.c_cflag |= CS8;
608		tmp_tc.c_oflag &= ~OPOST;
609	} else {
610		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
611		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
612		tmp_tc.c_oflag |= OPOST;
613	}
614#endif
615	onoff = 1;
616    }
617
618    if (f != -1) {
619#ifdef	SIGINT
620	SIG_FUNC_RET intr();
621#endif	/* SIGINT */
622#ifdef	SIGQUIT
623	SIG_FUNC_RET intr2();
624#endif	/* SIGQUIT */
625#ifdef	SIGTSTP
626	SIG_FUNC_RET susp();
627#endif	/* SIGTSTP */
628#ifdef	SIGINFO
629	SIG_FUNC_RET ayt();
630#endif
631
632#ifdef  SIGINT
633	(void) signal(SIGINT, intr);
634#endif
635#ifdef  SIGQUIT
636	(void) signal(SIGQUIT, intr2);
637#endif
638#ifdef	SIGTSTP
639	(void) signal(SIGTSTP, susp);
640#endif	/* SIGTSTP */
641#ifdef	SIGINFO
642	(void) signal(SIGINFO, ayt);
643#endif
644#if	defined(USE_TERMIO) && defined(NOKERNINFO)
645	tmp_tc.c_lflag |= NOKERNINFO;
646#endif
647	/*
648	 * We don't want to process ^Y here.  It's just another
649	 * character that we'll pass on to the back end.  It has
650	 * to process it because it will be processed when the
651	 * user attempts to read it, not when we send it.
652	 */
653#ifndef	USE_TERMIO
654	ltc.t_dsuspc = _POSIX_VDISABLE;
655#else
656# ifdef	VDSUSP
657	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
658# endif
659#endif
660#ifdef	USE_TERMIO
661	/*
662	 * If the VEOL character is already set, then use VEOL2,
663	 * otherwise use VEOL.
664	 */
665	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
666	if ((tmp_tc.c_cc[VEOL] != esc)
667# ifdef	VEOL2
668	    && (tmp_tc.c_cc[VEOL2] != esc)
669# endif
670	    ) {
671		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
672		    tmp_tc.c_cc[VEOL] = esc;
673# ifdef	VEOL2
674		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
675		    tmp_tc.c_cc[VEOL2] = esc;
676# endif
677	}
678#else
679	if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
680		tc.t_brkc = esc;
681#endif
682    } else {
683#ifdef	SIGINFO
684	SIG_FUNC_RET ayt_status();
685
686	(void) signal(SIGINFO, ayt_status);
687#endif
688#ifdef  SIGINT
689	(void) signal(SIGINT, SIG_DFL);
690#endif
691#ifdef  SIGQUIT
692	(void) signal(SIGQUIT, SIG_DFL);
693#endif
694#ifdef	SIGTSTP
695	(void) signal(SIGTSTP, SIG_DFL);
696# ifndef SOLARIS
697	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
698# else	SOLARIS
699	(void) sigrelse(SIGTSTP);
700# endif	SOLARIS
701#endif	/* SIGTSTP */
702#ifndef USE_TERMIO
703	ltc = oltc;
704	tc = otc;
705	sb = ottyb;
706	lmode = olmode;
707#else
708	tmp_tc = old_tc;
709#endif
710    }
711#ifndef USE_TERMIO
712    ioctl(tin, TIOCLSET, (char *)&lmode);
713    ioctl(tin, TIOCSLTC, (char *)&ltc);
714    ioctl(tin, TIOCSETC, (char *)&tc);
715    ioctl(tin, TIOCSETN, (char *)&sb);
716#else
717    if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
718	tcsetattr(tin, TCSANOW, &tmp_tc);
719#endif
720
721#if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
722# if	!defined(sysV88)
723    ioctl(tin, FIONBIO, (char *)&onoff);
724    ioctl(tout, FIONBIO, (char *)&onoff);
725# endif
726#endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
727#if	defined(TN3270)
728    if (noasynchtty == 0) {
729	ioctl(tin, FIOASYNC, (char *)&onoff);
730    }
731#endif	/* defined(TN3270) */
732
733}
734
735/*
736 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
737 */
738#if B4800 != 4800
739#define	DECODE_BAUD
740#endif
741
742#ifdef	DECODE_BAUD
743#ifndef	B7200
744#define B7200   B4800
745#endif
746
747#ifndef	B14400
748#define B14400  B9600
749#endif
750
751#ifndef	B19200
752# define B19200 B14400
753#endif
754
755#ifndef	B28800
756#define B28800  B19200
757#endif
758
759#ifndef	B38400
760# define B38400 B28800
761#endif
762
763#ifndef B57600
764#define B57600  B38400
765#endif
766
767#ifndef B76800
768#define B76800  B57600
769#endif
770
771#ifndef B115200
772#define B115200 B76800
773#endif
774
775#ifndef B230400
776#define B230400 B115200
777#endif
778
779
780/*
781 * This code assumes that the values B0, B50, B75...
782 * are in ascending order.  They do not have to be
783 * contiguous.
784 */
785struct termspeeds {
786	long speed;
787	long value;
788} termspeeds[] = {
789	{ 0,      B0 },      { 50,    B50 },    { 75,     B75 },
790	{ 110,    B110 },    { 134,   B134 },   { 150,    B150 },
791	{ 200,    B200 },    { 300,   B300 },   { 600,    B600 },
792	{ 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
793	{ 4800,   B4800 },   { 7200,  B7200 },  { 9600,   B9600 },
794	{ 14400,  B14400 },  { 19200, B19200 }, { 28800,  B28800 },
795	{ 38400,  B38400 },  { 57600, B57600 }, { 115200, B115200 },
796	{ 230400, B230400 }, { -1,    B230400 }
797};
798#endif	/* DECODE_BAUD */
799
800    void
801TerminalSpeeds(ispeed, ospeed)
802    long *ispeed;
803    long *ospeed;
804{
805#ifdef	DECODE_BAUD
806    register struct termspeeds *tp;
807#endif	/* DECODE_BAUD */
808    register long in, out;
809
810    out = cfgetospeed(&old_tc);
811    in = cfgetispeed(&old_tc);
812    if (in == 0)
813	in = out;
814
815#ifdef	DECODE_BAUD
816    tp = termspeeds;
817    while ((tp->speed != -1) && (tp->value < in))
818	tp++;
819    *ispeed = tp->speed;
820
821    tp = termspeeds;
822    while ((tp->speed != -1) && (tp->value < out))
823	tp++;
824    *ospeed = tp->speed;
825#else	/* DECODE_BAUD */
826	*ispeed = in;
827	*ospeed = out;
828#endif	/* DECODE_BAUD */
829}
830
831    int
832TerminalWindowSize(rows, cols)
833    long *rows, *cols;
834{
835#ifdef	TIOCGWINSZ
836    struct winsize ws;
837
838    if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
839	*rows = ws.ws_row;
840	*cols = ws.ws_col;
841	return 1;
842    }
843#endif	/* TIOCGWINSZ */
844    return 0;
845}
846
847    int
848NetClose(fd)
849    int	fd;
850{
851    return close(fd);
852}
853
854
855    void
856NetNonblockingIO(fd, onoff)
857    int fd;
858    int onoff;
859{
860    ioctl(fd, FIONBIO, (char *)&onoff);
861}
862
863#if	defined(TN3270)
864    void
865NetSigIO(fd, onoff)
866    int fd;
867    int onoff;
868{
869    ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
870}
871
872    void
873NetSetPgrp(fd)
874    int fd;
875{
876    int myPid;
877
878    myPid = getpid();
879    fcntl(fd, F_SETOWN, myPid);
880}
881#endif	/*defined(TN3270)*/
882
883/*
884 * Various signal handling routines.
885 */
886
887    /* ARGSUSED */
888    SIG_FUNC_RET
889deadpeer(sig)
890    int sig;
891{
892	setcommandmode();
893	longjmp(peerdied, -1);
894}
895
896    /* ARGSUSED */
897    SIG_FUNC_RET
898intr(sig)
899    int sig;
900{
901    if (localchars) {
902	intp();
903	return;
904    }
905    setcommandmode();
906    longjmp(toplevel, -1);
907}
908
909    /* ARGSUSED */
910    SIG_FUNC_RET
911intr2(sig)
912    int sig;
913{
914    if (localchars) {
915#ifdef	KLUDGELINEMODE
916	if (kludgelinemode)
917	    sendbrk();
918	else
919#endif
920	    sendabort();
921	return;
922    }
923}
924
925#ifdef	SIGTSTP
926    /* ARGSUSED */
927    SIG_FUNC_RET
928susp(sig)
929    int sig;
930{
931    if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
932	return;
933    if (localchars)
934	sendsusp();
935}
936#endif
937
938#ifdef	SIGWINCH
939    /* ARGSUSED */
940    SIG_FUNC_RET
941sendwin(sig)
942    int sig;
943{
944    if (connected) {
945	sendnaws();
946    }
947}
948#endif
949
950#ifdef	SIGINFO
951    /* ARGSUSED */
952    SIG_FUNC_RET
953ayt(sig)
954    int sig;
955{
956    if (connected)
957	sendayt();
958    else
959	ayt_status();
960}
961#endif
962
963
964    void
965sys_telnet_init()
966{
967    (void) signal(SIGINT, intr);
968    (void) signal(SIGQUIT, intr2);
969    (void) signal(SIGPIPE, deadpeer);
970#ifdef	SIGWINCH
971    (void) signal(SIGWINCH, sendwin);
972#endif
973#ifdef	SIGTSTP
974    (void) signal(SIGTSTP, susp);
975#endif
976#ifdef	SIGINFO
977    (void) signal(SIGINFO, ayt);
978#endif
979
980    setconnmode(0);
981
982    NetNonblockingIO(net, 1);
983
984#if	defined(TN3270)
985    if (noasynchnet == 0) {			/* DBX can't handle! */
986	NetSigIO(net, 1);
987	NetSetPgrp(net);
988    }
989#endif	/* defined(TN3270) */
990
991#if	defined(SO_OOBINLINE)
992    if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
993	perror("SetSockOpt");
994    }
995#endif	/* defined(SO_OOBINLINE) */
996}
997
998/*
999 * Process rings -
1000 *
1001 *	This routine tries to fill up/empty our various rings.
1002 *
1003 *	The parameter specifies whether this is a poll operation,
1004 *	or a block-until-something-happens operation.
1005 *
1006 *	The return value is 1 if something happened, 0 if not.
1007 */
1008
1009    int
1010process_rings(netin, netout, netex, ttyin, ttyout, poll)
1011    int poll;		/* If 0, then block until something to do */
1012{
1013    register int c;
1014		/* One wants to be a bit careful about setting returnValue
1015		 * to one, since a one implies we did some useful work,
1016		 * and therefore probably won't be called to block next
1017		 * time (TN3270 mode only).
1018		 */
1019    int returnValue = 0;
1020    static struct timeval TimeValue = { 0 };
1021
1022    if (netout) {
1023	FD_SET(net, &obits);
1024    }
1025    if (ttyout) {
1026	FD_SET(tout, &obits);
1027    }
1028#if	defined(TN3270)
1029    if (ttyin) {
1030	FD_SET(tin, &ibits);
1031    }
1032#else	/* defined(TN3270) */
1033    if (ttyin) {
1034	FD_SET(tin, &ibits);
1035    }
1036#endif	/* defined(TN3270) */
1037#if	defined(TN3270)
1038    if (netin) {
1039	FD_SET(net, &ibits);
1040    }
1041#   else /* !defined(TN3270) */
1042    if (netin) {
1043	FD_SET(net, &ibits);
1044    }
1045#   endif /* !defined(TN3270) */
1046    if (netex) {
1047	FD_SET(net, &xbits);
1048    }
1049    if ((c = select(16, &ibits, &obits, &xbits,
1050			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
1051	if (c == -1) {
1052		    /*
1053		     * we can get EINTR if we are in line mode,
1054		     * and the user does an escape (TSTP), or
1055		     * some other signal generator.
1056		     */
1057	    if (errno == EINTR) {
1058		return 0;
1059	    }
1060#	    if defined(TN3270)
1061		    /*
1062		     * we can get EBADF if we were in transparent
1063		     * mode, and the transcom process died.
1064		    */
1065	    if (errno == EBADF) {
1066			/*
1067			 * zero the bits (even though kernel does it)
1068			 * to make sure we are selecting on the right
1069			 * ones.
1070			*/
1071		FD_ZERO(&ibits);
1072		FD_ZERO(&obits);
1073		FD_ZERO(&xbits);
1074		return 0;
1075	    }
1076#	    endif /* defined(TN3270) */
1077		    /* I don't like this, does it ever happen? */
1078	    printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno));
1079	    sleep(5);
1080	}
1081	return 0;
1082    }
1083
1084    /*
1085     * Any urgent data?
1086     */
1087    if (FD_ISSET(net, &xbits)) {
1088	FD_CLR(net, &xbits);
1089	SYNCHing = 1;
1090	(void) ttyflush(1);	/* flush already enqueued data */
1091    }
1092
1093    /*
1094     * Something to read from the network...
1095     */
1096    if (FD_ISSET(net, &ibits)) {
1097	int canread;
1098
1099	FD_CLR(net, &ibits);
1100	canread = ring_empty_consecutive(&netiring);
1101#if	!defined(SO_OOBINLINE)
1102	    /*
1103	     * In 4.2 (and some early 4.3) systems, the
1104	     * OOB indication and data handling in the kernel
1105	     * is such that if two separate TCP Urgent requests
1106	     * come in, one byte of TCP data will be overlaid.
1107	     * This is fatal for Telnet, but we try to live
1108	     * with it.
1109	     *
1110	     * In addition, in 4.2 (and...), a special protocol
1111	     * is needed to pick up the TCP Urgent data in
1112	     * the correct sequence.
1113	     *
1114	     * What we do is:  if we think we are in urgent
1115	     * mode, we look to see if we are "at the mark".
1116	     * If we are, we do an OOB receive.  If we run
1117	     * this twice, we will do the OOB receive twice,
1118	     * but the second will fail, since the second
1119	     * time we were "at the mark", but there wasn't
1120	     * any data there (the kernel doesn't reset
1121	     * "at the mark" until we do a normal read).
1122	     * Once we've read the OOB data, we go ahead
1123	     * and do normal reads.
1124	     *
1125	     * There is also another problem, which is that
1126	     * since the OOB byte we read doesn't put us
1127	     * out of OOB state, and since that byte is most
1128	     * likely the TELNET DM (data mark), we would
1129	     * stay in the TELNET SYNCH (SYNCHing) state.
1130	     * So, clocks to the rescue.  If we've "just"
1131	     * received a DM, then we test for the
1132	     * presence of OOB data when the receive OOB
1133	     * fails (and AFTER we did the normal mode read
1134	     * to clear "at the mark").
1135	     */
1136	if (SYNCHing) {
1137	    int atmark;
1138	    static int bogus_oob = 0, first = 1;
1139
1140	    ioctl(net, SIOCATMARK, (char *)&atmark);
1141	    if (atmark) {
1142		c = recv(net, netiring.supply, canread, MSG_OOB);
1143		if ((c == -1) && (errno == EINVAL)) {
1144		    c = recv(net, netiring.supply, canread, 0);
1145		    if (clocks.didnetreceive < clocks.gotDM) {
1146			SYNCHing = stilloob(net);
1147		    }
1148		} else if (first && c > 0) {
1149		    /*
1150		     * Bogosity check.  Systems based on 4.2BSD
1151		     * do not return an error if you do a second
1152		     * recv(MSG_OOB).  So, we do one.  If it
1153		     * succeeds and returns exactly the same
1154		     * data, then assume that we are running
1155		     * on a broken system and set the bogus_oob
1156		     * flag.  (If the data was different, then
1157		     * we probably got some valid new data, so
1158		     * increment the count...)
1159		     */
1160		    int i;
1161		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
1162		    if (i == c &&
1163			memcmp(netiring.supply, netiring.supply + c, i) == 0) {
1164			bogus_oob = 1;
1165			first = 0;
1166		    } else if (i < 0) {
1167			bogus_oob = 0;
1168			first = 0;
1169		    } else
1170			c += i;
1171		}
1172		if (bogus_oob && c > 0) {
1173		    int i;
1174		    /*
1175		     * Bogosity.  We have to do the read
1176		     * to clear the atmark to get out of
1177		     * an infinate loop.
1178		     */
1179		    i = read(net, netiring.supply + c, canread - c);
1180		    if (i > 0)
1181			c += i;
1182		}
1183	    } else {
1184		c = recv(net, netiring.supply, canread, 0);
1185	    }
1186	} else {
1187	    c = recv(net, netiring.supply, canread, 0);
1188	}
1189	settimer(didnetreceive);
1190#else	/* !defined(SO_OOBINLINE) */
1191	c = recv(net, (char *)netiring.supply, canread, 0);
1192#endif	/* !defined(SO_OOBINLINE) */
1193	if (c < 0 && errno == EWOULDBLOCK) {
1194	    c = 0;
1195	} else if (c <= 0) {
1196	    return -1;
1197	}
1198	if (netdata) {
1199	    Dump('<', netiring.supply, c);
1200	}
1201	if (c)
1202	    ring_supplied(&netiring, c);
1203	returnValue = 1;
1204    }
1205
1206    /*
1207     * Something to read from the tty...
1208     */
1209    if (FD_ISSET(tin, &ibits)) {
1210	FD_CLR(tin, &ibits);
1211	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
1212	if (c < 0 && errno == EIO)
1213	    c = 0;
1214	if (c < 0 && errno == EWOULDBLOCK) {
1215	    c = 0;
1216	} else {
1217	    /* EOF detection for line mode!!!! */
1218	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
1219			/* must be an EOF... */
1220		*ttyiring.supply = termEofChar;
1221		c = 1;
1222	    }
1223	    if (c <= 0) {
1224		return -1;
1225	    }
1226	    if (termdata) {
1227		Dump('<', ttyiring.supply, c);
1228	    }
1229	    ring_supplied(&ttyiring, c);
1230	}
1231	returnValue = 1;		/* did something useful */
1232    }
1233
1234    if (FD_ISSET(net, &obits)) {
1235	FD_CLR(net, &obits);
1236	returnValue |= netflush();
1237    }
1238    if (FD_ISSET(tout, &obits)) {
1239	FD_CLR(tout, &obits);
1240	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
1241    }
1242
1243    return returnValue;
1244}
1245