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