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