Annotation of src/usr.bin/telnet/sys_bsd.c, Revision 1.1.1.1
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"; */
36: static char *rcsid = "$Id: sys_bsd.c,v 1.6 1995/03/17 18:03:08 mycroft Exp $";
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
533: # ifdef VLNEXT
534: tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
535: # endif
536: #endif
537: }
538:
539: if (f&MODE_SOFT_TAB) {
540: #ifndef USE_TERMIO
541: sb.sg_flags |= XTABS;
542: #else
543: # ifdef OXTABS
544: tmp_tc.c_oflag |= OXTABS;
545: # endif
546: # ifdef TABDLY
547: tmp_tc.c_oflag &= ~TABDLY;
548: tmp_tc.c_oflag |= TAB3;
549: # endif
550: #endif
551: } else {
552: #ifndef USE_TERMIO
553: sb.sg_flags &= ~XTABS;
554: #else
555: # ifdef OXTABS
556: tmp_tc.c_oflag &= ~OXTABS;
557: # endif
558: # ifdef TABDLY
559: tmp_tc.c_oflag &= ~TABDLY;
560: # endif
561: #endif
562: }
563:
564: if (f&MODE_LIT_ECHO) {
565: #ifndef USE_TERMIO
566: lmode &= ~LCTLECH;
567: #else
568: # ifdef ECHOCTL
569: tmp_tc.c_lflag &= ~ECHOCTL;
570: # endif
571: #endif
572: } else {
573: #ifndef USE_TERMIO
574: lmode |= LCTLECH;
575: #else
576: # ifdef ECHOCTL
577: tmp_tc.c_lflag |= ECHOCTL;
578: # endif
579: #endif
580: }
581:
582: if (f == -1) {
583: onoff = 0;
584: } else {
585: #ifndef USE_TERMIO
586: if (f & MODE_OUTBIN)
587: lmode |= LLITOUT;
588: else
589: lmode &= ~LLITOUT;
590:
591: if (f & MODE_INBIN)
592: lmode |= LPASS8;
593: else
594: lmode &= ~LPASS8;
595: #else
596: if (f & MODE_INBIN)
597: tmp_tc.c_iflag &= ~ISTRIP;
598: else
599: tmp_tc.c_iflag |= ISTRIP;
600: if (f & MODE_OUTBIN) {
601: tmp_tc.c_cflag &= ~(CSIZE|PARENB);
602: tmp_tc.c_cflag |= CS8;
603: tmp_tc.c_oflag &= ~OPOST;
604: } else {
605: tmp_tc.c_cflag &= ~(CSIZE|PARENB);
606: tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
607: tmp_tc.c_oflag |= OPOST;
608: }
609: #endif
610: onoff = 1;
611: }
612:
613: if (f != -1) {
614: #ifdef SIGTSTP
615: SIG_FUNC_RET susp();
616: #endif /* SIGTSTP */
617: #ifdef SIGINFO
618: SIG_FUNC_RET ayt();
619: #endif
620:
621: #ifdef SIGTSTP
622: (void) signal(SIGTSTP, susp);
623: #endif /* SIGTSTP */
624: #ifdef SIGINFO
625: (void) signal(SIGINFO, ayt);
626: #endif
627: #if defined(USE_TERMIO) && defined(NOKERNINFO)
628: tmp_tc.c_lflag |= NOKERNINFO;
629: #endif
630: /*
631: * We don't want to process ^Y here. It's just another
632: * character that we'll pass on to the back end. It has
633: * to process it because it will be processed when the
634: * user attempts to read it, not when we send it.
635: */
636: #ifndef USE_TERMIO
637: ltc.t_dsuspc = _POSIX_VDISABLE;
638: #else
639: # ifdef VDSUSP
640: tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
641: # endif
642: #endif
643: #ifdef USE_TERMIO
644: /*
645: * If the VEOL character is already set, then use VEOL2,
646: * otherwise use VEOL.
647: */
648: esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
649: if ((tmp_tc.c_cc[VEOL] != esc)
650: # ifdef VEOL2
651: && (tmp_tc.c_cc[VEOL2] != esc)
652: # endif
653: ) {
654: if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
655: tmp_tc.c_cc[VEOL] = esc;
656: # ifdef VEOL2
657: else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
658: tmp_tc.c_cc[VEOL2] = esc;
659: # endif
660: }
661: #else
662: if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
663: tc.t_brkc = esc;
664: #endif
665: } else {
666: #ifdef SIGINFO
667: SIG_FUNC_RET ayt_status();
668:
669: (void) signal(SIGINFO, ayt_status);
670: #endif
671: #ifdef SIGTSTP
672: (void) signal(SIGTSTP, SIG_DFL);
673: (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
674: #endif /* SIGTSTP */
675: #ifndef USE_TERMIO
676: ltc = oltc;
677: tc = otc;
678: sb = ottyb;
679: lmode = olmode;
680: #else
681: tmp_tc = old_tc;
682: #endif
683: }
684: #ifndef USE_TERMIO
685: ioctl(tin, TIOCLSET, (char *)&lmode);
686: ioctl(tin, TIOCSLTC, (char *)<c);
687: ioctl(tin, TIOCSETC, (char *)&tc);
688: ioctl(tin, TIOCSETN, (char *)&sb);
689: #else
690: if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
691: tcsetattr(tin, TCSANOW, &tmp_tc);
692: #endif
693:
694: #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
695: # if !defined(sysV88)
696: ioctl(tin, FIONBIO, (char *)&onoff);
697: ioctl(tout, FIONBIO, (char *)&onoff);
698: # endif
699: #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
700: #if defined(TN3270)
701: if (noasynchtty == 0) {
702: ioctl(tin, FIOASYNC, (char *)&onoff);
703: }
704: #endif /* defined(TN3270) */
705:
706: }
707:
708: #ifndef B19200
709: # define B19200 B9600
710: #endif
711:
712: #ifndef B38400
713: # define B38400 B19200
714: #endif
715:
716: /*
717: * This code assumes that the values B0, B50, B75...
718: * are in ascending order. They do not have to be
719: * contiguous.
720: */
721: struct termspeeds {
722: long speed;
723: long value;
724: } termspeeds[] = {
725: { 0, B0 }, { 50, B50 }, { 75, B75 },
726: { 110, B110 }, { 134, B134 }, { 150, B150 },
727: { 200, B200 }, { 300, B300 }, { 600, B600 },
728: { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
729: { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 },
730: { 38400, B38400 }, { -1, B38400 }
731: };
732:
733: void
734: TerminalSpeeds(ispeed, ospeed)
735: long *ispeed;
736: long *ospeed;
737: {
738: register struct termspeeds *tp;
739: register long in, out;
740:
741: out = cfgetospeed(&old_tc);
742: in = cfgetispeed(&old_tc);
743: if (in == 0)
744: in = out;
745:
746: tp = termspeeds;
747: while ((tp->speed != -1) && (tp->value < in))
748: tp++;
749: *ispeed = tp->speed;
750:
751: tp = termspeeds;
752: while ((tp->speed != -1) && (tp->value < out))
753: tp++;
754: *ospeed = tp->speed;
755: }
756:
757: int
758: TerminalWindowSize(rows, cols)
759: long *rows, *cols;
760: {
761: #ifdef TIOCGWINSZ
762: struct winsize ws;
763:
764: if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
765: *rows = ws.ws_row;
766: *cols = ws.ws_col;
767: return 1;
768: }
769: #endif /* TIOCGWINSZ */
770: return 0;
771: }
772:
773: int
774: NetClose(fd)
775: int fd;
776: {
777: return close(fd);
778: }
779:
780:
781: void
782: NetNonblockingIO(fd, onoff)
783: int fd;
784: int onoff;
785: {
786: ioctl(fd, FIONBIO, (char *)&onoff);
787: }
788:
789: #if defined(TN3270)
790: void
791: NetSigIO(fd, onoff)
792: int fd;
793: int onoff;
794: {
795: ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */
796: }
797:
798: void
799: NetSetPgrp(fd)
800: int fd;
801: {
802: int myPid;
803:
804: myPid = getpid();
805: fcntl(fd, F_SETOWN, myPid);
806: }
807: #endif /*defined(TN3270)*/
808:
809: /*
810: * Various signal handling routines.
811: */
812:
813: /* ARGSUSED */
814: SIG_FUNC_RET
815: deadpeer(sig)
816: int sig;
817: {
818: setcommandmode();
819: longjmp(peerdied, -1);
820: }
821:
822: /* ARGSUSED */
823: SIG_FUNC_RET
824: intr(sig)
825: int sig;
826: {
827: if (localchars) {
828: intp();
829: return;
830: }
831: setcommandmode();
832: longjmp(toplevel, -1);
833: }
834:
835: /* ARGSUSED */
836: SIG_FUNC_RET
837: intr2(sig)
838: int sig;
839: {
840: if (localchars) {
841: #ifdef KLUDGELINEMODE
842: if (kludgelinemode)
843: sendbrk();
844: else
845: #endif
846: sendabort();
847: return;
848: }
849: }
850:
851: #ifdef SIGTSTP
852: /* ARGSUSED */
853: SIG_FUNC_RET
854: susp(sig)
855: int sig;
856: {
857: if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
858: return;
859: if (localchars)
860: sendsusp();
861: }
862: #endif
863:
864: #ifdef SIGWINCH
865: /* ARGSUSED */
866: SIG_FUNC_RET
867: sendwin(sig)
868: int sig;
869: {
870: if (connected) {
871: sendnaws();
872: }
873: }
874: #endif
875:
876: #ifdef SIGINFO
877: /* ARGSUSED */
878: SIG_FUNC_RET
879: ayt(sig)
880: int sig;
881: {
882: if (connected)
883: sendayt();
884: else
885: ayt_status();
886: }
887: #endif
888:
889:
890: void
891: sys_telnet_init()
892: {
893: (void) signal(SIGINT, intr);
894: (void) signal(SIGQUIT, intr2);
895: (void) signal(SIGPIPE, deadpeer);
896: #ifdef SIGWINCH
897: (void) signal(SIGWINCH, sendwin);
898: #endif
899: #ifdef SIGTSTP
900: (void) signal(SIGTSTP, susp);
901: #endif
902: #ifdef SIGINFO
903: (void) signal(SIGINFO, ayt);
904: #endif
905:
906: setconnmode(0);
907:
908: NetNonblockingIO(net, 1);
909:
910: #if defined(TN3270)
911: if (noasynchnet == 0) { /* DBX can't handle! */
912: NetSigIO(net, 1);
913: NetSetPgrp(net);
914: }
915: #endif /* defined(TN3270) */
916:
917: #if defined(SO_OOBINLINE)
918: if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
919: perror("SetSockOpt");
920: }
921: #endif /* defined(SO_OOBINLINE) */
922: }
923:
924: /*
925: * Process rings -
926: *
927: * This routine tries to fill up/empty our various rings.
928: *
929: * The parameter specifies whether this is a poll operation,
930: * or a block-until-something-happens operation.
931: *
932: * The return value is 1 if something happened, 0 if not.
933: */
934:
935: int
936: process_rings(netin, netout, netex, ttyin, ttyout, poll)
937: int poll; /* If 0, then block until something to do */
938: {
939: register int c;
940: /* One wants to be a bit careful about setting returnValue
941: * to one, since a one implies we did some useful work,
942: * and therefore probably won't be called to block next
943: * time (TN3270 mode only).
944: */
945: int returnValue = 0;
946: static struct timeval TimeValue = { 0 };
947:
948: if (netout) {
949: FD_SET(net, &obits);
950: }
951: if (ttyout) {
952: FD_SET(tout, &obits);
953: }
954: #if defined(TN3270)
955: if (ttyin) {
956: FD_SET(tin, &ibits);
957: }
958: #else /* defined(TN3270) */
959: if (ttyin) {
960: FD_SET(tin, &ibits);
961: }
962: #endif /* defined(TN3270) */
963: #if defined(TN3270)
964: if (netin) {
965: FD_SET(net, &ibits);
966: }
967: # else /* !defined(TN3270) */
968: if (netin) {
969: FD_SET(net, &ibits);
970: }
971: # endif /* !defined(TN3270) */
972: if (netex) {
973: FD_SET(net, &xbits);
974: }
975: if ((c = select(16, &ibits, &obits, &xbits,
976: (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
977: if (c == -1) {
978: /*
979: * we can get EINTR if we are in line mode,
980: * and the user does an escape (TSTP), or
981: * some other signal generator.
982: */
983: if (errno == EINTR) {
984: return 0;
985: }
986: # if defined(TN3270)
987: /*
988: * we can get EBADF if we were in transparent
989: * mode, and the transcom process died.
990: */
991: if (errno == EBADF) {
992: /*
993: * zero the bits (even though kernel does it)
994: * to make sure we are selecting on the right
995: * ones.
996: */
997: FD_ZERO(&ibits);
998: FD_ZERO(&obits);
999: FD_ZERO(&xbits);
1000: return 0;
1001: }
1002: # endif /* defined(TN3270) */
1003: /* I don't like this, does it ever happen? */
1004: printf("sleep(5) from telnet, after select\r\n");
1005: sleep(5);
1006: }
1007: return 0;
1008: }
1009:
1010: /*
1011: * Any urgent data?
1012: */
1013: if (FD_ISSET(net, &xbits)) {
1014: FD_CLR(net, &xbits);
1015: SYNCHing = 1;
1016: (void) ttyflush(1); /* flush already enqueued data */
1017: }
1018:
1019: /*
1020: * Something to read from the network...
1021: */
1022: if (FD_ISSET(net, &ibits)) {
1023: int canread;
1024:
1025: FD_CLR(net, &ibits);
1026: canread = ring_empty_consecutive(&netiring);
1027: #if !defined(SO_OOBINLINE)
1028: /*
1029: * In 4.2 (and some early 4.3) systems, the
1030: * OOB indication and data handling in the kernel
1031: * is such that if two separate TCP Urgent requests
1032: * come in, one byte of TCP data will be overlaid.
1033: * This is fatal for Telnet, but we try to live
1034: * with it.
1035: *
1036: * In addition, in 4.2 (and...), a special protocol
1037: * is needed to pick up the TCP Urgent data in
1038: * the correct sequence.
1039: *
1040: * What we do is: if we think we are in urgent
1041: * mode, we look to see if we are "at the mark".
1042: * If we are, we do an OOB receive. If we run
1043: * this twice, we will do the OOB receive twice,
1044: * but the second will fail, since the second
1045: * time we were "at the mark", but there wasn't
1046: * any data there (the kernel doesn't reset
1047: * "at the mark" until we do a normal read).
1048: * Once we've read the OOB data, we go ahead
1049: * and do normal reads.
1050: *
1051: * There is also another problem, which is that
1052: * since the OOB byte we read doesn't put us
1053: * out of OOB state, and since that byte is most
1054: * likely the TELNET DM (data mark), we would
1055: * stay in the TELNET SYNCH (SYNCHing) state.
1056: * So, clocks to the rescue. If we've "just"
1057: * received a DM, then we test for the
1058: * presence of OOB data when the receive OOB
1059: * fails (and AFTER we did the normal mode read
1060: * to clear "at the mark").
1061: */
1062: if (SYNCHing) {
1063: int atmark;
1064: static int bogus_oob = 0, first = 1;
1065:
1066: ioctl(net, SIOCATMARK, (char *)&atmark);
1067: if (atmark) {
1068: c = recv(net, netiring.supply, canread, MSG_OOB);
1069: if ((c == -1) && (errno == EINVAL)) {
1070: c = recv(net, netiring.supply, canread, 0);
1071: if (clocks.didnetreceive < clocks.gotDM) {
1072: SYNCHing = stilloob(net);
1073: }
1074: } else if (first && c > 0) {
1075: /*
1076: * Bogosity check. Systems based on 4.2BSD
1077: * do not return an error if you do a second
1078: * recv(MSG_OOB). So, we do one. If it
1079: * succeeds and returns exactly the same
1080: * data, then assume that we are running
1081: * on a broken system and set the bogus_oob
1082: * flag. (If the data was different, then
1083: * we probably got some valid new data, so
1084: * increment the count...)
1085: */
1086: int i;
1087: i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
1088: if (i == c &&
1089: bcmp(netiring.supply, netiring.supply + c, i) == 0) {
1090: bogus_oob = 1;
1091: first = 0;
1092: } else if (i < 0) {
1093: bogus_oob = 0;
1094: first = 0;
1095: } else
1096: c += i;
1097: }
1098: if (bogus_oob && c > 0) {
1099: int i;
1100: /*
1101: * Bogosity. We have to do the read
1102: * to clear the atmark to get out of
1103: * an infinate loop.
1104: */
1105: i = read(net, netiring.supply + c, canread - c);
1106: if (i > 0)
1107: c += i;
1108: }
1109: } else {
1110: c = recv(net, netiring.supply, canread, 0);
1111: }
1112: } else {
1113: c = recv(net, netiring.supply, canread, 0);
1114: }
1115: settimer(didnetreceive);
1116: #else /* !defined(SO_OOBINLINE) */
1117: c = recv(net, (char *)netiring.supply, canread, 0);
1118: #endif /* !defined(SO_OOBINLINE) */
1119: if (c < 0 && errno == EWOULDBLOCK) {
1120: c = 0;
1121: } else if (c <= 0) {
1122: return -1;
1123: }
1124: if (netdata) {
1125: Dump('<', netiring.supply, c);
1126: }
1127: if (c)
1128: ring_supplied(&netiring, c);
1129: returnValue = 1;
1130: }
1131:
1132: /*
1133: * Something to read from the tty...
1134: */
1135: if (FD_ISSET(tin, &ibits)) {
1136: FD_CLR(tin, &ibits);
1137: c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
1138: if (c < 0 && errno == EWOULDBLOCK) {
1139: c = 0;
1140: } else {
1141: if (c < 0) {
1142: return -1;
1143: }
1144: if (c == 0) {
1145: /* must be an EOF... */
1146: if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
1147: *ttyiring.supply = termEofChar;
1148: c = 1;
1149: } else {
1150: clienteof = 1;
1151: shutdown(net, 1);
1152: return 0;
1153: }
1154: }
1155: if (termdata) {
1156: Dump('<', ttyiring.supply, c);
1157: }
1158: ring_supplied(&ttyiring, c);
1159: }
1160: returnValue = 1; /* did something useful */
1161: }
1162:
1163: if (FD_ISSET(net, &obits)) {
1164: FD_CLR(net, &obits);
1165: returnValue |= netflush();
1166: }
1167: if (FD_ISSET(tout, &obits)) {
1168: FD_CLR(tout, &obits);
1169: returnValue |= (ttyflush(SYNCHing|flushout) > 0);
1170: }
1171:
1172: return returnValue;
1173: }