|
|
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
6: * provided that this notice is preserved and that due credit is given
7: * to the University of California at Berkeley. The name of the University
8: * may not be used to endorse or promote products derived from this
9: * software without specific prior written permission. This software
10: * is provided ``as is'' without express or implied warranty.
11: */
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)sys_bsd.c 1.11 (Berkeley) 3/27/88";
15: #endif /* not lint */
16:
17: /*
18: * The following routines try to encapsulate what is system dependent
19: * (at least between 4.x and dos) which is used in telnet.c.
20: */
21:
22: #if defined(unix)
23:
24: #include <sys/ioctl.h>
25: #include <sys/types.h>
26: #include <sys/time.h>
27: #include <sys/socket.h>
28: #include <signal.h>
29: #include <errno.h>
30:
31: #include "ring.h"
32:
33: #include "fdset.h"
34:
35: #include "defines.h"
36: #include "externs.h"
37: #include "types.h"
38:
39: int
40: tout, /* Output file descriptor */
41: tin, /* Input file descriptor */
42: net,
43: HaveInput; /* There is input available to scan */
44:
45: static struct tchars otc = { 0 }, ntc = { 0 };
46: static struct ltchars oltc = { 0 }, nltc = { 0 };
47: static struct sgttyb ottyb = { 0 }, nttyb = { 0 };
48:
49: static fd_set ibits, obits, xbits;
50:
51:
52: init_sys()
53: {
54: tout = fileno(stdout);
55: tin = fileno(stdin);
56: FD_ZERO(&ibits);
57: FD_ZERO(&obits);
58: FD_ZERO(&xbits);
59:
60: errno = 0;
61: }
62:
63:
64: TerminalWrite(buf, n)
65: char *buf;
66: int n;
67: {
68: return write(tout, buf, n);
69: }
70:
71: TerminalRead(buf, n)
72: char *buf;
73: int n;
74: {
75: return read(tin, buf, n);
76: }
77:
78: /*
79: *
80: */
81:
82: int
83: TerminalAutoFlush()
84: {
85: #if defined(LNOFLSH)
86: int flush;
87:
88: ioctl(0, TIOCLGET, (char *)&flush);
89: return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */
90: #else /* LNOFLSH */
91: return 1;
92: #endif /* LNOFLSH */
93: }
94:
95: /*
96: * TerminalSpecialChars()
97: *
98: * Look at an input character to see if it is a special character
99: * and decide what to do.
100: *
101: * Output:
102: *
103: * 0 Don't add this character.
104: * 1 Do add this character
105: */
106:
107: int
108: TerminalSpecialChars(c)
109: int c;
110: {
111: void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
112:
113: if (c == ntc.t_intrc) {
114: intp();
115: return 0;
116: } else if (c == ntc.t_quitc) {
117: sendbrk();
118: return 0;
119: } else if (c == nltc.t_flushc) {
120: xmitAO(); /* Transmit Abort Output */
121: return 0;
122: } else if (!MODE_LOCAL_CHARS(globalmode)) {
123: if (c == nttyb.sg_kill) {
124: xmitEL();
125: return 0;
126: } else if (c == nttyb.sg_erase) {
127: xmitEC(); /* Transmit Erase Character */
128: return 0;
129: }
130: }
131: return 1;
132: }
133:
134:
135: /*
136: * Flush output to the terminal
137: */
138:
139: void
140: TerminalFlushOutput()
141: {
142: (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
143: }
144:
145: void
146: TerminalSaveState()
147: {
148: ioctl(0, TIOCGETP, (char *)&ottyb);
149: ioctl(0, TIOCGETC, (char *)&otc);
150: ioctl(0, TIOCGLTC, (char *)&oltc);
151:
152: ntc = otc;
153: nltc = oltc;
154: nttyb = ottyb;
155:
156: termEofChar = ntc.t_eofc;
157: termEraseChar = nttyb.sg_erase;
158: termFlushChar = nltc.t_flushc;
159: termIntChar = ntc.t_intrc;
160: termKillChar = nttyb.sg_kill;
161: termQuitChar = ntc.t_quitc;
162: }
163:
164: void
165: TerminalRestoreState()
166: {
167: }
168:
169: /*
170: * TerminalNewMode - set up terminal to a specific mode.
171: */
172:
173:
174: void
175: TerminalNewMode(f)
176: register int f;
177: {
178: static int prevmode = 0;
179: struct tchars *tc;
180: struct tchars tc3;
181: struct ltchars *ltc;
182: struct sgttyb sb;
183: int onoff;
184: int old;
185: struct tchars notc2;
186: struct ltchars noltc2;
187: static struct tchars notc = { -1, -1, -1, -1, -1, -1 };
188: static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
189:
190: globalmode = f;
191: if (prevmode == f)
192: return;
193: old = prevmode;
194: prevmode = f;
195: sb = nttyb;
196:
197: switch (f) {
198:
199: case 0:
200: onoff = 0;
201: tc = &otc;
202: ltc = &oltc;
203: break;
204:
205: case 1: /* remote character processing, remote echo */
206: case 2: /* remote character processing, local echo */
207: case 6: /* 3270 mode - like 1, but with xon/xoff local */
208: /* (might be nice to have "6" in telnet also...) */
209: sb.sg_flags |= CBREAK;
210: if ((f == 1) || (f == 6)) {
211: sb.sg_flags &= ~(ECHO|CRMOD);
212: } else {
213: sb.sg_flags |= ECHO|CRMOD;
214: }
215: sb.sg_erase = sb.sg_kill = -1;
216: if (f == 6) {
217: tc = &tc3;
218: tc3 = notc;
219: /* get XON, XOFF characters */
220: tc3.t_startc = otc.t_startc;
221: tc3.t_stopc = otc.t_stopc;
222: } else {
223: /*
224: * If user hasn't specified one way or the other,
225: * then default to not trapping signals.
226: */
227: if (!donelclchars) {
228: localchars = 0;
229: }
230: if (localchars) {
231: notc2 = notc;
232: notc2.t_intrc = ntc.t_intrc;
233: notc2.t_quitc = ntc.t_quitc;
234: tc = ¬c2;
235: } else {
236: tc = ¬c;
237: }
238: }
239: ltc = &noltc;
240: onoff = 1;
241: break;
242: case 3: /* local character processing, remote echo */
243: case 4: /* local character processing, local echo */
244: case 5: /* local character processing, no echo */
245: sb.sg_flags &= ~CBREAK;
246: sb.sg_flags |= CRMOD;
247: if (f == 4)
248: sb.sg_flags |= ECHO;
249: else
250: sb.sg_flags &= ~ECHO;
251: notc2 = ntc;
252: tc = ¬c2;
253: noltc2 = oltc;
254: ltc = &noltc2;
255: /*
256: * If user hasn't specified one way or the other,
257: * then default to trapping signals.
258: */
259: if (!donelclchars) {
260: localchars = 1;
261: }
262: if (localchars) {
263: notc2.t_brkc = nltc.t_flushc;
264: noltc2.t_flushc = -1;
265: } else {
266: notc2.t_intrc = notc2.t_quitc = -1;
267: }
268: noltc2.t_suspc = escape;
269: noltc2.t_dsuspc = -1;
270: onoff = 1;
271: break;
272:
273: default:
274: return;
275: }
276: ioctl(tin, TIOCSLTC, (char *)ltc);
277: ioctl(tin, TIOCSETC, (char *)tc);
278: ioctl(tin, TIOCSETP, (char *)&sb);
279: #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
280: ioctl(tin, FIONBIO, (char *)&onoff);
281: ioctl(tout, FIONBIO, (char *)&onoff);
282: #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
283: #if defined(TN3270)
284: if (noasynch == 0) {
285: ioctl(tin, FIOASYNC, (char *)&onoff);
286: }
287: #endif /* defined(TN3270) */
288:
289: if (MODE_LINE(f)) {
290: void doescape();
291:
292: signal(SIGTSTP, doescape);
293: } else if (MODE_LINE(old)) {
294: signal(SIGTSTP, SIG_DFL);
295: sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
296: }
297: }
298:
299:
300: int
301: NetClose(net)
302: int net;
303: {
304: return close(net);
305: }
306:
307:
308: void
309: NetNonblockingIO(fd, onoff)
310: int
311: fd,
312: onoff;
313: {
314: ioctl(fd, FIONBIO, (char *)&onoff);
315: }
316:
317: void
318: NetSigIO(fd, onoff)
319: int
320: fd,
321: onoff;
322: {
323: ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */
324: }
325:
326: void
327: NetSetPgrp(fd)
328: int fd;
329: {
330: int myPid;
331:
332: myPid = getpid();
333: #if defined(NOT43)
334: myPid = -myPid;
335: #endif /* defined(NOT43) */
336: ioctl(fd, SIOCSPGRP, (char *)&myPid); /* set my pid */
337: }
338:
339: /*
340: * Various signal handling routines.
341: */
342:
343: static void
344: deadpeer()
345: {
346: setcommandmode();
347: longjmp(peerdied, -1);
348: }
349:
350: static void
351: intr()
352: {
353: if (localchars) {
354: intp();
355: return;
356: }
357: setcommandmode();
358: longjmp(toplevel, -1);
359: }
360:
361: static void
362: intr2()
363: {
364: if (localchars) {
365: sendbrk();
366: return;
367: }
368: }
369:
370: static void
371: doescape()
372: {
373: command(0);
374: }
375:
376: void
377: sys_telnet_init()
378: {
379: #if defined(TN3270)
380: int myPid;
381: #endif /* defined(TN3270) */
382:
383: signal(SIGINT, intr);
384: signal(SIGQUIT, intr2);
385: signal(SIGPIPE, deadpeer);
386:
387: setconnmode();
388:
389: NetNonblockingIO(net, 1);
390:
391: #if defined(TN3270)
392: if (noasynch == 0) { /* DBX can't handle! */
393: NetSigIO(net, 1);
394: NetSetPgrp(net);
395: }
396: #endif /* defined(TN3270) */
397:
398: #if defined(SO_OOBINLINE)
399: SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
400: #endif /* defined(SO_OOBINLINE) */
401: }
402:
403: /*
404: * Process rings -
405: *
406: * This routine tries to fill up/empty our various rings.
407: *
408: * The parameter specifies whether this is a poll operation,
409: * or a block-until-something-happens operation.
410: *
411: * The return value is 1 if something happened, 0 if not.
412: */
413:
414: int
415: process_rings(netin, netout, netex, ttyin, ttyout, poll)
416: int poll; /* If 0, then block until something to do */
417: {
418: register int c;
419: /* One wants to be a bit careful about setting returnValue
420: * to one, since a one implies we did some useful work,
421: * and therefore probably won't be called to block next
422: * time (TN3270 mode only).
423: */
424: int returnValue = 0;
425: static struct timeval TimeValue = { 0 };
426:
427: if (netout) {
428: FD_SET(net, &obits);
429: }
430: if (ttyout) {
431: FD_SET(tout, &obits);
432: }
433: #if defined(TN3270)
434: if (ttyin) {
435: FD_SET(tin, &ibits);
436: }
437: #else /* defined(TN3270) */
438: if (ttyin) {
439: FD_SET(tin, &ibits);
440: }
441: #endif /* defined(TN3270) */
442: #if defined(TN3270)
443: if (netin) {
444: FD_SET(net, &ibits);
445: }
446: # else /* !defined(TN3270) */
447: if (netin) {
448: FD_SET(net, &ibits);
449: }
450: # endif /* !defined(TN3270) */
451: if (netex) {
452: FD_SET(net, &xbits);
453: }
454: if ((c = select(16, &ibits, &obits, &xbits,
455: (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
456: if (c == -1) {
457: /*
458: * we can get EINTR if we are in line mode,
459: * and the user does an escape (TSTP), or
460: * some other signal generator.
461: */
462: if (errno == EINTR) {
463: return 0;
464: }
465: # if defined(TN3270)
466: /*
467: * we can get EBADF if we were in transparent
468: * mode, and the transcom process died.
469: */
470: if (errno == EBADF) {
471: /*
472: * zero the bits (even though kernel does it)
473: * to make sure we are selecting on the right
474: * ones.
475: */
476: FD_ZERO(&ibits);
477: FD_ZERO(&obits);
478: FD_ZERO(&xbits);
479: return 0;
480: }
481: # endif /* defined(TN3270) */
482: /* I don't like this, does it ever happen? */
483: printf("sleep(5) from telnet, after select\r\n");
484: sleep(5);
485: }
486: return 0;
487: }
488:
489: /*
490: * Any urgent data?
491: */
492: if (FD_ISSET(net, &xbits)) {
493: FD_CLR(net, &xbits);
494: SYNCHing = 1;
495: ttyflush(1); /* flush already enqueued data */
496: }
497:
498: /*
499: * Something to read from the network...
500: */
501: if (FD_ISSET(net, &ibits)) {
502: int canread;
503:
504: FD_CLR(net, &ibits);
505: canread = ring_empty_consecutive(&netiring);
506: #if !defined(SO_OOBINLINE)
507: /*
508: * In 4.2 (and some early 4.3) systems, the
509: * OOB indication and data handling in the kernel
510: * is such that if two separate TCP Urgent requests
511: * come in, one byte of TCP data will be overlaid.
512: * This is fatal for Telnet, but we try to live
513: * with it.
514: *
515: * In addition, in 4.2 (and...), a special protocol
516: * is needed to pick up the TCP Urgent data in
517: * the correct sequence.
518: *
519: * What we do is: if we think we are in urgent
520: * mode, we look to see if we are "at the mark".
521: * If we are, we do an OOB receive. If we run
522: * this twice, we will do the OOB receive twice,
523: * but the second will fail, since the second
524: * time we were "at the mark", but there wasn't
525: * any data there (the kernel doesn't reset
526: * "at the mark" until we do a normal read).
527: * Once we've read the OOB data, we go ahead
528: * and do normal reads.
529: *
530: * There is also another problem, which is that
531: * since the OOB byte we read doesn't put us
532: * out of OOB state, and since that byte is most
533: * likely the TELNET DM (data mark), we would
534: * stay in the TELNET SYNCH (SYNCHing) state.
535: * So, clocks to the rescue. If we've "just"
536: * received a DM, then we test for the
537: * presence of OOB data when the receive OOB
538: * fails (and AFTER we did the normal mode read
539: * to clear "at the mark").
540: */
541: if (SYNCHing) {
542: int atmark;
543:
544: ioctl(net, SIOCATMARK, (char *)&atmark);
545: if (atmark) {
546: c = recv(net, netiring.supply, canread, MSG_OOB);
547: if ((c == -1) && (errno == EINVAL)) {
548: c = recv(net, netiring.supply, canread, 0);
549: if (clocks.didnetreceive < clocks.gotDM) {
550: SYNCHing = stilloob(net);
551: }
552: }
553: } else {
554: c = recv(net, netiring.supply, canread, 0);
555: }
556: } else {
557: c = recv(net, netiring.supply, canread, 0);
558: }
559: settimer(didnetreceive);
560: #else /* !defined(SO_OOBINLINE) */
561: c = recv(net, netiring.supply, canread, 0);
562: #endif /* !defined(SO_OOBINLINE) */
563: if (c < 0 && errno == EWOULDBLOCK) {
564: c = 0;
565: } else if (c <= 0) {
566: return -1;
567: }
568: if (netdata) {
569: Dump('<', netiring.supply, c);
570: }
571: if (c)
572: ring_supplied(&netiring, c);
573: returnValue = 1;
574: }
575:
576: /*
577: * Something to read from the tty...
578: */
579: if (FD_ISSET(tin, &ibits)) {
580: FD_CLR(tin, &ibits);
581: c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
582: if (c < 0 && errno == EWOULDBLOCK) {
583: c = 0;
584: } else {
585: /* EOF detection for line mode!!!! */
586: if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
587: /* must be an EOF... */
588: *ttyiring.supply = termEofChar;
589: c = 1;
590: }
591: if (c <= 0) {
592: return -1;
593: }
594: ring_supplied(&ttyiring, c);
595: }
596: returnValue = 1; /* did something useful */
597: }
598:
599: if (FD_ISSET(net, &obits)) {
600: FD_CLR(net, &obits);
601: returnValue |= netflush();
602: }
603: if (FD_ISSET(tout, &obits)) {
604: FD_CLR(tout, &obits);
605: returnValue |= ttyflush(SYNCHing|flushout);
606: }
607:
608: return returnValue;
609: }
610: #endif /* defined(unix) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.