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