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