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