sys_bsd.c revision 1.11 1 /* $NetBSD: sys_bsd.c,v 1.11 1996/02/28 21:04:10 thorpej 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 #ifndef lint
37 #if 0
38 from: static char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95";
39 #else
40 static char rcsid[] = "$NetBSD: sys_bsd.c,v 1.11 1996/02/28 21:04:10 thorpej Exp $";
41 #endif
42 #endif /* not lint */
43
44 /*
45 * The following routines try to encapsulate what is system dependent
46 * (at least between 4.x and dos) which is used in telnet.c.
47 */
48
49
50 #include <fcntl.h>
51 #include <sys/types.h>
52 #include <sys/time.h>
53 #include <sys/socket.h>
54 #include <signal.h>
55 #include <errno.h>
56 #include <arpa/telnet.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(CRAY) || (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
73 extern SIG_FUNC_RET ayt_status();
74 #endif
75
76 int
77 tout, /* Output file descriptor */
78 tin, /* Input file descriptor */
79 net;
80
81 #ifndef USE_TERMIO
82 struct tchars otc = { 0 }, ntc = { 0 };
83 struct ltchars oltc = { 0 }, nltc = { 0 };
84 struct sgttyb ottyb = { 0 }, nttyb = { 0 };
85 int 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 */
91 struct termio old_tc = { 0 };
92 extern 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
123 static fd_set ibits, obits, xbits;
124
125
126 void
127 init_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
140 TerminalWrite(buf, n)
141 char *buf;
142 int n;
143 {
144 return write(tout, buf, n);
145 }
146
147 int
148 TerminalRead(buf, n)
149 unsigned char *buf;
150 int n;
151 {
152 return read(tin, buf, n);
153 }
154
155 /*
156 *
157 */
158
159 int
160 TerminalAutoFlush()
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
173 extern 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
187 extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
188
189 int
190 TerminalSpecialChars(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
234 TerminalFlushOutput()
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
244 TerminalSaveState()
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 *
286 tcval(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
329 TerminalDefaultChars()
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 memmove(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
363 void
364 TerminalRestoreState()
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
393 TerminalNewMode(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 tmp_tc.c_lflag &= ~IEXTEN;
539 #endif
540 }
541
542 if (f&MODE_SOFT_TAB) {
543 #ifndef USE_TERMIO
544 sb.sg_flags |= XTABS;
545 #else
546 # ifdef OXTABS
547 tmp_tc.c_oflag |= OXTABS;
548 # endif
549 # ifdef TABDLY
550 tmp_tc.c_oflag &= ~TABDLY;
551 tmp_tc.c_oflag |= TAB3;
552 # endif
553 #endif
554 } else {
555 #ifndef USE_TERMIO
556 sb.sg_flags &= ~XTABS;
557 #else
558 # ifdef OXTABS
559 tmp_tc.c_oflag &= ~OXTABS;
560 # endif
561 # ifdef TABDLY
562 tmp_tc.c_oflag &= ~TABDLY;
563 # endif
564 #endif
565 }
566
567 if (f&MODE_LIT_ECHO) {
568 #ifndef USE_TERMIO
569 lmode &= ~LCTLECH;
570 #else
571 # ifdef ECHOCTL
572 tmp_tc.c_lflag &= ~ECHOCTL;
573 # endif
574 #endif
575 } else {
576 #ifndef USE_TERMIO
577 lmode |= LCTLECH;
578 #else
579 # ifdef ECHOCTL
580 tmp_tc.c_lflag |= ECHOCTL;
581 # endif
582 #endif
583 }
584
585 if (f == -1) {
586 onoff = 0;
587 } else {
588 #ifndef USE_TERMIO
589 if (f & MODE_OUTBIN)
590 lmode |= LLITOUT;
591 else
592 lmode &= ~LLITOUT;
593
594 if (f & MODE_INBIN)
595 lmode |= LPASS8;
596 else
597 lmode &= ~LPASS8;
598 #else
599 if (f & MODE_INBIN)
600 tmp_tc.c_iflag &= ~ISTRIP;
601 else
602 tmp_tc.c_iflag |= ISTRIP;
603 if (f & MODE_OUTBIN) {
604 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
605 tmp_tc.c_cflag |= CS8;
606 tmp_tc.c_oflag &= ~OPOST;
607 } else {
608 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
609 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
610 tmp_tc.c_oflag |= OPOST;
611 }
612 #endif
613 onoff = 1;
614 }
615
616 if (f != -1) {
617 #ifdef SIGTSTP
618 SIG_FUNC_RET susp();
619 #endif /* SIGTSTP */
620 #ifdef SIGINFO
621 SIG_FUNC_RET ayt();
622 #endif
623
624 #ifdef SIGTSTP
625 (void) signal(SIGTSTP, susp);
626 #endif /* SIGTSTP */
627 #ifdef SIGINFO
628 (void) signal(SIGINFO, ayt);
629 #endif
630 #if defined(USE_TERMIO) && defined(NOKERNINFO)
631 tmp_tc.c_lflag |= NOKERNINFO;
632 #endif
633 /*
634 * We don't want to process ^Y here. It's just another
635 * character that we'll pass on to the back end. It has
636 * to process it because it will be processed when the
637 * user attempts to read it, not when we send it.
638 */
639 #ifndef USE_TERMIO
640 ltc.t_dsuspc = _POSIX_VDISABLE;
641 #else
642 # ifdef VDSUSP
643 tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
644 # endif
645 #endif
646 #ifdef USE_TERMIO
647 /*
648 * If the VEOL character is already set, then use VEOL2,
649 * otherwise use VEOL.
650 */
651 esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
652 if ((tmp_tc.c_cc[VEOL] != esc)
653 # ifdef VEOL2
654 && (tmp_tc.c_cc[VEOL2] != esc)
655 # endif
656 ) {
657 if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
658 tmp_tc.c_cc[VEOL] = esc;
659 # ifdef VEOL2
660 else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
661 tmp_tc.c_cc[VEOL2] = esc;
662 # endif
663 }
664 #else
665 if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
666 tc.t_brkc = esc;
667 #endif
668 } else {
669 #ifdef SIGINFO
670 SIG_FUNC_RET ayt_status();
671
672 (void) signal(SIGINFO, ayt_status);
673 #endif
674 #ifdef SIGTSTP
675 (void) signal(SIGTSTP, SIG_DFL);
676 # ifndef SOLARIS
677 (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
678 # else SOLARIS
679 (void) sigrelse(SIGTSTP);
680 # endif SOLARIS
681 #endif /* SIGTSTP */
682 #ifndef USE_TERMIO
683 ltc = oltc;
684 tc = otc;
685 sb = ottyb;
686 lmode = olmode;
687 #else
688 tmp_tc = old_tc;
689 #endif
690 }
691 #ifndef USE_TERMIO
692 ioctl(tin, TIOCLSET, (char *)&lmode);
693 ioctl(tin, TIOCSLTC, (char *)<c);
694 ioctl(tin, TIOCSETC, (char *)&tc);
695 ioctl(tin, TIOCSETN, (char *)&sb);
696 #else
697 if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
698 tcsetattr(tin, TCSANOW, &tmp_tc);
699 #endif
700
701 #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
702 # if !defined(sysV88)
703 ioctl(tin, FIONBIO, (char *)&onoff);
704 ioctl(tout, FIONBIO, (char *)&onoff);
705 # endif
706 #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
707 #if defined(TN3270)
708 if (noasynchtty == 0) {
709 ioctl(tin, FIOASYNC, (char *)&onoff);
710 }
711 #endif /* defined(TN3270) */
712
713 }
714
715 /*
716 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
717 */
718 #if B4800 != 4800
719 #define DECODE_BAUD
720 #endif
721
722 #ifdef DECODE_BAUD
723 #ifndef B7200
724 #define B7200 B4800
725 #endif
726
727 #ifndef B14400
728 #define B14400 B9600
729 #endif
730
731 #ifndef B19200
732 # define B19200 B14400
733 #endif
734
735 #ifndef B28800
736 #define B28800 B19200
737 #endif
738
739 #ifndef B38400
740 # define B38400 B28800
741 #endif
742
743 #ifndef B57600
744 #define B57600 B38400
745 #endif
746
747 #ifndef B76800
748 #define B76800 B57600
749 #endif
750
751 #ifndef B115200
752 #define B115200 B76800
753 #endif
754
755 #ifndef B230400
756 #define B230400 B115200
757 #endif
758
759
760 /*
761 * This code assumes that the values B0, B50, B75...
762 * are in ascending order. They do not have to be
763 * contiguous.
764 */
765 struct termspeeds {
766 long speed;
767 long value;
768 } termspeeds[] = {
769 { 0, B0 }, { 50, B50 }, { 75, B75 },
770 { 110, B110 }, { 134, B134 }, { 150, B150 },
771 { 200, B200 }, { 300, B300 }, { 600, B600 },
772 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
773 { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 },
774 { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 },
775 { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 },
776 { 230400, B230400 }, { -1, B230400 }
777 };
778 #endif /* DECODE_BAUD */
779
780 void
781 TerminalSpeeds(ispeed, ospeed)
782 long *ispeed;
783 long *ospeed;
784 {
785 #ifdef DECODE_BAUD
786 register struct termspeeds *tp;
787 #endif /* DECODE_BAUD */
788 register long in, out;
789
790 out = cfgetospeed(&old_tc);
791 in = cfgetispeed(&old_tc);
792 if (in == 0)
793 in = out;
794
795 #ifdef DECODE_BAUD
796 tp = termspeeds;
797 while ((tp->speed != -1) && (tp->value < in))
798 tp++;
799 *ispeed = tp->speed;
800
801 tp = termspeeds;
802 while ((tp->speed != -1) && (tp->value < out))
803 tp++;
804 *ospeed = tp->speed;
805 #else /* DECODE_BAUD */
806 *ispeed = in;
807 *ospeed = out;
808 #endif /* DECODE_BAUD */
809 }
810
811 int
812 TerminalWindowSize(rows, cols)
813 long *rows, *cols;
814 {
815 #ifdef TIOCGWINSZ
816 struct winsize ws;
817
818 if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
819 *rows = ws.ws_row;
820 *cols = ws.ws_col;
821 return 1;
822 }
823 #endif /* TIOCGWINSZ */
824 return 0;
825 }
826
827 int
828 NetClose(fd)
829 int fd;
830 {
831 return close(fd);
832 }
833
834
835 void
836 NetNonblockingIO(fd, onoff)
837 int fd;
838 int onoff;
839 {
840 ioctl(fd, FIONBIO, (char *)&onoff);
841 }
842
843 #if defined(TN3270)
844 void
845 NetSigIO(fd, onoff)
846 int fd;
847 int onoff;
848 {
849 ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */
850 }
851
852 void
853 NetSetPgrp(fd)
854 int fd;
855 {
856 int myPid;
857
858 myPid = getpid();
859 fcntl(fd, F_SETOWN, myPid);
860 }
861 #endif /*defined(TN3270)*/
862
863 /*
865 * Various signal handling routines.
866 */
867
868 /* ARGSUSED */
869 SIG_FUNC_RET
870 deadpeer(sig)
871 int sig;
872 {
873 setcommandmode();
874 longjmp(peerdied, -1);
875 }
876
877 /* ARGSUSED */
878 SIG_FUNC_RET
879 intr(sig)
880 int sig;
881 {
882 if (localchars) {
883 intp();
884 return;
885 }
886 setcommandmode();
887 longjmp(toplevel, -1);
888 }
889
890 /* ARGSUSED */
891 SIG_FUNC_RET
892 intr2(sig)
893 int sig;
894 {
895 if (localchars) {
896 #ifdef KLUDGELINEMODE
897 if (kludgelinemode)
898 sendbrk();
899 else
900 #endif
901 sendabort();
902 return;
903 }
904 }
905
906 #ifdef SIGTSTP
907 /* ARGSUSED */
908 SIG_FUNC_RET
909 susp(sig)
910 int sig;
911 {
912 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
913 return;
914 if (localchars)
915 sendsusp();
916 }
917 #endif
918
919 #ifdef SIGWINCH
920 /* ARGSUSED */
921 SIG_FUNC_RET
922 sendwin(sig)
923 int sig;
924 {
925 if (connected) {
926 sendnaws();
927 }
928 }
929 #endif
930
931 #ifdef SIGINFO
932 /* ARGSUSED */
933 SIG_FUNC_RET
934 ayt(sig)
935 int sig;
936 {
937 if (connected)
938 sendayt();
939 else
940 ayt_status();
941 }
942 #endif
943
944
945 void
947 sys_telnet_init()
948 {
949 (void) signal(SIGINT, intr);
950 (void) signal(SIGQUIT, intr2);
951 (void) signal(SIGPIPE, deadpeer);
952 #ifdef SIGWINCH
953 (void) signal(SIGWINCH, sendwin);
954 #endif
955 #ifdef SIGTSTP
956 (void) signal(SIGTSTP, susp);
957 #endif
958 #ifdef SIGINFO
959 (void) signal(SIGINFO, ayt);
960 #endif
961
962 setconnmode(0);
963
964 NetNonblockingIO(net, 1);
965
966 #if defined(TN3270)
967 if (noasynchnet == 0) { /* DBX can't handle! */
968 NetSigIO(net, 1);
969 NetSetPgrp(net);
970 }
971 #endif /* defined(TN3270) */
972
973 #if defined(SO_OOBINLINE)
974 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
975 perror("SetSockOpt");
976 }
977 #endif /* defined(SO_OOBINLINE) */
978 }
979
980 /*
981 * Process rings -
982 *
983 * This routine tries to fill up/empty our various rings.
984 *
985 * The parameter specifies whether this is a poll operation,
986 * or a block-until-something-happens operation.
987 *
988 * The return value is 1 if something happened, 0 if not.
989 */
990
991 int
992 process_rings(netin, netout, netex, ttyin, ttyout, poll)
993 int poll; /* If 0, then block until something to do */
994 {
995 register int c;
996 /* One wants to be a bit careful about setting returnValue
997 * to one, since a one implies we did some useful work,
998 * and therefore probably won't be called to block next
999 * time (TN3270 mode only).
1000 */
1001 int returnValue = 0;
1002 static struct timeval TimeValue = { 0 };
1003
1004 if (netout) {
1005 FD_SET(net, &obits);
1006 }
1007 if (ttyout) {
1008 FD_SET(tout, &obits);
1009 }
1010 #if defined(TN3270)
1011 if (ttyin) {
1012 FD_SET(tin, &ibits);
1013 }
1014 #else /* defined(TN3270) */
1015 if (ttyin) {
1016 FD_SET(tin, &ibits);
1017 }
1018 #endif /* defined(TN3270) */
1019 #if defined(TN3270)
1020 if (netin) {
1021 FD_SET(net, &ibits);
1022 }
1023 # else /* !defined(TN3270) */
1024 if (netin) {
1025 FD_SET(net, &ibits);
1026 }
1027 # endif /* !defined(TN3270) */
1028 if (netex) {
1029 FD_SET(net, &xbits);
1030 }
1031 if ((c = select(16, &ibits, &obits, &xbits,
1032 (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
1033 if (c == -1) {
1034 /*
1035 * we can get EINTR if we are in line mode,
1036 * and the user does an escape (TSTP), or
1037 * some other signal generator.
1038 */
1039 if (errno == EINTR) {
1040 return 0;
1041 }
1042 # if defined(TN3270)
1043 /*
1044 * we can get EBADF if we were in transparent
1045 * mode, and the transcom process died.
1046 */
1047 if (errno == EBADF) {
1048 /*
1049 * zero the bits (even though kernel does it)
1050 * to make sure we are selecting on the right
1051 * ones.
1052 */
1053 FD_ZERO(&ibits);
1054 FD_ZERO(&obits);
1055 FD_ZERO(&xbits);
1056 return 0;
1057 }
1058 # endif /* defined(TN3270) */
1059 /* I don't like this, does it ever happen? */
1060 printf("sleep(5) from telnet, after select\r\n");
1061 sleep(5);
1062 }
1063 return 0;
1064 }
1065
1066 /*
1067 * Any urgent data?
1068 */
1069 if (FD_ISSET(net, &xbits)) {
1070 FD_CLR(net, &xbits);
1071 SYNCHing = 1;
1072 (void) ttyflush(1); /* flush already enqueued data */
1073 }
1074
1075 /*
1076 * Something to read from the network...
1077 */
1078 if (FD_ISSET(net, &ibits)) {
1079 int canread;
1080
1081 FD_CLR(net, &ibits);
1082 canread = ring_empty_consecutive(&netiring);
1083 #if !defined(SO_OOBINLINE)
1084 /*
1085 * In 4.2 (and some early 4.3) systems, the
1086 * OOB indication and data handling in the kernel
1087 * is such that if two separate TCP Urgent requests
1088 * come in, one byte of TCP data will be overlaid.
1089 * This is fatal for Telnet, but we try to live
1090 * with it.
1091 *
1092 * In addition, in 4.2 (and...), a special protocol
1093 * is needed to pick up the TCP Urgent data in
1094 * the correct sequence.
1095 *
1096 * What we do is: if we think we are in urgent
1097 * mode, we look to see if we are "at the mark".
1098 * If we are, we do an OOB receive. If we run
1099 * this twice, we will do the OOB receive twice,
1100 * but the second will fail, since the second
1101 * time we were "at the mark", but there wasn't
1102 * any data there (the kernel doesn't reset
1103 * "at the mark" until we do a normal read).
1104 * Once we've read the OOB data, we go ahead
1105 * and do normal reads.
1106 *
1107 * There is also another problem, which is that
1108 * since the OOB byte we read doesn't put us
1109 * out of OOB state, and since that byte is most
1110 * likely the TELNET DM (data mark), we would
1111 * stay in the TELNET SYNCH (SYNCHing) state.
1112 * So, clocks to the rescue. If we've "just"
1113 * received a DM, then we test for the
1114 * presence of OOB data when the receive OOB
1115 * fails (and AFTER we did the normal mode read
1116 * to clear "at the mark").
1117 */
1118 if (SYNCHing) {
1119 int atmark;
1120 static int bogus_oob = 0, first = 1;
1121
1122 ioctl(net, SIOCATMARK, (char *)&atmark);
1123 if (atmark) {
1124 c = recv(net, netiring.supply, canread, MSG_OOB);
1125 if ((c == -1) && (errno == EINVAL)) {
1126 c = recv(net, netiring.supply, canread, 0);
1127 if (clocks.didnetreceive < clocks.gotDM) {
1128 SYNCHing = stilloob(net);
1129 }
1130 } else if (first && c > 0) {
1131 /*
1132 * Bogosity check. Systems based on 4.2BSD
1133 * do not return an error if you do a second
1134 * recv(MSG_OOB). So, we do one. If it
1135 * succeeds and returns exactly the same
1136 * data, then assume that we are running
1137 * on a broken system and set the bogus_oob
1138 * flag. (If the data was different, then
1139 * we probably got some valid new data, so
1140 * increment the count...)
1141 */
1142 int i;
1143 i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
1144 if (i == c &&
1145 memcmp(netiring.supply, netiring.supply + c, i) == 0) {
1146 bogus_oob = 1;
1147 first = 0;
1148 } else if (i < 0) {
1149 bogus_oob = 0;
1150 first = 0;
1151 } else
1152 c += i;
1153 }
1154 if (bogus_oob && c > 0) {
1155 int i;
1156 /*
1157 * Bogosity. We have to do the read
1158 * to clear the atmark to get out of
1159 * an infinate loop.
1160 */
1161 i = read(net, netiring.supply + c, canread - c);
1162 if (i > 0)
1163 c += i;
1164 }
1165 } else {
1166 c = recv(net, netiring.supply, canread, 0);
1167 }
1168 } else {
1169 c = recv(net, netiring.supply, canread, 0);
1170 }
1171 settimer(didnetreceive);
1172 #else /* !defined(SO_OOBINLINE) */
1173 c = recv(net, (char *)netiring.supply, canread, 0);
1174 #endif /* !defined(SO_OOBINLINE) */
1175 if (c < 0 && errno == EWOULDBLOCK) {
1176 c = 0;
1177 } else if (c <= 0) {
1178 return -1;
1179 }
1180 if (netdata) {
1181 Dump('<', netiring.supply, c);
1182 }
1183 if (c)
1184 ring_supplied(&netiring, c);
1185 returnValue = 1;
1186 }
1187
1188 /*
1189 * Something to read from the tty...
1190 */
1191 if (FD_ISSET(tin, &ibits)) {
1192 FD_CLR(tin, &ibits);
1193 c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
1194 if (c < 0 && errno == EIO)
1195 c = 0;
1196 if (c < 0 && errno == EWOULDBLOCK) {
1197 c = 0;
1198 } else {
1199 if (c < 0) {
1200 return -1;
1201 }
1202 if (c == 0) {
1203 /* must be an EOF... */
1204 if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
1205 *ttyiring.supply = termEofChar;
1206 c = 1;
1207 } else {
1208 clienteof = 1;
1209 shutdown(net, 1);
1210 return 0;
1211 }
1212 }
1213 if (termdata) {
1214 Dump('<', ttyiring.supply, c);
1215 }
1216 ring_supplied(&ttyiring, c);
1217 }
1218 returnValue = 1; /* did something useful */
1219 }
1220
1221 if (FD_ISSET(net, &obits)) {
1222 FD_CLR(net, &obits);
1223 returnValue |= netflush();
1224 }
1225 if (FD_ISSET(tout, &obits)) {
1226 FD_CLR(tout, &obits);
1227 returnValue |= (ttyflush(SYNCHing|flushout) > 0);
1228 }
1229
1230 return returnValue;
1231 }
1232