2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 1988, 1990, 1993
8 * The Regents of the University of California. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
41 static char sccsid
[] = "@(#)sys_bsd.c 8.1 (Berkeley) 6/6/93";
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.
51 #include <sys/types.h>
53 #include <sys/socket.h>
57 #include <arpa/telnet.h>
65 #define SIG_FUNC_RET void
67 int tout
; /* Output file descriptor */
68 static int tin
; /* Input file descriptor */
73 struct tchars otc
= { 0 }, ntc
= { 0 };
74 struct ltchars oltc
= { 0 }, nltc
= { 0 };
75 struct sgttyb ottyb
= { 0 }, nttyb
= { 0 };
77 #define cfgetispeed(ptr) (ptr)->sg_ispeed
78 #define cfgetospeed(ptr) (ptr)->sg_ospeed
81 #else /* USE_TERMIO */
82 static struct termio old_tc
= { 0 };
83 extern struct termio new_tc
;
84 #endif /* USE_TERMIO */
86 static fd_set ibits
, obits
, xbits
;
88 static SIG_FUNC_RET
susp(int);
89 void fatal_tty_error(char *doing_what
);
95 tout
= fileno(stdout
);
106 TerminalWrite(buf
, n
)
110 return (write(tout
, buf
, n
));
118 return (read(tin
, buf
, n
));
121 #ifdef KLUDGELINEMODE
122 extern int kludgelinemode
;
125 * TerminalSpecialChars()
127 * Look at an input character to see if it is a special character
128 * and decide what to do.
132 * 0 Don't add this character.
133 * 1 Do add this character
136 TerminalSpecialChars(c
)
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
144 if (c
== termQuitChar
) {
145 #ifdef KLUDGELINEMODE
146 if (kludgelinemode
) {
147 if (sendbrk() == -1) {
148 /* This won't return. */
149 fatal_tty_error("write");
154 } else if (c
== termFlushChar
) {
155 /* Transmit Abort Output */
156 if (xmitAO() == -1) {
157 /* This won't return. */
158 fatal_tty_error("write");
161 } else if (!MODE_LOCAL_CHARS(globalmode
)) {
162 if (c
== termKillChar
) {
165 } else if (c
== termEraseChar
) {
166 xmitEC(); /* Transmit Erase Character */
175 * Flush output to the terminal
179 TerminalFlushOutput()
181 if (isatty(fileno(stdout
))) {
182 (void) ioctl(fileno(stdout
), TIOCFLUSH
, NULL
);
190 (void) ioctl(0, TIOCGETP
, &ottyb
);
191 (void) ioctl(0, TIOCGETC
, &otc
);
192 (void) ioctl(0, TIOCGLTC
, &oltc
);
193 (void) ioctl(0, TIOCLGET
, &olmode
);
199 #else /* USE_TERMIO */
200 (void) tcgetattr(0, &old_tc
);
203 termAytChar
= CONTROL('T');
204 #endif /* USE_TERMIO */
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
);
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
);
238 TerminalDefaultChars()
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 */
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
259 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
263 * local signal mapping
267 * Both Linemode and Single Character mode:
270 * local/no signal mapping
278 static int prevmode
= -2; /* guaranteed unique */
284 #else /* USE_TERMIO */
285 struct termio tmp_tc
;
286 #endif /* USE_TERMIO */
292 globalmode
= f
&~MODE_FORCE
;
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.
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).
313 old
= ttyflush(SYNCHing
|flushout
);
314 if (old
== -1 || old
> 1) {
316 (void) tcgetattr(tin
, &tmp_tc
);
317 #endif /* USE_TERMIO */
320 * Wait for data to drain, then flush again.
323 (void) tcsetattr(tin
, TCSADRAIN
, &tmp_tc
);
324 #endif /* USE_TERMIO */
325 old
= ttyflush(SYNCHing
|flushout
);
326 } while (old
== -1 || old
> 1);
330 prevmode
= f
&~MODE_FORCE
;
344 tmp_tc
.c_lflag
|= ECHO
;
345 tmp_tc
.c_oflag
|= ONLCR
;
347 tmp_tc
.c_iflag
|= ICRNL
;
351 sb
.sg_flags
&= ~ECHO
;
353 tmp_tc
.c_lflag
&= ~ECHO
;
354 tmp_tc
.c_oflag
&= ~ONLCR
;
357 tmp_tc
.c_iflag
&= ~ICRNL
;
362 if ((f
&MODE_FLOW
) == 0) {
364 tc
.t_startc
= _POSIX_VDISABLE
;
365 tc
.t_stopc
= _POSIX_VDISABLE
;
367 tmp_tc
.c_iflag
&= ~(IXOFF
|IXON
); /* Leave the IXANY bit alone */
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
;
375 tmp_tc
.c_iflag
|= IXOFF
|IXON
;
376 tmp_tc
.c_iflag
&= ~IXANY
;
381 if ((f
&MODE_TRAPSIG
) == 0) {
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
;
389 tmp_tc
.c_lflag
&= ~ISIG
;
394 tmp_tc
.c_lflag
|= ISIG
;
401 sb
.sg_flags
&= ~CBREAK
;
402 sb
.sg_flags
|= CRMOD
;
404 tmp_tc
.c_lflag
|= ICANON
;
408 sb
.sg_flags
|= CBREAK
;
410 sb
.sg_flags
|= CRMOD
;
412 sb
.sg_flags
&= ~CRMOD
;
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;
421 if ((f
&(MODE_EDIT
|MODE_TRAPSIG
)) == 0) {
423 ltc
.t_lnextc
= _POSIX_VDISABLE
;
425 tmp_tc
.c_cc
[VLNEXT
] = (cc_t
)(_POSIX_VDISABLE
);
429 if (f
&MODE_SOFT_TAB
) {
431 sb
.sg_flags
|= XTABS
;
433 tmp_tc
.c_oflag
&= ~TABDLY
;
434 tmp_tc
.c_oflag
|= TAB3
;
438 sb
.sg_flags
&= ~XTABS
;
440 tmp_tc
.c_oflag
&= ~TABDLY
;
444 if (f
&MODE_LIT_ECHO
) {
448 tmp_tc
.c_lflag
&= ~ECHOCTL
;
454 tmp_tc
.c_lflag
|= ECHOCTL
;
467 if (f
& MODE_OUTBIN
) {
468 tmp_tc
.c_cflag
&= ~(CSIZE
|PARENB
);
469 tmp_tc
.c_cflag
|= CS8
;
470 tmp_tc
.c_oflag
&= ~OPOST
;
472 tmp_tc
.c_cflag
&= ~(CSIZE
|PARENB
);
473 tmp_tc
.c_cflag
|= old_tc
.c_cflag
& (CSIZE
|PARENB
);
474 tmp_tc
.c_oflag
|= OPOST
;
482 (void) signal(SIGTSTP
, susp
);
484 #if defined(USE_TERMIO) && defined(NOKERNINFO)
485 tmp_tc
.c_lflag
|= NOKERNINFO
;
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.
494 ltc
.t_dsuspc
= _POSIX_VDISABLE
;
496 tmp_tc
.c_cc
[VDSUSP
] = (cc_t
)(_POSIX_VDISABLE
);
500 * If the VEOL character is already set, then use VEOL2,
501 * otherwise use VEOL.
503 esc
= (rlogin
!= _POSIX_VDISABLE
) ? rlogin
: escape
;
504 if ((tmp_tc
.c_cc
[VEOL
] != esc
)
506 (tmp_tc
.c_cc
[VEOL2
] != esc
)
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
;
514 if (tc
.t_brkc
== (cc_t
)(_POSIX_VDISABLE
))
518 (void) signal(SIGTSTP
, SIG_DFL
);
519 (void) sigemptyset(&nset
);
520 (void) sigaddset(&nset
, SIGTSTP
);
521 (void) sigprocmask(SIG_UNBLOCK
, &nset
, 0);
533 (void) ioctl(tin
, TIOCLSET
, &lmode
);
534 (void) ioctl(tin
, TIOCSLTC
, <c
);
535 (void) ioctl(tin
, TIOCSETC
, &tc
);
536 (void) ioctl(tin
, TIOCSETN
, &sb
);
538 if (tcsetattr(tin
, TCSADRAIN
, &tmp_tc
) < 0)
539 (void) tcsetattr(tin
, TCSANOW
, &tmp_tc
);
541 (void) ioctl(tin
, FIONBIO
, &onoff
);
542 (void) ioctl(tout
, FIONBIO
, &onoff
);
548 * This code assumes that the values B0, B50, B75...
549 * are in ascending order. They do not have to be
552 static struct 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
},
568 TerminalSpeeds(ispeed
, ospeed
)
572 register struct termspeeds
*tp
;
573 register int in
, out
;
575 out
= cfgetospeed(&old_tc
);
576 in
= cfgetispeed(&old_tc
);
581 while ((tp
->speed
!= -1) && (tp
->value
< in
)) {
585 tp
--; /* back up to fastest defined speed */
589 while ((tp
->speed
!= -1) && (tp
->value
< out
)) {
598 TerminalWindowSize(rows
, cols
)
599 unsigned short *rows
, *cols
;
603 if (ioctl(fileno(stdin
), TIOCGWINSZ
, &ws
) >= 0) {
612 NetNonblockingIO(fd
, onoff
)
616 (void) ioctl(fd
, FIONBIO
, &onoff
);
620 * Various signal handling routines.
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.
633 (void) signal(SIGPIPE
, SIG_IGN
);
636 longjmp(peerdied
, -1);
639 boolean_t intr_happened
= B_FALSE
;
640 boolean_t intr_waiting
= B_FALSE
;
651 (void) signal(SIGINT
, intr
);
657 longjmp(toplevel
, -1);
665 (void) signal(SIGQUIT
, intr2
);
668 * Ignore return to the next two function calls
669 * since we're doing SIGQUIT
671 #ifdef KLUDGELINEMODE
672 if (kludgelinemode
) {
687 (void) signal(SIGTSTP
, susp
);
688 if ((rlogin
!= _POSIX_VDISABLE
) && rlogin_susp())
699 (void) signal(SIGWINCH
, sendwin
);
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
);
716 NetNonblockingIO(net
, 1);
718 if (SetSockOpt(net
, SOL_SOCKET
, SO_OOBINLINE
, 1) == -1) {
719 perror("SetSockOpt");
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.
731 fatal_tty_error(char *doing_what
)
734 (void) fprintf(stderr
, "Error processing %s: %s\n", doing_what
,
743 * This routine tries to fill up/empty our various rings.
745 * The parameter specifies whether this is a poll operation,
746 * or a block-until-something-happens operation.
748 * The return value is 1 if something happened, 0 if not.
752 process_rings(netin
, netout
, netex
, ttyin
, ttyout
, poll
)
753 int poll
; /* If 0, then block until something to do */
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).
763 static struct timeval TimeValue
= { 0 };
770 FD_SET(tout
, &obits
);
781 if ((c
= select(16, &ibits
, &obits
, &xbits
,
782 (poll
== 0) ? NULL
: &TimeValue
)) < 0) {
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.
789 if (errno
== EINTR
) {
792 /* I don't like this, does it ever happen? */
793 (void) printf("sleep(5) from telnet, after select\r\n");
802 if (FD_ISSET(net
, &xbits
)) {
806 /* flush any data that is already enqueued */
809 /* This will not return. */
810 fatal_tty_error("write");
815 * Something to read from the network...
817 if (FD_ISSET(net
, &ibits
)) {
821 canread
= ring_empty_consecutive(&netiring
);
822 c
= recv(net
, netiring
.supply
, canread
, 0);
823 if (c
< 0 && errno
== EWOULDBLOCK
) {
829 Dump('<', netiring
.supply
, c
);
832 ring_supplied(&netiring
, c
);
837 * Something to read from the tty...
839 if (FD_ISSET(tin
, &ibits
)) {
841 c
= TerminalRead((char *)ttyiring
.supply
,
842 ring_empty_consecutive(&ttyiring
));
844 if (errno
!= EWOULDBLOCK
) {
845 /* This will not return. */
846 fatal_tty_error("read");
850 /* EOF detection for line mode!!!! */
851 if ((c
== 0) && MODE_LOCAL_CHARS(globalmode
) &&
853 /* must be an EOF... */
862 Dump('<', ttyiring
.supply
, c
);
864 ring_supplied(&ttyiring
, c
);
866 returnValue
= 1; /* did something useful */
870 if (FD_ISSET(net
, &obits
)) {
872 returnValue
|= netflush();
874 if (FD_ISSET(tout
, &obits
)) {
875 FD_CLR(tout
, &obits
);
876 i
= ttyflush(SYNCHing
|flushout
);
878 /* This will not return. */
879 fatal_tty_error("write");
881 returnValue
|= (i
> 0);
884 return (returnValue
);