Newsgroups: comp.sources.unix
From: thoth@cis.ufl.edu (Robert H. Forsman, Jr)
Subject: v29i037: netpipes-3 -- BSD network pipe tools, V3, Part01/01
Message-id: <1.814573567.17907@gw.home.vix.com>
Sender: unix-sources-moderator@gw.home.vix.com
Approved: vixie@gw.home.vix.com
Submitted-By: thoth@cis.ufl.edu (Robert H. Forsman, Jr)
Posting-Number: Volume 29, Issue 37
Archive-Name: netpipes-3/part01
This is an update of netpipes from Volume 26.
faucet and hose:
These two utilities are useful for connecting arbitrary programs
over sockets. The power of the '|' character in the shell can now be
used over the network.
#!/bin/sh
# This is a shell archive (produced by shar 3.50)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 10/24/1995 21:54 UTC by thoth@coast
# Source directory /tmp/netpipes3.0
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 1835 -r--r--r-- README
# 2196 -r--r--r-- Makefile
# 5348 -rw-r--r-- common.c
# 1802 -rw-r--r-- common.h
# 679 -rw-r--r-- version.c
# 7264 -rw-r--r-- faucet.1
# 11590 -rw-r--r-- faucet.c
# 6980 -r--r--r-- hose.1
# 12117 -rw-r--r-- hose.c
# 4263 -rw-r--r-- sockdown.1
# 2095 -rw-r--r-- sockdown.c
# 6118 -r--r--r-- getpeername.1
# 4042 -rw-r--r-- getpeername.c
# 4616 -r--r--r-- netpipes.1
# 7904 -rw-r--r-- faucet.html
# 6557 -rw-r--r-- getpeername.html
# 7541 -rw-r--r-- hose.html
# 5041 -rw-r--r-- netpipes.html
# 4558 -rw-r--r-- sockdown.html
# 17981 -rw-r--r-- COPYING
#
# ============= README ==============
if test -f 'README' -a X"$1" != X"-c"; then
echo 'x - skipping README (File already exists)'
else
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
X Enjoy NETPIPES 3
X
X by Robert Forsman
X
X Check the Makefile. You will want to change where it installs
stuff. Some systems require extra libraries or compile flags.
X
X There has been a change in the way that the subcommand is specified.
It is MUCH better than the old way. Read the manual pages.
X
X I think USE_IOCTL is now required. This is because I don't know the
canonical portable way to disassociate myself from the controlling
terminal. If anyone can tell me how to do this without using ioctl,
please do.
X
X Also, I need portable ways to clean up child processes. Maybe I'll
just read the perl source one day.
X
X This program has, in the past, been compiled and tested on a DEC
5100, an RS6k, an HP9k, an SGI and sees almost daily usage under SunOS
4.1.3 and Linux.
X
X If you compile this program on an architecture/OS not mentioned
above, drop me a line. If you have problems compiling on any
architecture, I want to hear about it (and I'll try to help you fix
the problem and make sure that the next version compiles out of the
box).
X
X Normally, I say all software sucks, but I can now proudly say that
NETPIPES RULES! If you disagree, tell me why and I'll see if I can
fix it.
X
X HEY CYPHERPUNKS!
X
X I'm having difficulty thinking of new things to add to netpipes.
The only thing I would like to add is some sort of authorization/
encryption filter so that two processes which normally wouldn't care
about authentication/encryption could be secured.
X
X I would write an RSA thingy myself, but I'm a U.S. citizen and
suffer from unwieldy export restrictions (yes, my appointed officials
are twits). If somebody in the U.K. (or wherever encryption is legal
to export) ever does write an encryption filter compatible with
netpipes, could you talk to me and I'll have you make a combo package
for export to the U.S.
SHAR_EOF
chmod 0444 README ||
echo 'restore of README failed'
Wc_c="`wc -c < 'README'`"
test 1835 -eq "$Wc_c" ||
echo 'README: original size 1835, current size' "$Wc_c"
fi
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
echo 'x - skipping Makefile (File already exists)'
else
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
# faucet and hose: network pipe utilities
# Copyright (C) 1992,1993 Robert Forsman
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
# You probably want to change this:
INSTROOT = ${HOME}
INSTBIN = ${INSTROOT}/bin
INSTMAN = ${INSTROOT}/man
X
# This might be necessary for HPUX
#LDLIBS=-lBSD
X
# I'm told this is required for Sequent SysV
#LDLIBS=-lsocket -linet -lnsl
X
# This will be necessary for Sun Solaris (the abomination)
#LDLIBS=-lsocket -lnsl
X
# For SunOS, add -DNO_MEMMOVE. It doesn't have this very handy function.
X
# If you don't want to use (or don't have) fcntl(2) try the -DUSE_IOCTL.
X
# Add -DSYSV if your signal handlers need reinstalling after being called.
# hpux has been known to require this. Solaris may or may not. I haven't
# experimented enough.
CFLAGS = -DUSE_IOCTL -g -DNO_MEMMOVE
X
FOBJS = faucet.o common.o version.o
HOBJS = hose.o common.o version.o
SOBJS = sockdown.o version.o
GOBJS = getpeername.o version.o
X
MANPAGES = netpipes.1 faucet.1 hose.1 sockdown.1 getpeername.1
PROGRAMS = faucet hose sockdown getpeername
X
all : ${PROGRAMS}
X
faucet : ${FOBJS}
X ${CC} ${CFLAGS} -o $@ ${FOBJS} ${LDLIBS}
X
hose : ${HOBJS}
X ${CC} ${CFLAGS} -o $@ ${HOBJS} ${LDLIBS}
X
sockdown: ${SOBJS}
X ${CC} ${CFLAGS} -o $@ ${SOBJS} ${LDLIBS}
X
getpeername: ${GOBJS}
X ${CC} ${CFLAGS} -o $@ ${GOBJS} ${LDLIBS}
X
install : all
X cp ${PROGRAMS} ${INSTBIN}/
X ln -s getpeername ${INSTBIN}/getsockname
X cp ${MANPAGES} ${INSTMAN}/man1/
X
clean :
X rm -f ${FOBJS} ${HOBJS} ${SOBJS}
X
spotless: clean
X rm -f *~ core ${PROGRAMS}
SHAR_EOF
chmod 0444 Makefile ||
echo 'restore of Makefile failed'
Wc_c="`wc -c < 'Makefile'`"
test 2196 -eq "$Wc_c" ||
echo 'Makefile: original size 2196, current size' "$Wc_c"
fi
# ============= common.c ==============
if test -f 'common.c' -a X"$1" != X"-c"; then
echo 'x - skipping common.c (File already exists)'
else
echo 'x - extracting common.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'common.c' &&
/*
X
X $Id: common.c,v 1.8 1995/10/24 19:15:47 thoth Exp thoth $, part of
X faucet and hose: network pipe utilities
X Copyright (C) 1992-95 Robert Forsman
X
X This program is free software; you can redistribute it and/or modify
X it under the terms of the GNU General Public License as published by
X the Free Software Foundation; either version 2 of the License, or
X (at your option) any later version.
X
X This program is distributed in the hope that it will be useful,
X but WITHOUT ANY WARRANTY; without even the implied warranty of
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
X GNU General Public License for more details.
X
X You should have received a copy of the GNU General Public License
X along with this program; if not, write to the Free Software
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X */
X
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
X
char *programname;
X
/**********************************************************************/
X
int *fds=0;
int nfds;
int fdsize=0;
X
int how_shutdown = -2;
X
void add_fd(fd)
X int fd;
{
X if (fds==0) {
X fds = (int*)malloc(sizeof(*fds)*(fdsize=4));
X } else if (nfds >= fdsize) {
X fds = (int*)realloc(sizeof(*fds)*(fdsize*=2));
X if (fds==0) {
X fprintf(stderr, "%s: Out of memory\n", programname);
X exit(1);
X }
X }
X fds[nfds++] = fd;
X if (fd>2)
X /* We should reserve this spot in the file descriptor table.
X If we don't it could get allocated by the socket(2) call and
X we would have an awful mess on our hands. */
X dup2(0, fd);
}
X
void dup_n(socket)
X int socket;
{
X int i;
#if 0
X printf("I will redirect fds");
X for (i=0; i=0)
X shutdown(socket, how_shutdown!=0);
X for (i=0; is_port;
X }
X else
X {
X int port;
X if (sscanf(portname,"%i",&port)!=1)
X {
X return 0;
X }
X else
X return htons(port);
X }
}
X
struct in_addr ** /* addr_array */
convert_hostname(name, count_ret)
X char *name;
X int *count_ret;
{
X struct hostent *hp;
X int len;
X struct in_addr **rval;
X
X hp = gethostbyname(name);
X if (hp != NULL) {
X int i;
X if (hp->h_length != sizeof(struct in_addr)) {
X fprintf(stderr, "%s: Funky: (hp->h_length = %d) != (sizeof(struct in_addr) = %d)\n", programname, hp->h_length, sizeof(struct in_addr));
X }
X for (i = 0; hp->h_addr_list[i]; i++)
X { }
X *count_ret = i;
X rval = (struct in_addr **)malloc(sizeof(*rval) * (i+1));
X for (i=0; i<*count_ret; i++) {
X rval[i] = (struct in_addr*)malloc(hp->h_length);
X memcpy((char*)rval[i], hp->h_addr_list[i], hp->h_length);
X }
X rval[*count_ret] = 0;
X return rval;
X } else {
X int count;
X unsigned int a1,a2,a3,a4;
X count = sscanf(name,"%i.%i.%i.%i%n", &a1, &a2, &a3, &a4, &len);
X if (4!=count || 0!=name[len] )
X return 0;
X
X *count_ret = 1;
X rval = (struct in_addr**)malloc(2*sizeof(*rval));
X rval[0] = (struct in_addr*)malloc(sizeof(struct in_addr));
X rval[0]->s_addr = (((((a1 << 8) | a2) << 8) | a3) << 8) | a4;
X rval[1] = 0;
X return rval;
X }
}
X
X
int
bindlocal(fd, name, addrname, domain)
X int fd, domain;
X char *name, *addrname;
{
X struct sockaddr *laddr;
X int addrlen;
X int countdown;
X int rval;
X
X if (domain==AF_INET)
X {
X static struct sockaddr_in srv;
X static int initted=0;
X
X laddr = (struct sockaddr*)&srv;
X addrlen = sizeof(srv);
X
X if (!initted) {
X srv.sin_family = AF_INET;
X
X if (addrname) {
X int count;
X struct in_addr **addresses;
X addresses = convert_hostname(addrname, &count);
X if (addresses == 0) {
X fprintf(stderr, "%s: Unable to convert %s to an internet address\n", programname);
X errno=0;
X return 0;
X }
X srv.sin_addr = *(addresses[0]);
X } else {
X srv.sin_addr.s_addr = INADDR_ANY;
X }
X
X srv.sin_port = name_to_inet_port(name);
X
X if (srv.sin_port==0)
X {
X fprintf(stderr, "%s: port %s unknown\n", programname, name);
X errno = 0;
X return 0;
X }
X }
X initted = 1; /* bindlocal is only called once in
X each netpipes program */
X }
X else
X {
X static struct sockaddr_un srv;
X laddr = (struct sockaddr*)&srv;
X addrlen = sizeof(srv);
X
X srv.sun_family = AF_UNIX;
X strcpy(srv.sun_path, name);
X }
X
X countdown= (domain==AF_UNIX)?1:10;
X do {
X rval = bind(fd, laddr, addrlen);
X if (rval)
X if (errno==EADDRINUSE && --countdown>0)
X {
X fprintf(stderr,"%s: Address %s in use, sleeping 10.\n",
X programname, name);
X sleep (10);
X fprintf(stderr,"%s: Trying again . . .\n", programname);
X }
X else
X return 0;
X } while (rval);
X
X return 1;
}
SHAR_EOF
chmod 0644 common.c ||
echo 'restore of common.c failed'
Wc_c="`wc -c < 'common.c'`"
test 5348 -eq "$Wc_c" ||
echo 'common.c: original size 5348, current size' "$Wc_c"
fi
# ============= common.h ==============
if test -f 'common.h' -a X"$1" != X"-c"; then
echo 'x - skipping common.h (File already exists)'
else
echo 'x - extracting common.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'common.h' &&
/*
X
X $id$, part of
X faucet and hose: network pipe utilities
X Copyright (C) 1992 Robert Forsman
X
X This program is free software; you can redistribute it and/or modify
X it under the terms of the GNU General Public License as published by
X the Free Software Foundation; either version 2 of the License, or
X (at your option) any later version.
X
X This program is distributed in the hope that it will be useful,
X but WITHOUT ANY WARRANTY; without even the implied warranty of
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
X GNU General Public License for more details.
X
X You should have received a copy of the GNU General Public License
X along with this program; if not, write to the Free Software
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X */
X
#ifndef common_h_
#define common_h_
X
/* set from argv[0] by the main() routine */
extern char *programname;
X
/* list of file descriptors to dup from the socket */
extern int *fds;
extern int nfds;
X
/* the mode to use when shutting down the socket
X <0: don't do any shutdown
X 0 : shut down recieves (write-only)
X >0: shut down sends (read-only)
X */
X
extern int how_shutdown;
X
/* add a file descriptor to the list */
void add_fd(/*int fd*/);
X
/* do the dup from the argument socket to the list of file descriptors,
X perform the requested shutdown... */
void dup_n(/*int socket*/);
X
/**********************************************************************/
X
int name_to_inet_port(/* char* */);
X
/**********************************************************************/
X
struct in_addr ** /* addr_array */
convert_hostname(/* char *, int * */);
X
/**********************************************************************/
X
int
bindlocal(/* int, char *, char*, int */);
X
#endif // common_h_
SHAR_EOF
chmod 0644 common.h ||
echo 'restore of common.h failed'
Wc_c="`wc -c < 'common.h'`"
test 1802 -eq "$Wc_c" ||
echo 'common.h: original size 1802, current size' "$Wc_c"
fi
# ============= version.c ==============
if test -f 'version.c' -a X"$1" != X"-c"; then
echo 'x - skipping version.c (File already exists)'
else
echo 'x - extracting version.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'version.c' &&
#include
X
void emit_version(progname, beginyear)
X char *progname;
X int beginyear;
{
X int thisyear=1995;
X fprintf(stderr, "%s version 3, ", progname);
X if (beginyear != thisyear) {
X fprintf(stderr, "Copyright (C) %d-%d Robert Forsman\n", beginyear, thisyear%100);
X } else {
X fprintf(stderr, "Copyright (C) %d Robert Forsman\n", thisyear);
X }
X fprintf(stderr, "\
%s comes with ABSOLUTELY NO WARRANTY;\n\
This is free software, and you are welcome to redistribute it\n\
under the GNU General Public License as published by the Free\n\
Software Foundation; either version 2 of the License, or\n\
(at your option) any later version.\n", progname);
}
SHAR_EOF
chmod 0644 version.c ||
echo 'restore of version.c failed'
Wc_c="`wc -c < 'version.c'`"
test 679 -eq "$Wc_c" ||
echo 'version.c: original size 679, current size' "$Wc_c"
fi
# ============= faucet.1 ==============
if test -f 'faucet.1' -a X"$1" != X"-c"; then
echo 'x - skipping faucet.1 (File already exists)'
else
echo 'x - extracting faucet.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'faucet.1' &&
.\"" faucet.1 Copyright 1992-95 by Robert Forsman
.TH FAUCET 1 "October 24 1995"
.SH NAME
faucet \- a fixture for a BSD network pipe
.SH SYNOPSIS
\fBfaucet\fP \fIport\fP
(\fB\-in\fP|\fB\-out\fP|\fB\-err\fP|\fB\-fd\fP\fIn\fP)+
[\fB\-once\fP]
[\fB\-verbose\fP]
[\fB\-quiet\fP]
[\fB\-unix\fP]
[\fB\-foreignhost\fP \fIaddr\fP]
[\fB\-foreignport\fP \fIport\fP]
[\fB\-localhost\fP \fIaddr\fP]
[\fB\-daemon\fP]
[\fB\-shutdown\fP (r|w) ]
[\fB\-serial\fP]
\fIcommand\fP \fIargs\fP
X
.SH DESCRIPTION
.LP
.B faucet
attempts to provide the functionality of pipes over the network.
It behaves as the server end of a server\-client connection.
When used with
.B hose(1)
it can function as a replacement for
.RS
.nf
tar \-cf \- . | rsh other "cd destdir; tar \-xf \-"
.fi
.RE
.B faucet
and
.B hose
are especially useful when you don't have easy access to the
destination machine.
X
.B faucet
creates a BSD socket, binds it to the
.I port
specified on the command line, and listens for connections.
X
Every time
.B faucet
gets a connection it exec(2)s \fIcommand\fP and its \fIargs\fP with
stdin, stdout, stderr, and/or arbitrary file descriptors redirected
according to the
.B \-in \-out \-err \-fd\fIn\fB
flags. \fBfaucet\fP also automagically shuts down the unused half of
the connection if only \fB-in\fP is specified or if only \fB-out\fP
and/or \fB-err\fP are specified. See the \fB-shutdown\fP option for
more information.
X
If the
.B \-once
flag is specified,
.B faucet
will exec(2) the
.I command
instead of fork(2)ing and exec(2)ing.
.B \-once
means that the network pipe
is only good for one shot.
X
The
.B \-verbose
flag specifies that
.B faucet
should print information about connecting hosts. This information
includes the numeric host address, host names, and foreign port numbers.
The
.B \-quiet
flag specifies that
.B faucet
should NOT print such info.
.B \-quiet
is the default.
X
The
.B \-unix
flag specifies that the
.I port
is not an internet port number or service name, but instead it is a
filename for a UNIX domain socket.
X
The
.B \-foreignhost
option specifies that faucet should reject all connections that do not
come from the
.I host
machine. Similarly
.B \-foreignport
specifies that faucet should reject all connections that are not bound
on their local machine to the
.I port
argument. The above two options allow a crude form of authentication.
Note that on most systems only root can bind a socket to a port number
below 1024.
X
.B Please
do not be fooled into thinking this makes faucet secure. There are
ways to spoof IP numbers that have been known for years (but only
publicized recently). I do think that this method is safe from DNS
spoofs, but you probably should have
.B nospoof on
in /etc/host.conf anyway.
X
.B \-localhost
specifies that the listening socket should be bound to a specific
internet address on this host. This is only useful on hosts with
several internet numbers.
X
.B \-daemon
specifies that the faucet should disassociate from the controlling
terminal once it has started listening on the socket. This is done
using the standard ``close all file descriptors, ioctl TIOCNOTTY,
fork() and parent exit'' sequence.
X
.B \-shutdown
is used to turn the (normally) bi-directional socket into a
uni-directional one
X If the `r' is present, then \fBfaucet\fP will close half the
connection to make it a read-only socket. If we try to write, it will
fail. If the remote connection tries to read, it will percieve the
socket as closed.
X If instead the `w' is present, then \fBfaucet\fP will close the
other half of the connection to make it a write-only socket. If we
try to read, we will percieve the socket as closed. If the remote
connection tries to write, it will fail.
X The default behavior is to leave both halves open, however the
shutdown of half of the connection is automagically done by certain
combinations of the \fB\-in\fP, \fB\-out\fP, and \fB\-err\fP flags.
To suppress their automagic behavior you can use (respectively) \-fd0,
\-fd1, and \-fd2.
X
.B \-serial
causes faucet to wait for one child to finish before accepting any
more connections. Serialization is a very crude form of
critical-section management.
X
.SH "EXAMPLES"
.LP
This creates a TCP\-IP socket on the local machine bound to port 3000.
.RS
.nf
example$ faucet 3000 \-out \-verbose tar \-cf \- .
.fi
.RE
Every time some process (from any machine) attempts to connect to
port 3000 on this machine the
.B faucet
program will fork(2) a process and the child will exec(2) a
.RS
.nf
tar \-cf \- .
.fi
.RE
The
.B \-out
option means that the output of the child process will have been
redirected into the new socket retrieved by the accept(2) call.
.B \-verbose
means that faucet will print information about each new connection.
X
.LP
This creates a UNIX domain socket in the current directory
.RS
.nf
example$ faucet u\-socket \-out \-err \-once \-unix csh \-c \\
X "dd if=angio.pgm | funky.perl.script"
.fi
.RE
The
.B \-out \-err
option means that stdout and stderr will be redirected in the child
process. The
.B \-once
option means that the faucet will not fork(2), but exec(2) the process
so that only the first process can connect to the u\-socket before the
faucet becomes unavailable.
X
.SH "SEE ALSO"
.BR netpipes (1),
.BR hose (1),
.BR sockdown (1),
.BR getpeername (1),
.BR socket (2),
.BR bind (2),
.BR listen (2),
.BR accept (2),
.BR shutdown (2),
.BR services (5),
.BR gethostbyaddr (3)
X
.SH "NOTES"
.LP
Doubtless there are bugs in this program, especially in the unix domain
socket portions. I welcome problem reports and would like to make
these programs as "clean" (no leftover files, sockets) as possible.
X
X Release 2.3 added support for multi-homed hosts: hosts with multiple
internet numbers (such as gateways). Before this faucet assumed that
the first internet number that gethostbyname returned was the only
one.
.B \-foreignport
authentication was weakened by this inadequacy so I beefed up the
algorithms.
.B \-foreignport
will accept a connection from any of the
internet numbers associated with the host name.
X
.SH "CREDITS"
.LP
Thanks to Steve Clift for SGI (SysV) patches.
.LP
Many people complained about the old way of specifying the command.
Thanks to whoever gave me the alternative which is now implemented.
It is much better.
.LP
Randy Fischer finally prodded me into fixing
the old lame non-handling of multi-homed host.
X
.SH "COPYRIGHT"
Copyright (C) 1992,1993,1994,1995 Robert Forsman
X
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
X
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
X
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
.SH "AUTHOR"
X Robert Forsman
X thoth@purplefrog.com
X Purple Frog Software
X http://www.purplefrog.com/~thoth/
SHAR_EOF
chmod 0644 faucet.1 ||
echo 'restore of faucet.1 failed'
Wc_c="`wc -c < 'faucet.1'`"
test 7264 -eq "$Wc_c" ||
echo 'faucet.1: original size 7264, current size' "$Wc_c"
fi
# ============= faucet.c ==============
if test -f 'faucet.c' -a X"$1" != X"-c"; then
echo 'x - skipping faucet.c (File already exists)'
else
echo 'x - extracting faucet.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'faucet.c' &&
/*
X
X faucet.c, part of
X faucet and hose: network pipe utilities
X Copyright (C) 1992-95 Robert Forsman
X
X This program is free software; you can redistribute it and/or modify
X it under the terms of the GNU General Public License as published by
X the Free Software Foundation; either version 2 of the License, or
X (at your option) any later version.
X
X This program is distributed in the hope that it will be useful,
X but WITHOUT ANY WARRANTY; without even the implied warranty of
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
X GNU General Public License for more details.
X
X You should have received a copy of the GNU General Public License
X along with this program; if not, write to the Free Software
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X */
X
static char info[] = "faucet: a network utility for sockets\nWritten 1992,1993 by Robert Forsman \n";
#include
#include
extern int errno; /* I hate the errno header file */
#include
#ifdef hpux
#include
#endif
#include
#include
#include
#ifdef USE_IOCTL
#include
#ifdef linux
#include
#else
/* find the FIOCLEX ioctl */
#include
#endif
#else
#include
#include
#include
#endif
#include
#include
#include
#include
/* for getrlimit with -daemon option */
#include
#include
#include "common.h"
X
int mastersocket;
#define DOONCE (1<<0)
#define DOVERBOSE (1<<1)
#define DOUNIX (1<<2)
#define DODAEMON (1<<3)
X
int doflags=0;
int running=1;
X
struct in_addr ** /* addr_array */ convert_hostname();
X
char *localhost=NULL;
char *foreignhost=NULL,*foreignport=NULL;
int foreignPORT;
int foreignCOUNT=0;
struct in_addr **foreignHOST;
int serialize=0;
X
extern int errno;
extern char *sys_errlist[];
X
X
int name_to_inet_port();
X
void nice_shutdown()
/* This procedure gets called when we are killed with one of the reasonable
X signals (TERM, HUP, that kind of thing). The main while loop then
X terminates and we get a chance to clean up. */
{
X running = 0;
}
X
X
/* print an internet host address prettily */
printhost(addr)
X struct in_addr *addr;
{
X struct hostent *h;
X char *s,**p;
X int i;
X
X h = gethostbyaddr((char*)addr, sizeof(*addr),AF_INET);
X s = (h==NULL) ? NULL : h->h_name;
X
X printf("%d", ((u_char*)addr)[0]);
X for (i=1; ih_aliases; *p; p++)
X printf(",%s",*p);
X printf(")");
}
X
int setup_socket(name)
char *name;
/* This procedure creates a socket and handles retries on the inet domain.
X Sockets seem to "stick" on my system (SunOS [43].x) */
{
X int sock;
X
X sock = socket((doflags&DOUNIX)?AF_UNIX:AF_INET, SOCK_STREAM, 0);
X /* I need a real value for the protocol eventually. IPPROTO_TCP sounds
X like a good value, but what about AF_UNIX sockets? It seems to have
X worked so far... */
X
X if (sock <0) {
X perror("opening stream socket");
X exit(1);
X }
X
X if (!bindlocal(sock, name, localhost, (doflags&DOUNIX)?AF_UNIX:AF_INET)) {
X fprintf(stderr,"%s: error binding stream socket %s (%s)",
X programname,name,sys_errlist[errno]);
X exit(1);
X }
X
X /* We used to ask for NOFILE (max number of open files) for the size
X of the connect queue. Linux didn't like it (NOFILE=256) so we
X hardcoded a smaller value. */
X listen(sock,8);
X
X return(sock);
}
X
X
void waitonchild()
X
{
X int status;
X
X int childpid;
X
X childpid = wait(&status);
X
#ifdef SYSV
X signal(SIGCHLD,waitonchild);
#endif
}
X
X
int
authorize_address(sin)
X struct sockaddr *sin;
{
X if (doflags&DOUNIX) {
X struct sockaddr_un *srv = (struct sockaddr_un*)sin;
X
X if (foreignport != NULL && 0!=strcmp(foreignport, srv->sun_path)) {
X if (doflags&DOVERBOSE) {
X printf("%s: refusing connection from port %s\n",
X programname, srv->sun_path);
X }
X return 0;
X }
X } else {
X struct sockaddr_in *srv = (struct sockaddr_in*)sin;
X int i;
X
X if (foreignhost) {
X for (i=0; isin_addr,
X foreignHOST[i], sizeof(struct in_addr)))
X break;
X }
X if (i>=foreignCOUNT) {
X if (doflags&DOVERBOSE) {
X printf("refusing connection from host ");
X printhost(&srv->sin_addr);
X printf(".\n");
X }
X return 0;
X }
X }
X
X if (foreignport!=NULL && foreignPORT != srv->sin_port) {
X if (doflags&DOVERBOSE) {
X printf("refusing connection from port %d.\n",
X ntohs(srv->sin_port));
X }
X return 0;
X }
X }
X
X return 1;
}
X
X
main (argc,argv)
int argc;
char ** argv;
X
{
X int rval, i;
X union {
X struct sockaddr_in in;
X struct sockaddr_un un;
X } saddr;
X struct sockaddr_in *sinp = &saddr.in;
X struct sockaddr_un *sunp = &saddr.un;
X char **cmd;
X
X programname = argv[0];
X
X if (argc<3) {
X fprintf(stderr,"Usage : %s (-in|-out|-err|-fdN)+ [-once] [-verb(|ose)] [-quiet] [-unix] [-foreignport ] [-foreignhost ] [-localhost ] [-daemon] [-shutdown (r|w)] [-serial] command args\n", programname);
X exit(1);
X }
X
X /* parse trailing args */
X for (i=2; i=0) {
X ioctl(rval, TIOCNOTTY, &rval);
X close(rval);
X if (fork()>0)
X exit(0);
X }
X }
X
X
X while (running) {
X
X {
X int length;
X
X length = sizeof(saddr);
X
X rval = accept(mastersocket,(struct sockaddr*)&saddr,&length);
X }
X
X if (rval<0) {
X if (errno==EWOULDBLOCK) {
X fprintf(stderr, "%s: No more connections to talk to.\n",programname);
X } else if (errno!=EINTR) {
X fprintf(stderr,"%s: error in accept (%s).",
X programname,sys_errlist[errno]);
X exit(1);
X }
X continue;
X }
X
X if (!authorize_address(&saddr)) {
X close(rval);
X continue;
X }
X
X if ( doflags&DOVERBOSE ) {
X printf("%s: Got connection from ",programname);
X if ( doflags&DOUNIX ) {
X printf("%s\n", sunp->sun_path);
X } else {
X printhost(&sinp->sin_addr);
X printf(" port %d\n",ntohs(sinp->sin_port));
X }
X }
X
X fflush(stdout);
X
X if ( doflags&DOONCE || fork()==0 ) {
X /* child process: frob descriptors and exec */
X char *s;
X
X if ( (doflags&(DOONCE|DOUNIX)) == (DOONCE|DOUNIX) )
X unlink(argv[1]);
X /* We don't want the unix domain socket anymore */
X
X /* put stderr somewhere safe temporarily */
X dup2(fileno(stderr),mastersocket);/*the old server socket is now closed*/
X
X /* but we don't want it to hang around after we exec... */
#ifdef USE_IOCTL
X ioctl(mastersocket,FIOCLEX,NULL);
#else
X fcntl(mastersocket,F_SETFD,FD_CLOEXEC);
#endif
X
X /* We don't need old stderr hanging around after an exec.
X The mastersocket has been closed by the dup2 */
X
X dup_n(rval); /* dup the socket onto all the chosen file descriptors */
X
X close(rval); /* rval has been properly duplicated */
X
X execvp(cmd[0], cmd);
X s ="exec failed\n";
X write(mastersocket,s,strlen(s));
X exit(0);
X } else {
X /* parent: close socket.
X Signal will arrive upon death of child. */
X close(rval);
X if (serialize) {
X int status;
X pid_t pid;
X pid = wait(&status);
X /* child has exited */
X if (pid == -1) {
X fprintf(stderr, "%s: error serializing (waiting on child) ",
X programname);
X perror("");
X }
X }
X }
X }
X
X /* clean up the socket when we're done */
X if (doflags&DOUNIX)
X unlink(argv[1]);
X close(mastersocket);
X
}
SHAR_EOF
chmod 0644 faucet.c ||
echo 'restore of faucet.c failed'
Wc_c="`wc -c < 'faucet.c'`"
test 11590 -eq "$Wc_c" ||
echo 'faucet.c: original size 11590, current size' "$Wc_c"
fi
# ============= hose.1 ==============
if test -f 'hose.1' -a X"$1" != X"-c"; then
echo 'x - skipping hose.1 (File already exists)'
else
echo 'x - extracting hose.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'hose.1' &&
.\" $Id: hose.1,v 1.7 1995/10/24 18:28:08 thoth Exp $
.\" Copyright 1992-1995 by Robert Forsman
.\""
.TH HOSE 1 "October 24, 1995"
.SH NAME
hose \- the client end of a BSD network pipe
.SH SYNOPSIS
\fBhose\fP \fIhostname\fP \fIport\fP
(\fB\-in\fP|\fB\-out\fP|\fB\-err\fP|\fB\-fd\fP\fIn\fP|\fB\-slave\fP)
[\fB\-unix\fP]
[\fB\-localport\fP \fIport\fP]
[\fB\-localhost\fP \fIaddr\fP]
[\fB\-retry\fP \fIn\fP]
[\fB\-delay\fP \fIn\fP]
[\fB\-shutdown\fP [r|w][a] ]
\fIcommand\fP \fIargs\fP
X
.SH DESCRIPTION
.LP
.B hose
attempts to provide the functionality of pipes over the network.
It behaves as the client end of a server\-client connection.
When used with
.B faucet(1)
it can function as a replacement for
.RS
.nf
tar \-cf \- . | rsh other "cd destdir; tar \-xf \-"
.fi
.RE
.B faucet
and
.B hose
are especially useful when you don't have easy access to the
destination machine.
X
.LP
.B hose
creates a BSD socket and, if the
.B \-localport
option is used, binds it to the port number (or service name)
specified immediately afterwards. If
.B \-localhost
is also specified then its argument is a local address to bind to. (
.B -localhost
is only useful on machines with multiple IP addresses.)
X
.B hose
then tries to connect to the foreign machine
.I hostname
with foreign port
.I port.
X
If successful
.B hose
redirects the socket to stdin, stdout, stderr, and/or arbitrary file
descriptors according to the
.B \-in \-out \-err \-fd\fIn\fB
flags. \fBhose\fP also automagically shuts down the unused half of
the connection if only \fB-in\fP is specified or if only \fB-out\fP
and/or \fB-err\fP are specified. See the \fB-shutdown\fP option for
more information.
X
.B hose
then exec(2)s a \fIcommand\fP with \fIargs\fP.
X
However, the \fB\-slave\fP flag turns \fBhose\fP into a primitive sort
of telnet. The \fIcommand\fP is ignored. Instead, \fBhose\fP goes
into a loop where it copies bytes from stdin to the socket, and bytes
from the socket to stdout. This is actually more useful than telnet
because telnet tries to perform interpretation on the byte stream and
generally gets in your way. \fBhose\fP just passes bytes without
mucking with them.
X
The
.B \-unix
flag specifies that the
.I port
is not an internet port number or service name, but instead it is a
filename for a UNIX domain socket. This option may be simulated by
using
.B \-unix\-
as the host name to connect to, or by renaming the
.B hose
program to \fBuhose\fP.
X
.B \-retry
.I n
allows the user to specify that
.b hose
should retry the connect(2) call for
.I n
times (or forever if
.I n
is negative).
.B \-delay
.I n
specifies how many seconds to delay between tries.
X
.B \-shutdown
is used to control two behaviors. The first set is controlled by the
`r' and `w' flags.
X If the `r' is present, then \fBhose\fP will close half the
connection to make it a read-only socket. If the child tries to
write, it will fail. If the remote connection tries to read, it will
percieve the socket as closed.
X If instead the `w' is present, then \fBhose\fP will close the other
half of the connection to make it a write-only socket. If the child
tries to read, it will percieve the socket as closed. If the remote
connection tries to write, it will fail.
X The default behavior is to leave both halves open, however the
shutdown of half of the connection is automagically done by certain
combinations of the \fB\-in\fP, \fB\-out\fP, and \fB\-err\fP flags.
To suppress their automagic behavior you can use (respectively) \-fd0,
\-fd1, and \-fd2.
X
X The other behavior is controlled by the `a' flag. If the `a' flag is
present then \fBhose\fP will fork(2) before execcing the
.I command
and when the child exits it will perform a shutdown(2) with how=2.
This closes both halves of the connection. This option is not
necessary for most applications since the closing of the file
descriptors is detected by the remote process, but some less
sophisticated network devices (such as printers) require a shutdown(2)
for proper operation.
X To make things perfectly clear, the list of acceptable arguments to
the \fB\-shutdown\fP option are `r', `w', `ra', `wa', `a'.
X
.SH "EXAMPLES"
.LP
This will connect to port 3000 on the machine reef and connect the socket
to the stdin of a tar command.
.RS
.nf
example$ hose reef 3000 \-in tar \-xf \- .
.fi
.RE
The command actually exec(2)ed by the
.B hose
program is
.RS
.nf
tar \-xf \- .
.fi
.RE
The
.B \-in
option means that the input of the child process will have been
redirected into the socket connected to reef.
X
.LP
This connects to a UNIX domain socket in the current directory
.RS
.nf
example$ hose \-unix\- u\-socket \-in csh \-c \\
X "unfunky.perl.script | dd of=sample.pgm"
.fi
.RE
The socket provides input to the csh command.
X
.SH "SEE ALSO"
.BR netpipes (1),
.BR faucet (1),
.BR sockdown (1),
.BR getpeername (1),
.BR socket (2),
.BR bind (2),
.BR connect (2),
.BR shutdown (2),
.BR services (5),
.BR gethostbyaddr (3)
X
.SH "NOTES"
.LP
Doubtless there are bugs in this program, especially in the unix domain
socket portions. I welcome problem reports and would like to make
these programs as "clean" (no leftover files, sockets) as possible.
X
X Release 2.3 added support for multi-homed hosts: hosts with multiple
internet numbers (such as gateways). Before this faucet assumed that
the first internet number that gethostbyname returned was the only
one.
.B -foreignport
authentication was weakened by this inadequacy so I beefed up the
algorithms.
.B -foreignport
X will accept a connection from any of the
internet numbers associated with the host name.
X
.SH "CREDITS"
.LP
Thanks to Steve Clift for SGI (SysV) patches.
.LP
Many people complained about the old way of specifying the command.
Thanks to whoever gave me the alternative which is now implemented.
It is much better.
.LP
Thanks to Sten Drescher for the -retry and
-delay patches and giving me the idea for the -shutdown option.
Evidently some printer doesn't appreciate the socket being close(2)d.
.LP
Randy Fischer finally prodded me into fixing
the old lame non-handling of multi-homed host.
X
X
.SH "COPYRIGHT"
Copyright (C) 1992,1993,1994,1995 Robert Forsman
X
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
X
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
X
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
.SH "AUTHOR"
X Robert Forsman
X thoth@cis.ufl.edu
X Purple Frog Software
X http://www.purplefrog.com/~thoth/
SHAR_EOF
chmod 0444 hose.1 ||
echo 'restore of hose.1 failed'
Wc_c="`wc -c < 'hose.1'`"
test 6980 -eq "$Wc_c" ||
echo 'hose.1: original size 6980, current size' "$Wc_c"
fi
# ============= hose.c ==============
if test -f 'hose.c' -a X"$1" != X"-c"; then
echo 'x - skipping hose.c (File already exists)'
else
echo 'x - extracting hose.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'hose.c' &&
/*
X
X $Id: hose.c,v 1.10 1995/10/24 19:16:07 thoth Exp thoth $, part of
X faucet and hose: network pipe utilities
X Copyright (C) 1992-95 Robert Forsman
X
X This program is free software; you can redistribute it and/or modify
X it under the terms of the GNU General Public License as published by
X the Free Software Foundation; either version 2 of the License, or
X (at your option) any later version.
X
X This program is distributed in the hope that it will be useful,
X but WITHOUT ANY WARRANTY; without even the implied warranty of
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
X GNU General Public License for more details.
X
X You should have received a copy of the GNU General Public License
X along with this program; if not, write to the Free Software
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X */
X
static char info[] = "hose: a network utility for sockets\nWritten 1992,1993 by Robert Forsman \n";
#include
#ifdef hpux
#include
#endif
#include
#include
#include
#include
#ifdef USE_IOCTL
#include
#ifdef linux
#include
#else
/* find the FIOCLEX ioctl */
#include
#endif
#else
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
X
#define DOUNIX (1<<0)
#define DOVERBOSE (1<<1)
#define DOJAM (1<<2)
#define DOSLAVE (1<<3)
X
struct in_addr ** /* addr_array */ convert_hostname();
long doflags=0;
X
int retry=0; /* how many times to retry after ECONNREFUSED */
unsigned delay=5; /* how long to wait between each retry */
int shutdn=0; /* should we fork, wait and shutdown? */
char *localport=NULL; /* local port name */
char *localaddr=NULL; /* local internet address */
char *programname;
extern int errno;
extern char *sys_errlist[];
X
X
int name_to_inet_port();
X
X
int setup_socket(hostname,portname)
char *hostname;
char *portname;
X
{
X int sock;
X struct in_addr ** addresses=0;
X struct sockaddr_un unix_addr;
X struct sockaddr_in inet_addr;
X int num_addresses;
X int length;
X int tries;
X int cstat;
X
X if (doflags&DOUNIX) {
X unix_addr.sun_family = AF_UNIX;
X strcpy( unix_addr.sun_path, portname);
X length = sizeof(struct sockaddr_un);
X num_addresses = 1;
X } else {
X inet_addr.sin_family = AF_INET;
X
X if (0==(addresses = convert_hostname(hostname, &num_addresses))) {
X fprintf(stderr, "%s: could not translate %s to a host address\n",
X programname, hostname);
X exit(1);
X }
X
X inet_addr.sin_port = name_to_inet_port(portname);
X if (inet_addr.sin_port==0) {
X fprintf(stderr,"%s: bogus port number %s\n",programname,portname);
X exit(1);
X }
X
X length = sizeof(struct sockaddr_in);
X }
X
X for (tries = 0; retry<0 || tries <= retry; tries++) {
X int j;
X
X for ( j=0; js_addr>>24)&0xff,
X (tmp->s_addr>>16)&0xff,
X (tmp->s_addr>> 8)&0xff,
X (tmp->s_addr>> 0)&0xff, ntohs(inet_addr.sin_port));
X }
X }
X cstat=connect(sock,
X (doflags&DOUNIX) ?
X ((struct sockaddr*)&unix_addr) :
X ((struct sockaddr*)&inet_addr) ,
X length);
X if (cstat==0)
X break; /* success */
X
X if (errno==ECONNREFUSED) {
X close(sock);
X sock = -1;
X } else {
X perror("connecting");
X exit(1);
X }
X }
X if (j=0 || fromsocklen>=0) {
X /********************/
X FD_ZERO(&readfds);
X FD_ZERO(&writefds);
X if (tosocklen>=0) {
X if (tosocklen==0) {
X FD_SET(0, &readfds);
X } else {
X FD_SET(sock, &writefds);
X }
X }
X if (fromsocklen>=0) {
X if (fromsocklen==0) {
X FD_SET(sock, &readfds);
X } else {
X FD_SET(1, &writefds);
X }
X }
X /********************/
X
X rval=select(sock+1, &readfds, &writefds,
X (fd_set*)0, (struct timeval*)0);
X /********************/
X if (rval<0) {
X if (errno != EINTR) {
X perror("during copyio() select(2)");
X exit(1);
X }
X } else if (rval==0) {
X break;
X }
X /********************/
X if (FD_ISSET(1, &writefds)) {
X rval = write(1, fromsockbuf, fromsocklen);
X if (rval<0) {
X perror("during copyio() write(2)(1)");
X exitval = 1;
X fromsocklen = -1;
X shutdown(sock, 0);
X } else {
X memmove(fromsockbuf, fromsockbuf+rval, fromsocklen-rval);
X fromsocklen -= rval;
X }
X }
X if (FD_ISSET(sock, &writefds)) {
X rval = write(sock, tosockbuf, tosocklen);
X if (rval<0) {
X perror("during copyio() write(2)(sock)");
X exitval = 1;
X tosocklen = -1;
X shutdown(sock, 1);
X } else {
X memmove(tosockbuf, tosockbuf+rval, tosocklen-rval);
X tosocklen -= rval;
X }
X }
X if (FD_ISSET(0, &readfds)) {
X tosocklen = read(0, tosockbuf, BSIZE);
X if (tosocklen<0) {
X perror("during copyio() read(2)(0)");
X exitval = 1;
X tosocklen = -1;
X } else if (tosocklen==0) {
X tosocklen = -1;
X shutdown(sock, 1);
X }
X }
X if (FD_ISSET(sock, &readfds)) {
X fromsocklen = read(sock, fromsockbuf, BSIZE);
X if (fromsocklen<0) {
X perror("during copyio() read(2)(0)");
X exitval = 1;
X fromsocklen = -1;
X } else if (fromsocklen==0) {
X fromsocklen = -1;
X shutdown(sock, 0);
X }
X }
X }
X exit(exitval);
}
X
void endjam()
{
X doflags &= ~DOJAM;
}
X
X
main (argc,argv)
X int argc;
X char ** argv;
X
{
X int sock,i;
X int jampipe[2];
X char **cmd;
X
X programname=argv[0];
X
X if (argc<4) {
X fprintf(stderr,"Usage : %s (-in|-out|-err|-fdN|-slave)+ [-verb(|ose)] [-unix] [-localport ] [-localhost ] [-retry n] [-delay n] [-shutdown [r|w][a]] \n",programname);
X exit(1);
X }
X if (strcmp(argv[1],"-unix-")==0 || strcmp(programname,"uhose")==0 )
X doflags |= DOUNIX;
X for (i=3; ipipe(jampipe)) {
X perror("opening jampipe");
X exit(1);
X }
X }
X
X while ( (doflags & DOJAM) && fork() ) {
X char ch;
X close (jampipe[1]);
X while (1==read(jampipe[0], &ch, 1))
X ;
X close (jampipe[0]);
X jampipe[0] = -1;
X if (0>pipe(jampipe)) {
X perror("opening jampipe");
X exit(1);
X }
X }
X
X if (doflags&DOJAM)
X close (jampipe[0]);
X
X sock = setup_socket(argv[1],argv[2]);
X
X if (doflags&DOUNIX && localport!=NULL)
X unlink(localport);
X
X if (doflags &DOSLAVE) {
X copyio(sock);
X }
X
X /* if we're to shutdown(2) the socket when the subprocess exits we
X need to fork */
X i = shutdn ? fork() : 0;
X
X if (i) {
X /* we are supposed to shutdown(2) the socket and we are the parent */
X int status;
X int pid;
X pid = wait(&status);
X if (pid != -1 && i!=pid)
X fprintf(stderr, "Strange, wait returned a child I don't know about. I'm an unwed father!\n");
X shutdown(sock, 2); /* shut the socket down nicely? */
X close(sock);
X exit( (status&0xff) ? 1 : ((status>>8)&0xff));
X } else {
X int sparefd;
X char *s;
X
X sparefd = dup(fileno(stderr));
#ifdef USE_IOCTL
X ioctl(sparefd,FIOCLEX,NULL);
#else
X fcntl(sparefd,F_SETFD,FD_CLOEXEC);
#endif
X
X dup_n(sock); /* dup the socket onto all the chosen file descriptors */
X
X close(sock);
X
X if (doflags&DOJAM)
X close (jampipe[1]);
X
X execvp(cmd[0], cmd);
X
X s ="exec failed for ";
X write(sparefd,s,strlen(s));
X write(sparefd,cmd[0],strlen(cmd[0]));
X write(sparefd,"\n",1);
X exit(1);
X }
}
SHAR_EOF
chmod 0644 hose.c ||
echo 'restore of hose.c failed'
Wc_c="`wc -c < 'hose.c'`"
test 12117 -eq "$Wc_c" ||
echo 'hose.c: original size 12117, current size' "$Wc_c"
fi
# ============= sockdown.1 ==============
if test -f 'sockdown.1' -a X"$1" != X"-c"; then
echo 'x - skipping sockdown.1 (File already exists)'
else
echo 'x - extracting sockdown.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'sockdown.1' &&
.\" $Id: sockdown.1,v 1.3 1995/10/24 18:40:05 thoth Exp thoth $ Copyright 1995 by Robert Forsman
.\""
.TH SOCKDOWN 1 "October 24, 1995"
.SH NAME
sockdown - shutdown(2) a socket
.SH SYNOPSIS
\fBsockdown\fP
[\fIfd\fP
[\fIhow\fP] ]
X
.SH DESCRIPTION
.LP
.B sockdown
performs the shutdown(2) system call on one of its file descriptors
specified by \fIfd\fP. The possible values for \fIhow\fP are
.RS
.nf
.ta +\w'(space)\0'u +\w'convert to write-only file descriptor\0'u
0 convert to write-only file descriptor
writeonly symbolic for same as above
1 convert to read-only file descriptor
readonly symbolic for same as above
2 complete shutdown. no reads or writes allowed in the future
totally symbolic for same as above
.fi
.RE
X The default \fIfd\fP is 1 (stdout) and the
default \fIhow\fP is 1.
X
.SH EXAMPLES
X
Imagine you have a machine that can perform a service (in this case
conversion from ASCII to fancy postscript) :
.RS
.nf
server$ faucet 3000 \-in \-out enscript \-2rGhp \-
.fi
.RE
You may then connect to it with a hose. However, the first example enters deadlock :
.RS
.nf
client$ hose server 3000 \-in \-out \\
X sh -c " cat blah.txt & cat > blah.ps "
.fi
.RE
The enscript blocks waiting for input from the socket because not all
of the client processes have exited. While the cat blah.txt is
finished, the cat > blah.ps is not, and will not be finished until the
remote enscript process finishes writing. The enscript process will
not finish writing until it is finished reading, but that
client->server half of the socket is still open and will not be closed
until all the client processes are done. The result is deadlock.
X
So, we use sockdown to close half of the pipe
.RS
.nf
client$ hose server 3000 \-in \-out \\
X sh -c " ( cat blah.txt ; sockdown ) & cat > blah.ps "
.fi
.RE
This way when the cat blah.txt is done, half of the socket is shut
down and the remote enscript process runs out of input, causing it to
flush its output and exit, so eventually the whole mess finishes
cleanly.
X
Note: the & on the hose is necessary to prevent another deadlock. If
we simply used the ; to serialize the two cat processes it is possible
that the enscript would fill up its write buffer before the first cat
was done causing both processes to block and preventing the second cat
from draining the pipe.
X
.SH ERRORS
.B Socket operation on non-socket
X The \fIfd\fP you specified does not refer to a socket. This happens
when you run sockdown by itself (it is unlikely that any of the file
descriptors attached to an interactive shell are actually sockets) or
if you goof up your faucet/hose command and forgot to dup(2) one of
your descriptors.
X
.B Bad file number
X You gave it a bad file number for \fIfd\fP. If you have enough
skill to actually generate this error, you probably know what is
wrong.
X
If you encounter any other errors, clue me in.
X
X
.SH "SEE ALSO"
.BR netpipes (1)
.BR faucet (1),
.BR hose (1),
.BR getpeername (1),
.BR socket (2),
.BR shutdown (2),
X
.SH NOTES
.LP
Any normal human would assume a program this simple has to be bug
free, but I am an experienced programmer.
X
X Just avoid doing anything funky like passing \fBsockdown\fP strings
and it should serve you well. You should not have to pass it any
arguments unless you are doing something fairly funky.
X
X Perhaps I should ditch the \fBshutdown -a\fP semantics on hose since
a \fBsockdown 1 2\fP would do the job.
X
.SH "CREDITS"
``Hi Mom! Hi Dad!''
X
.SH "COPYRIGHT"
Copyright (C) 1995 Robert Forsman
X
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
X
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
X
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
.SH "AUTHOR"
X Robert Forsman
X thoth@cis.ufl.edu
X Purple Frog Software
X http://www.purplefrog.com/~thoth/
SHAR_EOF
chmod 0644 sockdown.1 ||
echo 'restore of sockdown.1 failed'
Wc_c="`wc -c < 'sockdown.1'`"
test 4263 -eq "$Wc_c" ||
echo 'sockdown.1: original size 4263, current size' "$Wc_c"
fi
# ============= sockdown.c ==============
if test -f 'sockdown.c' -a X"$1" != X"-c"; then
echo 'x - skipping sockdown.c (File already exists)'
else
echo 'x - extracting sockdown.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'sockdown.c' &&
/*
X
X $Id: sockdown.c,v 1.2 1995/10/24 18:40:36 thoth Exp thoth $, part of
X faucet and hose: network pipe utilities
X Copyright (C) 1995 Robert Forsman
X
X This program is free software; you can redistribute it and/or modify
X it under the terms of the GNU General Public License as published by
X the Free Software Foundation; either version 2 of the License, or
X (at your option) any later version.
X
X This program is distributed in the hope that it will be useful,
X but WITHOUT ANY WARRANTY; without even the implied warranty of
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
X GNU General Public License for more details.
X
X You should have received a copy of the GNU General Public License
X along with this program; if not, write to the Free Software
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X */
X
static char info[] = "sockdown: a network utility for sockets\nWritten 1995 by Robert Forsman \n";
#include
X
#include
#include
#include
X
char *programname;
X
int main(argc, argv)
X int argc;
X char **argv;
{
X int fd;
X int how;
X int verbose=0;
X
X programname=argv[0];
X
X if (argc>1&&
X 0==strncmp(argv[1], "-verbose", strlen(argv[1]))) {
X verbose=1;
X argc--;
X argv++;
X }
X if (argc<2) {
X fd = 1;
X how = 1;
X } else {
X fd = atoi(argv[1]);
X if (argc<3) {
X how = 1;
X } else {
X if (0==strncmp("readonly", argv[2], strlen(argv[2]))) {
X how = 1;
X } else if (0==strncmp("writeonly", argv[2], strlen(argv[2]))) {
X how = 0;
X } else if (0==strncmp("totally", argv[2], strlen(argv[2]))) {
X how = 2;
X } else {
X how = atoi(argv[2]);
X }
X }
X }
X
X if (verbose) {
X emit_version("sockdown", 1995);
X fprintf(stderr,
X "%s: Performing shutdown on descriptor %d with mode %d\n",
X programname, fd, how);
X }
X
X if ( 0==shutdown(fd, how) ) {
X exit(0);
X } else {
X fprintf(stderr, "%s: Error %d during shutdown(%d, %d) of socket. ",
X programname, errno, fd, how);
X perror("");
X exit(1);
X }
}
SHAR_EOF
chmod 0644 sockdown.c ||
echo 'restore of sockdown.c failed'
Wc_c="`wc -c < 'sockdown.c'`"
test 2095 -eq "$Wc_c" ||
echo 'sockdown.c: original size 2095, current size' "$Wc_c"
fi
# ============= getpeername.1 ==============
if test -f 'getpeername.1' -a X"$1" != X"-c"; then
echo 'x - skipping getpeername.1 (File already exists)'
else
echo 'x - extracting getpeername.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'getpeername.1' &&
.\" $Id: getpeername.1,v 1.1 1995/10/24 18:20:15 thoth Exp $ Copyright 1995 by Robert Forsman
.\""
.TH GETPEERNAME 1 "October 24, 1995"
.SH NAME
getpeername \- get information about this or that end of the socket's connection
.SH SYNOPSIS
\fBgetpeername\fP
[ \fB\-verbose\fP ]
[ \fB\-sock\fP ]
[ \fIfd\fP ]
X
\fBgetsockname\fP
[ \fB\-verbose\fP ]
[ \fB\-peer\fP ]
[ \fIfd\fP ]
.SH DESCRIPTION
X
.B getpeername
performs a getpeername(2) system call on one of its file descriptors
specified by \fIfd\fP and prints out the results. The default \fIfd\fP
is 0 (stdin). You may cause
.B getpeername
to behave like
.B getsockname
by providing the \-sock argument.
X
.B getsockname
performs a getsockname(2) system call on one of its file descriptors
specified by \fIfd\fP and prints out the results. The default \fIfd\fP
is 0 (stdin). You may cause
.B getsockname
to behave like
.B getpeername
by providing the \-peer argument.
X
There is a severe limitation of \fBgetpeername\fP. If the remote
process has closed the connection, getpeername will fail with a
`Socket is not connected' error. This will happen with dismaying
frequency when the remote process is not dependent upon the local
process for input and it is only sending small amounts of output
before closing the connection. Hopefully the practical uses of
getpeername (if there are any) will not exercise this problem.
X
X You can use
.B getpeername
to find out the address of the opposite end of a socket. You can use
.B getsockname
to find out the address of the local end of a socket. They are in
fact the same program with different names. We will refer to both of
them by the name
.B getpeername
in the following description.
X
.B getpeername
knows how to display peer information about UNIX and Internet sockets.
If you try to use it on another type of socket, it will fail with an
"unknown address family" error. If you regularly deal with strange
sockets and wish getpeername to work with them, send me email.
X
If the socket is a UNIX domain socket, then getpeername prints the
name of the file (which is the port) on a single line. If
.B \-verbose
was specified, getpeername prints a more detailed report consisting of
the word `Unix' on the first line, the word `Port' on the second line,
and the name of the file on the third line.
X
If the socket is an Internet socket, then getpeername prints the port
number on the first line and the numeric address on the second line. If
.B \-verbose
was specified, getpeername prints a more detailed report consisting of
the word `Internet' on the first line, the word `Port' on the second
line, the port numer on the third line, the word `Host' on the fourth
line. On the fifth and following lines it prints all of the numeric
internet addresses followed by all the host names returned by the
gethostbyaddr(3) library routine.
X
.SH EASTER EGG
X
X If you specify \fB-verbose\fP twice, the program will print a
copyright notice.
X
.SH EXAMPLES
X
X I have a feeling any practical uses of the getpeername program are
fairly complicated. If you actually do use it in a non-trivial way,
drop me a line.
X
.RS
.nf
client$ hose mail.cis.ufl.edu smtp \-in ./getpeername
25
128.227.224.13
.fi
.RE
X
X You connected to mail.cis.ufl.edu on the SMTP port (port 25). For a
verbose report:
X
.RS
.nf
X aviator:80 $ ./hose mail.cis.ufl.edu smtp -in ./getpeername -v
Internet
Port
25
Host
128.227.224.13
128.227.100.196
inlet.cis.ufl.edu
.fi
.RE
X
X Now let's give an example of a race condition which will cause
getpeername to fail:
X
.RS
.nf
client$ hose www.cis.ufl.edu 80 -in ./getpeername
./getpeername: getpeername failed on descriptor 0: Socket is not connected
.fi
.RE
X
X The HTTP daemon tries to read a request, finds that half of the full
duplex connection closed (by the special behavior of the -in option on
hose(1)) and drops the connection before getpeername can query the
file descriptor. We can cause the HTTP daemon to wait for us by
leaving both halves of the duplex connection open.
X
.RS
.nf
client$ hose www.cis.ufl.edu 80 -fd0 ./getpeername -v
Internet
Port
25
Host
128.227.224.13
128.227.100.196
inlet.cis.ufl.edu
.fi
.RE
X
X And, finally, let's extract some useful information from our socket.
X
.RS
.nf
client$ hose www.cis.ufl.edu 80 -fd0 sh -c " ./getpeername -v | \\
X tail +5 | egrep -v '^[0-9.]*$' | head -1"
sand.cis.ufl.edu
.fi
.RE
X
.SH ERRORS
.B Socket operation on non-socket
X The \fIfd\fP you specified does not refer to a socket, or refers to
a socket that has been closed. This happens when you run getpeername
by itself (it is unlikely that any of the file descriptors attached to
an interactive shell are actually sockets), or if you goof up your
faucet/hose command and forgot to dup(2) one of your descriptors, or
if the remote machine manages to close the connection before
getpeername could run.
X
.B Bad file number
X You gave it a bad file number for \fIfd\fP. If you have enough
skill to actually generate this error, you probably know what is
wrong.
X
If you encounter any other errors, clue me in.
X
X
.SH "SEE ALSO"
.BR netpipes (1),
.BR faucet (1),
.BR hose (1),
.BR sockdown (1),
.BR socket (2),
.BR shutdown (2),
X
.SH NOTES
.LP
X Just avoid doing anything funky like passing \fBgetpeername\fP
strings and it should serve you well.
X
.SH "CREDITS"
X
"Hi Mom! Hi Dad!"
X
.SH "COPYRIGHT"
Copyright (C) 1995 Robert Forsman
X
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
X
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
X
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
.SH "AUTHOR"
X Robert Forsman
X thoth@cis.ufl.edu
X Purple Frog Software
X http://www.purplefrog.com/~thoth/
SHAR_EOF
chmod 0444 getpeername.1 ||
echo 'restore of getpeername.1 failed'
Wc_c="`wc -c < 'getpeername.1'`"
test 6118 -eq "$Wc_c" ||
echo 'getpeername.1: original size 6118, current size' "$Wc_c"
fi
# ============= getpeername.c ==============
if test -f 'getpeername.c' -a X"$1" != X"-c"; then
echo 'x - skipping getpeername.c (File already exists)'
else
echo 'x - extracting getpeername.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'getpeername.c' &&
/*
X
X getpeername.c, part of
X faucet and hose: network pipe utilities
X Copyright (C) 1995 Robert Forsman
X
X This program is free software; you can redistribute it and/or modify
X it under the terms of the GNU General Public License as published by
X the Free Software Foundation; either version 2 of the License, or
X (at your option) any later version.
X
X This program is distributed in the hope that it will be useful,
X but WITHOUT ANY WARRANTY; without even the implied warranty of
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
X GNU General Public License for more details.
X
X You should have received a copy of the GNU General Public License
X along with this program; if not, write to the Free Software
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X */
X
static char info[] = "getpeername: a network utility for sockets\nWritten 1995 by Robert Forsman \n";
#include
#include
extern int errno; /* I hate the errno header file */
#include
#include
#include
#include
#include
X
char *progname;
X
void usage()
{
X fprintf(stderr, "Usage: %s [ -verbose ] [ fd# ]\n", progname);
}
X
int getpeername();
int getsockname();
X
int main(argc, argv)
X int argc;
X char **argv;
{
X int i;
X int peer_not_sock = 1;
X int fd = 0; /* assume socket is attached to stdin.
X (if it's attached to stdout, our
X output will go over the socket) */
X int verbose=0;
X
X progname = argv[0];
X if (0==strcmp(progname + strlen(progname) - 11, "getsockname") &&
X (strlen(progname)<12 || progname[strlen(progname)-12] == '/'))
X peer_not_sock = 0;
X
X for (i=1; i1) {
X emit_version("sockdown", 1995);
X }
X
X {
X union {
X struct sockaddr base;
X struct sockaddr_in in;
X struct sockaddr_un un;
X } saddr;
X struct sockaddr_in *sinp = &saddr.in;
X struct sockaddr_un *sunp = &saddr.un;
X int saddrlen = sizeof(saddr);
X int (*f)();
X char *name;
X if (peer_not_sock) {
X f = getpeername;
X name = "peer";
X } else {
X f = getsockname;
X name = "sock";
X }
X
X if (0!= f(fd, &saddr, &saddrlen)) {
X fprintf(stderr, "%s: get%sname failed on descriptor %d: ", progname, name, fd);
X perror("");
X exit(1);
X }
X if (saddr.base.sa_family == AF_UNIX) {
X if (verbose) puts("Unix\nPort");
X puts(sunp->sun_path); /* with newline */
X } else if (saddr.base.sa_family == AF_INET) {
X if (verbose) puts("Internet\nPort");
X printf("%d\n", sinp->sin_port);
X if (verbose) puts("Host");
X {
X struct in_addr* addr = &sinp->sin_addr;
X int i;
X printf("%d", ((u_char*)addr)[0]);
X for (i=1; isin_addr, sizeof(sinp->sin_addr),
X AF_INET);
X if (host) {
X int j,k;
X for (j=0; host->h_addr_list[j]; j++) {
X struct in_addr *ia =
X (struct in_addr *)host->h_addr_list[j];
X if (0==memcmp(host->h_addr_list[j],
X &sinp->sin_addr, host->h_length)) {
X continue; /* skip this one */
X }
X printf("%d", ((u_char*)ia)[0]);
X for (k=1; kh_name);
X for (j=0; host->h_aliases[j]; j++) {
X puts(host->h_aliases[j]);
X }
X } else {
X puts(" (no name for host)");
X }
X }
X } else {
X fprintf(stderr, "%s: unknown address family (%d) returned by get%sname\n", saddr.base.sa_family, name);
X }
X }
}
SHAR_EOF
chmod 0644 getpeername.c ||
echo 'restore of getpeername.c failed'
Wc_c="`wc -c < 'getpeername.c'`"
test 4042 -eq "$Wc_c" ||
echo 'getpeername.c: original size 4042, current size' "$Wc_c"
fi
# ============= netpipes.1 ==============
if test -f 'netpipes.1' -a X"$1" != X"-c"; then
echo 'x - skipping netpipes.1 (File already exists)'
else
echo 'x - extracting netpipes.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'netpipes.1' &&
.\" $Id: netpipes.1,v 1.2 1995/10/24 18:30:04 thoth Exp $ Copyright 1995 by Robert Forsman
.\""
.TH NETPIPES 1 "June 12, 1995"
.SH NAME
netpipes \- a package to manipulate BSD TCP/IP stream sockets
.SH SYNOPSIS
\fBfaucet\fP \fIport\fP
(\fB\-in\fP|\fB\-out\fP|\fB\-err\fP|\fB\-fd\fP\fIn\fP)
[\fB\-once\fP]
[\fB\-verbose\fP]
[\fB\-quiet\fP]
[\fB\-unix\fP]
[\fB\-foreignhost\fP \fIaddr\fP]
[\fB\-foreignport\fP \fIport\fP]
[\fB\-localhost\fP \fIaddr\fP]
[\fB\-daemon\fP]
[\fB\-shutdown\fP (r|w) ]
[\fB\-serial\fP]
\fIcommand\fP \fIargs\fP
X
\fBhose\fP \fIhostname\fP \fIport\fP
(\fB\-in\fP|\fB\-out\fP|\fB\-err\fP|\fB\-fd\fP\fIn\fP|\fB\-slave\fP)
[\fB\-unix\fP]
[\fB\-localport\fP \fIport\fP]
[\fB\-localhost\fP \fIaddr\fP]
[\fB\-retry\fP \fIn\fP]
[\fB\-delay\fP \fIn\fP]
[\fB\-shutdown\fP [r|w][a] ]
\fIcommand\fP \fIargs\fP
X
\fBsockdown\fP
[\fIfd\fP
[\fIhow\fP] ]
X
\fBgetpeername\fP
[ \fB\-verbose\fP ]
[ \fB\-sock\fP ]
[ \fIfd\fP ]
X
\fBgetsockname\fP
[ \fB\-verbose\fP ]
[ \fB\-peer\fP ]
[ \fIfd\fP ]
X
.SH DESCRIPTION
X
X The netpipes package makes TCP/IP streams usable in shell scripts.
It can also simplify client/server code by allowing the programmer to
skip all the tedious programming bits related to sockets and
concentrate on writing a filter/service.
X
X \fBfaucet\fP is the server end of a TCP/IP stream. It listens on a
port of the local machine waiting for connections. Every time it gets
a connection it forks a process to perform a service for the
connecting client.
X
X \fBhose\fP is the client end of a TCP/IP stream. It actively
connects to a remote port and execs a process to request a service.
X
X \fBsockdown\fP is a simple program designed to shut down part or all
of the socket connection. It is primarily useful when the processes
connected to the socket perform both input and output.
X
X \fBgetpeername\fP and \fBgetsockname\fP are two names for a program
designed to print out the addresses of the ends of a socket.
\fBgetpeername\fP prints the address of the remote end and
\fBgetsockname\fP prints the address of the local end.
X
X
.SH EXAMPLES
X
Here is a simple command I often perform to transfer directory trees
between machines. (rsh does not work because one machine is connected
using SLIP and .rhosts are out of the question).
.RS
.nf
server$ faucet 3000 -out tar cf - .
client$ hose server 3000 -in tar xvf -
.fi
.RE
X
Here is a minimal HTTP client. It is so minimal it speaks old HTTP.
.RS
.nf
cairo$ hose www.cis.ufl.edu 80 -in -out \\
X sh -c "(echo 'GET /'; sockdown) & cat > result"
.fi
.RE
X
And of course, there is Nick Trown's metaserver for Netrek
.RS
.nf
cairo$ hose metaserver.ecst.csuchico.edu 3521 -in cat
.fi
.RE
X
Finally, allow me to apologize ahead of time for the convolutedness of
the following example. It requires an understanding of Bourne shell
file descriptor redirection syntax (and illustrates why csh and tcsh
suck eggs). Do not try to type this from your tcsh command line. Get
a bash (GNU's Bourne Again SHell).
.RS
.nf
server$ faucet 3000 -in -out -verbose enscript -2rGhp -
client$ ps aux | hose server 3000 -in -out \\
X sh -c " (cat <&3; sockdown ) & cat >&4 " 3<&0 4>&1 | \\
X lpr -Pps422
.fi
.RE
This proves that hose \fIcan\fP be used as part of a pipeline to
perform a sort of remote procedure call (RPC). After you have figured
out that example, you will know how to use Bourne shell to shuffle
file descriptors around. It is a handy skill.
X
Now we go to the extreme, but simplify things by using the
\fI-slave\fP option of hose. The following is a socket relay
.RS
.nf
gateway$ faucet 3000 -in -out \\
X sh -c "hose server 4000 -slave "
.fi
.RE
It's a handy little bugger when you want to tunnel through a firewall
on an occasional basis.
X
.SH "SEE ALSO"
.BR faucet (1),
.BR hose (1),
.BR sockdown (1),
.BR getpeername (1),
X
.SH "COPYRIGHT"
Copyright (C) 1995 Robert Forsman
X
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
X
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
X
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
.SH "AUTHOR"
X Robert Forsman
X thoth@cis.ufl.edu
X Purple Frog Software
X http://www.purplefrog.com/~thoth/
SHAR_EOF
chmod 0444 netpipes.1 ||
echo 'restore of netpipes.1 failed'
Wc_c="`wc -c < 'netpipes.1'`"
test 4616 -eq "$Wc_c" ||
echo 'netpipes.1: original size 4616, current size' "$Wc_c"
fi
# ============= faucet.html ==============
if test -f 'faucet.html' -a X"$1" != X"-c"; then
echo 'x - skipping faucet.html (File already exists)'
else
echo 'x - extracting faucet.html (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'faucet.html' &&
faucet
FAUCET(1)
X
NAME
faucet - a fixture for a BSD network pipe
X
SYNOPSIS
faucet
port
X (-in
|-out
|-err
|-fd
n
)+ [-once
] [-verbose
]
[-quiet
] [-unix
] [-foreignhost
addr
] [-foreignport
port
]
[-localhost
addr
] [-daemon
] [-shutdown
X (r|w) ] [-serial
]
command args
X
DESCRIPTION
faucet
X attempts to provide the functionality of pipes over
the network. It behaves as the server end of a
server-client connection. When used with hose(1)
X it can
function as a replacement for
tar -cf - . | rsh other "cd destdir; tar -xf -"
faucet
X and hose
X are especially useful when you don't have
easy access to the destination machine.
X
faucet
X creates a BSD socket, binds it to the port
X specified on the command line, and listens for connections.
Every time faucet
X gets a connection it exec(2)s command
and its args
X with stdin, stdout, stderr, and/or arbitrary
file descriptors redirected according to the -in -out -err
-fdn
X flags. faucet
X also automagically shuts down the
unused half of the connection if only -in
X is specified or
if only -out
X and/or -err
X are specified. See the -shutdown
option for more information.
If the -once
X flag is specified, faucet
X will exec(2) the
command
X instead of fork(2)ing and exec(2)ing. -once
X means
that the network pipe is only good for one shot.
The -verbose
X flag specifies that faucet
X should print
information about connecting hosts. This information
includes the numeric host address, host names, and foreign
port numbers. The -quiet
X flag specifies that faucet
should NOT print such info. -quiet
X is the default.
The -unix
X flag specifies that the port
X is not an internet
port number or service name, but instead it is a filename
for a UNIX domain socket.
The -foreignhost
X option specifies that faucet should
reject all connections that do not come from the host
machine. Similarly -foreignport
X specifies that faucet
should reject all connections that are not bound on their
local machine to the port
X argument. The above two options
allow a crude form of authentication. Note that on most
systems only root can bind a socket to a port number below
1024.
X
Please
X do not be fooled into thinking this makes faucet
secure. There are ways to spoof IP numbers that have been
known for years (but only publicized recently). I do
think that this method is safe from DNS spoofs, but you
probably should have nospoof on
X in /etc/host.conf anyway.
X
-localhost
X specifies that the listening socket should be
bound to a specific internet address on this host. This
is only useful on hosts with several internet numbers.
X
-daemon
X specifies that the faucet should disassociate from
the controlling terminal once it has started listening on
the socket. This is done using the standard ``close all
file descriptors, ioctl TIOCNOTTY, fork() and parent
exit'' sequence.
X
-shutdown
X is used to turn the (normally) bi-directional
socket into a uni-directional one
If the `r' is present, then faucet
X will close half the
connection to make it a read-only socket. If we try to
write, it will fail. If the remote connection tries to
read, it will percieve the socket as closed.
If instead the `w' is present, then faucet
X will close
the other half of the connection to make it a write-only
socket. If we try to read, we will percieve the socket as
closed. If the remote connection tries to write, it will
fail.
The default behavior is to leave both halves open, however the shutdown of half of the connection is automagically done by certain combinations of the -in
, -out
, and
-err
X flags. To suppress their automagic behavior you can
use (respectively) -fd0, -fd1, and -fd2.
X
-serial
X causes faucet to wait for one child to finish
before accepting any more connections. Serialization is a
very crude form of critical-section management.
X
EXAMPLES
This creates a TCP-IP socket on the local machine bound to
port 3000.
example$ faucet 3000 -out -verbose tar -cf - .
Every time some process (from any machine) attempts to
connect to port 3000 on this machine the faucet
X program
will fork(2) a process and the child will exec(2) a
tar -cf - .
The -out
X option means that the output of the child process
will have been redirected into the new socket retrieved by
the accept(2) call. -verbose
X means that faucet will print
information about each new connection.
This creates a UNIX domain socket in the current directory
example$ faucet u-socket -out -err -once -unix csh -c \
X "dd if=angio.pgm | funky.perl.script"
The -out -err
X option means that stdout and stderr will be
redirected in the child process. The -once
X option means
that the faucet will not fork(2), but exec(2) the process
so that only the first process can connect to the u-socket
before the faucet becomes unavailable.
X
SEE ALSO
netpipes(1),
hose(1),
sockdown(1),
getpeername(1),
socket(2),
bind(2),
listen(2),
accept(2),
shutdown(2),
services(5),
gethostbyaddr(3)
X
NOTES
Doubtless there are bugs in this program, especially in
the unix domain socket portions. I welcome problem
reports and would like to make these programs as "clean"
(no leftover files, sockets) as possible.
Release 2.3 added support for multi-homed hosts: hosts
with multiple internet numbers (such as gateways). Before
this faucet assumed that the first internet number that
gethostbyname returned was the only one. -foreignport
authentication was weakened by this inadequacy so I beefed
up the algorithms. -foreignport
X will accept a connection
from any of the internet numbers associated with the host
name.
X
CREDITS
Thanks to Steve Clift <clift@ml.csiro.au> for SGI (SysV)
patches.
Many people complained about the old way of specifying the
command. Thanks to whoever gave me the alternative which
is now implemented. It is much better.
Randy Fischer <fischer@ucet.ufl.edu> finally prodded me
into fixing the old lame non-handling of multi-homed host.
X
COPYRIGHT
Copyright (C) 1992,1993,1994,1995 Robert Forsman
This program is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
02139, USA.
X
AUTHOR
Robert Forsman
thoth@cis.ufl.edu
Purple Frog Software
http://www.purplefrog.com/~thoth/
SHAR_EOF
chmod 0644 faucet.html ||
echo 'restore of faucet.html failed'
Wc_c="`wc -c < 'faucet.html'`"
test 7904 -eq "$Wc_c" ||
echo 'faucet.html: original size 7904, current size' "$Wc_c"
fi
# ============= getpeername.html ==============
if test -f 'getpeername.html' -a X"$1" != X"-c"; then
echo 'x - skipping getpeername.html (File already exists)'
else
echo 'x - extracting getpeername.html (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'getpeername.html' &&
getpeername
GETPEERNAME(1)
X
NAME
getpeername - get information about this or that end of
the socket's connection
X
SYNOPSIS
getpeername
X [ -verbose
X ] [ -sock
X ] [ fd
X ]
X
getsockname
X [ -verbose
X ] [ -peer
X ] [ fd
X ]
X
DESCRIPTION
getpeername
X performs a getpeername(2) system call on one
of its file descriptors specified by fd
X and prints out the
results. The default fd
X is 0 (stdin). You may cause get
peername
X to behave like getsockname
X by providing the -sock
argument.
X
getsockname
X performs a getsockname(2) system call on one
of its file descriptors specified by fd
X and prints out the
results. The default fd
X is 0 (stdin). You may cause get
sockname
X to behave like getpeername
X by providing the -peer
argument.
There is a severe limitation of getpeername
. If the
remote process has closed the connection, getpeername will
fail with a `Socket is not connected' error. This will
happen with dismaying frequency when the remote process is
not dependent upon the local process for input and it is
only sending small amounts of output before closing the
connection. Hopefully the practical uses of getpeername
(if there are any) will not exercise this problem.
You can use getpeername
X to find out the address of the
opposite end of a socket. You can use getsockname
X to find
out the address of the local end of a socket. They are in
fact the same program with different names. We will refer
to both of them by the name getpeername
X in the following
description.
X
getpeername
X knows how to display peer information about
UNIX and Internet sockets. If you try to use it on
another type of socket, it will fail with an "unknown
address family" error. If you regularly deal with strange
sockets and wish getpeername to work with them, send me
email.
If the socket is a UNIX domain socket, then getpeername
prints the name of the file (which is the port) on a single line. If -verbose
X was specified, getpeername prints a
more detailed report consisting of the word `Unix' on the
first line, the word `Port' on the second line, and the
name of the file on the third line.
If the socket is an Internet socket, then getpeername
prints the port number on the first line and the numeric
address on the second line. If -verbose
X was specified,
getpeername prints a more detailed report consisting of
the word `Internet' on the first line, the word `Port' on
the second line, the port numer on the third line, the
word `Host' on the fourth line. On the fifth and following lines it prints all of the numeric internet addresses
followed by all the host names returned by the gethostbyaddr(3) library routine.
X
EASTER EGG
If you specify -verbose
X twice, the program will print a
copyright notice.
X
EXAMPLES
I have a feeling any practical uses of the getpeername
program are fairly complicated. If you actually do use it
in a non-trivial way, drop me a line.
client$ hose mail.cis.ufl.edu smtp -in ./getpeername
25
128.227.224.13
You connected to mail.cis.ufl.edu on the SMTP port (port
25). For a verbose report:
aviator:80 $ ./hose mail.cis.ufl.edu smtp -in ./getpeername -v
Internet
Port
25
Host
128.227.224.13
128.227.100.196
inlet.cis.ufl.edu
Now let's give an example of a race condition which will
cause getpeername to fail:
client$ hose www.cis.ufl.edu 80 -in ./getpeername
The HTTP daemon tries to read a request, finds that half
of the full duplex connection closed (by the special
behavior of the -in option on hose(1)) and drops the connection before getpeername can query the file descriptor.
We can cause the HTTP daemon to wait for us by leaving
both halves of the duplex connection open.
client$ hose www.cis.ufl.edu 80 -fd0 ./getpeername -v
Internet
Port
25
Host
128.227.224.13
128.227.100.196
inlet.cis.ufl.edu
And, finally, let's extract some useful information from
our socket.
client$ hose www.cis.ufl.edu 80 -fd0 sh -c " ./getpeername -v | \
X tail +5 | egrep -v '^[0-9.]*$' | head -1"
sand.cis.ufl.edu
X
ERRORS
Socket operation on non-socket
The fd
X you specified does not refer to a socket, or
refers to a socket that has been closed. This happens
when you run getpeername by itself (it is unlikely that
any of the file descriptors attached to an interactive
shell are actually sockets), or if you goof up your
faucet/hose command and forgot to dup(2) one of your
descriptors, or if the remote machine manages to close the
connection before getpeername could run.
X
Bad file number
You gave it a bad file number for fd
. If you have
enough skill to actually generate this error, you probably
know what is wrong.
If you encounter any other errors, clue me in.
X
SEE ALSO
netpipes(1),
faucet(1),
hose(1),
sockdown(1),
socket(2),
shutdown(2),
X
X
NOTES
Just avoid doing anything funky like passing getpeername
strings and it should serve you well.
X
CREDITS
``Hi Mom! Hi Dad!''
X
COPYRIGHT
Copyright (C) 1995 Robert Forsman
This program is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
02139, USA.
X
AUTHOR
Robert Forsman
thoth@cis.ufl.edu
Purple Frog Software
http://www.purplefrog.com/~thoth/
HOSE(1)
X
NAME
hose - the client end of a BSD network pipe
X
SYNOPSIS
hose
hostname port
X (-in
|-out
|-err
|-fd
n
|-slave
) [-unix
]
[-localport
port
] [-localhost
addr
] [-retry
n
] [-delay
n
]
[-shutdown
X [r|w][a] ] command args
X
DESCRIPTION
hose
X attempts to provide the functionality of pipes over
the network. It behaves as the client end of a
server-client connection. When used with faucet(1)
X it can
function as a replacement for
tar -cf - . | rsh other "cd destdir; tar -xf -"
faucet
X and hose
X are especially useful when you don't have
easy access to the destination machine.
X
hose
X creates a BSD socket and, if the -localport
X option is
used, binds it to the port number (or service name) specified immediately afterwards. If -localhost
X is also specified then its argument is a local address to bind to. (
-localhost
X is only useful on machines with multiple IP
addresses.)
X
hose
X then tries to connect to the foreign machine hostname
with foreign port port.
If successful hose
X redirects the socket to stdin, stdout,
stderr, and/or arbitrary file descriptors according to the
-in -out -err -fd
n
X flags. hose
X also automagically shuts
down the unused half of the connection if only -in
X is
specified or if only -out
X and/or -err
X are specified. See
the -shutdown
X option for more information.
X
hose
X then exec(2)s a command
X with args
.
However, the -slave
X flag turns hose
X into a primitive sort
of telnet. The command
X is ignored. Instead, hose
X goes
into a loop where it copies bytes from stdin to the
socket, and bytes from the socket to stdout. This is
actually more useful than telnet because telnet tries to
perform interpretation on the byte stream and generally
gets in your way. hose
X just passes bytes without mucking
with them.
The -unix
X flag specifies that the port
X is not an internet
port number or service name, but instead it is a filename
for a UNIX domain socket. This option may be simulated by
using -unix-
X as the host name to connect to, or by renaming the hose
X program to uhose
.
X
-retry
n
X allows the user to specify that should retry the
connect(2) call for n
X times (or forever if n
X is negative).
-delay
n
X specifies how many seconds to delay between
tries.
X
-shutdown
X is used to control two behaviors. The first set
is controlled by the `r' and `w' flags.
If the `r' is present, then hose
X will close half the
connection to make it a read-only socket. If the child
tries to write, it will fail. If the remote connection
tries to read, it will percieve the socket as closed.
If instead the `w' is present, then hose
X will close the
other half of the connection to make it a write-only
socket. If the child tries to read, it will percieve the
socket as closed. If the remote connection tries to
write, it will fail.
The default behavior is to leave both halves open, however the shutdown of half of the connection is automagically done by certain combinations of the -in
, -out
, and
-err
X flags. To suppress their automagic behavior you can
use (respectively) -fd0, -fd1, and -fd2.
The other behavior is controlled by the `a' flag. If the
`a' flag is present then hose
X will fork(2) before execcing
the command
X and when the child exits it will perform a
shutdown(2) with how=2. This closes both halves of the
connection. This option is not necessary for most applications since the closing of the file descriptors is
detected by the remote process, but some less sophisticated network devices (such as printers) require a shutdown(2) for proper operation.
To make things perfectly clear, the list of acceptable
arguments to the -shutdown
X option are `r', `w', `ra',
`wa', `a'.
X
EXAMPLES
This will connect to port 3000 on the machine reef and
connect the socket to the stdin of a tar command.
example$ hose reef 3000 -in tar -xf - .
The command actually exec(2)ed by the hose
X program is
tar -xf - .
The -in
X option means that the input of the child process
will have been redirected into the socket connected to
reef.
This connects to a UNIX domain socket in the current
directory
example$ hose -unix- u-socket -in csh -c \
X "unfunky.perl.script | dd of=sample.pgm"
The socket provides input to the csh command.
X
SEE ALSO
netpipes(1),
faucet(1),
sockdown(1),
getpeername(1),
socket(2),
bind(2),
connect(2),
shutdown(2),
services(5),
gethostbyaddr(3)
X
X
NOTES
Doubtless there are bugs in this program, especially in
the unix domain socket portions. I welcome problem
reports and would like to make these programs as "clean"
(no leftover files, sockets) as possible.
Release 2.3 added support for multi-homed hosts: hosts
with multiple internet numbers (such as gateways). Before
this faucet assumed that the first internet number that
gethostbyname returned was the only one. -foreignport
authentication was weakened by this inadequacy so I beefed
up the algorithms. -foreignport
will accept a connection from any of the internet numbers
associated with the host name.
X
CREDITS
Thanks to Steve Clift <clift@ml.csiro.au> for SGI (SysV)
patches.
Many people complained about the old way of specifying the
command. Thanks to whoever gave me the alternative which
is now implemented. It is much better.
Thanks to Sten Drescher <smd@hrt213.brooks.af.mil> for the
-retry and -delay patches and giving me the idea for the
-shutdown option. Evidently some printer doesn't appreciate the socket being close(2)d.
Randy Fischer <fischer@ucet.ufl.edu> finally prodded me
into fixing the old lame non-handling of multi-homed host.
X
COPYRIGHT
Copyright (C) 1992,1993,1994,1995 Robert Forsman
This program is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
02139, USA.
X
AUTHOR
Robert Forsman
thoth@cis.ufl.edu
Purple Frog Software
http://www.purplefrog.com/~thoth/
NETPIPES(1)
X
NAME
netpipes - a package to manipulate BSD TCP/IP stream sockets
X
SYNOPSIS
faucet
port
X (-in
|-out
|-err
|-fd
n
) [-once
] [-verbose
]
[-quiet
] [-unix
] [-foreignhost
addr
] [-foreignport
port
]
[-localhost
addr
] [-daemon
] [-shutdown
X (r|w) ] [-serial
]
command args
X
hose
hostname port
X (-in
|-out
|-err
|-fd
n
|-slave
) [-unix
]
[-localport
port
] [-localhost
addr
] [-retry
n
] [-delay
n
]
[-shutdown
X [r|w][a] ] command args
X
sockdown
X [fd
X [how
] ]
X
getpeername
X [ -verbose
X ] [ -sock
X ] [ fd
X ]
X
getsockname
X [ -verbose
X ] [ -peer
X ] [ fd
X ]
X
DESCRIPTION
The netpipes package makes TCP/IP streams usable in
shell scripts. It can also simplify client/server code by
allowing the programmer to skip all the tedious programming bits related to sockets and concentrate on writing a
filter/service.
X
faucet
X is the server end of a TCP/IP stream. It listens
on a port of the local machine waiting for connections.
Every time it gets a connection it forks a process to perform a service for the connecting client.
X
hose
X is the client end of a TCP/IP stream. It actively
connects to a remote port and execs a process to request a
service.
X
sockdown
X is a simple program designed to shut down part
or all of the socket connection. It is primarily useful
when the processes connected to the socket perform both
input and output.
X
getpeername
X and getsockname
X are two names for a program
designed to print out the addresses of the ends of a
socket. getpeername
X prints the address of the remote end
and getsockname
X prints the address of the local end.
X
EXAMPLES
Here is a simple command I often perform to transfer
directory trees between machines. (rsh does not work
because one machine is connected using SLIP and .rhosts
are out of the question).
server$ faucet 3000 -out tar cf - .
client$ hose server 3000 -in tar xvf -
Here is a minimal HTTP client. It is so minimal it speaks
old HTTP.
cairo$ hose www.cis.ufl.edu 80 -in -out \
X sh -c "(echo 'GET /'; sockdown) & cat > result"
And of course, there is Nick Trown's metaserver for Netrek
cairo$ hose metaserver.ecst.csuchico.edu 3521 -in cat
Finally, allow me to apologize ahead of time for the convolutedness of the following example. It requires an
understanding of Bourne shell file descriptor redirection
syntax (and illustrates why csh and tcsh suck eggs). Do
not try to type this from your tcsh command line. Get a
bash (GNU's Bourne Again SHell).
server$ faucet 3000 -in -out -verbose enscript -2rGhp -
client$ ps aux | hose server 3000 -in -out \
X sh -c " (cat <&3; sockdown ) & cat >&4 " 3<&0 4>&1 | \
X lpr -Pps422
This proves that hose can
X be used as part of a pipeline to
perform a sort of remote procedure call (RPC). After you
have figured out that example, you will know how to use
Bourne shell to shuffle file descriptors around. It is a
handy skill.
Now we go to the extreme, but simplify things by using the
-slave
X option of hose. The following is a socket relay
gateway$ faucet 3000 -in -out \
X sh -c "hose server 4000 -slave "
It's a handy little bugger when you want to tunnel through
a firewall on an occasional basis.
X
SEE ALSO
faucet(1),
hose(1),
sockdown(1),
getpeername(1),
X
COPYRIGHT
Copyright (C) 1995 Robert Forsman
This program is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
02139, USA.
X
AUTHOR
Robert Forsman
thoth@cis.ufl.edu
Purple Frog Software
http://www.purplefrog.com/~thoth/
SOCKDOWN(1)
X
NAME
sockdown - shutdown(2) a socket
X
SYNOPSIS
sockdown
X [fd
X [how
] ]
X
DESCRIPTION
sockdown
X performs the shutdown(2) system call on one of
its file descriptors specified by fd
. The possible values
for how
X are
0 convert to write-only file descriptor
writeonly symbolic for same as above
1 convert to read-only file descriptor
readonly symbolic for same as above
2 complete shutdown. no reads or writes allowed in the future
totally symbolic for same as above
The default fd
X is 1 (stdout) and the default how
X is 1.
X
EXAMPLES
Imagine you have a machine that can perform a service (in
this case conversion from ASCII to fancy postscript) :
server$ faucet 3000 -in -out enscript -2rGhp -
You may then connect to it with a hose. However, the
first example enters deadlock :
client$ hose server 3000 -in -out \
X sh -c " cat blah.txt & cat > blah.ps "
The enscript blocks waiting for input from the socket
because not all of the client processes have exited.
While the cat blah.txt is finished, the cat > blah.ps is
not, and will not be finished until the remote enscript
process finishes writing. The enscript process will not
finish writing until it is finished reading, but that
client->server half of the socket is still open and will
not be closed until all the client processes are done.
The result is deadlock.
So, we use sockdown to close half of the pipe
client$ hose server 3000 -in -out \
X sh -c " ( cat blah.txt ; sockdown ) & cat > blah.ps "
This way when the cat blah.txt is done, half of the socket
is shut down and the remote enscript process runs out of
input, causing it to flush its output and exit, so eventually the whole mess finishes cleanly.
Note: the & on the hose is necessary to prevent another
deadlock. If we simply used the ; to serialize the two
cat processes it is possible that the enscript would fill
up its write buffer before the first cat was done causing
both processes to block and preventing the second cat from
draining the pipe.
X
ERRORS
Socket operation on non-socket
The fd
X you specified does not refer to a socket. This
happens when you run sockdown by itself (it is unlikely
that any of the file descriptors attached to an interactive shell are actually sockets) or if you goof up your
faucet/hose command and forgot to dup(2) one of your
descriptors.
X
Bad file number
You gave it a bad file number for fd
. If you have
enough skill to actually generate this error, you probably
know what is wrong.
If you encounter any other errors, clue me in.
X
SEE ALSO
netpipes(1),
faucet(1),
hose(1),
getpeername(1),
socket(2),
shutdown(2)
X
NOTES
Any normal human would assume a program this simple has to
be bug free, but I am an experienced programmer.
Just avoid doing anything funky like passing sockdown
strings and it should serve you well. You should not have
to pass it any arguments unless you are doing something
fairly funky.
Perhaps I should ditch the shutdown -a
X semantics on hose
since a sockdown 1 2
X would do the job.
X
CREDITS
``Hi Mom! Hi Dad!''
COPYRIGHT
Copyright (C) 1995 Robert Forsman
This program is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
02139, USA.
X
AUTHOR
Robert Forsman
thoth@cis.ufl.edu
Purple Frog Software
http://www.purplefrog.com/~thoth/