home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume4
/
rlogin
< prev
next >
Wrap
Text File
|
1986-11-30
|
40KB
|
1,557 lines
Subject: 4.2bsd rlogin enhancements
Newsgroups: mod.sources
Approved: jpn@panda.UUCP
Mod.sources: Volume 4, Issue 52
Submitted by: genrad!decvax!philabs!nyit!rick
---CUT HERE---CUT HERE---CUT HERE---CUT HERE---CUT HERE--CUT HERE--
echo shar: extracting README
cat - << \SHAR_EOF > README
NYIT rlogin performance enhancements 01-Apr-86
INTRODUCTION
This package contains a set of source code modifications to
4.2bsd UNIX to enhance the performance of rlogin connections.
Performance improvement results from reducing the involvement
of the agent processes (rlogin and rlogind) in the task of
passing characters between the client and server hosts.
In this implementation, the agent processes retain their
previous function of establishing an rlogin-style connection
between two hosts; however, once the connection is established,
the agents sleep until the connection is interrrupted by an
escape character on the client host, or terminated by either host.
The character-switching functions formerly performed by rlogin
and rlogind are now handled entirely within kernel interrupt
logic, eliminating the delays and scheduling overhead of the
original implementation and improving response and throughput.
It is important to note that, although the character traffic
is now being handled exclusively in the kernel, the rlogin
protocol has been maintained. This ensures that an enhanced
client can interoperate with a vanilla 4.2bsd server, and
vice versa, still gaining an improvement in performance.
The implementation is separated into two logical parts: client
and server. The client part is called the NVT, an acronym for
Network Virtual Terminal; the server is called the NVS, meaning
Network Virtual Server. Within the kernel, NVT logic appears
within a "#ifdef KNVT" conditional, and NVS logic appears
within a "#ifdef KNVS" conditional. All user-mode NVT logic
resides in /usr/ucb/rlogin. All user-mode NVS logic resides
in /etc/rlogind.
AFFECTED SOFTWARE
The following executables are affected:
1. The 4.2bsd kernel
2. /usr/ucb/rlogin
3. /etc/rlogind
The vanilla and enhanced versions of any of these programs can be
used in any combination with no risk. The NVT and NVS logic
in the kernel remains dormant unless invoked by an enhanced
rlogin or rlogind; the enhanced kernel support the vanilla
rlogin/rlogind as well as their new counterparts. The enhanced
rlogin and rlogind determine if the kernel offers the enhanced
NVT or NVS service, and, if not, they will operate in vanilla
4.2bsd rlogin mode.
BUGS
The user interface of rlogin is slightly different with regard
to the operation of the escape character. This is not an
unavoidable consequence of this implementation, but rather an
issue of expediency made during development; it can be fixed.
The implementation within the kernel is practical, but not
elegant. I grovel in advance for the indulgence of the purists.
[Remember: you didn't *pay money* to buy this :-)]
No explicit aid is offered for telnet connections; however,
inspection of this implementation might inspire those who
use telnet to improve its performance in a similar fashion.
CONTENTS OF THIS DISTRIBUTION
[Explanations of changes appear in brackets]
README This file
diff_files diff -c of kernel conf/files
[add two new kernel source files: tty_nv[st].c]
diff_ioctl.h diff -c of kernel h/ioctl.h
[add ioctl defs SIOCJNVS and SIOCJNVT]
diff_rlogin.c diff -c of source for /usr/ucb/rlogin
[invoke SIOCJNVT ioctl to join socket and tty]
diff_rlogind.c diff -c of source for /etc/rlogind
[invoke SIOCJNVS ioctl to join socket and pty]
diff_socketvar.h diff -c of kernel h/socketvar.h
[add defs SB_NVS and SB_NVT]
diff_tcp_usrreq.c diff -c of kernel netinet/tcp_usrreq.c
[add code to handle SIOCJNVS and SIOCJNVT ioctls]
diff_tty.c diff -c of kernel sys/tty.c
[add hook in ttyinput() to intercept NVT characters]
diff_tty.h diff -c of kernel h/tty.h
[add def TS_NVT]
diff_tty_pty.c diff -c of kernel sys/tty_pty.c
[add subroutines driven off pty data structures]
diff_tty_subr.c diff -c of kernel sys/tty_subr.c
[remove #ifdef notdef surrounding q_to_b]
diff_uipc_socket2.c diff -c of kernel sys/uipc_socket2.c
[add hooks in sbwakeup() to intercept NVS/NVT traffic]
tty_nvs.c New kernel source file sys/tty_nvs.c
[most of the logic to implement NVS service]
tty_nvt.c New kernel source file sys/tty_nvt.c
[most of the logic to implement NVT service]
INSTALLATION
1. Copy tty_nvs.c and tty_nvt.c into /sys/sys.
2. Locate files whose names begin with "diff_". These files
represent Berkeley 4.2bsd source modules that must be modified.
Apply the changes in each "diff_" file to their respective
4.2bsd source modules.
3. cd to /sys/conf and add the following two lines to your
kernel configuration file:
options NKVS
options KNVT
4. Run /etc/config to regenerate the kernel configuration files.
5. cd to the kernel directory and run "make" to build a new kernel.
6. Install the new kernel in /.
7. Recompile and install /usr/ucb/rlogin (must be setuid-root).
8. Recompile and install /etc/rlogind.
9. Reboot and enjoy more responsive rlogin connections.
Please address comments, questions, bugfixes (please, no flames
about hooks in ttyinput() or sbwakeup()) to the author:
Rick Ace
New York Institute of Technology
Computer Graphics Laboratory
Wheatley Road
Old Westbury, NY 11568
(516) 686-7644
USENET: {decvax,seismo}!philabs!nyit!rick
SHAR_EOF
echo shar: extracting diff_files
cat - << \SHAR_EOF > diff_files
*** conf/files420 Sun Jun 12 18:45:11 1983
--- conf/files Tue Apr 1 07:20:48 1986
***************
*** 102,104
sys/vm_swap.c standard
sys/vm_swp.c standard
sys/vm_text.c standard
--- 102,106 -----
sys/vm_swap.c standard
sys/vm_swp.c standard
sys/vm_text.c standard
+ sys/tty_nvs.c standard
+ sys/tty_nvt.c standard
SHAR_EOF
echo shar: extracting diff_ioctl.h
cat - << \SHAR_EOF > diff_ioctl.h
*** h/ioctl.h420 Sat Aug 20 19:04:34 1983
--- h/ioctl.h Tue Apr 1 07:27:50 1986
***************
*** 194,199
#define SIOCATMARK _IOR(s, 7, int) /* at oob mark? */
#define SIOCSPGRP _IOW(s, 8, int) /* set process group */
#define SIOCGPGRP _IOR(s, 9, int) /* get process group */
#define SIOCADDRT _IOW(r, 10, struct rtentry) /* add route */
#define SIOCDELRT _IOW(r, 11, struct rtentry) /* delete route */
--- 194,201 -----
#define SIOCATMARK _IOR(s, 7, int) /* at oob mark? */
#define SIOCSPGRP _IOW(s, 8, int) /* set process group */
#define SIOCGPGRP _IOR(s, 9, int) /* get process group */
+ #define SIOCJNVT _IOW(s, 70, int) /* join NVT tty&socket */
+ #define SIOCJNVS _IOW(s, 71, int) /* join NVS pty&socket */
#define SIOCADDRT _IOW(r, 10, struct rtentry) /* add route */
#define SIOCDELRT _IOW(r, 11, struct rtentry) /* delete route */
SHAR_EOF
echo shar: extracting diff_rlogin.c
cat - << \SHAR_EOF > diff_rlogin.c
*** 4.2rlogin.c Tue Apr 1 12:12:32 1986
--- rlogin.c Tue Apr 1 11:17:44 1986
***************
*** 144,149
signal(SIGINT, exit);
signal(SIGHUP, exit);
signal(SIGQUIT, exit);
child = fork();
if (child == -1) {
perror("rlogin: fork");
--- 144,150 -----
signal(SIGINT, exit);
signal(SIGHUP, exit);
signal(SIGQUIT, exit);
+ knvt(); /* returns iff no kernel NVT service */
child = fork();
if (child == -1) {
perror("rlogin: fork");
***************
*** 376,380
{
signal(SIGPIPE, SIG_IGN);
prf("\007Connection closed.");
done();
}
--- 377,429 -----
{
signal(SIGPIPE, SIG_IGN);
prf("\007Connection closed.");
+ done();
+ }
+
+ nvtsig()
+ {
+ signal(SIGINT, nvtsig);
+ }
+
+ /*
+ * Invoke kernel NVT service
+ *
+ * Returns iff kernel does not support NVT service (i.e., do the
+ * job the old-fashioned way)
+ */
+ knvt()
+ {
+ char cmdc;
+ static int ttyfd = 0;
+
+ signal(SIGINT, nvtsig);
+ notc.t_intrc = cmdchar;
+ mode(1);
+ while (ioctl(rem, SIOCJNVT, &ttyfd) < 0) {
+ if (errno != EINTR) {
+ /*
+ * Unexpected error, assume the kernel does not
+ * honor the ioctl call and return to doit().
+ */
+ notc.t_intrc = -1;
+ return;
+ }
+ /*
+ * The user typed the escape character. Read the next
+ * character from the terminal to see what I should do.
+ */
+ if (read(0, &cmdc, 1) != 1)
+ cmdc = deftc.t_eofc;
+ if (cmdc == '.' || cmdc == deftc.t_eofc)
+ break;
+ if (cmdc == defltc.t_suspc ||
+ cmdc == defltc.t_dsuspc) {
+ write(0, CRLF, sizeof(CRLF));
+ mode(0);
+ kill(getpid(), SIGTSTP);
+ mode(1);
+ }
+ }
+ prf("\r\nConnection closed");
done();
}
SHAR_EOF
echo shar: extracting diff_rlogind.c
cat - << \SHAR_EOF > diff_rlogind.c
*** 4.2rlogind.c Tue Apr 1 12:12:50 1986
--- rlogind.c Tue Apr 1 09:32:50 1986
***************
*** 200,205
ioctl(p, TIOCPKT, &on);
signal(SIGTSTP, SIG_IGN);
signal(SIGCHLD, cleanup);
for (;;) {
int ibits = 0, obits = 0;
--- 200,219 -----
ioctl(p, TIOCPKT, &on);
signal(SIGTSTP, SIG_IGN);
signal(SIGCHLD, cleanup);
+ /* BEGIN NVS support */
+ /*
+ * If kernel supports high-performance NVS operation,
+ * invoke it and sleep until connection is broken.
+ * If remote end dies: ioctl() returns 0.
+ * If local job exits: ioctl() returns -1 / EINTR.
+ * Any other return from ioctl() is interpreted to mean
+ * the kernel doesn't support high-performance NVS
+ * operation, so do the job the standard Berkeley way.
+ */
+ if (ioctl(f, SIOCJNVS, (char *)&p) == 0 ||
+ errno == EINTR)
+ cleanup();
+ /* END NVS support */
for (;;) {
int ibits = 0, obits = 0;
***************
*** 292,297
rmut();
vhangup(); /* XXX */
shutdown(netf, 2);
kill(0, SIGKILL);
exit(1);
--- 306,313 -----
rmut();
vhangup(); /* XXX */
+ #ifdef notdef
+ /* NYIT remove bogus statement (netf is never set!) */
shutdown(netf, 2);
#endif
kill(0, SIGKILL);
***************
*** 293,298
rmut();
vhangup(); /* XXX */
shutdown(netf, 2);
kill(0, SIGKILL);
exit(1);
}
--- 309,315 -----
#ifdef notdef
/* NYIT remove bogus statement (netf is never set!) */
shutdown(netf, 2);
+ #endif
kill(0, SIGKILL);
exit(1);
}
SHAR_EOF
echo shar: extracting diff_socketvar.h
cat - << \SHAR_EOF > diff_socketvar.h
*** h/socketvar.h420 Fri Jul 29 09:49:20 1983
--- h/socketvar.h Tue Apr 1 07:24:02 1986
***************
*** 49,54
#define SB_WAIT 0x04 /* someone is waiting for data/space */
#define SB_SEL 0x08 /* buffer is selected */
#define SB_COLL 0x10 /* collision selecting */
short so_timeo; /* connection timeout */
u_short so_error; /* error affecting connection */
short so_oobmark; /* chars to oob mark */
--- 49,56 -----
#define SB_WAIT 0x04 /* someone is waiting for data/space */
#define SB_SEL 0x08 /* buffer is selected */
#define SB_COLL 0x10 /* collision selecting */
+ #define SB_NVT 0x20 /* socket crossbared to NVT tty */
+ #define SB_NVS 0x40 /* socket crossbared to NVS tty/pty */
short so_timeo; /* connection timeout */
u_short so_error; /* error affecting connection */
short so_oobmark; /* chars to oob mark */
SHAR_EOF
echo shar: extracting diff_tcp_usrreq.c
cat - << \SHAR_EOF > diff_tcp_usrreq.c
*** netinet/tcp_usrreq.c420 Fri Jul 29 10:14:49 1983
--- netinet/tcp_usrreq.c Tue Apr 1 07:32:53 1986
***************
*** 24,29
#include "../netinet/tcpip.h"
#include "../netinet/tcp_debug.h"
/*
* TCP protocol interface to socket abstraction.
*/
--- 24,33 -----
#include "../netinet/tcpip.h"
#include "../netinet/tcp_debug.h"
+ #if defined(KNVS) || defined(KNVT)
+ #include "../h/ioctl.h"
+ #endif
+
/*
* TCP protocol interface to socket abstraction.
*/
***************
*** 233,238
/* SOME AS YET UNIMPLEMENTED HOOKS */
case PRU_CONTROL:
error = EOPNOTSUPP;
break;
--- 237,260 -----
/* SOME AS YET UNIMPLEMENTED HOOKS */
case PRU_CONTROL:
+ #ifdef KNVS
+ if ((int)m == SIOCJNVS) {
+ if (tp->t_state == TCPS_ESTABLISHED)
+ error = nvs_ioc_join(so, *(int *)nam);
+ else
+ error = ENOTCONN;
+ break;
+ }
+ #endif
+ #ifdef KNVT
+ if ((int)m == SIOCJNVT) {
+ if (tp->t_state == TCPS_ESTABLISHED)
+ error = nvt_ioc_join(so, *(int *)nam);
+ else
+ error = ENOTCONN;
+ break;
+ }
+ #endif
error = EOPNOTSUPP;
break;
SHAR_EOF
echo shar: extracting diff_tty.c
cat - << \SHAR_EOF > diff_tty.c
*** sys/tty.c420 Sun Oct 2 02:06:25 1983
--- sys/tty.c Tue Apr 1 08:04:59 1986
***************
*** 826,831
}
endcase:
/*
* If DEC-style start/stop is enabled don't restart
* output until seeing the start character.
--- 826,838 -----
}
endcase:
+ #ifdef KNVT
+ /*
+ * If this tty is operating as an NVT, pass character to remote host
+ */
+ if (tp->t_state & TS_NVT)
+ nvt_output(tp);
+ #endif KNVT
/*
* If DEC-style start/stop is enabled don't restart
* output until seeing the start character.
SHAR_EOF
echo shar: extracting diff_tty.h
cat - << \SHAR_EOF > diff_tty.h
*** h/tty.h420 Thu Aug 4 23:58:20 1983
--- h/tty.h Tue Apr 1 08:02:28 1986
***************
*** 117,122
#define TS_LNCH 0x080000 /* next character is literal */
#define TS_TYPEN 0x100000 /* retyping suspended input (PENDIN) */
#define TS_CNTTB 0x200000 /* counting tab width; leave FLUSHO alone */
#define TS_LOCAL (TS_BKSL|TS_QUOT|TS_ERASE|TS_LNCH|TS_TYPEN|TS_CNTTB)
--- 117,123 -----
#define TS_LNCH 0x080000 /* next character is literal */
#define TS_TYPEN 0x100000 /* retyping suspended input (PENDIN) */
#define TS_CNTTB 0x200000 /* counting tab width; leave FLUSHO alone */
+ #define TS_NVT 0x400000 /* NVT tty is bound to a socket */
#define TS_LOCAL (TS_BKSL|TS_QUOT|TS_ERASE|TS_LNCH|TS_TYPEN|TS_CNTTB)
SHAR_EOF
echo shar: extracting diff_tty_pty.c
cat - << \SHAR_EOF > diff_tty_pty.c
*** sys/tty_pty.c420 Sun Oct 2 02:06:25 1983
--- sys/tty_pty.c Tue Apr 1 07:55:36 1986
***************
*** 24,29
#define NPTY 32 /* crude XXX */
#endif
#define BUFSIZ 100 /* Chunk size iomoved from user */
/*
--- 24,34 -----
#define NPTY 32 /* crude XXX */
#endif
+ #ifdef KNVS
+ #include "../h/socketvar.h"
+ struct socket *ptynvsso[NPTY]; /* socket indexed by pty minor dev# */
+ #endif
+
#define BUFSIZ 100 /* Chunk size iomoved from user */
/*
***************
*** 78,83
tp = &pt_tty[minor(dev)];
(*linesw[tp->t_line].l_close)(tp);
ttyclose(tp);
}
ptsread(dev, uio)
--- 83,89 -----
tp = &pt_tty[minor(dev)];
(*linesw[tp->t_line].l_close)(tp);
ttyclose(tp);
+ ptcwakeup(tp); /* wake master */
}
ptsread(dev, uio)
***************
*** 439,445
tp->t_startc == ('q'&037));
if (pti->pt_flags & PF_NOSTOP) {
if (stop) {
! pti->pt_send &= TIOCPKT_NOSTOP;
pti->pt_send |= TIOCPKT_DOSTOP;
pti->pt_flags &= ~PF_NOSTOP;
ptcwakeup(tp);
--- 445,451 -----
tp->t_startc == ('q'&037));
if (pti->pt_flags & PF_NOSTOP) {
if (stop) {
! pti->pt_send &= ~TIOCPKT_NOSTOP;
pti->pt_send |= TIOCPKT_DOSTOP;
pti->pt_flags &= ~PF_NOSTOP;
ptcwakeup(tp);
***************
*** 455,458
}
return (error);
}
#endif
--- 461,511 -----
}
return (error);
}
+
+ #ifdef KNVS
+
+ /*
+ * Transfer characters from NVS tty outq to associated socket
+ * (Simply a jacket because timeout() accepts only 1 argument).
+ *
+ * Called at or below network IPL
+ */
+ ptsnvsnet(tp)
+ struct tty *tp;
+ {
+ nvs_output(tp, &pt_ioctl[minor(tp->t_dev)].pt_send);
+ }
+
+ /*
+ * Alternate t_oproc routine used when the pty is operating as an NVS
+ */
+ ptsnvsstart(tp)
+ register struct tty *tp;
+ {
+ register int s;
+
+ s = spl5();
+ /*
+ * TS_BUSY set means Ptsnvsnet() is either running or queued to run
+ */
+ if ((tp->t_state & TS_BUSY) == 0) {
+ tp->t_state |= TS_BUSY;
+ #ifdef vax
+ /*
+ * If at low IPL, can make output happen now;
+ * otherwise must sequence it through softclock
+ */
+ if (s == 0) {
+ (void) spl0(); /* reduce IPL */
+ nvs_output(tp, &pt_ioctl[minor(tp->t_dev)].pt_send);
+ }
+ else
+ #endif vax
+ timeout(ptsnvsnet, (caddr_t)tp, 0);
+ }
+ splx(s);
+ }
+
+ #endif KNVS
+
#endif
SHAR_EOF
echo shar: extracting diff_tty_subr.c
cat - << \SHAR_EOF > diff_tty_subr.c
*** sys/tty_subr.c420 Fri Jul 29 10:07:23 1983
--- sys/tty_subr.c Tue Apr 1 09:04:49 1986
***************
*** 54,60
return(c);
}
- #ifdef notdef
/*
* copy clist to buffer.
* return number of bytes moved.
--- 54,59 -----
return(c);
}
/*
* copy clist to buffer.
* return number of bytes moved.
***************
*** 110,116
splx(s);
return(cp-acp);
}
- #endif
/*
* Return count of contiguous characters
--- 109,114 -----
splx(s);
return(cp-acp);
}
/*
* Return count of contiguous characters
SHAR_EOF
echo shar: extracting diff_uipc_socket2.c
cat - << \SHAR_EOF > diff_uipc_socket2.c
*** sys/uipc_socket2.c420 Fri Jul 29 10:07:27 1983
--- sys/uipc_socket2.c Tue Apr 1 07:59:50 1986
***************
*** 243,248
register struct sockbuf *sb;
{
if (sb->sb_sel) {
selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL);
sb->sb_sel = 0;
--- 243,260 -----
register struct sockbuf *sb;
{
+ #ifdef KNVS
+ if (sb->sb_flags & SB_NVS) {
+ nvs_input(sb);
+ return;
+ }
+ #endif KNVS
+ #ifdef KNVT
+ if (sb->sb_flags & SB_NVT) {
+ nvt_input(sb);
+ return;
+ }
+ #endif KNVT
if (sb->sb_sel) {
selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL);
sb->sb_sel = 0;
SHAR_EOF
echo shar: extracting tty_nvs.c
cat - << \SHAR_EOF > tty_nvs.c
/*
* Network virtual terminals via sockets - server end
*
* Rick Ace
* New York Institute of Technology
* Computer Graphics Laboratory
* Old Westbury, New York 11568
*/
/*
* The code in this module supports the NVS, or remote end of the connection
* (i.e., the link between the network and the pseudo-terminal).
* The purpose of this code is to emulate efficiently the character-
* shuffling functions performed by /etc/rlogind. The rlogin on the other
* host will believe it is talking to rlogind, when it is in reality
* talking to the NVS kernel software herein.
*
* The NVS kernel software achieves performance improvements by handling
* incoming character traffic at interrupt level, eliminating the overhead
* and delays resulting from scheduling a user-mode process (rlogind).
* Outgoing character traffic is dumped directly into the socket by
* Ptsnvsstart() in tty_pty.c, further eliminating the need for service
* by a user-mode process.
*
* The implementation is broken into two main layers:
* 1) high-level software, common to all NVSs (nvs_XXX subrs)
* 2) protocol-specific stuff (tcp_XXX, etc.)
* Presently, there is only a TCP implementation for layer # 2.
*/
#ifdef KNVS
#include "../h/param.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h" /* for lint */
#include "../h/file.h"
#include "../h/tty.h"
#include "../h/mbuf.h"
#include "../h/protosw.h"
#include "../h/socketvar.h"
#ifdef NFS
#include "../h/vnode.h"
#include "../ufs/inode.h"
#else NFS
#include "../h/inode.h"
#endif NFS
#define nvs_emsg nvt_emsg
#define MAXNVS 16 /* should be in a parameter file */
/*
* tp-to-socket correspondence table.
*
* This table is searched linearly. A highest-entry mark is maintained
* to keep search overhead low. If there is a need to support large
* numbers of NVSs, the linear search should be replaced by hashing.
*/
struct nvsj {
struct tty *nvs_tp; /* tty/pty context, or 0 if free */
struct socket *nvs_so; /* socket context */
} nvsj[MAXNVS + 1];
struct nvsj *nvshij = &nvsj[0]; /* highest active entry */
#ifndef lint
int nvsj_n = MAXNVS; /* for kernel debug utilities */
#endif
int nvsichz;
extern struct socket *ptynvsso[ /* NPTY */ ]; /* socket indexed by pty minor */
int ptsstart(), ptsnvsstart(), ptsnvsnet();
/*
* Mate a tty and a socket
*
* Returns UNIX error code
* Must be called at splimp
*/
nvs_add(tp, so, anvs)
struct tty *tp;
struct socket *so;
struct nvsj **anvs; /* return addr of NVS context here */
{
register struct nvsj *nvs, *nx;
extern int hz; /* XXX */
if (nvsichz == 0)
nvsichz = hz / 3; /* XXX */
if (tp->t_oproc != ptsstart)
return ENOTTY; /* not a pty or not in right mode */
nvs = 0;
nx = &nvsj[MAXNVS - 1];
do {
if (nx->nvs_tp) {
if (nx->nvs_tp == tp || nx->nvs_so == so)
return EBUSY; /* tty or socket already an NVS */
}
else
nvs = nx; /* remember lowest empty slot */
} while (--nx >= &nvsj[0]);
if (nvs == 0)
return ENFILE; /* all slots are in use */
/*
* All is clear, mate them
*/
if (nvs > nvshij)
nvshij = nvs; /* update highest active entry */
*anvs = nvs; /* pass context pointer to caller */
nvs->nvs_so = so;
nvs->nvs_tp = tp;
so->so_rcv.sb_flags |= SB_NVS;
tp->t_oproc = ptsnvsstart;
ptynvsso[minor(tp->t_dev)] = so;
sbwakeup(&so->so_rcv); /* get characters flowing */
ptsnvsstart(tp); /* ditto */
return 0;
}
/*
* Undo a tty/socket correspondence
*
* Must be called at splimp
*/
nvs_del(nvs)
register struct nvsj *nvs;
{
register struct tty *tp;
nvs->nvs_so->so_rcv.sb_flags &= ~SB_NVS;
tp = nvs->nvs_tp;
if (tp->t_oproc == ptsnvsstart)
tp->t_oproc = ptsstart;
ptynvsso[minor(tp->t_dev)] = 0;
/*
* Delete this entry and adjust Nvshij if necessary
*/
nvs->nvs_tp = 0; /* mark entry as free */
if (nvshij == nvs)
while (nvshij > &nvsj[0] && nvshij->nvs_tp == 0)
nvshij--;
}
/*
* Called from sbwakeup() when NVS has incoming characters from the net,
* to transfer those characters from the socket to the tty's input queue
*
* Logic here is similar to that of soreceive() in uipc_socket.c
*/
nvs_input(sb)
struct sockbuf *sb; /* so_rcv */
{
#define STRUCT_OFF(strnam, elem) \
((char *)&((struct strnam *)0)->elem - (char *)0)
register struct socket *so;
register struct nvsj *nvs;
register struct tty *tp;
register struct mbuf *m;
register unsigned char *cp;
register int n;
struct mbuf *mz;
/*
* Convert so_rcv address to socket address (a bit gross),
* then search the active-connection table for that socket
*/
so = (struct socket *)((char *)sb - STRUCT_OFF(socket, so_rcv));
nvs = &nvsj[0];
while (nvs->nvs_so != so || (tp = nvs->nvs_tp) == 0) {
if (++nvs > nvshij) {
nvs_emsg("nvs input no so %x\n", so);
return;
}
}
/*
* Have located the tty, now pass it the data
*/
so->so_state &= ~SS_RCVATMARK; /* ignore out-of-band data */
so->so_oobmark = 0; /* ditto */
/*
* Process each mbuf on the socket's rcv queue
*/
while (so->so_rcv.sb_cc > 0) {
m = so->so_rcv.sb_mb;
if (m == 0)
panic("nvs_input");
cp = mtod(m, unsigned char *);
for (n = m->m_len; --n >= 0; )
(*linesw[tp->t_line].l_rint)(*cp++, tp);
sbfree(&so->so_rcv, m);
MFREE(m, mz);
so->so_rcv.sb_mb = m = mz;
}
/*
* Notify protocol that more space is available in the socket
*/
if ((so->so_state & SS_CANTRCVMORE) == 0 &&
so->so_proto->pr_flags & PR_WANTRCVD &&
so->so_pcb)
(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
/*
* If socket closes at remote end first (not the most common case),
* wake up the agent process so it can exit.
*/
if (so->so_state & (SS_CANTRCVMORE | SS_CANTSENDMORE)) {
so->so_rcv.sb_flags &= ~SB_NVS;
wakeup((caddr_t)nvs);
}
}
/*
* Handle ioctl request on socket to join socket and pty, called
* from protocol ioctl logic. Protocol-specific validation is
* done before you get here.
*
* If the connection was successfully established, sleep and wait
* until it is broken at the remote end, or until a signal is
* received on the local end.
*
* Returns
* 0 = remote NVT closed the connection
* EINTR = interrupted by signal
* Anything else = an error establishing the connection
*/
nvs_ioc_join(so, ptyfd)
register struct socket *so;
int ptyfd; /* pty file descriptor */
{
register struct file *fp;
register struct inode *ip;
register struct tty *tp;
int error, s;
struct nvsj *nvsp;
int ptcopen();
/*
* Validate file descriptor and ensure it references a pty
*/
if ((unsigned)ptyfd >= NOFILE || (fp = u.u_ofile[ptyfd]) == 0)
return EBADF;
#ifdef NFS
{
register struct vnode *vp;
vp = (struct vnode *)fp->f_data;
if (fp->f_type != DTYPE_VNODE || vp->v_op != &ufs_vnodeops)
return ENOTTY;
ip = VTOI(vp);
if ((ip->i_mode & IFMT) != IFCHR ||
cdevsw[major(ip->i_rdev)].d_open != ptcopen)
return ENOTTY; /* really ENOTPTY :-) */
}
#else NFS
ip = (struct inode *)fp->f_data;
if (fp->f_type != DTYPE_INODE ||
(ip->i_mode & IFMT) != IFCHR ||
cdevsw[major(ip->i_rdev)].d_open != ptcopen)
return ENOTTY; /* really ENOTPTY :-) */
#endif NFS
/*
* Argument socket and pty are valid, now join them and wait
*/
tp = cdevsw[major(ip->i_rdev)].d_ttys;
s = splimp();
if (error = nvs_add(tp + minor(ip->i_rdev), so, &nvsp)) {
splx(s);
return error;
}
if (setjmp(&u.u_qsave)) {
/*
* The process received a signal
*/
nvs_del(nvsp); /* disassociate pty&socket */
splx(s);
return EINTR;
}
do sleep((caddr_t)nvsp, PZERO + 1); /* wait for signal or disconnect */
while (nvsp->nvs_so->so_rcv.sb_flags & SB_NVS);
/*
* The remote disconnected.
*/
nvs_del(nvsp); /* disassociate pty&socket */
splx(s);
return 0;
}
/*
* Move characters from pty outq to network
* TS_BUSY is assumed to be set upon entry
*
* Must be called at or below net IPL
*/
/*ARGSUSED*/
nvs_output(tp, urgentp)
register struct tty *tp;
int *urgentp; /* call by reference because I can zero it */
{
register struct mbuf *m;
register struct socket *so;
register int error, s, space;
s = splnet();
if ((so = ptynvsso[minor(tp->t_dev)]) == 0) { /* paranoid */
/*
* no longer an NVS!
*/
tp->t_state &= ~TS_BUSY;
if (tp->t_oproc)
(*tp->t_oproc)(tp);
goto rspl;
}
if (so->so_state & SS_CANTSENDMORE) {
while (getc(&tp->t_outq) >= 0)
;
*urgentp = 0;
}
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0)
goto out;
/*
* If there is urgent data to send, ship it now
*/
if (*urgentp) {
*mtod(m, unsigned char *) = *urgentp;
*urgentp = 0;
m->m_len = 1;
error = (*so->so_proto->pr_usrreq)(so,
PRU_SENDOOB, m, (struct mbuf *)0, (struct mbuf *)0);
if (error)
nvs_emsg("nvs SENDOOB %d\n", error);
goto out;
}
while (1) {
/*
* Send a chunk of character traffic that may be pending
*/
space = sbspace(&so->so_snd);
if (space > MLEN)
space = MLEN;
if ((m->m_len = q_to_b(&tp->t_outq, mtod(m, char *), space)) == 0) {
/*
* No outq traffic or socket is saturated
*/
(void) m_free(m);
goto out;
}
error = (*so->so_proto->pr_usrreq)(so,
PRU_SEND, m, (struct mbuf *)0, (struct mbuf *)0);
#ifdef lint
/* Same actuals as above, better information for lint */
error = tcp_usrreq(so,
PRU_SEND, m, (struct mbuf *)0, (struct mbuf *)0);
#endif
/*
* If space != MLEN then socket is saturating or I've drained
* the tty's outq, so there's not much sense in continuing.
* Otherwise, remain in loop to feed the socket.
*/
if (space != MLEN)
goto out;
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0)
goto out;
}
out: /*
* Perpetuate myself if work remains
*/
(void) spl5(); /* block out tty activity */
if (tp->t_outq.c_cc > 0 || *urgentp)
timeout(ptsnvsnet, (caddr_t)tp, nvsichz); /* TS_BUSY remains set */
else
tp->t_state &= ~TS_BUSY;
/*
* Wake up sleepers
*/
if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
if (tp->t_state&TS_ASLEEP) {
tp->t_state &= ~TS_ASLEEP;
wakeup((caddr_t)&tp->t_outq);
}
if (tp->t_wsel) {
selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
tp->t_wsel = 0;
tp->t_state &= ~TS_WCOLL;
}
}
rspl: splx(s);
}
#endif KNVS
SHAR_EOF
echo shar: extracting tty_nvt.c
cat - << \SHAR_EOF > tty_nvt.c
/*
* Network virtual terminals via sockets - client end
*
* Rick Ace
* New York Institute of Technology
* Computer Graphics Laboratory
* Old Westbury, New York 11568
*/
/*
* The code in this module supports the NVT, or local end of the connection
* (i.e., the link between the network and the user's physical terminal).
* The purpose of this code is to emulate efficiently the character-
* shuffling functions performed by rlogin(1). The rlogind on the remote
* host will believe it is talking to an rlogin, when it is in reality
* talking to the NVT kernel software herein.
*
* The NVT kernel software achieves performance improvements by handling
* incoming and outgoing character traffic at interrupt level, eliminating
* the overhead and delays resulting from scheduling a user-mode process.
*
* The implementation is broken into two main layers:
* 1) high-level software, common to all NVTs (nvt_XXX subrs)
* 2) protocol-specific stuff (tcp_XXX, etc.)
* Presently, there is only a TCP implementation for layer # 2.
*/
#ifdef KNVT
#include "../h/param.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/file.h"
#include "../h/ioctl.h"
#include "../h/tty.h"
#include "../h/mbuf.h"
#include "../h/protosw.h"
#include "../h/socketvar.h"
#ifdef NFS
#include "../h/vnode.h"
#include "../ufs/inode.h"
#else NFS
#include "../h/inode.h"
#endif NFS
#define MAXNVT 16 /* should be in a parameter file */
/*
* tp-to-socket correspondence table.
*
* This table is searched linearly. A highest-entry mark is maintained
* to keep search overhead low. If there is a need to support large
* numbers of NVTs, the linear search should be replaced by hashing.
*/
struct nvtj {
struct tty *nvt_tp; /* tty context, or 0 if free slot */
struct socket *nvt_so; /* socket context */
char nvt_ostopc; /* original tty stop character */
char nvt_ostartc; /* original tty start character */
} nvtj[MAXNVT];
struct nvtj *nvthij = &nvtj[0]; /* highest active entry */
#ifndef lint
int nvtj_n = MAXNVT; /* for kernel debug utilities */
#endif
int nvtichz; /* hz between icpy scans */
int nvtnmsg = 10; /* # of kernel printfs remaining */
short nvtricpy; /* icpy: callout request exists */
short nvtrocpy; /* ocpy: callout request exists */
int nvt_icpy();
/*
* Mate a tty and a socket
*
* Returns UNIX error code
* Must be called at splimp
*/
nvt_add(tp, so, anvt)
struct tty *tp;
struct socket *so;
struct nvtj **anvt; /* return addr of NVT context here */
{
register struct nvtj *nvt, *nx;
extern int hz; /* XXX */
if (nvtichz == 0)
nvtichz = hz / 3; /* XXX */
nvt = 0;
nx = &nvtj[MAXNVT - 1];
do {
if (nx->nvt_tp) {
if (nx->nvt_tp == tp || nx->nvt_so == so)
return EBUSY; /* tty or socket already an NVT */
}
else
nvt = nx; /* remember lowest empty slot */
} while (--nx >= &nvtj[0]);
if (nvt == 0)
return ENFILE; /* all slots are in use */
/*
* All is clear, mate them
*/
if (nvt > nvthij)
nvthij = nvt; /* update highest active entry */
*anvt = nvt; /* pass context pointer to caller */
nvt->nvt_so = so;
nvt->nvt_tp = tp;
so->so_rcv.sb_flags |= SB_NVT;
tp->t_state |= TS_NVT;
nvt->nvt_ostopc = tp->t_stopc;
nvt->nvt_ostartc = tp->t_startc;
sbwakeup(&so->so_rcv); /* get characters flowing */
return 0;
}
/*
* Undo a tty/socket correspondence
*
* Must be called at splimp
*/
nvt_del(nvt)
register struct nvtj *nvt;
{
register struct tty *tp;
tp = nvt->nvt_tp;
if (tp == 0)
panic("Nvt_del");
tp->t_state &= ~TS_NVT;
tp->t_stopc = nvt->nvt_ostopc;
tp->t_startc = nvt->nvt_ostartc;
nvt->nvt_so->so_rcv.sb_flags &= ~SB_NVT;
/*
* Delete this entry and adjust Nvthij if necessary
*/
nvt->nvt_tp = 0; /* mark entry as free */
if (nvthij == nvt)
while (nvthij > &nvtj[0] && nvthij->nvt_tp == 0)
nvthij--;
}
/*
* Kernel printf error message
*/
/*VARARGS1*/
nvt_emsg(msg, dat)
char *msg; /* error message with optional % */
int dat; /* optional data */
{
if (--nvtnmsg >= 0)
printf(msg, dat);
}
/*
* Copy incoming NVT characters from socket to tty
*
* Logic here is similar to that of soreceive() in uipc_socket.c
*/
nvt_i1cpy(nvt)
struct nvtj *nvt;
{
register struct socket *so = nvt->nvt_so;
register struct tty *tp = nvt->nvt_tp;
register struct mbuf *m;
register int n, s;
s = splnet();
while (1) {
/*
* Handle out-of-band data if I'm at that point
*/
if (so->so_state & SS_RCVATMARK) {
m = m_get(M_DONTWAIT, MT_DATA);
if (m == 0)
goto out;
if ((n = (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
m, (struct mbuf *)0, (struct mbuf *)0)) == 0) {
nvt_oob(nvt, *mtod(m, unsigned char *));
so->so_state &= ~SS_RCVATMARK;
}
else
nvt_emsg("nvt RCVOOB %d\n", n);
(void) m_free(m);
}
if (so->so_rcv.sb_cc <= 0)
goto out;
/*
* Check for out-of-band data preceded by character traffic.
* If present, flush the precding character traffic;
* otherwise, just transfer character traffic to the tty.
*/
if ((n = so->so_oobmark) <= 0) { /* if no OOB data... */
n = TTHIWAT(tp);
n -= tp->t_outq.c_cc;
if (n <= 0) {
/*
* No room in tty's outq for more characters, so
* set up delay to retry after a brief interval.
*/
if (!nvtricpy) {
nvtricpy++;
timeout(nvt_icpy, (caddr_t)0, nvtichz);
}
goto out;
}
}
/*
* Attack the first mbuf on the socket's rcv queue
*/
m = so->so_rcv.sb_mb;
if (m == 0)
panic("nvt_i1cpy");
if (n > m->m_len)
n = m->m_len;
if (so->so_oobmark <= 0 &&
b_to_q(mtod(m, char *), n, &tp->t_outq))
nvt_emsg("nvt b_to_q resid tp=%x\n", tp);
ttstart(tp);
if (n == m->m_len) {
struct mbuf *mz;
sbfree(&so->so_rcv, m);
MFREE(m, mz);
so->so_rcv.sb_mb = m = mz;
}
else {
m->m_off += n;
m->m_len -= n;
so->so_rcv.sb_cc -= n;
}
if (so->so_oobmark > 0 && (so->so_oobmark -= n) == 0)
so->so_state |= SS_RCVATMARK;
/*
* Notify protocol that more space is available in the socket
*/
if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
}
out: /*
* If the remote has closed its output and I have passed all
* incoming traffic to the tty, dissolve the NVT connection
* between the socket and the local tty, and wake up rlogin.
*/
if (so->so_state & SS_CANTRCVMORE && so->so_rcv.sb_cc <= 0) {
so->so_rcv.sb_flags &= ~SB_NVT;
tp->t_state &= ~TS_NVT;
wakeup((caddr_t)nvt);
}
splx(s);
}
/*
* Softclock interrupt routine to move characters from
* socket receive buffer to tty output queue. This
* is used only to retry transfering characters to ttys
* whose output queues were saturated.
*/
/*ARGSUSED*/
nvt_icpy(d)
caddr_t d; /* 2nd argument of timeout() */
{
register struct nvtj *nvt;
nvtricpy = 0;
/*
* Scan all NVT sockets for incoming traffic
*/
nvt = &nvtj[0];
do {
if (nvt->nvt_tp && nvt->nvt_so->so_rcv.sb_cc > 0)
nvt_i1cpy(nvt);
} while (++nvt <= nvthij);
}
/*
* Called to report that an NVT has incoming characters from the net
*/
nvt_input(sb)
struct sockbuf *sb; /* so_rcv */
{
#define STRUCT_OFF(strnam, elem) \
((char *)&((struct strnam *)0)->elem - (char *)0)
register struct socket *so;
register struct nvtj *nvt;
/*
* Convert so_rcv address to socket address (a bit gross),
* then search the active-connection table for that socket
*/
so = (struct socket *)((char *)sb - STRUCT_OFF(socket, so_rcv));
nvt = &nvtj[0];
do {
if (nvt->nvt_so == so && nvt->nvt_tp) {
/*
* Have located the tty, now pass it the data
*/
nvt_i1cpy(nvt);
return;
}
} while (++nvt <= nvthij);
nvt_emsg("nvt input no so %x\n", so);
}
/*
* Handle ioctl request on socket to join socket and tty, called
* from protocol ioctl logic. Protocol-specific validation is
* done before you get here.
*
* If the connection was successfully established, sleep and wait
* until it is broken at the remote end, or until a signal is
* received on the local end (viz., from the local tty driver
* when the user types the escape character).
*
* Returns
* 0 = remote closed the connection
* EINTR = signal from local tty (connection can be re-established)
* Anything else = an error establishing the connection
*/
nvt_ioc_join(so, ttyfd)
register struct socket *so;
int ttyfd; /* tty file descriptor */
{
register struct file *fp;
register struct inode *ip;
register struct tty *tp;
int error, s;
struct nvtj *nvtp;
/*
* Validate file descriptor and ensure it references a tty
*/
if ((unsigned)ttyfd >= NOFILE || (fp = u.u_ofile[ttyfd]) == 0)
return EBADF;
#ifdef NFS
{
register struct vnode *vp;
vp = (struct vnode *)fp->f_data;
if (fp->f_type != DTYPE_VNODE || vp->v_op != &ufs_vnodeops)
return ENOTTY;
ip = VTOI(vp);
if ((ip->i_mode & IFMT) != IFCHR ||
(tp = cdevsw[major(ip->i_rdev)].d_ttys) == 0)
return ENOTTY;
}
#else NFS
ip = (struct inode *)fp->f_data;
if (fp->f_type != DTYPE_INODE ||
(ip->i_mode & IFMT) != IFCHR ||
(tp = cdevsw[major(ip->i_rdev)].d_ttys) == 0)
return ENOTTY;
#endif NFS
/*
* Argument socket and tty are valid, now join them and wait
*/
s = splimp();
if (error = nvt_add(tp + minor(ip->i_rdev), so, &nvtp)) {
splx(s);
return error;
}
if (setjmp(&u.u_qsave)) {
/*
* The process received a signal
*/
nvt_del(nvtp); /* disassociate tty&socket */
splx(s);
return EINTR;
}
do sleep((caddr_t)nvtp, PZERO + 1); /* wait for signal or disconnect */
while (nvtp->nvt_so->so_rcv.sb_flags & SB_NVT);
/*
* The remote disconnected.
*/
nvt_del(nvtp); /* disassociate tty&socket */
splx(s);
return 0;
}
/*
* Softclock interrupt routine to move characters from local tty
* input queues to network
*/
/*ARGSUSED*/
nvt_ocpy(d)
caddr_t d; /* 2nd argument of Timeout() */
{
register struct mbuf *m;
register struct tty *tp;
register int c;
register unsigned char *cp, *cplim;
register struct nvtj *nvt;
int error;
nvtrocpy = 0;
/*
* Scan all NVT ttys for outbound characters
*/
nvt = &nvtj[0];
do {
if ((tp = nvt->nvt_tp) == 0)
continue; /* slot is not active */
if (tp->t_rawq.c_cc <= 0 && tp->t_canq.c_cc <= 0)
continue; /* no data */
if (nvt->nvt_so->so_state & SS_CANTSENDMORE)
continue;
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0)
continue;
cp = m->m_dat;
cplim = cp + MLEN;
if (tp->t_canq.c_cc > 0) /* unlikely */
while ((c = getc(&tp->t_canq)) >= 0) {
*cp++ = c;
if (cp >= cplim)
goto mfull;
}
while ((c = getc(&tp->t_rawq)) >= 0) {
if (tp->t_flags & RAW && (c & 0177) == tp->t_intrc) {
/*
* rlogin escape character typed in raw mode,
* simulate ttyinput() processing thereof
*/
gsignal(tp->t_pgrp, SIGINT);
continue;
}
*cp++ = c;
if (cp >= cplim)
goto mfull;
}
mfull: m->m_len = cp - m->m_dat;
error = (*nvt->nvt_so->so_proto->pr_usrreq)(nvt->nvt_so,
PRU_SEND, m, (struct mbuf *)0, (struct mbuf *)0);
#ifdef lint
/* Same actuals as above, better information for lint */
error = tcp_usrreq(nvt->nvt_so,
PRU_SEND, m, (struct mbuf *)0, (struct mbuf *)0);
#endif
if (error)
nvt_emsg("nvt SEND %d\n", error);
} while (++nvt <= nvthij);
}
/*
* Process out-of-band data from remote
*/
nvt_oob(nvt, od)
register struct nvtj *nvt;
unsigned char od; /* data */
{
register struct tty *tp = nvt->nvt_tp;
ttyflush(tp, FWRITE);
if (od & TIOCPKT_NOSTOP) {
tp->t_stopc = -1;
tp->t_startc = -1;
}
if (od & TIOCPKT_DOSTOP) {
tp->t_stopc = nvt->nvt_ostopc;
tp->t_startc = nvt->nvt_ostartc;
}
if (nvtnmsg > 10)
nvt_emsg("nvt oob %x\n", od);
}
/*
* Send characters typed at a local terminal across the net
*
* Called from tty hardware interrupt handler, so must queue request
* to be handled at net IPL
*/
nvt_output(tp)
register struct tty *tp;
{
register struct nvtj *nvt;
nvt = &nvtj[0];
do {
if (nvt->nvt_tp == tp) {
if (!nvtrocpy) {
nvtrocpy++;
timeout(nvt_ocpy, (caddr_t)0, 0);
}
return;
}
} while (++nvt <= nvthij);
/*
* Not in my list, this tty is no longer associated with a socket
*/
tp->t_state &= ~TS_NVT;
}
#endif KNVT
SHAR_EOF