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