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