SLIP/getty/printers on Terminal Servers
Ross Cartlidge
rossc at extro.ucc.su.oz.au
Sat Dec 9 06:16:10 AEST 1989
Original-posting-by: rossc at extro.ucc.su.oz.au (Ross Cartlidge)
Reposted-by: emv at math.lsa.umich.edu (Edward Vielmetti)
Posting-id: 891208.1915
Posting-number: Volume TEST, Number TEST
Archive-name: tcpcon -- connect an arbitrary process to a device
[This is an experimental alt.sources re-posting from the
newsgroup(s) comp.protocols.tcp-ip.
No attempt has been made to edit, clean, modify, or otherwise
change the contents of the original posting, or to contact the
author. Please consider cross-posting all sources postings to
alt.sources as a matter of course.]
[Comments on this service to emv at math.lsa.umich.edu (Edward Vielmetti)]
For all those people which replied to my posting
here is the source:-
________________________________________________________________________
Ross Rodney Cartlidge | rossc at extro.ucc.su.oz.au
University Computing Service, H08 | Phone: +61 2 6923497
University of Sydney, NSW 2006, Australia | FAX: +61 2 6606557
------------------------------- Cut Here -------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# Makefile
# README
# nd.1
# nd.c
# tcpcon.1
# tcpcon.c
# tcpserv.1
# tcpserv.c
# This archive created: Fri Dec 8 16:58:58 1989
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'Makefile'
then
echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# Set the follwing for your site
#
# INSTALLDIR Place to install binaries
# XCFLAGS Extra libraries needed for bsd stuff
# XLIBS Extra libraries needed for bsd stuff
#
# Values for MIPS RISC/OS 3/4
INSTALLDIR=/usr/local
XCFLAGS=-I/usr/include/bsd
XLIBS=-lbsd
#
# Values for BSD 4.3
#INSTALLDIR=/usr/local
#XCFLAGS=
#XLIBS=
#
PROGS=nd tcpserv tcpcon
all: $(PROGS)
tcpcon: tcpcon.c
$(CC) $(XCFLAGS) $(CFLAGS) -o $@ tcpcon.c $(LIBS) $(XLIBS)
nd: nd.c
$(CC) $(XCFLAGS) $(CFLAGS) -o $@ nd.c $(LIBS) $(XLIBS)
tcpserv: tcpserv.c
$(CC) $(XCFLAGS) $(CFLAGS) -o $@ tcpserv.c $(LIBS) $(XLIBS)
install: all
/etc/install -o -f $(INSTALLDIR) nd
/etc/install -o -f $(INSTALLDIR) tcpcon
/etc/install -o -f $(INSTALLDIR) tcpserv
clean:
clobber: clean
rm -f $(PROGS)
SHAR_EOF
fi
if test -f 'README'
then
echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
This distribution is a set of programs to connect
an arbitrary process to a device.
It works by attaching the process to the master side
of a pty device. This makes the slave side appear to be
a connection to this process.
The process can do anything, however, most commonly
it is a process to establish a network connection
such as telnet or tcpcon , a command supplied which
connects to an arbitrary tcp address and port.
It is usually used to assign a device to a port
on a terminal server so that the port can be used
just like a real port on a machine. This enables the
port to connect a printer, run a getty, slip, uucp, ACSnet, etc.
FILES:-
Makefile
README
nd.1
nd.c
tcpcon.1
tcpcon.c
tcpserv.1
tcpserv.c
INSTALLATION:
. Edit Makefile to reflect your machine
. type "make install"
. Install the manual entries.
. Set up an "nd" device (See manual entries and also notes below)
A TEST:
Try these commands to test it
nd -l /dev/ptypf tcpcon localhost smtp &
cat < /dev/ttypf &
stty -echo < /dev/ttypf # < should be > for BSD systems
cat > /dev/ttypf
You should now be talking to the SMTP server of your machine.
try the command help<CR>
Use <CNTL>D to kill cat and then
kill the async cat.
Notes for Bridge/3COM terminal servers.
. Enable the generic port 2000 service for your terminal
servers.
. Assign an IP address to the server port to which
you wish to connect.
. Make the port a host device.
. Set the Physical parameters of the port ( Use CTS/RTS flow control
and 8bit no parity if possible)
To set up a connection to a port with address "ipaddr"
set up the following line in /etc/inittab after creating the directory
"/etc/tcpcon.d"
vn:respawn:/usr/local/nd -r -d /etc/tcpcon.d -t ptypf /usr/local/tcpcon -l /dev/ptypf ipaddr 2000
If you don't have inittab then the nd command should be in a startup rc file.
The pty's should be allocated from your last pty downward to stop nd
clashing with automatically allocated ptys.
Notes for Bridge/3COM terminal servers.
. Create a server process for each port you wish to
put a virtual device on, calling each process port<n>
and assigning it to TCP port 2000+n.
. Attach the appropriate server to the port.
. Set the Physical parameters of the port ( Use CTS/RTS flow control
and 8bit no parity if possible)
. Enable the server.
To set up device on port 6 of a cmc server with IP name cmcip, say
set up the following line in /etc/inittab after creating the directory
"/etc/tcpcon.d"
vn:respawn:/usr/local/nd -r -d /etc/tcpcon.d -t ptypf /usr/local/tcpcon -l /dev/ptypf cmcip 2006
If you don't have inittab then the nd command should be in a startup rc file.
The pty's should be allocated from your last pty downward to stop nd
clashing with automatically allocated ptys.
Caveats
I only just added the UDP support so it might be buggy
Some systems (RISC/OS 4.0.1 eg) don't make a read return
on a pty when the corresponding tty is closed. This makes the
process (eg the tcp connection) continue, when the tty is closed,
this is annoying if you wish to cause a modem drop at the other end.
To get round this you have to send a SIGINT to the nd process. See nd(1)
for more details.
SHAR_EOF
fi
if test -f 'nd.1'
then
echo shar: "will not over-write existing file 'nd.1'"
else
cat << \SHAR_EOF > 'nd.1'
.TH ND 1 "April 1989"
.SH NAME
nd \- connect a process to a pty
.SH SYNOPSIS
.B nd
[
.B \-r
]
[
.B \-l
pty
]
[
.B \-f
failtime
]
[
.B \-c
cleartime
]
[
.B \-d
piddir
]
[
.B \-t
pidtag
]
.I command
.SH DESCRIPTION
.B Nd
runs the process specified in
.I command
with standard input, output, error
and controlling terminal assigned
to the device specified by the
.IR pty
specified in the
.B \-l
option.
If no
.B \-l
option is supplied then
.I command
must
open the appropriate pty.
The command is passed to a forked
.I sh
as
.BI "sh \-c 'exec " "command" "'" "'"
so any legal
.I sh
syntax can appear in the
.I command
field.
.PP
Unless
.B \-r
is specified,
.B nd
dies
.I cleartime
seconds after the successful completion of
.IR command ,
allowing the other side of the connection to clear
the connection. By default
.I cleartime
is set to 2 seconds.
In the event of
.I command
exiting with a non-zero exit status
.B nd
will sleep for
.I failtime
before exiting.
If
.B \-r
is specified
.B nd
will re-exec
.I command
after waiting for
.I cleartime
or
.I failtime
as appropriate.
The
.I failtime
is to stop
.B nd
from exec-ing
the command too often.
By default
.I failtime
is set to 15 seconds,
preventing
.B nd
from respawning more than 10 times
in 2 minutes and being disabled by
.BR init (1M),
if it is being spawned from an entry in
.B inittab (4)
.PP
.BR Init (1M)
will respawn
.B nd
automatically
if a line similar to:-
.IP
.BI p1:234:respawn: " nd command"
.LP
is added to
.B /etc/inittab.
.PP
If you don't wish to run it from inittab or don't have inittab,
.B nd
should be started with the
.B \-r
option if you wish the connection to be permanent.
.SH OPTIONS
.TP 1i
.BI \-l " pty"
Attach
.I command
to
.IR pty .
.TP 1i
.BI \-d " piddir"
Log the
.B pid
of
.I command
in
.IR piddir/tag .
Where
.I tag
is the tag specified by
.BR \-t
or if not specified
the basename of
.I dev
or if no
.B \-l
specified then
tag defaults to
.IR pid. "<pid of command>."
Therefore if you wish to drop the connection,
then kill the process with the
.B pid
stored in this file.
.TP 1i
.BI \-t " tag"
set the name of the file which stores the
pid of command to
.IR tag .
.I failtime
seconds.
.TP 1i
.BI \-f " failtime"
set the fail sleep time to
.I failtime
seconds.
.TP 1i
.BI \-c " cleartime"
set the clear sleep time to
.I cleartime
seconds.
.SH EXAMPLES
.IP
.B
nd -r /dev/ptyqf telnet nos
.LP
will make the device
.I /dev/ttyqf
a direct connection
to the
.B telnet
session to the host
.IR nos .
The connection will be respawned
everytime the
.I telnet
dies.
.IP
.B
kill `cat /etc/tcpcon.d/ptyqf`
.LP
will drop the connection established in
the previous example.
.IP
.B
nd tcpcon \-l /dev/ptyqe terminal_server 2000
.LP
will make the device
.I /dev/ttyqe
a direct connection
to the
the
.B TCP
port
2000
on the host
.IR terminal_server .
.IP
.B
nd \-l /dev/ptyqd tcpserv 2000
.LP
will make the device
.I /dev/ttyqd
a direct connection
to any client which connects to
.B TCP
port
2000.
.SH SIGNALS
.TP 1i
SIGHUP
Sends a SIGTERM at the process group associated
with
.IR command
and restarts
.IR command .
.TP 1i
SIGTERM
Sends a SIGTERM at the process group associated
with
.I command
and exits.
.SH "SEE ALSO"
.BR tcpserv (1),
.BR tcpcon (1),
.BR telnet (1),
.BR pty (7),
.BR inittab (4).
.SH FILES
.PD 0
.TP 2i
/etc/services
List of ports and services
.TP 2i
/etc/hosts
List of hosts
.TP 2i
/etc/inittab
Script for init processes
.PD
SHAR_EOF
fi
if test -f 'nd.c'
then
echo shar: "will not over-write existing file 'nd.c'"
else
cat << \SHAR_EOF > 'nd.c'
/*
Written by Ross Cartlidge (rossc at extro.ucc.su.oz)
University Computer Service
March 1989
tcpcon - Program to connect a tty to a tcp socket
Developed on a MIPS M/2000 running SysVr3
Ported to BSD/SUN-OS
*/
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <syslog.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#if defined(SYSTYPE_BSD43)
#define sigset signal
#define sighold(s) sigblock(sigmask(s))
#define sigrelse(s) sigsetmask(sigsetmask(-1) & ~sigmask(s))
#endif
int pid;
int to;
int term;
char *piddir;
main(argc, argv)
int argc;
char *argv[];
{
int i;
char sh_c[2048];
int ret;
char *dev = (char *)0;
int failtime = 15; /* > 2m/10 for init */
int cleantime = 2; /* tcp connection to cleanup*/
int respawn = 0; /* respawn process*/
char *tag = (char *)0;
int c;
int errflg = 0;
int retval;
void terminate();
void timeout();
extern int errno;
extern char *sys_errlist[];
extern char *optarg;
extern int optind;
openlog(argv[0], 0, LOG_LOCAL0);
while ((c = getopt(argc, argv, "rl:f:c:d:t:")) != -1)
switch (c)
{
case 'f':
failtime = atoi(optarg);
break;
case 'c':
cleantime = atoi(optarg);
break;
case 'l':
dev = optarg;
break;
case 'd':
piddir = optarg;
break;
case 't':
tag = optarg;
break;
case 'r':
respawn++;
break;
case '?':
errflg++;
}
if (errflg || optind >= argc)
{
syslog(LOG_ERR, "Usage: %s [ -d <pty> ] <command>", argv[0]);
exit(2);
}
strcpy(sh_c, "exec");
for (i = optind; i < argc; i++)
{
strcat(sh_c, " ");
strcat(sh_c, argv[i]);
}
do
{
sighold(SIGTERM);
sighold(SIGHUP);
sigset(SIGTERM, terminate);
sigset(SIGHUP, terminate);
if (pid = fork())
{
char pidf[64];
FILE *pidfs;
if (piddir)
{
if (!tag)
{
if (dev)
{
if (tag = strrchr(dev , '/'))
tag++;
else
tag = dev;
sprintf(pidf, "%s/%s", piddir, tag);
}
else
sprintf(pidf, "%s/pid.%d", piddir, pid);
}
else
sprintf(pidf, "%s/%s", piddir, tag);
if ((pidfs = fopen(pidf, "w")) == NULL)
syslog(LOG_ERR, "open(%s) - %s", pidf, sys_errlist[errno]);
else
{
fprintf(pidfs, "%d\n", pid);
fclose(pidfs);
}
}
if (failtime > 0)
{
sigset(SIGALRM, timeout);
alarm(failtime);
}
else
to = 1;
sigrelse(SIGTERM);
sigrelse(SIGHUP);
while (wait(&ret) != -1 || errno == EINTR)
;
if ((ret & 0xff) == 0)
{
if ((ret >> 8 & 0xff) != 0)
{
unlink(pidf);
syslog(LOG_ERR, "Failed(%d) %s", ret >> 8, sh_c);
sighold(SIGALRM);
while (!to)
sigpause(SIGALRM);
sigrelse(SIGALRM);
retval = 1;
continue;
}
else
syslog(LOG_DEBUG, "Completed %s", sh_c);
}
else
syslog(LOG_DEBUG, "Killed(%d) %s", ret, sh_c);
unlink(pidf);
sleep(cleantime);
retval = 0;
continue;
}
#if defined(SYSTYPE_BSD43)
ioctl(0, TIOCNOTTY, 0);
setpgrp(0, getpid());
#endif
#if defined(SYSTYPE_SYSV)
setpgrp();
#endif
close(0);
close(1);
close(2);
sigset(SIGTERM, SIG_DFL);
sigset(SIGHUP, SIG_DFL);
sigrelse(SIGTERM);
sigrelse(SIGHUP);
if (dev)
{
if (open(dev, O_RDWR) == -1)
{
syslog(LOG_ERR, "open(%s) - %s", dev, sys_errlist[errno]);
exit(2);
}
dup(0);
dup(0);
}
else
{
open("/dev/null", O_RDONLY);
open("/dev/null", O_WRONLY);
dup(1);
}
syslog(LOG_DEBUG, "Started %s", sh_c);
execl("/bin/sh", "sh", "-c", sh_c, (char *)0);
syslog(LOG_ERR, "Exec failed %s", sh_c);
}
while (!term);
}
void
terminate(s)
int s;
{
if (s == SIGTERM)
term = 1;
kill(-pid, SIGTERM);
}
void
timeout(s)
int s;
{
to = 1;
}
SHAR_EOF
fi
if test -f 'tcpcon.1'
then
echo shar: "will not over-write existing file 'tcpcon.1'"
else
cat << \SHAR_EOF > 'tcpcon.1'
.TH TCPCON 1 "April 1989"
.SH NAME
tcpcon \- Connect to a TCP socket
.SH SYNOPSIS
.B tcpcon
[
.B \-a
]
[
.B \-l
pty
]
[
.B \-k
tty
]
[
.B \-t
mintime
]
[
.B \-r
minreads
]
[
.B \-u
]
.I host
.I port
.SH DESCRIPTION
.B Tcpcon
sets up a
.B TCP
connection to
.I host
on port number
.IR port ,
forwarding standard input down the connection
and writing data from the connection
to standard output.
No data is sent down the connection until
either
.I minreads
have been received
or
.I mintime
has expired.
This is because many terminal servers
accept connections to send information
such as
.B "Host Busy"
and then close the connection.
Data sent down these transient connections
would be lost.
.PP
It is is usually used with
.BR nd (1)
to attach a
.B TCP
connection to a device.
.SH OPTIONS
.TP 1i
.BI \-a
Set socket connection in
.B KEEPALIVE
mode so that the connection will die
if the other side goes down.
.TP 1i
.BI \-l " pty"
Attach the TCP connection
to
.I pty
rather than standard input and output.
Only open
.I pty
after
.I mintime
or
.I minreads
has occurred.
This will ensure that the slave will
block until a reliable
connection is created.
.TP 1i
.BI \-k " tty"
Open
.I tty
after setting up the TCP connection
so that the connection will be kept
open when other processes close the
.IR tty .
If
this option is specified
.I tty
should be the slave partner to
the device specified in the
.B -l
option.
.TP 1i
.BI \-t " mintime"
Set the minimum time
a connection must be up before
sending characters down the connection to
.I mintime
seconds.
.TP 1i
.BI \-r " minreads"
Set the minimum number of reads received
before
sending characters down the connection to
.I mintime
seconds.
.TP 1i
.BI \-u
connect to a UDP socket instead of a TCP socket.
.SH EXAMPLES
.IP
.B
tcpcon -l /dev/ptyqe localhost smtp
.LP
connect to the
.B smtp
server on the local machine
and attach this connection to
.IR /dev/ttyqe .
.IP
.B
kill `cat /etc/tcpcon.d/ptyqe`
.LP
will drop the connection established in
the previous example.
.SH "SEE ALSO"
.BR nd (1),
.BR setsockopt (2),
.BR tcpserv (1),
.SH FILES
.PD 0
.TP 2i
/etc/hosts
List of hosts
.TP 2i
/etc/services
List of ports and services
.PD
SHAR_EOF
fi
if test -f 'tcpcon.c'
then
echo shar: "will not over-write existing file 'tcpcon.c'"
else
cat << \SHAR_EOF > 'tcpcon.c'
/*
Written by Ross Cartlidge (rossc at extro.ucc.su.oz)
University Computer Service
March 1989
tcpcon - Program to connect a tty to a tcp socket
Developed on a MIPS M/2000 running SysVr3
Ported to BSD/SUN-OS
*/
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <syslog.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <setjmp.h>
#define max(a,b) (a<b ? b : a)
#define min(a,b) (a>b ? b : a)
#if defined(SYSTYPE_BSD43)
#define sigset signal
#define sighold(s) sigblock(sigmask(s))
#define sigrelse(s) sigsetmask(sigsetmask(-1) & ~sigmask(s))
extern int errno;
#endif
#if !defined(FD_SET)
#define fd_set int
#define FD_SET(n,p) (*(p) |= 1 << (n))
#define FD_CLR(n,p) (*(p) &= ~(1 << (n)))
#define FD_ISSET(n,p) (*(p) & 1 << (n))
#define FD_ZERO(p) (*(p) = 0)
#endif
#define BUFSIZE 1024
struct buf
{
char buf[BUFSIZE];
int cnt;
};
jmp_buf env;
int keepalive = 0;
int pid;
main(argc, argv)
int argc;
char *argv[];
{
struct hostent *host;
struct servent *serv;
struct sockaddr_in sin;
int s;
int i;
int r;
char perror_fmt[128];
char usage[128];
int p;
fd_set rfds;
fd_set efds;
fd_set wfds;
int mintime = 2;
int minreads = 2;
char *dev = (char *)0;
char *kdev = (char *)0;
int errflg = 0;
void terminate();
int c;
int status;
struct buf *bufs;
int timeout();
int con_type = SOCK_STREAM;
extern char *optarg;
extern int optind;
sprintf(perror_fmt, "PERROR_FMT=%s: %%t %%s%%m - (%%e)", argv[0]);
sprintf
(
usage,
"USAGE: %s [-a] [-t mintime ] [-r minreads] [-l pty] [-k tty] <IP Address> <TCP Port>\n", argv[0]
);
#if defined(SYSTYPE_SYSV)
putenv(perror_fmt);
#endif
while ((c = getopt(argc, argv, "at:l:r:k:u")) != -1)
switch (c)
{
case 'u':
con_type = SOCK_DGRAM;
break;
case 'a':
keepalive = 1;
break;
case 'k':
kdev = optarg;
break;
case 't':
mintime = atoi(optarg);
break;
case 'r':
minreads = atoi(optarg);
break;
case 'l':
dev = optarg;
break;
case '?':
errflg++;
}
if (errflg || optind + 1 >= argc)
{
fputs(usage, stderr);
exit(2);
}
if ((sin.sin_addr.s_addr = inet_addr(argv[optind])) != -1)
sin.sin_family = AF_INET;
else
{
if (host = gethostbyname(argv[optind]))
{
sin.sin_family = host->h_addrtype;
memcpy(&sin.sin_addr.s_addr, host->h_addr, host->h_length);
}
else
{
fprintf
(
stderr,
"%s: %s: unknown host\n",
argv[0],
argv[optind]
);
exit(2);
}
}
if (serv = getservbyname(argv[optind + 1], "tcp"))
sin.sin_port = serv->s_port;
else
if
(
(
sin.sin_port
=
htons
(
(short)strtol(argv[optind + 1],
(char **)0, 0)
)
)
<=
0
)
{
fprintf
(
stderr,
"%s: %s: unknown service\n",
argv[0],
argv[optind + 1]
);
exit(2);
}
if ((s = connectsocket(&sin, con_type)) < 0)
exit(1);
if ((bufs = (struct buf *)calloc(max(minreads, 1) ,sizeof (struct buf))) < 0)
{
perror("calloc bufs");
exit(1);
}
sigset(SIGALRM, timeout);
sighold(SIGALRM);
alarm(mintime);
if (setjmp(env) == 0)
for (i = 0; i < minreads; i++)
{
sigrelse(SIGALRM);
r = read(s, bufs[i].buf, BUFSIZE);
sighold(SIGALRM);
if (r <= 0)
exit(1);
else
bufs[i].cnt = r;
}
alarm(0);
sigset(SIGALRM, SIG_IGN);
sigrelse(SIGALRM);
if (dev)
{
close(0);
close(1);
sighold(SIGTERM);
if (pid = fork())
{
sigset(SIGTERM, terminate);
sigrelse(SIGTERM);
if (kdev != (char *)0 && open(kdev, O_RDWR) == -1)
kill(pid, SIGTERM);
#if defined(SYSTYPE_BSD43)
ioctl(0, TIOCNOTTY, 0);
setpgrp(0, getpid());
#endif
#if defined(SYSTYPE_SYSV)
setpgrp();
#endif
while (wait(&status) != -1 || errno == EINTR)
;
if ((status & 0xff) == 0 && (status >> 8 & 0xff))
exit(status >> 8 & 0xff);
else
exit(0);
}
#if defined(SYSTYPE_BSD43)
ioctl(0, TIOCNOTTY, 0);
setpgrp(0, getpid());
#endif
#if defined(SYSTYPE_SYSV)
setpgrp();
#endif
sigrelse(SIGTERM);
if (open(dev, O_RDWR) == -1)
{
perror(dev);
exit(1);
}
dup(0);
}
for (i = 0; i < minreads && bufs[i].cnt > 0; i++)
if (write(1, bufs[i].buf, bufs[i].cnt) != bufs[i].cnt)
exit(0);
for (;;)
{
char *buf = bufs[0].buf;
FD_ZERO(&rfds);
FD_ZERO(&efds);
FD_SET(0, &rfds);
FD_SET(s, &rfds);
FD_SET(0, &efds);
FD_SET(s, &efds);
select(s + 1, &rfds, (fd_set *)0, &efds, (struct timeval *)0);
if (FD_ISSET(s, &rfds) || FD_ISSET(s, &efds))
{
if ((r = read(s, buf, BUFSIZE)) <= 0)
{
perror("read");
exit(0);
}
if (write(1, buf, r) != r)
{
perror("write");
exit(0);
}
}
if ((FD_ISSET(0, &rfds) || FD_ISSET(0, &efds)))
{
if ((r = read(0, buf, BUFSIZE)) <= 0)
{
perror("read");
exit(0);
}
if (write(s, buf, r) != r)
{
perror("write");
exit(0);
}
}
}
}
connectsocket(sinp, t)
struct sockaddr_in *sinp;
int t;
{
int s;
int l;
int sockopt;
if ((s = socket(AF_INET, t, 0)) < 0)
{
perror("socket");
return -1;
}
l = sizeof *sinp;
if (connect(s, sinp, l) < 0)
{
perror("connect");
return -1;
}
if
(
t == SOCK_STREAM
&&
keepalive == 1
&&
setsockopt
(
s,
SOL_SOCKET,
SO_KEEPALIVE,
(sockopt = 1, (char *)&sockopt),
sizeof sockopt
)
<
0
)
{
perror("setsockopt");
return -1;
}
return s;
}
timeout(s)
int s;
{
longjmp(env, 1);
}
void
terminate(s)
int s;
{
kill(pid, s);
}
SHAR_EOF
fi
if test -f 'tcpserv.1'
then
echo shar: "will not over-write existing file 'tcpserv.1'"
else
cat << \SHAR_EOF > 'tcpserv.1'
.TH TCPSERV 1 "April 1989"
.SH NAME
tcpserv \- accept a TCP connection
.SH SYNOPSIS
.B tcpserv
[
.B \-u
]
.I port
.SH DESCRIPTION
.B Tcpserv
accepts a
.B TCP
connection on
on port number
.IR port ,
forwarding standard input down the connection
and writing data from the connection
to standard output.
.PP
It is usually used with
.BR nd (1)
to attach a
.B TCP
connection to a device.
.SH OPTIONS
.BI \-u
service a UDP socket instead of a TCP socket.
.SH EXAMPLES
.IP
.B
tcpserv smtp
.LP
accepts connections to the
.B smtp
port on the local machine.
.SH "SEE ALSO"
.BR nd (1),
.BR tcpcon (1).
.SH FILES
.PD 0
.TP 2i
/etc/services
List of ports and services
.PD
.SH BUGS
SHAR_EOF
fi
if test -f 'tcpserv.c'
then
echo shar: "will not over-write existing file 'tcpserv.c'"
else
cat << \SHAR_EOF > 'tcpserv.c'
/*
Written by Ross Cartlidge (rossc at extro.ucc.su.oz)
University Computer Service
March 1989
*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#if !defined(FD_SET)
#define fd_set int
#define FD_SET(n,p) (*(p) |= 1 << (n))
#define FD_CLR(n,p) (*(p) &= ~(1 << (n)))
#define FD_ISSET(n,p) (*(p) & 1 << (n))
#define FD_ZERO(p) (*(p) = 0)
#endif
#define BUFSIZE 1024
char buf[BUFSIZE];
main(argc, argv)
int argc;
char *argv[];
{
struct sockaddr_in sin;
struct sockaddr_in from;
int fromlen;
int s;
int c;
int errflg = 0;
int r;
char perror_fmt[128];
char usage[128];
int nfds;
fd_set rfds;
fd_set efds;
int sockopt;
int con_type = SOCK_STREAM;
extern char *optarg;
extern int optind;
sprintf(perror_fmt, "PERROR_FMT=%s: %%t %%s%%m - (%%e)", argv[0]);
sprintf(usage, "USAGE: %s <TCP Port>\n", argv[0]);
#if defined(SYSTYPE_SYSV)
putenv(perror_fmt);
#endif
while ((c = getopt(argc, argv, "u")) != -1)
switch (c)
{
case 'u':
con_type = SOCK_DGRAM;
break;
case '?':
errflg++;
break;
}
if (errflg || optind >= argc)
{
fputs(usage, stderr);
exit(2);
}
if ((s = socket(AF_INET, con_type, 0)) < 0)
{
perror("socket");
exit(1);
}
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
if ((sin.sin_port = htons((short)strtol(argv[optind], (char **)0, 0))) <= 0)
{
fputs(usage, stderr);
exit(2);
}
if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0)
{
perror("bind");
exit(1);
}
if (con_type == SOCK_STREAM)
{
listen(s, 5);
if ((s = accept(s, (struct sockaddr *)0, (int *)0)) < 0)
{
perror("accept");
exit(1);
}
if
(
setsockopt
(
s,
SOL_SOCKET,
SO_KEEPALIVE,
(sockopt = 1, (char *)&sockopt),
sizeof sockopt
)
<
0
)
{
perror("setsockopt");
exit(1);
}
}
else
{
fromlen = sizeof from;
if ((r = recvfrom(s, buf, sizeof buf, 0, &from , &fromlen)) == -1)
{
perror("recvfom");
exit(1);
}
if (connect(s, &from, sizeof from) == -1)
{
perror("connect");
exit(1);
}
if (write(1, buf, r) != r)
{
perror("write");
exit(0);
}
}
for (;;)
{
FD_ZERO(&rfds);
FD_ZERO(&efds);
FD_SET(0, &rfds);
FD_SET(s, &rfds);
FD_SET(0, &efds);
FD_SET(s, &efds);
select(s + 1, &rfds, (fd_set *)0, &efds, (struct timeval *)0);
if (FD_ISSET(0, &rfds) || FD_ISSET(0, &efds))
{
if ((r = read(0, buf, BUFSIZE)) <= 0)
{
perror("read");
exit(0);
}
if (write(s, buf, r) != r)
{
perror("write");
exit(0);
}
}
if (FD_ISSET(s, &rfds) || FD_ISSET(s, &efds))
{
if ((r = read(s, buf, BUFSIZE)) <= 0)
{
perror("read");
exit(0);
}
if (write(1, buf, r) != r)
{
perror("write");
exit(0);
}
}
}
}
SHAR_EOF
fi
exit 0
# End of shell archive
--
________________________________________________________________________
Ross Rodney Cartlidge | rossc at extro.ucc.su.oz.au
University Computing Service, H08 | Phone: +61 2 6923497
University of Sydney, NSW 2006, Australia | FAX: +61 2 6606557
More information about the Alt.sources
mailing list