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