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