1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 1988, 1990, 1993
8 * The Regents of the University of California. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 */
39
40 /*
41 * The following routines try to encapsulate what is system dependent
42 * (at least between 4.x and dos) which is used in telnet.c.
43 */
44
45
46 #include <fcntl.h>
47 #include <sys/types.h>
48 #include <sys/time.h>
49 #include <sys/socket.h>
50 #include <sys/uio.h>
51 #include <signal.h>
52 #include <errno.h>
53 #include <arpa/telnet.h>
54
55 #include "ring.h"
56
57 #include "defines.h"
58 #include "externs.h"
59 #include "types.h"
60
61 #define SIG_FUNC_RET void
62
63 int tout; /* Output file descriptor */
64 static int tin; /* Input file descriptor */
65 int net = -1;
66
67
68 #ifndef USE_TERMIO
69 struct tchars otc = { 0 }, ntc = { 0 };
70 struct ltchars oltc = { 0 }, nltc = { 0 };
71 struct sgttyb ottyb = { 0 }, nttyb = { 0 };
72 int olmode = 0;
73 #define cfgetispeed(ptr) (ptr)->sg_ispeed
74 #define cfgetospeed(ptr) (ptr)->sg_ospeed
75 #define old_tc ottyb
76
77 #else /* USE_TERMIO */
78 static struct termio old_tc = { 0 };
79 extern struct termio new_tc;
80 #endif /* USE_TERMIO */
81
82 static fd_set ibits, obits, xbits;
83
84 static SIG_FUNC_RET susp(int);
85 void fatal_tty_error(char *doing_what);
86
87
88 void
init_sys()89 init_sys()
90 {
91 tout = fileno(stdout);
92 tin = fileno(stdin);
93 FD_ZERO(&ibits);
94 FD_ZERO(&obits);
95 FD_ZERO(&xbits);
96
97 errno = 0;
98 }
99
100
101 int
TerminalWrite(buf,n)102 TerminalWrite(buf, n)
103 char *buf;
104 int n;
105 {
106 return (write(tout, buf, n));
107 }
108
109 static int
TerminalRead(buf,n)110 TerminalRead(buf, n)
111 char *buf;
112 int n;
113 {
114 return (read(tin, buf, n));
115 }
116
117 #ifdef KLUDGELINEMODE
118 extern int kludgelinemode;
119 #endif
120 /*
121 * TerminalSpecialChars()
122 *
123 * Look at an input character to see if it is a special character
124 * and decide what to do.
125 *
126 * Output:
127 *
128 * 0 Don't add this character.
129 * 1 Do add this character
130 */
131 int
TerminalSpecialChars(c)132 TerminalSpecialChars(c)
133 int c;
134 {
135 /*
136 * Don't check for signal characters here. If MODE_TRAPSIG is on,
137 * then the various signal handlers will catch the characters. If
138 * the character in question gets here, then it must have been LNEXTed
139 */
140 if (c == termQuitChar) {
141 #ifdef KLUDGELINEMODE
142 if (kludgelinemode) {
143 if (sendbrk() == -1) {
144 /* This won't return. */
145 fatal_tty_error("write");
146 }
147 return (0);
148 }
149 #endif
150 } else if (c == termFlushChar) {
151 /* Transmit Abort Output */
152 if (xmitAO() == -1) {
153 /* This won't return. */
154 fatal_tty_error("write");
155 }
156 return (0);
157 } else if (!MODE_LOCAL_CHARS(globalmode)) {
158 if (c == termKillChar) {
159 xmitEL();
160 return (0);
161 } else if (c == termEraseChar) {
162 xmitEC(); /* Transmit Erase Character */
163 return (0);
164 }
165 }
166 return (1);
167 }
168
169
170 /*
171 * Flush output to the terminal
172 */
173
174 void
TerminalFlushOutput()175 TerminalFlushOutput()
176 {
177 if (isatty(fileno(stdout))) {
178 (void) ioctl(fileno(stdout), TIOCFLUSH, NULL);
179 }
180 }
181
182 void
TerminalSaveState()183 TerminalSaveState()
184 {
185 #ifndef USE_TERMIO
186 (void) ioctl(0, TIOCGETP, &ottyb);
187 (void) ioctl(0, TIOCGETC, &otc);
188 (void) ioctl(0, TIOCGLTC, &oltc);
189 (void) ioctl(0, TIOCLGET, &olmode);
190
191 ntc = otc;
192 nltc = oltc;
193 nttyb = ottyb;
194
195 #else /* USE_TERMIO */
196 (void) tcgetattr(0, &old_tc);
197
198 new_tc = old_tc;
199 termAytChar = CONTROL('T');
200 #endif /* USE_TERMIO */
201 }
202
203 cc_t *
tcval(func)204 tcval(func)
205 register int func;
206 {
207 switch (func) {
208 case SLC_IP: return (&termIntChar);
209 case SLC_ABORT: return (&termQuitChar);
210 case SLC_EOF: return (&termEofChar);
211 case SLC_EC: return (&termEraseChar);
212 case SLC_EL: return (&termKillChar);
213 case SLC_XON: return (&termStartChar);
214 case SLC_XOFF: return (&termStopChar);
215 case SLC_FORW1: return (&termForw1Char);
216 #ifdef USE_TERMIO
217 case SLC_FORW2: return (&termForw2Char);
218 case SLC_AO: return (&termFlushChar);
219 case SLC_SUSP: return (&termSuspChar);
220 case SLC_EW: return (&termWerasChar);
221 case SLC_RP: return (&termRprntChar);
222 case SLC_LNEXT: return (&termLiteralNextChar);
223 #endif
224
225 case SLC_SYNCH:
226 case SLC_BRK:
227 case SLC_EOR:
228 default:
229 return ((cc_t *)0);
230 }
231 }
232
233 void
TerminalDefaultChars()234 TerminalDefaultChars()
235 {
236 #ifndef USE_TERMIO
237 ntc = otc;
238 nltc = oltc;
239 nttyb.sg_kill = ottyb.sg_kill;
240 nttyb.sg_erase = ottyb.sg_erase;
241 #else /* USE_TERMIO */
242 (void) memcpy(new_tc.c_cc, old_tc.c_cc, sizeof (old_tc.c_cc));
243 termAytChar = CONTROL('T');
244 #endif /* USE_TERMIO */
245 }
246
247 /*
248 * TerminalNewMode - set up terminal to a specific mode.
249 * MODE_ECHO: do local terminal echo
250 * MODE_FLOW: do local flow control
251 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
252 * MODE_EDIT: do local line editing
253 *
254 * Command mode:
255 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
256 * local echo
257 * local editing
258 * local xon/xoff
259 * local signal mapping
260 *
261 * Linemode:
262 * local/no editing
263 * Both Linemode and Single Character mode:
264 * local/remote echo
265 * local/no xon/xoff
266 * local/no signal mapping
267 */
268
269
270 void
TerminalNewMode(f)271 TerminalNewMode(f)
272 register int f;
273 {
274 static int prevmode = -2; /* guaranteed unique */
275 #ifndef USE_TERMIO
276 struct tchars tc;
277 struct ltchars ltc;
278 struct sgttyb sb;
279 int lmode;
280 #else /* USE_TERMIO */
281 struct termio tmp_tc;
282 #endif /* USE_TERMIO */
283 int onoff;
284 int old;
285 cc_t esc;
286 sigset_t nset;
287
288 globalmode = f&~MODE_FORCE;
289 if (prevmode == f)
290 return;
291
292 /*
293 * Write any outstanding data before switching modes
294 * ttyflush() returns 0 only when there was no data
295 * to write out; it returns -1 if it couldn't do
296 * anything at all, returns -2 if there was a write
297 * error (other than EWOULDBLOCK), and otherwise it
298 * returns 1 + the number of characters left to write.
299 */
300 #ifndef USE_TERMIO
301 /*
302 * We would really like ask the kernel to wait for the output
303 * to drain, like we can do with the TCSADRAIN, but we don't have
304 * that option. The only ioctl that waits for the output to
305 * drain, TIOCSETP, also flushes the input queue, which is NOT
306 * what we want(TIOCSETP is like TCSADFLUSH).
307 */
308 #endif
309 old = ttyflush(SYNCHing|flushout);
310 if (old == -1 || old > 1) {
311 #ifdef USE_TERMIO
312 (void) tcgetattr(tin, &tmp_tc);
313 #endif /* USE_TERMIO */
314 do {
315 /*
316 * Wait for data to drain, then flush again.
317 */
318 #ifdef USE_TERMIO
319 (void) tcsetattr(tin, TCSADRAIN, &tmp_tc);
320 #endif /* USE_TERMIO */
321 old = ttyflush(SYNCHing|flushout);
322 } while (old == -1 || old > 1);
323 }
324
325 old = prevmode;
326 prevmode = f&~MODE_FORCE;
327 #ifndef USE_TERMIO
328 sb = nttyb;
329 tc = ntc;
330 ltc = nltc;
331 lmode = olmode;
332 #else
333 tmp_tc = new_tc;
334 #endif
335
336 if (f&MODE_ECHO) {
337 #ifndef USE_TERMIO
338 sb.sg_flags |= ECHO;
339 #else
340 tmp_tc.c_lflag |= ECHO;
341 tmp_tc.c_oflag |= ONLCR;
342 if (crlf)
343 tmp_tc.c_iflag |= ICRNL;
344 #endif
345 } else {
346 #ifndef USE_TERMIO
347 sb.sg_flags &= ~ECHO;
348 #else
349 tmp_tc.c_lflag &= ~ECHO;
350 tmp_tc.c_oflag &= ~ONLCR;
351 #ifdef notdef
352 if (crlf)
353 tmp_tc.c_iflag &= ~ICRNL;
354 #endif
355 #endif
356 }
357
358 if ((f&MODE_FLOW) == 0) {
359 #ifndef USE_TERMIO
360 tc.t_startc = _POSIX_VDISABLE;
361 tc.t_stopc = _POSIX_VDISABLE;
362 #else
363 tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */
364 } else {
365 if (restartany < 0) {
366 /* Leave the IXANY bit alone */
367 tmp_tc.c_iflag |= IXOFF|IXON;
368 } else if (restartany > 0) {
369 tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
370 } else {
371 tmp_tc.c_iflag |= IXOFF|IXON;
372 tmp_tc.c_iflag &= ~IXANY;
373 }
374 #endif
375 }
376
377 if ((f&MODE_TRAPSIG) == 0) {
378 #ifndef USE_TERMIO
379 tc.t_intrc = _POSIX_VDISABLE;
380 tc.t_quitc = _POSIX_VDISABLE;
381 tc.t_eofc = _POSIX_VDISABLE;
382 ltc.t_suspc = _POSIX_VDISABLE;
383 ltc.t_dsuspc = _POSIX_VDISABLE;
384 #else
385 tmp_tc.c_lflag &= ~ISIG;
386 #endif
387 localchars = 0;
388 } else {
389 #ifdef USE_TERMIO
390 tmp_tc.c_lflag |= ISIG;
391 #endif
392 localchars = 1;
393 }
394
395 if (f&MODE_EDIT) {
396 #ifndef USE_TERMIO
397 sb.sg_flags &= ~CBREAK;
398 sb.sg_flags |= CRMOD;
399 #else
400 tmp_tc.c_lflag |= ICANON;
401 #endif
402 } else {
403 #ifndef USE_TERMIO
404 sb.sg_flags |= CBREAK;
405 if (f&MODE_ECHO)
406 sb.sg_flags |= CRMOD;
407 else
408 sb.sg_flags &= ~CRMOD;
409 #else
410 tmp_tc.c_lflag &= ~ICANON;
411 tmp_tc.c_iflag &= ~ICRNL;
412 tmp_tc.c_cc[VMIN] = 1;
413 tmp_tc.c_cc[VTIME] = 0;
414 #endif
415 }
416
417 if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
418 #ifndef USE_TERMIO
419 ltc.t_lnextc = _POSIX_VDISABLE;
420 #else
421 tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
422 #endif
423 }
424
425 if (f&MODE_SOFT_TAB) {
426 #ifndef USE_TERMIO
427 sb.sg_flags |= XTABS;
428 #else
429 tmp_tc.c_oflag &= ~TABDLY;
430 tmp_tc.c_oflag |= TAB3;
431 #endif
432 } else {
433 #ifndef USE_TERMIO
434 sb.sg_flags &= ~XTABS;
435 #else
436 tmp_tc.c_oflag &= ~TABDLY;
437 #endif
438 }
439
440 if (f&MODE_LIT_ECHO) {
441 #ifndef USE_TERMIO
442 lmode &= ~LCTLECH;
443 #else
444 tmp_tc.c_lflag &= ~ECHOCTL;
445 #endif
446 } else {
447 #ifndef USE_TERMIO
448 lmode |= LCTLECH;
449 #else
450 tmp_tc.c_lflag |= ECHOCTL;
451 #endif
452 }
453
454 if (f == -1) {
455 onoff = 0;
456 } else {
457 #ifndef USE_TERMIO
458 if (f & MODE_OUTBIN)
459 lmode |= LLITOUT;
460 else
461 lmode &= ~LLITOUT;
462 #else
463 if (f & MODE_OUTBIN) {
464 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
465 tmp_tc.c_cflag |= CS8;
466 tmp_tc.c_oflag &= ~OPOST;
467 } else {
468 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
469 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
470 tmp_tc.c_oflag |= OPOST;
471 }
472 #endif
473 onoff = 1;
474 }
475
476 if (f != -1) {
477
478 (void) signal(SIGTSTP, susp);
479
480 #if defined(USE_TERMIO) && defined(NOKERNINFO)
481 tmp_tc.c_lflag |= NOKERNINFO;
482 #endif
483 /*
484 * We don't want to process ^Y here. It's just another
485 * character that we'll pass on to the back end. It has
486 * to process it because it will be processed when the
487 * user attempts to read it, not when we send it.
488 */
489 #ifndef USE_TERMIO
490 ltc.t_dsuspc = _POSIX_VDISABLE;
491 #else
492 tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
493 #endif
494 #ifdef USE_TERMIO
495 /*
496 * If the VEOL character is already set, then use VEOL2,
497 * otherwise use VEOL.
498 */
499 esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
500 if ((tmp_tc.c_cc[VEOL] != esc)
501 /* XXX */ &&
502 (tmp_tc.c_cc[VEOL2] != esc)
503 /* XXX */) {
504 if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
505 tmp_tc.c_cc[VEOL] = esc;
506 else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
507 tmp_tc.c_cc[VEOL2] = esc;
508 }
509 #else
510 if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
511 tc.t_brkc = esc;
512 #endif
513 } else {
514 (void) signal(SIGTSTP, SIG_DFL);
515 (void) sigemptyset(&nset);
516 (void) sigaddset(&nset, SIGTSTP);
517 (void) sigprocmask(SIG_UNBLOCK, &nset, 0);
518 #ifndef USE_TERMIO
519 ltc = oltc;
520 tc = otc;
521 sb = ottyb;
522 lmode = olmode;
523 #else
524 tmp_tc = old_tc;
525 #endif
526 }
527 if (isatty(tin)) {
528 #ifndef USE_TERMIO
529 (void) ioctl(tin, TIOCLSET, &lmode);
530 (void) ioctl(tin, TIOCSLTC, <c);
531 (void) ioctl(tin, TIOCSETC, &tc);
532 (void) ioctl(tin, TIOCSETN, &sb);
533 #else
534 if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
535 (void) tcsetattr(tin, TCSANOW, &tmp_tc);
536 #endif
537 (void) ioctl(tin, FIONBIO, &onoff);
538 (void) ioctl(tout, FIONBIO, &onoff);
539 }
540
541 }
542
543 /*
544 * This code assumes that the values B0, B50, B75...
545 * are in ascending order. They do not have to be
546 * contiguous.
547 */
548 static struct termspeeds {
549 int speed;
550 int value;
551 } termspeeds[] = {
552 { 0, B0 }, { 50, B50 }, { 75, B75 },
553 { 110, B110 }, { 134, B134 }, { 150, B150 },
554 { 200, B200 }, { 300, B300 }, { 600, B600 },
555 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
556 { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 },
557 { 38400, B38400 }, { 57600, B57600 }, { 76800, B76800 },
558 { 115200, B115200 }, { 153600, B153600 }, { 230400, B230400 },
559 { 307200, B307200 }, { 460800, B460800 }, { 921600, B921600 },
560 { 1000000, B1000000 }, { 1152000, B1152000 }, { 1500000, B1500000 },
561 { 2000000, B2000000 }, { 2500000, B2500000 }, { 3000000, B3000000 },
562 { 3500000, B3500000 }, { 4000000, B4000000 }, { -1, B0 }
563 };
564
565 void
TerminalSpeeds(ispeed,ospeed)566 TerminalSpeeds(ispeed, ospeed)
567 int *ispeed;
568 int *ospeed;
569 {
570 register struct termspeeds *tp;
571 register int in, out;
572
573 out = cfgetospeed(&old_tc);
574 in = cfgetispeed(&old_tc);
575 if (in == 0)
576 in = out;
577
578 tp = termspeeds;
579 while ((tp->speed != -1) && (tp->value < in)) {
580 tp++;
581 }
582 if (tp->speed == -1)
583 tp--; /* back up to fastest defined speed */
584 *ispeed = tp->speed;
585
586 tp = termspeeds;
587 while ((tp->speed != -1) && (tp->value < out)) {
588 tp++;
589 }
590 if (tp->speed == -1)
591 tp--;
592 *ospeed = tp->speed;
593 }
594
595 int
TerminalWindowSize(rows,cols)596 TerminalWindowSize(rows, cols)
597 unsigned short *rows, *cols;
598 {
599 struct winsize ws;
600
601 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) {
602 *rows = ws.ws_row;
603 *cols = ws.ws_col;
604 return (1);
605 }
606 return (0);
607 }
608
609 static void
NetNonblockingIO(fd,onoff)610 NetNonblockingIO(fd, onoff)
611 int fd;
612 int onoff;
613 {
614 (void) ioctl(fd, FIONBIO, &onoff);
615 }
616
617 /*
618 * Various signal handling routines.
619 */
620
621 /* ARGSUSED */
622 static SIG_FUNC_RET
deadpeer(sig)623 deadpeer(sig)
624 int sig;
625 {
626 /*
627 * Once is all we should catch SIGPIPE. If we get it again,
628 * it means we tried to put still more data out to a pipe
629 * which has disappeared. In that case, telnet will exit.
630 */
631 (void) signal(SIGPIPE, SIG_IGN);
632 flushout = 1;
633 setcommandmode();
634 longjmp(peerdied, -1);
635 }
636
637 boolean_t intr_happened = B_FALSE;
638 boolean_t intr_waiting = B_FALSE;
639
640 /* ARGSUSED */
641 static SIG_FUNC_RET
intr(sig)642 intr(sig)
643 int sig;
644 {
645 if (intr_waiting) {
646 intr_happened = 1;
647 return;
648 }
649 (void) signal(SIGINT, intr);
650 if (localchars) {
651 intp();
652 return;
653 }
654 setcommandmode();
655 longjmp(toplevel, -1);
656 }
657
658 /* ARGSUSED */
659 static SIG_FUNC_RET
intr2(sig)660 intr2(sig)
661 int sig;
662 {
663 (void) signal(SIGQUIT, intr2);
664 if (localchars) {
665 /*
666 * Ignore return to the next two function calls
667 * since we're doing SIGQUIT
668 */
669 #ifdef KLUDGELINEMODE
670 if (kludgelinemode) {
671 (void) sendbrk();
672 }
673 else
674 #endif
675 sendabort();
676 return;
677 }
678 }
679
680 /* ARGSUSED */
681 static SIG_FUNC_RET
susp(sig)682 susp(sig)
683 int sig;
684 {
685 (void) signal(SIGTSTP, susp);
686 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
687 return;
688 if (localchars)
689 sendsusp();
690 }
691
692 /* ARGSUSED */
693 static SIG_FUNC_RET
sendwin(sig)694 sendwin(sig)
695 int sig;
696 {
697 (void) signal(SIGWINCH, sendwin);
698 if (connected) {
699 sendnaws();
700 }
701 }
702
703 void
sys_telnet_init()704 sys_telnet_init()
705 {
706 (void) signal(SIGINT, intr);
707 (void) signal(SIGQUIT, intr2);
708 (void) signal(SIGPIPE, deadpeer);
709 (void) signal(SIGWINCH, sendwin);
710 (void) signal(SIGTSTP, susp);
711
712 setconnmode(0);
713
714 NetNonblockingIO(net, 1);
715
716 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
717 perror("SetSockOpt");
718 }
719 }
720
721
722 /*
723 * fatal_tty_error -
724 * Handle case where there is an unrecoverable error on the tty
725 * connections. Print an error, reset the terminal settings
726 * and get out as painlessly as possible.
727 */
728 void
fatal_tty_error(char * doing_what)729 fatal_tty_error(char *doing_what)
730 {
731 TerminalNewMode(-1);
732 (void) fprintf(stderr, "Error processing %s: %s\n", doing_what,
733 strerror(errno));
734 exit(1);
735 }
736
737
738 /*
739 * Process rings -
740 *
741 * This routine tries to fill up/empty our various rings.
742 *
743 * The parameter specifies whether this is a poll operation,
744 * or a block-until-something-happens operation.
745 *
746 * The return value is 1 if something happened, 0 if not.
747 * If poll == 0, then block until something to do.
748 */
749 int
process_rings(int netin,int netout,int netex,int ttyin,int ttyout,int poll)750 process_rings(int netin, int netout, int netex, int ttyin, int ttyout, int poll)
751 {
752 int c;
753 /*
754 * One wants to be a bit careful about setting returnValue
755 * to one, since a one implies we did some useful work,
756 * and therefore probably won't be called to block next
757 * time (TN3270 mode only).
758 */
759 int returnValue = 0;
760 static struct timeval TimeValue = { 0 };
761 int i;
762
763 if (netout) {
764 FD_SET(net, &obits);
765 }
766 if (ttyout) {
767 FD_SET(tout, &obits);
768 }
769 if (ttyin) {
770 FD_SET(tin, &ibits);
771 }
772 if (netin) {
773 FD_SET(net, &ibits);
774 }
775 if (netex) {
776 FD_SET(net, &xbits);
777 }
778 if ((c = select(16, &ibits, &obits, &xbits,
779 (poll == 0) ? NULL : &TimeValue)) < 0) {
780 if (c == -1) {
781 /*
782 * we can get EINTR if we are in line mode,
783 * and the user does an escape (TSTP), or
784 * some other signal generator.
785 */
786 if (errno == EINTR) {
787 return (0);
788 }
789 /* I don't like this, does it ever happen? */
790 (void) printf("sleep(5) from telnet, after select\r\n");
791 (void) sleep(5);
792 }
793 return (0);
794 }
795
796 /*
797 * Any urgent data?
798 */
799 if (FD_ISSET(net, &xbits)) {
800 FD_CLR(net, &xbits);
801 SYNCHing = 1;
802
803 /* flush any data that is already enqueued */
804 i = ttyflush(1);
805 if (i == -2) {
806 /* This will not return. */
807 fatal_tty_error("write");
808 }
809 }
810
811 /*
812 * Something to read from the network...
813 */
814 if (FD_ISSET(net, &ibits)) {
815 int canread;
816
817 FD_CLR(net, &ibits);
818 canread = ring_empty_consecutive(&netiring);
819 c = recv(net, netiring.supply, canread, 0);
820 if (c < 0 && errno == EWOULDBLOCK) {
821 c = 0;
822 } else if (c <= 0) {
823 return (-1);
824 }
825 if (netdata) {
826 Dump('<', netiring.supply, c);
827 }
828 if (c)
829 ring_supplied(&netiring, c);
830 returnValue = 1;
831 }
832
833 /*
834 * Something to read from the tty...
835 */
836 if (FD_ISSET(tin, &ibits)) {
837 FD_CLR(tin, &ibits);
838 c = TerminalRead((char *)ttyiring.supply,
839 ring_empty_consecutive(&ttyiring));
840 if (c < 0) {
841 if (errno != EWOULDBLOCK) {
842 /* This will not return. */
843 fatal_tty_error("read");
844 }
845 c = 0;
846 } else {
847 /* EOF detection for line mode!!!! */
848 if ((c == 0) && MODE_LOCAL_CHARS(globalmode) &&
849 isatty(tin)) {
850 /* must be an EOF... */
851 eof_pending = 1;
852 return (1);
853 }
854 if (c <= 0) {
855 returnValue = -1;
856 goto next;
857 }
858 if (termdata) {
859 Dump('<', ttyiring.supply, c);
860 }
861 ring_supplied(&ttyiring, c);
862 }
863 returnValue = 1; /* did something useful */
864 }
865
866 next:
867 if (FD_ISSET(net, &obits)) {
868 FD_CLR(net, &obits);
869 returnValue |= netflush();
870 }
871 if (FD_ISSET(tout, &obits)) {
872 FD_CLR(tout, &obits);
873 i = ttyflush(SYNCHing|flushout);
874 if (i == -2) {
875 /* This will not return. */
876 fatal_tty_error("write");
877 }
878 returnValue |= (i > 0);
879 }
880
881 return (returnValue);
882 }
883