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