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