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