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